diff --git a/web/src/components/auto-keywords-form-field.tsx b/web/src/components/auto-keywords-form-field.tsx new file mode 100644 index 000000000..d25a7af1f --- /dev/null +++ b/web/src/components/auto-keywords-form-field.tsx @@ -0,0 +1,30 @@ +import { useTranslate } from '@/hooks/common-hooks'; +import { SliderInputFormField } from './slider-input-form-field'; + +export function AutoKeywordsFormField() { + const { t } = useTranslate('knowledgeDetails'); + + return ( + + ); +} + +export function AutoQuestionsFormField() { + const { t } = useTranslate('knowledgeDetails'); + + return ( + + ); +} diff --git a/web/src/components/chunk-method-dialog/index.tsx b/web/src/components/chunk-method-dialog/index.tsx index add64edba..764ea4989 100644 --- a/web/src/components/chunk-method-dialog/index.tsx +++ b/web/src/components/chunk-method-dialog/index.tsx @@ -14,21 +14,42 @@ import { FormLabel, FormMessage, } from '@/components/ui/form'; +import { DocumentParserType } from '@/constants/knowledge'; import { useTranslate } from '@/hooks/common-hooks'; +import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request'; import { IModalProps } from '@/interfaces/common'; import { IParserConfig } from '@/interfaces/database/document'; import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; import { zodResolver } from '@hookform/resolvers/zod'; -import { useForm } from 'react-hook-form'; +import {} from 'module'; +import { useMemo } from 'react'; +import { useForm, useWatch } from 'react-hook-form'; import { z } from 'zod'; import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '../ui/select'; -import { useFetchParserListOnMount } from './hooks'; + AutoKeywordsFormField, + AutoQuestionsFormField, +} from '../auto-keywords-form-field'; +import { DatasetConfigurationContainer } from '../dataset-configuration-container'; +import { DelimiterFormField } from '../delimiter-form-field'; +import { EntityTypesFormField } from '../entity-types-form-field'; +import { ExcelToHtmlFormField } from '../excel-to-html-form-field'; +import { + DocumentType, + LayoutRecognizeFormField, +} from '../layout-recognize-form-field'; +import { MaxTokenNumberFormField } from '../max-token-number-from-field'; +import { + UseGraphRagFormField, + showGraphRagItems, +} from '../parse-configuration/graph-rag-form-fields'; +import RaptorFormFields, { + showRaptorParseConfiguration, +} from '../parse-configuration/raptor-form-fields'; +import { Input } from '../ui/input'; +import { RAGFlowSelect } from '../ui/select'; +import { useFetchParserListOnMount, useShowAutoKeywords } from './hooks'; + +const FormId = 'ChunkMethodDialogForm'; interface IProps extends IModalProps<{ @@ -42,6 +63,15 @@ interface IProps documentId: string; } +const hidePagesChunkMethods = [ + DocumentParserType.Qa, + DocumentParserType.Table, + DocumentParserType.Picture, + DocumentParserType.Resume, + DocumentParserType.One, + DocumentParserType.KnowledgeGraph, +]; + export function ChunkMethodDialog({ hideModal, onOk, @@ -58,68 +88,171 @@ export function ChunkMethodDialog({ // form, ); + const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration(); + + const useGraphRag = useMemo(() => { + return knowledgeDetails.parser_config?.graphrag?.use_graphrag; + }, [knowledgeDetails.parser_config?.graphrag?.use_graphrag]); + const FormSchema = z.object({ - name: z + parser_id: z .string() .min(1, { message: 'namePlaceholder', }) .trim(), + parser_config: z.object({ + task_page_size: z.coerce.number(), + layout_recognize: z.string(), + }), }); const form = useForm>({ resolver: zodResolver(FormSchema), - defaultValues: { name: '' }, + defaultValues: { + parser_id: parserId, + parser_config: { + task_page_size: 12, + layout_recognize: DocumentType.DeepDOC, + }, + }, }); + const layoutRecognize = useWatch({ + name: 'parser_config.layout_recognize', + control: form.control, + }); + + const selectedTag = useWatch({ + name: 'parser_id', + control: form.control, + }); + + const isPdf = documentExtension === 'pdf'; + + const showPages = useMemo(() => { + return isPdf && hidePagesChunkMethods.every((x) => x !== selectedTag); + }, [selectedTag, isPdf]); + + const showOne = useMemo(() => { + return ( + isPdf && + hidePagesChunkMethods + .filter((x) => x !== DocumentParserType.One) + .every((x) => x !== selectedTag) + ); + }, [selectedTag, isPdf]); + + const showMaxTokenNumber = + selectedTag === DocumentParserType.Naive || + selectedTag === DocumentParserType.KnowledgeGraph; + + const showEntityTypes = selectedTag === DocumentParserType.KnowledgeGraph; + + const showExcelToHtml = + selectedTag === DocumentParserType.Naive && documentExtension === 'xlsx'; + + const showAutoKeywords = useShowAutoKeywords(); + async function onSubmit(data: z.infer) { - const ret = await onOk?.(); - if (ret) { - hideModal?.(); - } + console.log('🚀 ~ onSubmit ~ data:', data); + // const ret = await onOk?.(); + // if (ret) { + // hideModal?.(); + // } } return ( - + {t('chunkMethod')}
- + ( {t('name')} - + options={parserList} + > )} /> + {showPages && layoutRecognize && ( + ( + + + {t('taskPageSize')} + + + + + + + )} + /> + )} + + {showOne && } + {showMaxTokenNumber && ( + <> + + + + )} + + + {showAutoKeywords(selectedTag) && ( + <> + + + + )} + {showExcelToHtml && } + + {showRaptorParseConfiguration( + selectedTag as DocumentParserType, + ) && ( + + + + )} + {showGraphRagItems(selectedTag as DocumentParserType) && + useGraphRag && } + {showEntityTypes && } - +
diff --git a/web/src/components/delimiter-form-field.tsx b/web/src/components/delimiter-form-field.tsx new file mode 100644 index 000000000..8b5c8d635 --- /dev/null +++ b/web/src/components/delimiter-form-field.tsx @@ -0,0 +1,59 @@ +import { forwardRef } from 'react'; +import { useFormContext } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from './ui/form'; +import { Input, InputProps } from './ui/input'; + +interface IProps { + value?: string | undefined; + onChange?: (val: string | undefined) => void; +} + +export const DelimiterInput = forwardRef( + ({ value, onChange, maxLength, defaultValue }, ref) => { + const nextValue = value?.replaceAll('\n', '\\n'); + const handleInputChange = (e: React.ChangeEvent) => { + const val = e.target.value; + const nextValue = val.replaceAll('\\n', '\n'); + onChange?.(nextValue); + }; + return ( + + ); + }, +); + +export function DelimiterFormField() { + const { t } = useTranslation(); + const form = useFormContext(); + + return ( + ( + + + {t('knowledgeDetails.delimiter')} + + + + + + + )} + /> + ); +} diff --git a/web/src/components/entity-types-form-field.tsx b/web/src/components/entity-types-form-field.tsx new file mode 100644 index 000000000..6cf3e364b --- /dev/null +++ b/web/src/components/entity-types-form-field.tsx @@ -0,0 +1,37 @@ +import { useTranslate } from '@/hooks/common-hooks'; +import { useFormContext } from 'react-hook-form'; +import EditTag from './edit-tag'; +import { + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from './ui/form'; + +type EntityTypesFormFieldProps = { + name?: string; +}; + +export function EntityTypesFormField({ + name = 'parser_config.entity_types', +}: EntityTypesFormFieldProps) { + const { t } = useTranslate('knowledgeConfiguration'); + const form = useFormContext(); + + return ( + ( + + {t('entityTypes')} + + + + + + )} + /> + ); +} diff --git a/web/src/components/excel-to-html-form-field.tsx b/web/src/components/excel-to-html-form-field.tsx new file mode 100644 index 000000000..2e4ba1139 --- /dev/null +++ b/web/src/components/excel-to-html-form-field.tsx @@ -0,0 +1,34 @@ +import { useTranslate } from '@/hooks/common-hooks'; +import { useFormContext } from 'react-hook-form'; +import { + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from './ui/form'; +import { Switch } from './ui/switch'; + +export function ExcelToHtmlFormField() { + const form = useFormContext(); + const { t } = useTranslate('knowledgeDetails'); + + return ( + ( + + {t('html4excel')} + + + + + + )} + /> + ); +} diff --git a/web/src/components/layout-recognize-form-field.tsx b/web/src/components/layout-recognize-form-field.tsx new file mode 100644 index 000000000..0c95ef660 --- /dev/null +++ b/web/src/components/layout-recognize-form-field.tsx @@ -0,0 +1,70 @@ +import { LlmModelType } from '@/constants/knowledge'; +import { useTranslate } from '@/hooks/common-hooks'; +import { useSelectLlmOptionsByModelType } from '@/hooks/llm-hooks'; +import { camelCase } from 'lodash'; +import { useMemo } from 'react'; +import { useFormContext } from 'react-hook-form'; +import { + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from './ui/form'; +import { RAGFlowSelect } from './ui/select'; + +export const enum DocumentType { + DeepDOC = 'DeepDOC', + PlainText = 'Plain Text', +} + +export function LayoutRecognizeFormField() { + const form = useFormContext(); + + const { t } = useTranslate('knowledgeDetails'); + const allOptions = useSelectLlmOptionsByModelType(); + + const options = useMemo(() => { + const list = [DocumentType.DeepDOC, DocumentType.PlainText].map((x) => ({ + label: x === DocumentType.PlainText ? t(camelCase(x)) : 'DeepDoc', + value: x, + })); + + const image2TextList = allOptions[LlmModelType.Image2text].map((x) => { + return { + ...x, + options: x.options.map((y) => { + return { + ...y, + label: ( +
+ {y.label} + Experimental +
+ ), + }; + }), + }; + }); + + return [...list, ...image2TextList]; + }, [allOptions, t]); + + return ( + ( + + + {t('layoutRecognize')} + + + + + + + )} + /> + ); +} diff --git a/web/src/components/max-token-number-from-field.tsx b/web/src/components/max-token-number-from-field.tsx new file mode 100644 index 000000000..bc82cfe51 --- /dev/null +++ b/web/src/components/max-token-number-from-field.tsx @@ -0,0 +1,19 @@ +import { useTranslate } from '@/hooks/common-hooks'; +import { SliderInputFormField } from './slider-input-form-field'; + +interface IProps { + initialValue?: number; + max?: number; +} + +export function MaxTokenNumberFormField({ max = 2048 }: IProps) { + const { t } = useTranslate('knowledgeConfiguration'); + + return ( + + ); +} diff --git a/web/src/components/parse-configuration/graph-rag-form-fields.tsx b/web/src/components/parse-configuration/graph-rag-form-fields.tsx new file mode 100644 index 000000000..c92ca5697 --- /dev/null +++ b/web/src/components/parse-configuration/graph-rag-form-fields.tsx @@ -0,0 +1,173 @@ +import { DocumentParserType } from '@/constants/knowledge'; +import { useTranslate } from '@/hooks/common-hooks'; +import { cn } from '@/lib/utils'; +import { Switch as AntSwitch, Form, Select } from 'antd'; +import { upperFirst } from 'lodash'; +import { useCallback, useMemo } from 'react'; +import { useFormContext } from 'react-hook-form'; +import { DatasetConfigurationContainer } from '../dataset-configuration-container'; +import EntityTypesItem from '../entity-types-item'; +import { + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '../ui/form'; +import { Switch } from '../ui/switch'; + +const excludedTagParseMethods = [ + DocumentParserType.Table, + DocumentParserType.KnowledgeGraph, + DocumentParserType.Tag, +]; + +export const showTagItems = (parserId: DocumentParserType) => { + return !excludedTagParseMethods.includes(parserId); +}; + +const enum MethodValue { + General = 'general', + Light = 'light', +} + +export const excludedParseMethods = [ + DocumentParserType.Table, + DocumentParserType.Resume, + DocumentParserType.Picture, + DocumentParserType.KnowledgeGraph, + DocumentParserType.Qa, + DocumentParserType.Tag, +]; + +export const showGraphRagItems = (parserId: DocumentParserType | undefined) => { + return !excludedParseMethods.some((x) => x === parserId); +}; + +type GraphRagItemsProps = { + marginBottom?: boolean; +}; + +export function UseGraphRagItem() { + const { t } = useTranslate('knowledgeConfiguration'); + + return ( + + + + ); +} + +export function UseGraphRagFormField() { + const form = useFormContext(); + const { t } = useTranslate('knowledgeConfiguration'); + + return ( + ( + + + {t('useGraphRag')} + + + + + + + )} + /> + ); +} + +// The three types "table", "resume" and "one" do not display this configuration. +const GraphRagItems = ({ marginBottom = false }: GraphRagItemsProps) => { + const { t } = useTranslate('knowledgeConfiguration'); + + const methodOptions = useMemo(() => { + return [MethodValue.Light, MethodValue.General].map((x) => ({ + value: x, + label: upperFirst(x), + })); + }, []); + + const renderWideTooltip = useCallback( + (title: React.ReactNode | string) => { + return { + title: typeof title === 'string' ? t(title) : title, + overlayInnerStyle: { width: '32vw' }, + }; + }, + [t], + ); + + return ( + + + + prevValues.parser_config.graphrag.use_graphrag !== + curValues.parser_config.graphrag.use_graphrag + } + > + {({ getFieldValue }) => { + const useRaptor = getFieldValue([ + 'parser_config', + 'graphrag', + 'use_graphrag', + ]); + + return ( + useRaptor && ( + <> + + , + )} + initialValue={MethodValue.Light} + > +