diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 9de38e2be..3aa04a5c2 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -1704,6 +1704,7 @@ This delimiter is used to split the input text into several text pieces echo of parserMethod: 'Parser method', exportJson: 'Export JSON', viewResult: 'View Result', + running: 'Running', }, }, }; diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 2d81f8426..045ca20fc 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -1622,6 +1622,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 parserMethod: '解析方法', exportJson: '导出 JSON', viewResult: '查看结果', + running: '运行中', }, }, }; diff --git a/web/src/pages/data-flow/canvas/index.tsx b/web/src/pages/data-flow/canvas/index.tsx index 0ea2e6d90..a079b63c7 100644 --- a/web/src/pages/data-flow/canvas/index.tsx +++ b/web/src/pages/data-flow/canvas/index.tsx @@ -40,6 +40,7 @@ import { ButtonEdge } from './edge'; import styles from './index.less'; import { RagNode } from './node'; import { BeginNode } from './node/begin-node'; +import { ContextNode } from './node/context-node'; import { InnerNextStepDropdown } from './node/dropdown/next-step-dropdown'; import { HierarchicalMergerNode } from './node/hierarchical-merger-node'; import NoteNode from './node/note-node'; @@ -55,6 +56,7 @@ export const nodeTypes: NodeTypes = { tokenizerNode: TokenizerNode, splitterNode: SplitterNode, hierarchicalMergerNode: HierarchicalMergerNode, + contextNode: ContextNode, }; const edgeTypes = { diff --git a/web/src/pages/data-flow/canvas/node/context-node.tsx b/web/src/pages/data-flow/canvas/node/context-node.tsx new file mode 100644 index 000000000..ebeec332e --- /dev/null +++ b/web/src/pages/data-flow/canvas/node/context-node.tsx @@ -0,0 +1 @@ +export { RagNode as ContextNode } from './index'; diff --git a/web/src/pages/data-flow/canvas/node/dropdown/next-step-dropdown.tsx b/web/src/pages/data-flow/canvas/node/dropdown/next-step-dropdown.tsx index 9f5259593..ae16c43ee 100644 --- a/web/src/pages/data-flow/canvas/node/dropdown/next-step-dropdown.tsx +++ b/web/src/pages/data-flow/canvas/node/dropdown/next-step-dropdown.tsx @@ -124,6 +124,7 @@ function AccordionOperators({ Operator.Tokenizer, Operator.Splitter, Operator.HierarchicalMerger, + Operator.Context, ]} isCustomDropdown={isCustomDropdown} mousePosition={mousePosition} diff --git a/web/src/pages/data-flow/constant.tsx b/web/src/pages/data-flow/constant.tsx index a181cfc1f..6572a515e 100644 --- a/web/src/pages/data-flow/constant.tsx +++ b/web/src/pages/data-flow/constant.tsx @@ -34,6 +34,7 @@ export enum Operator { Tokenizer = 'Tokenizer', Splitter = 'Splitter', HierarchicalMerger = 'HierarchicalMerger', + Context = 'Context', } export const SwitchLogicOperatorOptions = ['and', 'or']; @@ -76,6 +77,12 @@ export enum ImageParseMethod { OCR = 'ocr', } +export enum TokenizerFields { + Text = 'text', + Questions = 'questions', + Summary = 'summary', +} + export const initialBeginValues = { mode: AgentDialogueMode.Conversational, prologue: `Hi! I'm your assistant. What can I do for you?`, @@ -100,7 +107,7 @@ export const initialTokenizerValues = { TokenizerSearchMethod.FullText, ], filename_embd_weight: 0.1, - fields: ['text'], + fields: TokenizerFields.Text, outputs: {}, }; @@ -146,6 +153,10 @@ export const initialHierarchicalMergerValues = { ], }; +export const initialContextValues = { + outputs: {}, +}; + export const CategorizeAnchorPointPositions = [ { top: 1, right: 34 }, { top: 8, right: 18 }, @@ -178,6 +189,7 @@ export const NodeMap = { [Operator.Tokenizer]: 'tokenizerNode', [Operator.Splitter]: 'splitterNode', [Operator.HierarchicalMerger]: 'hierarchicalMergerNode', + [Operator.Context]: 'contextNode', }; export enum BeginQueryType { diff --git a/web/src/pages/data-flow/form-sheet/form-config-map.tsx b/web/src/pages/data-flow/form-sheet/form-config-map.tsx index 707e48111..a50521747 100644 --- a/web/src/pages/data-flow/form-sheet/form-config-map.tsx +++ b/web/src/pages/data-flow/form-sheet/form-config-map.tsx @@ -1,4 +1,5 @@ import { Operator } from '../constant'; +import ContextForm from '../form/context-form'; import HierarchicalMergerForm from '../form/hierarchical-merger-form'; import ParserForm from '../form/parser-form'; import SplitterForm from '../form/splitter-form'; @@ -23,4 +24,7 @@ export const FormConfigMap = { [Operator.HierarchicalMerger]: { component: HierarchicalMergerForm, }, + [Operator.Context]: { + component: ContextForm, + }, }; diff --git a/web/src/pages/data-flow/form/context-form/index.tsx b/web/src/pages/data-flow/form/context-form/index.tsx new file mode 100644 index 000000000..337965c57 --- /dev/null +++ b/web/src/pages/data-flow/form/context-form/index.tsx @@ -0,0 +1,102 @@ +import { DelimiterInput } from '@/components/delimiter-form-field'; +import { RAGFlowFormItem } from '@/components/ragflow-form'; +import { SliderInputFormField } from '@/components/slider-input-form-field'; +import { BlockButton, Button } from '@/components/ui/button'; +import { Form } from '@/components/ui/form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { Trash2 } from 'lucide-react'; +import { memo } from 'react'; +import { useFieldArray, useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { z } from 'zod'; +import { initialContextValues } from '../../constant'; +import { useFormValues } from '../../hooks/use-form-values'; +import { useWatchFormChange } from '../../hooks/use-watch-form-change'; +import { INextOperatorForm } from '../../interface'; +import { buildOutputList } from '../../utils/build-output-list'; +import { FormWrapper } from '../components/form-wrapper'; +import { Output } from '../components/output'; + +const outputList = buildOutputList(initialContextValues.outputs); + +export const FormSchema = z.object({ + chunk_token_size: z.number(), + delimiters: z.array( + z.object({ + value: z.string().optional(), + }), + ), + overlapped_percent: z.number(), // 0.0 - 0.3 +}); + +export type ContextFormSchemaType = z.infer; + +const ContextForm = ({ node }: INextOperatorForm) => { + const defaultValues = useFormValues(initialContextValues, node); + const { t } = useTranslation(); + + const form = useForm({ + defaultValues, + resolver: zodResolver(FormSchema), + }); + const name = 'delimiters'; + + const { fields, append, remove } = useFieldArray({ + name: name, + control: form.control, + }); + + useWatchFormChange(node?.id, form); + + return ( +
+ + + +
+ {t('flow.delimiters')} +
+ {fields.map((field, index) => ( +
+
+ + + +
+ +
+ ))} +
+
+ append({ value: '\n' })}> + {t('common.add')} + +
+
+ +
+
+ ); +}; + +export default memo(ContextForm); diff --git a/web/src/pages/data-flow/form/tokenizer-form/index.tsx b/web/src/pages/data-flow/form/tokenizer-form/index.tsx index c9b272d46..9acc0e2be 100644 --- a/web/src/pages/data-flow/form/tokenizer-form/index.tsx +++ b/web/src/pages/data-flow/form/tokenizer-form/index.tsx @@ -1,3 +1,4 @@ +import { SelectWithSearch } from '@/components/originui/select-with-search'; import { RAGFlowFormItem } from '@/components/ragflow-form'; import { SliderInputFormField } from '@/components/slider-input-form-field'; import { Form } from '@/components/ui/form'; @@ -8,7 +9,11 @@ import { memo } from 'react'; import { useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { z } from 'zod'; -import { initialTokenizerValues, TokenizerSearchMethod } from '../../constant'; +import { + initialTokenizerValues, + TokenizerFields, + TokenizerSearchMethod, +} from '../../constant'; import { useFormValues } from '../../hooks/use-form-values'; import { useWatchFormChange } from '../../hooks/use-watch-form-change'; import { INextOperatorForm } from '../../interface'; @@ -21,11 +26,12 @@ const outputList = buildOutputList(initialTokenizerValues.outputs); export const FormSchema = z.object({ search_method: z.array(z.string()).min(1), filename_embd_weight: z.number(), + fields: z.string(), }); const SearchMethodOptions = buildOptions(TokenizerSearchMethod); -const FieldsOptions = [{ label: 'text', value: 'text' }]; +const FieldsOptions = buildOptions(TokenizerFields); const TokenizerForm = ({ node }: INextOperatorForm) => { const { t } = useTranslation(); @@ -62,14 +68,7 @@ const TokenizerForm = ({ node }: INextOperatorForm) => { step={0.01} > - {(field) => ( - - )} + {(field) => }
diff --git a/web/src/pages/data-flow/hooks/use-add-node.ts b/web/src/pages/data-flow/hooks/use-add-node.ts index 3c10417e6..111f81e75 100644 --- a/web/src/pages/data-flow/hooks/use-add-node.ts +++ b/web/src/pages/data-flow/hooks/use-add-node.ts @@ -8,6 +8,7 @@ import { NodeMap, Operator, initialBeginValues, + initialContextValues, initialHierarchicalMergerValues, initialNoteValues, initialParserValues, @@ -29,6 +30,7 @@ export const useInitializeOperatorParams = () => { [Operator.Tokenizer]: initialTokenizerValues, [Operator.Splitter]: initialSplitterValues, [Operator.HierarchicalMerger]: initialHierarchicalMergerValues, + [Operator.Context]: initialContextValues, }; }, []); diff --git a/web/src/pages/data-flow/index.tsx b/web/src/pages/data-flow/index.tsx index 02d8ce6ca..8c97d6fac 100644 --- a/web/src/pages/data-flow/index.tsx +++ b/web/src/pages/data-flow/index.tsx @@ -136,9 +136,13 @@ export default function DataFlow() { > {t('flow.save')} -
diff --git a/web/src/pages/data-flow/log-sheet/index.tsx b/web/src/pages/data-flow/log-sheet/index.tsx index 220edccd0..a907ce52e 100644 --- a/web/src/pages/data-flow/log-sheet/index.tsx +++ b/web/src/pages/data-flow/log-sheet/index.tsx @@ -40,7 +40,10 @@ export function LogSheet({ return ( - + e.preventDefault()} + > {t('flow.log')}