mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Dynamically increase the configuration of the parser operator #9869 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
25
web/src/components/llm-setting-items/llm-form-field.tsx
Normal file
25
web/src/components/llm-setting-items/llm-form-field.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { LlmModelType } from '@/constants/knowledge';
|
||||||
|
import { useComposeLlmOptionsByModelTypes } from '@/hooks/llm-hooks';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { SelectWithSearch } from '../originui/select-with-search';
|
||||||
|
import { RAGFlowFormItem } from '../ragflow-form';
|
||||||
|
|
||||||
|
type LLMFormFieldProps = {
|
||||||
|
options?: any[];
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function LLMFormField({ options, name }: LLMFormFieldProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const modelOptions = useComposeLlmOptionsByModelTypes([
|
||||||
|
LlmModelType.Chat,
|
||||||
|
LlmModelType.Image2text,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RAGFlowFormItem name={name || 'llm_id'} label={t('model')}>
|
||||||
|
<SelectWithSearch options={options || modelOptions}></SelectWithSearch>
|
||||||
|
</RAGFlowFormItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,11 +1,9 @@
|
|||||||
import { LlmModelType, ModelVariableType } from '@/constants/knowledge';
|
import { ModelVariableType } from '@/constants/knowledge';
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
import { useComposeLlmOptionsByModelTypes } from '@/hooks/llm-hooks';
|
|
||||||
import { camelCase } from 'lodash';
|
import { camelCase } from 'lodash';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useFormContext } from 'react-hook-form';
|
import { useFormContext } from 'react-hook-form';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { SelectWithSearch } from '../originui/select-with-search';
|
|
||||||
import {
|
import {
|
||||||
FormControl,
|
FormControl,
|
||||||
FormField,
|
FormField,
|
||||||
@ -20,6 +18,7 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from '../ui/select';
|
} from '../ui/select';
|
||||||
|
import { LLMFormField } from './llm-form-field';
|
||||||
import { SliderInputSwitchFormField } from './slider';
|
import { SliderInputSwitchFormField } from './slider';
|
||||||
import { useHandleFreedomChange } from './use-watch-change';
|
import { useHandleFreedomChange } from './use-watch-change';
|
||||||
|
|
||||||
@ -61,11 +60,6 @@ export function LlmSettingFieldItems({
|
|||||||
const form = useFormContext();
|
const form = useFormContext();
|
||||||
const { t } = useTranslate('chat');
|
const { t } = useTranslate('chat');
|
||||||
|
|
||||||
const modelOptions = useComposeLlmOptionsByModelTypes([
|
|
||||||
LlmModelType.Chat,
|
|
||||||
LlmModelType.Image2text,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const getFieldWithPrefix = useCallback(
|
const getFieldWithPrefix = useCallback(
|
||||||
(name: string) => {
|
(name: string) => {
|
||||||
return prefix ? `${prefix}.${name}` : name;
|
return prefix ? `${prefix}.${name}` : name;
|
||||||
@ -82,22 +76,7 @@ export function LlmSettingFieldItems({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
<FormField
|
<LLMFormField options={options}></LLMFormField>
|
||||||
control={form.control}
|
|
||||||
name={'llm_id'}
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>{t('model')}</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<SelectWithSearch
|
|
||||||
options={options || modelOptions}
|
|
||||||
{...field}
|
|
||||||
></SelectWithSearch>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name={'parameter'}
|
name={'parameter'}
|
||||||
|
|||||||
@ -523,3 +523,15 @@ export enum AgentExceptionMethod {
|
|||||||
Comment = 'comment',
|
Comment = 'comment',
|
||||||
Goto = 'goto',
|
Goto = 'goto',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum FileType {
|
||||||
|
PDF = 'pdf',
|
||||||
|
Spreadsheet = 'spreadsheet',
|
||||||
|
Image = 'image',
|
||||||
|
Email = 'email',
|
||||||
|
TextMarkdown = 'text&markdown',
|
||||||
|
Docx = 'docx',
|
||||||
|
PowerPoint = 'ppt',
|
||||||
|
Video = 'video',
|
||||||
|
Audio = 'audio',
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
import { LLMFormField } from '@/components/llm-setting-items/llm-form-field';
|
||||||
|
import { SelectWithSearch } from '@/components/originui/select-with-search';
|
||||||
|
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
||||||
|
import { CommonProps } from './interface';
|
||||||
|
import { buildFieldNameWithPrefix } from './utils';
|
||||||
|
|
||||||
|
export function LanguageFormField({ prefix }: CommonProps) {
|
||||||
|
return (
|
||||||
|
<RAGFlowFormItem
|
||||||
|
name={buildFieldNameWithPrefix(`lang`, prefix)}
|
||||||
|
label="lang"
|
||||||
|
>
|
||||||
|
<SelectWithSearch options={[]}></SelectWithSearch>
|
||||||
|
</RAGFlowFormItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function OutputFormatFormField({ prefix }: CommonProps) {
|
||||||
|
return (
|
||||||
|
<RAGFlowFormItem
|
||||||
|
name={buildFieldNameWithPrefix(`output_format`, prefix)}
|
||||||
|
label="output_format"
|
||||||
|
>
|
||||||
|
<SelectWithSearch options={[]}></SelectWithSearch>
|
||||||
|
</RAGFlowFormItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ParserMethodFormField({ prefix }: CommonProps) {
|
||||||
|
return (
|
||||||
|
<RAGFlowFormItem
|
||||||
|
name={buildFieldNameWithPrefix(`parse_method`, prefix)}
|
||||||
|
label="parse_method"
|
||||||
|
>
|
||||||
|
<SelectWithSearch options={[]}></SelectWithSearch>
|
||||||
|
</RAGFlowFormItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LargeModelFormField({ prefix }: CommonProps) {
|
||||||
|
return (
|
||||||
|
<LLMFormField
|
||||||
|
name={buildFieldNameWithPrefix('llm_id', prefix)}
|
||||||
|
></LLMFormField>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
import { SelectWithSearch } from '@/components/originui/select-with-search';
|
||||||
|
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
||||||
|
import { buildOptions } from '@/utils/form';
|
||||||
|
import { OutputFormatFormField } from './common-form-fields';
|
||||||
|
import { CommonProps } from './interface';
|
||||||
|
import { buildFieldNameWithPrefix } from './utils';
|
||||||
|
|
||||||
|
const options = buildOptions([
|
||||||
|
'from',
|
||||||
|
'to',
|
||||||
|
'cc',
|
||||||
|
'bcc',
|
||||||
|
'date',
|
||||||
|
'subject',
|
||||||
|
'body',
|
||||||
|
'attachments',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function EmailFormFields({ prefix }: CommonProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<RAGFlowFormItem
|
||||||
|
name={buildFieldNameWithPrefix(`fields`, prefix)}
|
||||||
|
label="fields"
|
||||||
|
>
|
||||||
|
<SelectWithSearch options={options}></SelectWithSearch>
|
||||||
|
</RAGFlowFormItem>
|
||||||
|
<OutputFormatFormField prefix={prefix}></OutputFormatFormField>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
import {
|
||||||
|
LargeModelFormField,
|
||||||
|
OutputFormatFormField,
|
||||||
|
ParserMethodFormField,
|
||||||
|
} from './common-form-fields';
|
||||||
|
import { CommonProps } from './interface';
|
||||||
|
|
||||||
|
export function ImageFormFields({ prefix }: CommonProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ParserMethodFormField prefix={prefix}></ParserMethodFormField>
|
||||||
|
{/* Multimodal Model */}
|
||||||
|
<LargeModelFormField prefix={prefix}></LargeModelFormField>
|
||||||
|
<OutputFormatFormField prefix={prefix}></OutputFormatFormField>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,135 +1,101 @@
|
|||||||
import { FormContainer } from '@/components/form-container';
|
import { FormContainer } from '@/components/form-container';
|
||||||
import NumberInput from '@/components/originui/number-input';
|
|
||||||
import { SelectWithSearch } from '@/components/originui/select-with-search';
|
import { SelectWithSearch } from '@/components/originui/select-with-search';
|
||||||
import {
|
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
||||||
Form,
|
import { BlockButton, Button } from '@/components/ui/button';
|
||||||
FormControl,
|
import { Form } from '@/components/ui/form';
|
||||||
FormField,
|
import { buildOptions } from '@/utils/form';
|
||||||
FormItem,
|
|
||||||
FormLabel,
|
|
||||||
FormMessage,
|
|
||||||
} from '@/components/ui/form';
|
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { memo } from 'react';
|
import { Trash2 } from 'lucide-react';
|
||||||
import { useForm, useFormContext } from 'react-hook-form';
|
import { memo, useCallback } from 'react';
|
||||||
|
import { useFieldArray, useForm } from 'react-hook-form';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { initialParserValues } from '../../constant';
|
import { FileType, initialParserValues } from '../../constant';
|
||||||
import { useFormValues } from '../../hooks/use-form-values';
|
import { useFormValues } from '../../hooks/use-form-values';
|
||||||
import { useWatchFormChange } from '../../hooks/use-watch-form-change';
|
import { useWatchFormChange } from '../../hooks/use-watch-form-change';
|
||||||
import { INextOperatorForm } from '../../interface';
|
import { INextOperatorForm } from '../../interface';
|
||||||
import { GoogleCountryOptions, GoogleLanguageOptions } from '../../options';
|
|
||||||
import { buildOutputList } from '../../utils/build-output-list';
|
import { buildOutputList } from '../../utils/build-output-list';
|
||||||
import { ApiKeyField } from '../components/api-key-field';
|
|
||||||
import { FormWrapper } from '../components/form-wrapper';
|
|
||||||
import { Output } from '../components/output';
|
import { Output } from '../components/output';
|
||||||
import { QueryVariable } from '../components/query-variable';
|
import { OutputFormatFormField } from './common-form-fields';
|
||||||
|
import { EmailFormFields } from './email-form-fields';
|
||||||
|
import { ImageFormFields } from './image-form-fields';
|
||||||
|
import { PdfFormFields } from './pdf-form-fields';
|
||||||
|
import { buildFieldNameWithPrefix } from './utils';
|
||||||
|
import { VideoFormFields } from './video-form-fields';
|
||||||
|
|
||||||
const outputList = buildOutputList(initialParserValues.outputs);
|
const outputList = buildOutputList(initialParserValues.outputs);
|
||||||
|
|
||||||
export const GoogleFormPartialSchema = {
|
const FileFormatOptions = buildOptions(FileType);
|
||||||
api_key: z.string(),
|
|
||||||
country: z.string(),
|
const FileFormatWidgetMap = {
|
||||||
language: z.string(),
|
[FileType.PDF]: PdfFormFields,
|
||||||
|
[FileType.Video]: VideoFormFields,
|
||||||
|
[FileType.Audio]: VideoFormFields,
|
||||||
|
[FileType.Email]: EmailFormFields,
|
||||||
|
[FileType.Image]: ImageFormFields,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FormSchema = z.object({
|
export const FormSchema = z.object({
|
||||||
...GoogleFormPartialSchema,
|
parser: z.array(
|
||||||
q: z.string(),
|
z.object({
|
||||||
start: z.number(),
|
fileFormat: z.string().optional(),
|
||||||
num: z.number(),
|
}),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function GoogleFormWidgets() {
|
|
||||||
const form = useFormContext();
|
|
||||||
const { t } = useTranslate('flow');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name={`country`}
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="flex-1">
|
|
||||||
<FormLabel>{t('country')}</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<SelectWithSearch
|
|
||||||
{...field}
|
|
||||||
options={GoogleCountryOptions}
|
|
||||||
></SelectWithSearch>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name={`language`}
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="flex-1">
|
|
||||||
<FormLabel>{t('language')}</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<SelectWithSearch
|
|
||||||
{...field}
|
|
||||||
options={GoogleLanguageOptions}
|
|
||||||
></SelectWithSearch>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ParserForm = ({ node }: INextOperatorForm) => {
|
const ParserForm = ({ node }: INextOperatorForm) => {
|
||||||
const { t } = useTranslate('flow');
|
|
||||||
const defaultValues = useFormValues(initialParserValues, node);
|
const defaultValues = useFormValues(initialParserValues, node);
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof FormSchema>>({
|
const form = useForm<z.infer<typeof FormSchema>>({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
resolver: zodResolver(FormSchema),
|
resolver: zodResolver(FormSchema),
|
||||||
|
shouldUnregister: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const name = 'parser';
|
||||||
|
const { fields, remove, append } = useFieldArray({
|
||||||
|
name,
|
||||||
|
control: form.control,
|
||||||
|
});
|
||||||
|
|
||||||
|
const add = useCallback(() => {
|
||||||
|
append({
|
||||||
|
fileFormat: undefined,
|
||||||
|
});
|
||||||
|
}, [append]);
|
||||||
|
|
||||||
useWatchFormChange(node?.id, form);
|
useWatchFormChange(node?.id, form);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<FormWrapper>
|
{fields.map((field, index) => {
|
||||||
<FormContainer>
|
const prefix = `${name}.${index}`;
|
||||||
<QueryVariable name="q"></QueryVariable>
|
const fileFormat = form.getValues(`${name}.${index}.fileFormat`);
|
||||||
</FormContainer>
|
|
||||||
<FormContainer>
|
const Widget =
|
||||||
<ApiKeyField placeholder={t('apiKeyPlaceholder')}></ApiKeyField>
|
fileFormat && fileFormat in FileFormatWidgetMap
|
||||||
<FormField
|
? FileFormatWidgetMap[
|
||||||
control={form.control}
|
fileFormat as keyof typeof FileFormatWidgetMap
|
||||||
name={`start`}
|
]
|
||||||
render={({ field }) => (
|
: OutputFormatFormField;
|
||||||
<FormItem>
|
return (
|
||||||
<FormLabel>{t('flowStart')}</FormLabel>
|
<FormContainer key={field.id}>
|
||||||
<FormControl>
|
<div className="flex justify-between items-center">
|
||||||
<NumberInput {...field} className="w-full"></NumberInput>
|
<span className="text-text-primary text-sm">Parser {index}</span>
|
||||||
</FormControl>
|
<Button variant={'ghost'} onClick={() => remove(index)}>
|
||||||
<FormMessage />
|
<Trash2 />
|
||||||
</FormItem>
|
</Button>
|
||||||
)}
|
</div>
|
||||||
/>
|
<RAGFlowFormItem
|
||||||
<FormField
|
name={buildFieldNameWithPrefix(`fileFormat`, prefix)}
|
||||||
control={form.control}
|
label="File Formats"
|
||||||
name={`num`}
|
>
|
||||||
render={({ field }) => (
|
<SelectWithSearch options={FileFormatOptions}></SelectWithSearch>
|
||||||
<FormItem>
|
</RAGFlowFormItem>
|
||||||
<FormLabel>{t('flowNum')}</FormLabel>
|
<Widget prefix={prefix}></Widget>
|
||||||
<FormControl>
|
</FormContainer>
|
||||||
<NumberInput {...field} className="w-full"></NumberInput>
|
);
|
||||||
</FormControl>
|
})}
|
||||||
<FormMessage />
|
<BlockButton onClick={add}>Add Parser</BlockButton>
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<GoogleFormWidgets></GoogleFormWidgets>
|
|
||||||
</FormContainer>
|
|
||||||
</FormWrapper>
|
|
||||||
<div className="p-5">
|
<div className="p-5">
|
||||||
<Output list={outputList}></Output>
|
<Output list={outputList}></Output>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
3
web/src/pages/data-flow/form/parser-form/interface.ts
Normal file
3
web/src/pages/data-flow/form/parser-form/interface.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export type CommonProps = {
|
||||||
|
prefix: string;
|
||||||
|
};
|
||||||
19
web/src/pages/data-flow/form/parser-form/pdf-form-fields.tsx
Normal file
19
web/src/pages/data-flow/form/parser-form/pdf-form-fields.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import {
|
||||||
|
LanguageFormField,
|
||||||
|
LargeModelFormField,
|
||||||
|
OutputFormatFormField,
|
||||||
|
ParserMethodFormField,
|
||||||
|
} from './common-form-fields';
|
||||||
|
import { CommonProps } from './interface';
|
||||||
|
|
||||||
|
export function PdfFormFields({ prefix }: CommonProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ParserMethodFormField prefix={prefix}></ParserMethodFormField>
|
||||||
|
{/* Multimodal Model */}
|
||||||
|
<LargeModelFormField prefix={prefix}></LargeModelFormField>
|
||||||
|
<LanguageFormField prefix={prefix}></LanguageFormField>
|
||||||
|
<OutputFormatFormField prefix={prefix}></OutputFormatFormField>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
3
web/src/pages/data-flow/form/parser-form/utils.ts
Normal file
3
web/src/pages/data-flow/form/parser-form/utils.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export function buildFieldNameWithPrefix(name: string, prefix: string) {
|
||||||
|
return `${prefix}.${name}`;
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
import {
|
||||||
|
LargeModelFormField,
|
||||||
|
OutputFormatFormField,
|
||||||
|
} from './common-form-fields';
|
||||||
|
import { CommonProps } from './interface';
|
||||||
|
|
||||||
|
export function VideoFormFields({ prefix }: CommonProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Multimodal Model */}
|
||||||
|
<LargeModelFormField prefix={prefix}></LargeModelFormField>
|
||||||
|
<OutputFormatFormField prefix={prefix}></OutputFormatFormField>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user