mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-05-30 01:55:47 +08:00
### What problem does this PR solve? Feat: Use shadcn-ui to build GenerateForm. #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
651422127c
commit
244cf49ba4
@ -1,5 +1,14 @@
|
|||||||
import { Form, InputNumber } from 'antd';
|
import { Form, InputNumber } from 'antd';
|
||||||
|
import { useFormContext } from 'react-hook-form';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from './ui/form';
|
||||||
|
import { Input } from './ui/input';
|
||||||
|
|
||||||
const MessageHistoryWindowSizeItem = ({
|
const MessageHistoryWindowSizeItem = ({
|
||||||
initialValue,
|
initialValue,
|
||||||
@ -21,3 +30,24 @@ const MessageHistoryWindowSizeItem = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default MessageHistoryWindowSizeItem;
|
export default MessageHistoryWindowSizeItem;
|
||||||
|
|
||||||
|
export function MessageHistoryWindowSizeFormField() {
|
||||||
|
const form = useFormContext();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={'message_history_window_size'}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>{t('flow.messageHistoryWindowSize')}</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} type={'number'}></Input>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -52,10 +52,12 @@ export default SimilaritySlider;
|
|||||||
|
|
||||||
interface SimilaritySliderFormFieldProps {
|
interface SimilaritySliderFormFieldProps {
|
||||||
vectorSimilarityWeightName?: string;
|
vectorSimilarityWeightName?: string;
|
||||||
|
isTooltipShown?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SimilaritySliderFormField({
|
export function SimilaritySliderFormField({
|
||||||
vectorSimilarityWeightName = 'vector_similarity_weight',
|
vectorSimilarityWeightName = 'vector_similarity_weight',
|
||||||
|
isTooltipShown,
|
||||||
}: SimilaritySliderFormFieldProps) {
|
}: SimilaritySliderFormFieldProps) {
|
||||||
const form = useFormContext();
|
const form = useFormContext();
|
||||||
const { t } = useTranslate('knowledgeDetails');
|
const { t } = useTranslate('knowledgeDetails');
|
||||||
@ -67,7 +69,9 @@ export function SimilaritySliderFormField({
|
|||||||
name={'similarity_threshold'}
|
name={'similarity_threshold'}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('similarityThreshold')}</FormLabel>
|
<FormLabel tooltip={isTooltipShown && t('similarityThresholdTip')}>
|
||||||
|
{t('similarityThreshold')}
|
||||||
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SingleFormSlider
|
<SingleFormSlider
|
||||||
{...field}
|
{...field}
|
||||||
@ -84,7 +88,11 @@ export function SimilaritySliderFormField({
|
|||||||
name={vectorSimilarityWeightName}
|
name={vectorSimilarityWeightName}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('vectorSimilarityWeight')}</FormLabel>
|
<FormLabel
|
||||||
|
tooltip={isTooltipShown && t('vectorSimilarityWeightTip')}
|
||||||
|
>
|
||||||
|
{t('vectorSimilarityWeight')}
|
||||||
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SingleFormSlider
|
<SingleFormSlider
|
||||||
{...field}
|
{...field}
|
||||||
|
@ -14,6 +14,8 @@ import {
|
|||||||
|
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { Info } from 'lucide-react';
|
||||||
|
import { Tooltip, TooltipContent, TooltipTrigger } from './tooltip';
|
||||||
|
|
||||||
const Form = FormProvider;
|
const Form = FormProvider;
|
||||||
|
|
||||||
@ -88,17 +90,31 @@ FormItem.displayName = 'FormItem';
|
|||||||
|
|
||||||
const FormLabel = React.forwardRef<
|
const FormLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & {
|
||||||
>(({ className, ...props }, ref) => {
|
tooltip?: React.ReactNode;
|
||||||
|
}
|
||||||
|
>(({ className, tooltip, ...props }, ref) => {
|
||||||
const { error, formItemId } = useFormField();
|
const { error, formItemId } = useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Label
|
<Label
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(error && 'text-destructive', className)}
|
className={cn(error && 'text-destructive', className, 'flex')}
|
||||||
htmlFor={formItemId}
|
htmlFor={formItemId}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
>
|
||||||
|
{props.children}
|
||||||
|
{tooltip && (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<Info className="size-3 ml-2" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>{tooltip}</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Label>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
FormLabel.displayName = 'FormLabel';
|
FormLabel.displayName = 'FormLabel';
|
||||||
|
@ -122,7 +122,7 @@ const FormSheet = ({
|
|||||||
<span>{t(`${lowerFirst(operatorName)}Description`)}</span>
|
<span>{t(`${lowerFirst(operatorName)}Description`)}</span>
|
||||||
</section>
|
</section>
|
||||||
</SheetHeader>
|
</SheetHeader>
|
||||||
<section>
|
<section className="pt-4">
|
||||||
{visible && (
|
{visible && (
|
||||||
<FlowFormContext.Provider value={node}>
|
<FlowFormContext.Provider value={node}>
|
||||||
<OperatorForm
|
<OperatorForm
|
||||||
|
@ -82,8 +82,15 @@ export function useFormConfigMap() {
|
|||||||
},
|
},
|
||||||
[Operator.Generate]: {
|
[Operator.Generate]: {
|
||||||
component: GenerateForm,
|
component: GenerateForm,
|
||||||
defaultValues: {},
|
defaultValues: {
|
||||||
schema: z.object({}),
|
cite: true,
|
||||||
|
prompt: t('flow.promptText'),
|
||||||
|
},
|
||||||
|
schema: z.object({
|
||||||
|
prompt: z.string().min(1, {
|
||||||
|
message: t('flow.promptMessage'),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
[Operator.Answer]: {
|
[Operator.Answer]: {
|
||||||
component: AnswerForm,
|
component: AnswerForm,
|
||||||
|
@ -121,7 +121,7 @@ export function DynamicInputVariable({ node }: IProps) {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Collapsible defaultOpen className="group/collapsible pt-4">
|
<Collapsible defaultOpen className="group/collapsible">
|
||||||
<CollapsibleTrigger className="flex justify-between w-full pb-2">
|
<CollapsibleTrigger className="flex justify-between w-full pb-2">
|
||||||
<span className="font-bold text-2xl text-colors-text-neutral-strong">
|
<span className="font-bold text-2xl text-colors-text-neutral-strong">
|
||||||
{t('flow.input')}
|
{t('flow.input')}
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
import { EditableCell, EditableRow } from '@/components/editable-cell';
|
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
|
||||||
import { RAGFlowNodeType } from '@/interfaces/database/flow';
|
|
||||||
import { DeleteOutlined } from '@ant-design/icons';
|
|
||||||
import { Button, Flex, Select, Table, TableProps } from 'antd';
|
|
||||||
import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query';
|
|
||||||
import { IGenerateParameter } from '../../interface';
|
|
||||||
import { useHandleOperateParameters } from './hooks';
|
|
||||||
|
|
||||||
import styles from './index.less';
|
|
||||||
interface IProps {
|
|
||||||
node?: RAGFlowNodeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const components = {
|
|
||||||
body: {
|
|
||||||
row: EditableRow,
|
|
||||||
cell: EditableCell,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const DynamicParameters = ({ node }: IProps) => {
|
|
||||||
const nodeId = node?.id;
|
|
||||||
const { t } = useTranslate('flow');
|
|
||||||
|
|
||||||
const options = useBuildComponentIdSelectOptions(nodeId, node?.parentId);
|
|
||||||
const {
|
|
||||||
dataSource,
|
|
||||||
handleAdd,
|
|
||||||
handleRemove,
|
|
||||||
handleSave,
|
|
||||||
handleComponentIdChange,
|
|
||||||
} = useHandleOperateParameters(nodeId!);
|
|
||||||
|
|
||||||
const columns: TableProps<IGenerateParameter>['columns'] = [
|
|
||||||
{
|
|
||||||
title: t('key'),
|
|
||||||
dataIndex: 'key',
|
|
||||||
key: 'key',
|
|
||||||
width: '40%',
|
|
||||||
onCell: (record: IGenerateParameter) => ({
|
|
||||||
record,
|
|
||||||
editable: true,
|
|
||||||
dataIndex: 'key',
|
|
||||||
title: 'key',
|
|
||||||
handleSave,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('value'),
|
|
||||||
dataIndex: 'component_id',
|
|
||||||
key: 'component_id',
|
|
||||||
align: 'center',
|
|
||||||
width: '40%',
|
|
||||||
render(text, record) {
|
|
||||||
return (
|
|
||||||
<Select
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
allowClear
|
|
||||||
options={options}
|
|
||||||
value={text}
|
|
||||||
onChange={handleComponentIdChange(record)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('operation'),
|
|
||||||
dataIndex: 'operation',
|
|
||||||
width: 20,
|
|
||||||
key: 'operation',
|
|
||||||
align: 'center',
|
|
||||||
fixed: 'right',
|
|
||||||
render(_, record) {
|
|
||||||
return <DeleteOutlined onClick={handleRemove(record.id)} />;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section>
|
|
||||||
<Flex justify="end">
|
|
||||||
<Button size="small" onClick={handleAdd}>
|
|
||||||
{t('add')}
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
|
||||||
<Table
|
|
||||||
dataSource={dataSource}
|
|
||||||
columns={columns}
|
|
||||||
rowKey={'id'}
|
|
||||||
className={styles.variableTable}
|
|
||||||
components={components}
|
|
||||||
rowClassName={() => styles.editableRow}
|
|
||||||
scroll={{ x: true }}
|
|
||||||
bordered
|
|
||||||
/>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DynamicParameters;
|
|
@ -1,70 +0,0 @@
|
|||||||
import get from 'lodash/get';
|
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
import { v4 as uuid } from 'uuid';
|
|
||||||
import { IGenerateParameter } from '../../interface';
|
|
||||||
import useGraphStore from '../../store';
|
|
||||||
|
|
||||||
export const useHandleOperateParameters = (nodeId: string) => {
|
|
||||||
const { getNode, updateNodeForm } = useGraphStore((state) => state);
|
|
||||||
const node = getNode(nodeId);
|
|
||||||
const dataSource: IGenerateParameter[] = useMemo(
|
|
||||||
() => get(node, 'data.form.parameters', []) as IGenerateParameter[],
|
|
||||||
[node],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleComponentIdChange = useCallback(
|
|
||||||
(row: IGenerateParameter) => (value: string) => {
|
|
||||||
const newData = [...dataSource];
|
|
||||||
const index = newData.findIndex((item) => row.id === item.id);
|
|
||||||
const item = newData[index];
|
|
||||||
newData.splice(index, 1, {
|
|
||||||
...item,
|
|
||||||
component_id: value,
|
|
||||||
});
|
|
||||||
|
|
||||||
updateNodeForm(nodeId, { parameters: newData });
|
|
||||||
},
|
|
||||||
[updateNodeForm, nodeId, dataSource],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleRemove = useCallback(
|
|
||||||
(id?: string) => () => {
|
|
||||||
const newData = dataSource.filter((item) => item.id !== id);
|
|
||||||
updateNodeForm(nodeId, { parameters: newData });
|
|
||||||
},
|
|
||||||
[updateNodeForm, nodeId, dataSource],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleAdd = useCallback(() => {
|
|
||||||
updateNodeForm(nodeId, {
|
|
||||||
parameters: [
|
|
||||||
...dataSource,
|
|
||||||
{
|
|
||||||
id: uuid(),
|
|
||||||
key: '',
|
|
||||||
component_id: undefined,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}, [dataSource, nodeId, updateNodeForm]);
|
|
||||||
|
|
||||||
const handleSave = (row: IGenerateParameter) => {
|
|
||||||
const newData = [...dataSource];
|
|
||||||
const index = newData.findIndex((item) => row.id === item.id);
|
|
||||||
const item = newData[index];
|
|
||||||
newData.splice(index, 1, {
|
|
||||||
...item,
|
|
||||||
...row,
|
|
||||||
});
|
|
||||||
|
|
||||||
updateNodeForm(nodeId, { parameters: newData });
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
handleAdd,
|
|
||||||
handleRemove,
|
|
||||||
handleComponentIdChange,
|
|
||||||
handleSave,
|
|
||||||
dataSource,
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,21 +0,0 @@
|
|||||||
.variableTable {
|
|
||||||
margin-top: 14px;
|
|
||||||
}
|
|
||||||
.editableRow {
|
|
||||||
:global(.editable-cell) {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.editable-cell-value-wrap) {
|
|
||||||
padding: 5px 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 30px !important;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
:global(.editable-cell-value-wrap) {
|
|
||||||
padding: 4px 11px;
|
|
||||||
border: 1px solid #d9d9d9;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +1,76 @@
|
|||||||
import LLMSelect from '@/components/llm-select';
|
import LLMSelect from '@/components/llm-select';
|
||||||
import MessageHistoryWindowSizeItem from '@/components/message-history-window-size-item';
|
import { MessageHistoryWindowSizeFormField } from '@/components/message-history-window-size-item';
|
||||||
import { PromptEditor } from '@/components/prompt-editor';
|
import { PromptEditor } from '@/components/prompt-editor';
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
import {
|
||||||
import { Form, Switch } from 'antd';
|
Form,
|
||||||
import { IOperatorForm } from '../../interface';
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from '@/components/ui/form';
|
||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { INextOperatorForm } from '../../interface';
|
||||||
|
|
||||||
const GenerateForm = ({ onValuesChange, form }: IOperatorForm) => {
|
const GenerateForm = ({ form }: INextOperatorForm) => {
|
||||||
const { t } = useTranslate('flow');
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form {...form}>
|
||||||
name="basic"
|
<form
|
||||||
autoComplete="off"
|
className="space-y-6"
|
||||||
form={form}
|
onSubmit={(e) => {
|
||||||
onValuesChange={onValuesChange}
|
e.preventDefault();
|
||||||
layout={'vertical'}
|
}}
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
name={'llm_id'}
|
|
||||||
label={t('model', { keyPrefix: 'chat' })}
|
|
||||||
tooltip={t('modelTip', { keyPrefix: 'chat' })}
|
|
||||||
>
|
>
|
||||||
<LLMSelect></LLMSelect>
|
<FormField
|
||||||
</Form.Item>
|
control={form.control}
|
||||||
<Form.Item
|
name="llm_id"
|
||||||
name={['prompt']}
|
render={({ field }) => (
|
||||||
label={t('systemPrompt')}
|
<FormItem>
|
||||||
initialValue={t('promptText')}
|
<FormLabel tooltip={t('chat.modelTip')}>
|
||||||
tooltip={t('promptTip', { keyPrefix: 'knowledgeConfiguration' })}
|
{t('chat.model')}
|
||||||
rules={[
|
</FormLabel>
|
||||||
{
|
<FormControl>
|
||||||
required: true,
|
<LLMSelect {...field} />
|
||||||
message: t('promptMessage'),
|
</FormControl>
|
||||||
},
|
<FormMessage />
|
||||||
]}
|
</FormItem>
|
||||||
>
|
)}
|
||||||
{/* <Input.TextArea rows={8}></Input.TextArea> */}
|
/>
|
||||||
<PromptEditor></PromptEditor>
|
<FormField
|
||||||
</Form.Item>
|
control={form.control}
|
||||||
<Form.Item
|
name="prompt"
|
||||||
name={['cite']}
|
render={({ field }) => (
|
||||||
label={t('cite')}
|
<FormItem>
|
||||||
initialValue={true}
|
<FormLabel tooltip={t('knowledgeConfiguration.promptTip')}>
|
||||||
valuePropName="checked"
|
{t('flow.systemPrompt')}
|
||||||
tooltip={t('citeTip')}
|
</FormLabel>
|
||||||
>
|
<FormControl>
|
||||||
<Switch />
|
<PromptEditor {...field} />
|
||||||
</Form.Item>
|
</FormControl>
|
||||||
<MessageHistoryWindowSizeItem
|
<FormMessage />
|
||||||
initialValue={12}
|
</FormItem>
|
||||||
></MessageHistoryWindowSizeItem>
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="cite"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel tooltip={t('flow.citeTip')}>
|
||||||
|
{t('flow.cite')}
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Switch {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<MessageHistoryWindowSizeFormField></MessageHistoryWindowSizeFormField>
|
||||||
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,10 @@ const RetrievalForm = ({ form, node }: INextOperatorForm) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DynamicInputVariable node={node}></DynamicInputVariable>
|
<DynamicInputVariable node={node}></DynamicInputVariable>
|
||||||
<SimilaritySliderFormField vectorSimilarityWeightName="keywords_similarity_weight"></SimilaritySliderFormField>
|
<SimilaritySliderFormField
|
||||||
|
vectorSimilarityWeightName="keywords_similarity_weight"
|
||||||
|
isTooltipShown
|
||||||
|
></SimilaritySliderFormField>
|
||||||
<TopNFormField></TopNFormField>
|
<TopNFormField></TopNFormField>
|
||||||
<RerankFormFields></RerankFormFields>
|
<RerankFormFields></RerankFormFields>
|
||||||
<KnowledgeBaseFormField></KnowledgeBaseFormField>
|
<KnowledgeBaseFormField></KnowledgeBaseFormField>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user