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 { useComposeLlmOptionsByModelTypes } from '@/hooks/llm-hooks';
|
||||
import { camelCase } from 'lodash';
|
||||
import { useCallback } from 'react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { SelectWithSearch } from '../originui/select-with-search';
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
@ -20,6 +18,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '../ui/select';
|
||||
import { LLMFormField } from './llm-form-field';
|
||||
import { SliderInputSwitchFormField } from './slider';
|
||||
import { useHandleFreedomChange } from './use-watch-change';
|
||||
|
||||
@ -61,11 +60,6 @@ export function LlmSettingFieldItems({
|
||||
const form = useFormContext();
|
||||
const { t } = useTranslate('chat');
|
||||
|
||||
const modelOptions = useComposeLlmOptionsByModelTypes([
|
||||
LlmModelType.Chat,
|
||||
LlmModelType.Image2text,
|
||||
]);
|
||||
|
||||
const getFieldWithPrefix = useCallback(
|
||||
(name: string) => {
|
||||
return prefix ? `${prefix}.${name}` : name;
|
||||
@ -82,22 +76,7 @@ export function LlmSettingFieldItems({
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'llm_id'}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('model')}</FormLabel>
|
||||
<FormControl>
|
||||
<SelectWithSearch
|
||||
options={options || modelOptions}
|
||||
{...field}
|
||||
></SelectWithSearch>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<LLMFormField options={options}></LLMFormField>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'parameter'}
|
||||
|
||||
@ -523,3 +523,15 @@ export enum AgentExceptionMethod {
|
||||
Comment = 'comment',
|
||||
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 NumberInput from '@/components/originui/number-input';
|
||||
import { SelectWithSearch } from '@/components/originui/select-with-search';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
||||
import { BlockButton, Button } from '@/components/ui/button';
|
||||
import { Form } from '@/components/ui/form';
|
||||
import { buildOptions } from '@/utils/form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { memo } from 'react';
|
||||
import { useForm, useFormContext } from 'react-hook-form';
|
||||
import { Trash2 } from 'lucide-react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useFieldArray, useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { initialParserValues } from '../../constant';
|
||||
import { FileType, initialParserValues } from '../../constant';
|
||||
import { useFormValues } from '../../hooks/use-form-values';
|
||||
import { useWatchFormChange } from '../../hooks/use-watch-form-change';
|
||||
import { INextOperatorForm } from '../../interface';
|
||||
import { GoogleCountryOptions, GoogleLanguageOptions } from '../../options';
|
||||
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 { 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);
|
||||
|
||||
export const GoogleFormPartialSchema = {
|
||||
api_key: z.string(),
|
||||
country: z.string(),
|
||||
language: z.string(),
|
||||
const FileFormatOptions = buildOptions(FileType);
|
||||
|
||||
const FileFormatWidgetMap = {
|
||||
[FileType.PDF]: PdfFormFields,
|
||||
[FileType.Video]: VideoFormFields,
|
||||
[FileType.Audio]: VideoFormFields,
|
||||
[FileType.Email]: EmailFormFields,
|
||||
[FileType.Image]: ImageFormFields,
|
||||
};
|
||||
|
||||
export const FormSchema = z.object({
|
||||
...GoogleFormPartialSchema,
|
||||
q: z.string(),
|
||||
start: z.number(),
|
||||
num: z.number(),
|
||||
parser: z.array(
|
||||
z.object({
|
||||
fileFormat: z.string().optional(),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
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 { t } = useTranslate('flow');
|
||||
const defaultValues = useFormValues(initialParserValues, node);
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
defaultValues,
|
||||
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);
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<FormWrapper>
|
||||
<FormContainer>
|
||||
<QueryVariable name="q"></QueryVariable>
|
||||
</FormContainer>
|
||||
<FormContainer>
|
||||
<ApiKeyField placeholder={t('apiKeyPlaceholder')}></ApiKeyField>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`start`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('flowStart')}</FormLabel>
|
||||
<FormControl>
|
||||
<NumberInput {...field} className="w-full"></NumberInput>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`num`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('flowNum')}</FormLabel>
|
||||
<FormControl>
|
||||
<NumberInput {...field} className="w-full"></NumberInput>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<GoogleFormWidgets></GoogleFormWidgets>
|
||||
</FormContainer>
|
||||
</FormWrapper>
|
||||
{fields.map((field, index) => {
|
||||
const prefix = `${name}.${index}`;
|
||||
const fileFormat = form.getValues(`${name}.${index}.fileFormat`);
|
||||
|
||||
const Widget =
|
||||
fileFormat && fileFormat in FileFormatWidgetMap
|
||||
? FileFormatWidgetMap[
|
||||
fileFormat as keyof typeof FileFormatWidgetMap
|
||||
]
|
||||
: OutputFormatFormField;
|
||||
return (
|
||||
<FormContainer key={field.id}>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-text-primary text-sm">Parser {index}</span>
|
||||
<Button variant={'ghost'} onClick={() => remove(index)}>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</div>
|
||||
<RAGFlowFormItem
|
||||
name={buildFieldNameWithPrefix(`fileFormat`, prefix)}
|
||||
label="File Formats"
|
||||
>
|
||||
<SelectWithSearch options={FileFormatOptions}></SelectWithSearch>
|
||||
</RAGFlowFormItem>
|
||||
<Widget prefix={prefix}></Widget>
|
||||
</FormContainer>
|
||||
);
|
||||
})}
|
||||
<BlockButton onClick={add}>Add Parser</BlockButton>
|
||||
<div className="p-5">
|
||||
<Output list={outputList}></Output>
|
||||
</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