mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +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:
@ -6,6 +6,12 @@ const list = new Array(15).fill({
|
||||
content: `Lorem ipsum odor amet, consectetuer adipiscing elit. Ullamcorper vulputate id laoreet malesuada commodo molestie. Lectus convallis class euismod; consequat in curabitur. Ablandit praesent inceptos nibh placerat lectus fringilla finibus. Hac vivamus id scelerisque et gravida nec ligula et non. Consectetur eu himenaeos eget felis quis habitant tellus. Tellus commodo inceptos litora habitant per himenaeos faucibus pretium. Gravida velit pretium amet purus rhoncus taciti. `,
|
||||
});
|
||||
|
||||
const SimilarityList = [
|
||||
{ label: '混合相似度', value: 45.88 },
|
||||
{ label: '关键词似度', value: 45.88 },
|
||||
{ label: '向量相似度', value: 45.88 },
|
||||
];
|
||||
|
||||
export default function RetrievalTesting() {
|
||||
return (
|
||||
<section className="flex divide-x h-full">
|
||||
@ -13,7 +19,7 @@ export default function RetrievalTesting() {
|
||||
<TestingForm></TestingForm>
|
||||
</div>
|
||||
<div className="p-4 flex-1 ">
|
||||
<h2 className="text-3xl font-bold mb-8 px-[10%]">
|
||||
<h2 className="text-4xl font-bold mb-8 px-[10%]">
|
||||
15 Results from 3 files
|
||||
</h2>
|
||||
<section className="flex flex-col gap-4 overflow-auto h-[83vh] px-[10%]">
|
||||
@ -25,24 +31,18 @@ export default function RetrievalTesting() {
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="bg-colors-background-inverse-strong p-2 rounded-xl text-base"
|
||||
>
|
||||
混合相似度 45.88
|
||||
</Badge>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="bg-colors-background-inverse-strong p-2 rounded-xl text-base"
|
||||
>
|
||||
关键词似度 45.88
|
||||
</Badge>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="bg-colors-background-inverse-strong p-2 rounded-xl text-base"
|
||||
>
|
||||
向量相似度 45.88
|
||||
</Badge>
|
||||
{SimilarityList.map((x, idx) => (
|
||||
<Badge
|
||||
key={idx}
|
||||
variant="outline"
|
||||
className="bg-colors-background-inverse-strong p-1.5 rounded-xl text-colors-text-inverse-weak text-base"
|
||||
>
|
||||
{x.label}
|
||||
<span className="text-colors-text-inverse-strong ml-1 text-lg leading-none">
|
||||
{x.value}
|
||||
</span>
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
@ -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