mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-25 08:06:48 +08:00
### What problem does this PR solve? Feat: Add VariablePickerMenuPlugin to select variables in the prompt text box by menu #4764 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -2,11 +2,8 @@ import LLMLabel from '@/components/llm-select/llm-label';
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { IGenerateNode } from '@/interfaces/database/flow';
|
||||
import { Handle, NodeProps, Position } from '@xyflow/react';
|
||||
import { Flex } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { get } from 'lodash';
|
||||
import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query';
|
||||
import { IGenerateParameter } from '../../interface';
|
||||
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
|
||||
import styles from './index.less';
|
||||
import NodeHeader from './node-header';
|
||||
@ -17,8 +14,6 @@ export function GenerateNode({
|
||||
isConnectable = true,
|
||||
selected,
|
||||
}: NodeProps<IGenerateNode>) {
|
||||
const parameters: IGenerateParameter[] = get(data, 'form.parameters', []);
|
||||
const getLabel = useGetComponentLabelByValue(id);
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<section
|
||||
@ -57,21 +52,6 @@ export function GenerateNode({
|
||||
<div className={styles.nodeText}>
|
||||
<LLMLabel value={get(data, 'form.llm_id')}></LLMLabel>
|
||||
</div>
|
||||
<Flex gap={8} vertical className={styles.generateParameters}>
|
||||
{parameters.map((x) => (
|
||||
<Flex
|
||||
key={x.id}
|
||||
align="center"
|
||||
gap={6}
|
||||
className={styles.conditionBlock}
|
||||
>
|
||||
<label htmlFor="">{x.key}</label>
|
||||
<span className={styles.parameterValue}>
|
||||
{getLabel(x.component_id)}
|
||||
</span>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@ -671,7 +671,6 @@ export const RestrictedUpstreamMap = {
|
||||
Operator.Message,
|
||||
Operator.Generate,
|
||||
Operator.RewriteQuestion,
|
||||
Operator.Categorize,
|
||||
Operator.Relevant,
|
||||
],
|
||||
[Operator.KeywordExtract]: [
|
||||
|
||||
6
web/src/pages/flow/context.ts
Normal file
6
web/src/pages/flow/context.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { RAGFlowNodeType } from '@/interfaces/database/flow';
|
||||
import { createContext } from 'react';
|
||||
|
||||
export const FlowFormContext = createContext<RAGFlowNodeType | undefined>(
|
||||
undefined,
|
||||
);
|
||||
@ -2,7 +2,7 @@ import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { IModalProps } from '@/interfaces/common';
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import { Drawer, Flex, Form, Input } from 'antd';
|
||||
import { lowerFirst } from 'lodash';
|
||||
import { get, isPlainObject, lowerFirst } from 'lodash';
|
||||
import { Play } from 'lucide-react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { BeginId, Operator, operatorMap } from '../constant';
|
||||
@ -40,10 +40,15 @@ import WikipediaForm from '../form/wikipedia-form';
|
||||
import YahooFinanceForm from '../form/yahoo-finance-form';
|
||||
import { useHandleFormValuesChange, useHandleNodeNameChange } from '../hooks';
|
||||
import OperatorIcon from '../operator-icon';
|
||||
import { getDrawerWidth, needsSingleStepDebugging } from '../utils';
|
||||
import {
|
||||
buildCategorizeListFromObject,
|
||||
getDrawerWidth,
|
||||
needsSingleStepDebugging,
|
||||
} from '../utils';
|
||||
import SingleDebugDrawer from './single-debug-drawer';
|
||||
|
||||
import { RAGFlowNodeType } from '@/interfaces/database/flow';
|
||||
import { FlowFormContext } from '../context';
|
||||
import { RunTooltip } from '../flow-tooltip';
|
||||
import IterationForm from '../form/iteration-from';
|
||||
import styles from './index.less';
|
||||
@ -122,10 +127,21 @@ const FormDrawer = ({
|
||||
if (node?.id !== previousId.current) {
|
||||
form.resetFields();
|
||||
}
|
||||
form.setFieldsValue(node?.data?.form);
|
||||
|
||||
if (operatorName === Operator.Categorize) {
|
||||
const items = buildCategorizeListFromObject(
|
||||
get(node, 'data.form.category_description', {}),
|
||||
);
|
||||
const formData = node?.data?.form;
|
||||
if (isPlainObject(formData)) {
|
||||
form.setFieldsValue({ ...formData, items });
|
||||
}
|
||||
} else {
|
||||
form.setFieldsValue(node?.data?.form);
|
||||
}
|
||||
previousId.current = node?.id;
|
||||
}
|
||||
}, [visible, form, node?.data?.form, node?.id]);
|
||||
}, [visible, form, node?.data?.form, node?.id, node, operatorName]);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
@ -176,11 +192,13 @@ const FormDrawer = ({
|
||||
>
|
||||
<section className={styles.formWrapper}>
|
||||
{visible && (
|
||||
<OperatorForm
|
||||
onValuesChange={handleValuesChange}
|
||||
form={form}
|
||||
node={node}
|
||||
></OperatorForm>
|
||||
<FlowFormContext.Provider value={node}>
|
||||
<OperatorForm
|
||||
onValuesChange={handleValuesChange}
|
||||
form={form}
|
||||
node={node}
|
||||
></OperatorForm>
|
||||
</FlowFormContext.Provider>
|
||||
)}
|
||||
</section>
|
||||
{singleDebugDrawerVisible && (
|
||||
|
||||
@ -1,38 +1,10 @@
|
||||
import get from 'lodash/get';
|
||||
import omit from 'lodash/omit';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import {
|
||||
ICategorizeItem,
|
||||
ICategorizeItemResult,
|
||||
IOperatorForm,
|
||||
} from '../../interface';
|
||||
import useGraphStore from '../../store';
|
||||
|
||||
/**
|
||||
* convert the following object into a list
|
||||
*
|
||||
* {
|
||||
"product_related": {
|
||||
"description": "The question is about product usage, appearance and how it works.",
|
||||
"examples": "Why it always beaming?\nHow to install it onto the wall?\nIt leaks, what to do?",
|
||||
"to": "generate:0"
|
||||
}
|
||||
}
|
||||
*/
|
||||
const buildCategorizeListFromObject = (
|
||||
categorizeItem: ICategorizeItemResult,
|
||||
) => {
|
||||
// Categorize's to field has two data sources, with edges as the data source.
|
||||
// Changes in the edge or to field need to be synchronized to the form field.
|
||||
return Object.keys(categorizeItem)
|
||||
.reduce<Array<ICategorizeItem>>((pre, cur) => {
|
||||
// synchronize edge data to the to field
|
||||
|
||||
pre.push({ name: cur, ...categorizeItem[cur] });
|
||||
return pre;
|
||||
}, [])
|
||||
.sort((a, b) => a.index - b.index);
|
||||
};
|
||||
} from '@/interfaces/database/flow';
|
||||
import omit from 'lodash/omit';
|
||||
import { useCallback } from 'react';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
/**
|
||||
* Convert the list in the following form into an object
|
||||
@ -58,12 +30,7 @@ const buildCategorizeObjectFromList = (list: Array<ICategorizeItem>) => {
|
||||
|
||||
export const useHandleFormValuesChange = ({
|
||||
onValuesChange,
|
||||
form,
|
||||
nodeId,
|
||||
}: IOperatorForm) => {
|
||||
const getNode = useGraphStore((state) => state.getNode);
|
||||
const node = getNode(nodeId);
|
||||
|
||||
const handleValuesChange = useCallback(
|
||||
(changedValues: any, values: any) => {
|
||||
onValuesChange?.(changedValues, {
|
||||
@ -74,14 +41,5 @@ export const useHandleFormValuesChange = ({
|
||||
[onValuesChange],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const items = buildCategorizeListFromObject(
|
||||
get(node, 'data.form.category_description', {}),
|
||||
);
|
||||
form?.setFieldsValue({
|
||||
items,
|
||||
});
|
||||
}, [form, node]);
|
||||
|
||||
return { handleValuesChange };
|
||||
};
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import LLMSelect from '@/components/llm-select';
|
||||
import MessageHistoryWindowSizeItem from '@/components/message-history-window-size-item';
|
||||
import { PromptEditor } from '@/components/prompt-editor';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, Switch } from 'antd';
|
||||
import { Form, Switch } from 'antd';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import DynamicParameters from './dynamic-parameters';
|
||||
|
||||
const GenerateForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
const GenerateForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
return (
|
||||
@ -35,7 +35,7 @@ const GenerateForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input.TextArea rows={8} />
|
||||
<PromptEditor></PromptEditor>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={['cite']}
|
||||
@ -49,7 +49,6 @@ const GenerateForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
<MessageHistoryWindowSizeItem
|
||||
initialValue={12}
|
||||
></MessageHistoryWindowSizeItem>
|
||||
<DynamicParameters node={node}></DynamicParameters>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { Form, Input } from 'antd';
|
||||
import { PromptEditor } from '@/components/prompt-editor';
|
||||
import { Form } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import DynamicParameters from '../generate-form/dynamic-parameters';
|
||||
|
||||
const TemplateForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
const TemplateForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@ -15,10 +15,8 @@ const TemplateForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
layout={'vertical'}
|
||||
>
|
||||
<Form.Item name={['content']} label={t('flow.content')}>
|
||||
<Input.TextArea rows={8} placeholder={t('flow.blank')} />
|
||||
<PromptEditor></PromptEditor>
|
||||
</Form.Item>
|
||||
|
||||
<DynamicParameters node={node}></DynamicParameters>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import {
|
||||
DSLComponents,
|
||||
ICategorizeItem,
|
||||
ICategorizeItemResult,
|
||||
RAGFlowNodeType,
|
||||
} from '@/interfaces/database/flow';
|
||||
@ -389,3 +390,29 @@ export const generateDuplicateNode = (
|
||||
dragHandle: getNodeDragHandle(label),
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* convert the following object into a list
|
||||
*
|
||||
* {
|
||||
"product_related": {
|
||||
"description": "The question is about product usage, appearance and how it works.",
|
||||
"examples": "Why it always beaming?\nHow to install it onto the wall?\nIt leaks, what to do?",
|
||||
"to": "generate:0"
|
||||
}
|
||||
}
|
||||
*/
|
||||
export const buildCategorizeListFromObject = (
|
||||
categorizeItem: ICategorizeItemResult,
|
||||
) => {
|
||||
// Categorize's to field has two data sources, with edges as the data source.
|
||||
// Changes in the edge or to field need to be synchronized to the form field.
|
||||
return Object.keys(categorizeItem)
|
||||
.reduce<Array<ICategorizeItem>>((pre, cur) => {
|
||||
// synchronize edge data to the to field
|
||||
|
||||
pre.push({ name: cur, ...categorizeItem[cur] });
|
||||
return pre;
|
||||
}, [])
|
||||
.sort((a, b) => a.index - b.index);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user