mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Translate the fields of the parsing operator #9869 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -18,7 +18,7 @@ export function LLMFormField({ options, name }: LLMFormFieldProps) {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RAGFlowFormItem name={name || 'llm_id'} label={t('model')}>
|
<RAGFlowFormItem name={name || 'llm_id'} label={t('chat.model')}>
|
||||||
<SelectWithSearch options={options || modelOptions}></SelectWithSearch>
|
<SelectWithSearch options={options || modelOptions}></SelectWithSearch>
|
||||||
</RAGFlowFormItem>
|
</RAGFlowFormItem>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1636,6 +1636,11 @@ This delimiter is used to split the input text into several text pieces echo of
|
|||||||
chunkerDescription: 'Chunker',
|
chunkerDescription: 'Chunker',
|
||||||
tokenizer: 'Tokenizer',
|
tokenizer: 'Tokenizer',
|
||||||
tokenizerDescription: 'Tokenizer',
|
tokenizerDescription: 'Tokenizer',
|
||||||
|
outputFormat: 'Output format',
|
||||||
|
lang: 'Language',
|
||||||
|
fileFormats: 'File formats',
|
||||||
|
fields: 'Fields',
|
||||||
|
addParser: 'Add Parser',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1544,6 +1544,11 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
|||||||
chunkerDescription: '分块器',
|
chunkerDescription: '分块器',
|
||||||
tokenizer: '分词器',
|
tokenizer: '分词器',
|
||||||
tokenizerDescription: '分词器',
|
tokenizerDescription: '分词器',
|
||||||
|
outputFormat: '输出格式',
|
||||||
|
lang: '语言',
|
||||||
|
fileFormats: '文件格式',
|
||||||
|
fields: '字段',
|
||||||
|
addParser: '增加解析器',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -388,7 +388,7 @@ export const initialStringTransformValues = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initialParserValues = { outputs: {} };
|
export const initialParserValues = { outputs: {}, parser: [] };
|
||||||
|
|
||||||
export const CategorizeAnchorPointPositions = [
|
export const CategorizeAnchorPointPositions = [
|
||||||
{ top: 1, right: 34 },
|
{ top: 1, right: 34 },
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
} from '@/components/originui/select-with-search';
|
} from '@/components/originui/select-with-search';
|
||||||
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
||||||
import { buildOptions } from '@/utils/form';
|
import { buildOptions } from '@/utils/form';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FileType } from '../../constant';
|
import { FileType } from '../../constant';
|
||||||
import { OutputFormatMap } from './constant';
|
import { OutputFormatMap } from './constant';
|
||||||
import { CommonProps } from './interface';
|
import { CommonProps } from './interface';
|
||||||
@ -28,10 +29,11 @@ export function OutputFormatFormField({
|
|||||||
prefix,
|
prefix,
|
||||||
fileType,
|
fileType,
|
||||||
}: OutputFormatFormFieldProps) {
|
}: OutputFormatFormFieldProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<RAGFlowFormItem
|
<RAGFlowFormItem
|
||||||
name={buildFieldNameWithPrefix(`output_format`, prefix)}
|
name={buildFieldNameWithPrefix(`output_format`, prefix)}
|
||||||
label="output_format"
|
label={t('dataflow.outputFormat')}
|
||||||
>
|
>
|
||||||
<SelectWithSearch
|
<SelectWithSearch
|
||||||
options={buildOutputOptionsFormatMap()[fileType]}
|
options={buildOutputOptionsFormatMap()[fileType]}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { SelectWithSearch } from '@/components/originui/select-with-search';
|
import { SelectWithSearch } from '@/components/originui/select-with-search';
|
||||||
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
||||||
import { buildOptions } from '@/utils/form';
|
import { buildOptions } from '@/utils/form';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FileType } from '../../constant';
|
import { FileType } from '../../constant';
|
||||||
import { OutputFormatFormField } from './common-form-fields';
|
import { OutputFormatFormField } from './common-form-fields';
|
||||||
import { CommonProps } from './interface';
|
import { CommonProps } from './interface';
|
||||||
@ -18,11 +19,12 @@ const options = buildOptions([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
export function EmailFormFields({ prefix }: CommonProps) {
|
export function EmailFormFields({ prefix }: CommonProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RAGFlowFormItem
|
<RAGFlowFormItem
|
||||||
name={buildFieldNameWithPrefix(`fields`, prefix)}
|
name={buildFieldNameWithPrefix(`fields`, prefix)}
|
||||||
label="fields"
|
label={t('dataflow.fields')}
|
||||||
>
|
>
|
||||||
<SelectWithSearch options={options}></SelectWithSearch>
|
<SelectWithSearch options={options}></SelectWithSearch>
|
||||||
</RAGFlowFormItem>
|
</RAGFlowFormItem>
|
||||||
|
|||||||
@ -8,13 +8,14 @@ import { buildOptions } from '@/utils/form';
|
|||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useHover } from 'ahooks';
|
import { useHover } from 'ahooks';
|
||||||
import { Trash2 } from 'lucide-react';
|
import { Trash2 } from 'lucide-react';
|
||||||
import { memo, useCallback, useRef } from 'react';
|
import { memo, useCallback, useMemo, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
UseFieldArrayRemove,
|
UseFieldArrayRemove,
|
||||||
useFieldArray,
|
useFieldArray,
|
||||||
useForm,
|
useForm,
|
||||||
useFormContext,
|
useFormContext,
|
||||||
} from 'react-hook-form';
|
} from 'react-hook-form';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { FileType, initialParserValues } from '../../constant';
|
import { FileType, initialParserValues } from '../../constant';
|
||||||
import { useFormValues } from '../../hooks/use-form-values';
|
import { useFormValues } from '../../hooks/use-form-values';
|
||||||
@ -48,26 +49,57 @@ type ParserItemProps = {
|
|||||||
remove: UseFieldArrayRemove;
|
remove: UseFieldArrayRemove;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const FormSchema = z.object({
|
||||||
|
parser: z.array(
|
||||||
|
z.object({
|
||||||
|
fileFormat: z.string().nullish(),
|
||||||
|
output_format: z.string().optional(),
|
||||||
|
parse_method: z.string().optional(),
|
||||||
|
llm_id: z.string().optional(),
|
||||||
|
lang: z.string().optional(),
|
||||||
|
fields: z.array(z.string()).optional(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type FormSchemaType = z.infer<typeof FormSchema>;
|
||||||
|
|
||||||
function ParserItem({ name, index, fieldLength, remove }: ParserItemProps) {
|
function ParserItem({ name, index, fieldLength, remove }: ParserItemProps) {
|
||||||
const form = useFormContext();
|
const { t } = useTranslation();
|
||||||
|
const form = useFormContext<FormSchemaType>();
|
||||||
const ref = useRef(null);
|
const ref = useRef(null);
|
||||||
const isHovering = useHover(ref);
|
const isHovering = useHover(ref);
|
||||||
|
|
||||||
const prefix = `${name}.${index}`;
|
const prefix = `${name}.${index}`;
|
||||||
const fileFormat = form.getValues(`${name}.${index}.fileFormat`);
|
const fileFormat = form.getValues(`parser.${index}.fileFormat`);
|
||||||
|
|
||||||
|
const values = form.getValues();
|
||||||
|
const parserList = values.parser.slice(); // Adding, deleting, or modifying the parser array will not change the reference.
|
||||||
|
|
||||||
|
const filteredFileFormatOptions = useMemo(() => {
|
||||||
|
const otherFileFormatList = parserList
|
||||||
|
.filter((_, idx) => idx !== index)
|
||||||
|
.map((x) => x.fileFormat);
|
||||||
|
|
||||||
|
return FileFormatOptions.filter((x) => {
|
||||||
|
return !otherFileFormatList.includes(x.value);
|
||||||
|
});
|
||||||
|
}, [index, parserList]);
|
||||||
|
|
||||||
const Widget =
|
const Widget =
|
||||||
fileFormat && fileFormat in FileFormatWidgetMap
|
typeof fileFormat === 'string' && fileFormat in FileFormatWidgetMap
|
||||||
? FileFormatWidgetMap[fileFormat as keyof typeof FileFormatWidgetMap]
|
? FileFormatWidgetMap[fileFormat as keyof typeof FileFormatWidgetMap]
|
||||||
: OutputFormatFormField;
|
: OutputFormatFormField;
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
className={cn('space-y-5 p-5 rounded-md', {
|
className={cn('space-y-5 px-5 py-2.5 rounded-md', {
|
||||||
'bg-state-error-5': isHovering,
|
'bg-state-error-5': isHovering,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span className="text-text-primary text-sm">Parser {index}</span>
|
<span className="text-text-primary text-sm font-medium">
|
||||||
|
Parser {index}
|
||||||
|
</span>
|
||||||
{index > 0 && (
|
{index > 0 && (
|
||||||
<Button variant={'ghost'} onClick={() => remove(index)} ref={ref}>
|
<Button variant={'ghost'} onClick={() => remove(index)} ref={ref}>
|
||||||
<Trash2 />
|
<Trash2 />
|
||||||
@ -76,9 +108,11 @@ function ParserItem({ name, index, fieldLength, remove }: ParserItemProps) {
|
|||||||
</div>
|
</div>
|
||||||
<RAGFlowFormItem
|
<RAGFlowFormItem
|
||||||
name={buildFieldNameWithPrefix(`fileFormat`, prefix)}
|
name={buildFieldNameWithPrefix(`fileFormat`, prefix)}
|
||||||
label="File Formats"
|
label={t('dataflow.fileFormats')}
|
||||||
>
|
>
|
||||||
<SelectWithSearch options={FileFormatOptions}></SelectWithSearch>
|
<SelectWithSearch
|
||||||
|
options={filteredFileFormatOptions}
|
||||||
|
></SelectWithSearch>
|
||||||
</RAGFlowFormItem>
|
</RAGFlowFormItem>
|
||||||
<Widget prefix={prefix} fileType={fileFormat as FileType}></Widget>
|
<Widget prefix={prefix} fileType={fileFormat as FileType}></Widget>
|
||||||
{index < fieldLength - 1 && <Separator />}
|
{index < fieldLength - 1 && <Separator />}
|
||||||
@ -86,15 +120,8 @@ function ParserItem({ name, index, fieldLength, remove }: ParserItemProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FormSchema = z.object({
|
|
||||||
parser: z.array(
|
|
||||||
z.object({
|
|
||||||
fileFormat: z.string().optional(),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
const ParserForm = ({ node }: INextOperatorForm) => {
|
const ParserForm = ({ node }: INextOperatorForm) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const defaultValues = useFormValues(initialParserValues, node);
|
const defaultValues = useFormValues(initialParserValues, node);
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof FormSchema>>({
|
const form = useForm<z.infer<typeof FormSchema>>({
|
||||||
@ -111,7 +138,12 @@ const ParserForm = ({ node }: INextOperatorForm) => {
|
|||||||
|
|
||||||
const add = useCallback(() => {
|
const add = useCallback(() => {
|
||||||
append({
|
append({
|
||||||
fileFormat: undefined,
|
fileFormat: null,
|
||||||
|
output_format: '',
|
||||||
|
parse_method: '',
|
||||||
|
llm_id: '',
|
||||||
|
lang: '',
|
||||||
|
fields: [],
|
||||||
});
|
});
|
||||||
}, [append]);
|
}, [append]);
|
||||||
|
|
||||||
@ -131,8 +163,8 @@ const ParserForm = ({ node }: INextOperatorForm) => {
|
|||||||
></ParserItem>
|
></ParserItem>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<BlockButton onClick={add} type="button">
|
<BlockButton onClick={add} type="button" className="mt-2.5">
|
||||||
Add Parser
|
{t('dataflow.addParser')}
|
||||||
</BlockButton>
|
</BlockButton>
|
||||||
</form>
|
</form>
|
||||||
<div className="p-5">
|
<div className="p-5">
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { CrossLanguageFormField } from '@/components/cross-language-form-field';
|
import { CrossLanguageFormField } from '@/components/cross-language-form-field';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FileType } from '../../constant';
|
import { FileType } from '../../constant';
|
||||||
import {
|
import {
|
||||||
LargeModelFormField,
|
LargeModelFormField,
|
||||||
@ -9,6 +10,7 @@ import { CommonProps } from './interface';
|
|||||||
import { buildFieldNameWithPrefix } from './utils';
|
import { buildFieldNameWithPrefix } from './utils';
|
||||||
|
|
||||||
export function PdfFormFields({ prefix }: CommonProps) {
|
export function PdfFormFields({ prefix }: CommonProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ParserMethodFormField prefix={prefix}></ParserMethodFormField>
|
<ParserMethodFormField prefix={prefix}></ParserMethodFormField>
|
||||||
@ -16,7 +18,7 @@ export function PdfFormFields({ prefix }: CommonProps) {
|
|||||||
<LargeModelFormField prefix={prefix}></LargeModelFormField>
|
<LargeModelFormField prefix={prefix}></LargeModelFormField>
|
||||||
<CrossLanguageFormField
|
<CrossLanguageFormField
|
||||||
name={buildFieldNameWithPrefix(`lang`, prefix)}
|
name={buildFieldNameWithPrefix(`lang`, prefix)}
|
||||||
label="lang"
|
label={t('dataflow.lang')}
|
||||||
></CrossLanguageFormField>
|
></CrossLanguageFormField>
|
||||||
<OutputFormatFormField
|
<OutputFormatFormField
|
||||||
prefix={prefix}
|
prefix={prefix}
|
||||||
|
|||||||
Reference in New Issue
Block a user