mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
Fixes: Added session variable types and modified configuration (#11269)
### What problem does this PR solve? Fixes: Added session variable types and modified configuration - Added more types of session variables - Modified the embedding model switching logic in the knowledge base configuration ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -61,6 +61,12 @@ export interface FormFieldConfig {
|
|||||||
horizontal?: boolean;
|
horizontal?: boolean;
|
||||||
onChange?: (value: any) => void;
|
onChange?: (value: any) => void;
|
||||||
tooltip?: React.ReactNode;
|
tooltip?: React.ReactNode;
|
||||||
|
customValidate?: (
|
||||||
|
value: any,
|
||||||
|
formValues: any,
|
||||||
|
) => string | boolean | Promise<string | boolean>;
|
||||||
|
dependencies?: string[];
|
||||||
|
schema?: ZodSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Component props interface
|
// Component props interface
|
||||||
@ -94,36 +100,40 @@ const generateSchema = (fields: FormFieldConfig[]): ZodSchema<any> => {
|
|||||||
let fieldSchema: ZodSchema;
|
let fieldSchema: ZodSchema;
|
||||||
|
|
||||||
// Create base validation schema based on field type
|
// Create base validation schema based on field type
|
||||||
switch (field.type) {
|
if (field.schema) {
|
||||||
case FormFieldType.Email:
|
fieldSchema = field.schema;
|
||||||
fieldSchema = z.string().email('Please enter a valid email address');
|
} else {
|
||||||
break;
|
switch (field.type) {
|
||||||
case FormFieldType.Number:
|
case FormFieldType.Email:
|
||||||
fieldSchema = z.coerce.number();
|
fieldSchema = z.string().email('Please enter a valid email address');
|
||||||
if (field.validation?.min !== undefined) {
|
break;
|
||||||
fieldSchema = (fieldSchema as z.ZodNumber).min(
|
case FormFieldType.Number:
|
||||||
field.validation.min,
|
fieldSchema = z.coerce.number();
|
||||||
field.validation.message ||
|
if (field.validation?.min !== undefined) {
|
||||||
`Value cannot be less than ${field.validation.min}`,
|
fieldSchema = (fieldSchema as z.ZodNumber).min(
|
||||||
);
|
field.validation.min,
|
||||||
}
|
field.validation.message ||
|
||||||
if (field.validation?.max !== undefined) {
|
`Value cannot be less than ${field.validation.min}`,
|
||||||
fieldSchema = (fieldSchema as z.ZodNumber).max(
|
);
|
||||||
field.validation.max,
|
}
|
||||||
field.validation.message ||
|
if (field.validation?.max !== undefined) {
|
||||||
`Value cannot be greater than ${field.validation.max}`,
|
fieldSchema = (fieldSchema as z.ZodNumber).max(
|
||||||
);
|
field.validation.max,
|
||||||
}
|
field.validation.message ||
|
||||||
break;
|
`Value cannot be greater than ${field.validation.max}`,
|
||||||
case FormFieldType.Checkbox:
|
);
|
||||||
fieldSchema = z.boolean();
|
}
|
||||||
break;
|
break;
|
||||||
case FormFieldType.Tag:
|
case FormFieldType.Checkbox:
|
||||||
fieldSchema = z.array(z.string());
|
fieldSchema = z.boolean();
|
||||||
break;
|
break;
|
||||||
default:
|
case FormFieldType.Tag:
|
||||||
fieldSchema = z.string();
|
fieldSchema = z.array(z.string());
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
fieldSchema = z.string();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle required fields
|
// Handle required fields
|
||||||
@ -300,10 +310,90 @@ const DynamicForm = {
|
|||||||
|
|
||||||
// Initialize form
|
// Initialize form
|
||||||
const form = useForm<T>({
|
const form = useForm<T>({
|
||||||
resolver: zodResolver(schema),
|
resolver: async (data, context, options) => {
|
||||||
|
const zodResult = await zodResolver(schema)(data, context, options);
|
||||||
|
|
||||||
|
let combinedErrors = { ...zodResult.errors };
|
||||||
|
|
||||||
|
const fieldErrors: Record<string, { type: string; message: string }> =
|
||||||
|
{};
|
||||||
|
for (const field of fields) {
|
||||||
|
if (field.customValidate && data[field.name] !== undefined) {
|
||||||
|
try {
|
||||||
|
const result = await field.customValidate(
|
||||||
|
data[field.name],
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
if (typeof result === 'string') {
|
||||||
|
fieldErrors[field.name] = {
|
||||||
|
type: 'custom',
|
||||||
|
message: result,
|
||||||
|
};
|
||||||
|
} else if (result === false) {
|
||||||
|
fieldErrors[field.name] = {
|
||||||
|
type: 'custom',
|
||||||
|
message:
|
||||||
|
field.validation?.message || `${field.label} is invalid`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
fieldErrors[field.name] = {
|
||||||
|
type: 'custom',
|
||||||
|
message:
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: 'Validation failed',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
combinedErrors = {
|
||||||
|
...combinedErrors,
|
||||||
|
...fieldErrors,
|
||||||
|
} as any;
|
||||||
|
console.log('combinedErrors', combinedErrors);
|
||||||
|
return {
|
||||||
|
values: Object.keys(combinedErrors).length ? {} : data,
|
||||||
|
errors: combinedErrors,
|
||||||
|
} as any;
|
||||||
|
},
|
||||||
defaultValues,
|
defaultValues,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const dependencyMap: Record<string, string[]> = {};
|
||||||
|
|
||||||
|
fields.forEach((field) => {
|
||||||
|
if (field.dependencies && field.dependencies.length > 0) {
|
||||||
|
field.dependencies.forEach((dep) => {
|
||||||
|
if (!dependencyMap[dep]) {
|
||||||
|
dependencyMap[dep] = [];
|
||||||
|
}
|
||||||
|
dependencyMap[dep].push(field.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const subscriptions = Object.keys(dependencyMap).map((depField) => {
|
||||||
|
return form.watch((values: any, { name }) => {
|
||||||
|
if (name === depField && dependencyMap[depField]) {
|
||||||
|
dependencyMap[depField].forEach((dependentField) => {
|
||||||
|
form.trigger(dependentField as any);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
subscriptions.forEach((sub) => {
|
||||||
|
if (sub.unsubscribe) {
|
||||||
|
sub.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, [fields, form]);
|
||||||
|
|
||||||
// Expose form methods via ref
|
// Expose form methods via ref
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
submit: () => form.handleSubmit(onSubmit)(),
|
submit: () => form.handleSubmit(onSubmit)(),
|
||||||
|
|||||||
@ -51,6 +51,7 @@ export interface SegmentedProps
|
|||||||
direction?: 'ltr' | 'rtl';
|
direction?: 'ltr' | 'rtl';
|
||||||
motionName?: string;
|
motionName?: string;
|
||||||
activeClassName?: string;
|
activeClassName?: string;
|
||||||
|
itemClassName?: string;
|
||||||
rounded?: keyof typeof segmentedVariants.round;
|
rounded?: keyof typeof segmentedVariants.round;
|
||||||
sizeType?: keyof typeof segmentedVariants.size;
|
sizeType?: keyof typeof segmentedVariants.size;
|
||||||
buttonSize?: keyof typeof segmentedVariants.buttonSize;
|
buttonSize?: keyof typeof segmentedVariants.buttonSize;
|
||||||
@ -62,6 +63,7 @@ export function Segmented({
|
|||||||
onChange,
|
onChange,
|
||||||
className,
|
className,
|
||||||
activeClassName,
|
activeClassName,
|
||||||
|
itemClassName,
|
||||||
rounded = 'default',
|
rounded = 'default',
|
||||||
sizeType = 'default',
|
sizeType = 'default',
|
||||||
buttonSize = 'default',
|
buttonSize = 'default',
|
||||||
@ -92,12 +94,13 @@ export function Segmented({
|
|||||||
<div
|
<div
|
||||||
key={actualValue}
|
key={actualValue}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center text-base font-normal cursor-pointer',
|
'inline-flex items-center text-base font-normal cursor-pointer',
|
||||||
segmentedVariants.round[rounded],
|
segmentedVariants.round[rounded],
|
||||||
segmentedVariants.buttonSize[buttonSize],
|
segmentedVariants.buttonSize[buttonSize],
|
||||||
{
|
{
|
||||||
'text-text-primary bg-bg-base': selectedValue === actualValue,
|
'text-text-primary bg-bg-base': selectedValue === actualValue,
|
||||||
},
|
},
|
||||||
|
itemClassName,
|
||||||
activeClassName && selectedValue === actualValue
|
activeClassName && selectedValue === actualValue
|
||||||
? activeClassName
|
? activeClassName
|
||||||
: '',
|
: '',
|
||||||
|
|||||||
@ -1009,6 +1009,7 @@ Example: general/v2/`,
|
|||||||
pleaseUploadAtLeastOneFile: 'Please upload at least one file',
|
pleaseUploadAtLeastOneFile: 'Please upload at least one file',
|
||||||
},
|
},
|
||||||
flow: {
|
flow: {
|
||||||
|
formatTypeError: 'Format or type error',
|
||||||
variableNameMessage:
|
variableNameMessage:
|
||||||
'Variable name can only contain letters and underscores',
|
'Variable name can only contain letters and underscores',
|
||||||
variableDescription: 'Variable Description',
|
variableDescription: 'Variable Description',
|
||||||
|
|||||||
@ -956,6 +956,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
|||||||
pleaseUploadAtLeastOneFile: '请上传至少一个文件',
|
pleaseUploadAtLeastOneFile: '请上传至少一个文件',
|
||||||
},
|
},
|
||||||
flow: {
|
flow: {
|
||||||
|
formatTypeError: '格式或类型错误',
|
||||||
variableNameMessage: '名称只能包含字母和下划线',
|
variableNameMessage: '名称只能包含字母和下划线',
|
||||||
variableDescription: '变量的描述',
|
variableDescription: '变量的描述',
|
||||||
defaultValue: '默认值',
|
defaultValue: '默认值',
|
||||||
|
|||||||
@ -0,0 +1,134 @@
|
|||||||
|
import {
|
||||||
|
DynamicForm,
|
||||||
|
DynamicFormRef,
|
||||||
|
FormFieldConfig,
|
||||||
|
} from '@/components/dynamic-form';
|
||||||
|
import { Modal } from '@/components/ui/modal/modal';
|
||||||
|
import { t } from 'i18next';
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
import { FieldValues } from 'react-hook-form';
|
||||||
|
import { TypeMaps, TypesWithArray } from '../constant';
|
||||||
|
import { useHandleForm } from '../hooks/use-form';
|
||||||
|
import { useObjectFields } from '../hooks/use-object-fields';
|
||||||
|
|
||||||
|
export const AddVariableModal = (props: {
|
||||||
|
fields?: FormFieldConfig[];
|
||||||
|
setFields: (value: any) => void;
|
||||||
|
visible?: boolean;
|
||||||
|
hideModal: () => void;
|
||||||
|
defaultValues?: FieldValues;
|
||||||
|
setDefaultValues?: (value: FieldValues) => void;
|
||||||
|
}) => {
|
||||||
|
const {
|
||||||
|
fields,
|
||||||
|
setFields,
|
||||||
|
visible,
|
||||||
|
hideModal,
|
||||||
|
defaultValues,
|
||||||
|
setDefaultValues,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const { handleSubmit: submitForm, loading } = useHandleForm();
|
||||||
|
|
||||||
|
const { handleCustomValidate, handleCustomSchema, handleRender } =
|
||||||
|
useObjectFields();
|
||||||
|
|
||||||
|
const formRef = useRef<DynamicFormRef>(null);
|
||||||
|
|
||||||
|
const handleFieldUpdate = (
|
||||||
|
fieldName: string,
|
||||||
|
updatedField: Partial<FormFieldConfig>,
|
||||||
|
) => {
|
||||||
|
setFields((prevFields: any) =>
|
||||||
|
prevFields.map((field: any) =>
|
||||||
|
field.name === fieldName ? { ...field, ...updatedField } : field,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const typeField = fields?.find((item) => item.name === 'type');
|
||||||
|
|
||||||
|
if (typeField) {
|
||||||
|
typeField.onChange = (value) => {
|
||||||
|
handleFieldUpdate('value', {
|
||||||
|
type: TypeMaps[value as keyof typeof TypeMaps],
|
||||||
|
render: handleRender(value),
|
||||||
|
customValidate: handleCustomValidate(value),
|
||||||
|
schema: handleCustomSchema(value),
|
||||||
|
});
|
||||||
|
const values = formRef.current?.getValues();
|
||||||
|
// setTimeout(() => {
|
||||||
|
switch (value) {
|
||||||
|
case TypesWithArray.Boolean:
|
||||||
|
setDefaultValues?.({ ...values, value: false });
|
||||||
|
break;
|
||||||
|
case TypesWithArray.Number:
|
||||||
|
setDefaultValues?.({ ...values, value: 0 });
|
||||||
|
break;
|
||||||
|
case TypesWithArray.Object:
|
||||||
|
setDefaultValues?.({ ...values, value: {} });
|
||||||
|
break;
|
||||||
|
case TypesWithArray.ArrayString:
|
||||||
|
setDefaultValues?.({ ...values, value: [''] });
|
||||||
|
break;
|
||||||
|
case TypesWithArray.ArrayNumber:
|
||||||
|
setDefaultValues?.({ ...values, value: [''] });
|
||||||
|
break;
|
||||||
|
case TypesWithArray.ArrayBoolean:
|
||||||
|
setDefaultValues?.({ ...values, value: [false] });
|
||||||
|
break;
|
||||||
|
case TypesWithArray.ArrayObject:
|
||||||
|
setDefaultValues?.({ ...values, value: [] });
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
setDefaultValues?.({ ...values, value: '' });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// }, 0);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [fields]);
|
||||||
|
|
||||||
|
const handleSubmit = async (fieldValue: FieldValues) => {
|
||||||
|
await submitForm(fieldValue);
|
||||||
|
hideModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title={t('flow.add') + t('flow.conversationVariable')}
|
||||||
|
open={visible || false}
|
||||||
|
onCancel={hideModal}
|
||||||
|
showfooter={false}
|
||||||
|
>
|
||||||
|
<DynamicForm.Root
|
||||||
|
ref={formRef}
|
||||||
|
fields={fields || []}
|
||||||
|
onSubmit={(data) => {
|
||||||
|
console.log(data);
|
||||||
|
}}
|
||||||
|
defaultValues={defaultValues}
|
||||||
|
onFieldUpdate={handleFieldUpdate}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-end w-full gap-2">
|
||||||
|
<DynamicForm.CancelButton
|
||||||
|
handleCancel={() => {
|
||||||
|
hideModal?.();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<DynamicForm.SavingButton
|
||||||
|
submitLoading={loading || false}
|
||||||
|
buttonText={t('common.ok')}
|
||||||
|
submitFunc={(values: FieldValues) => {
|
||||||
|
handleSubmit(values);
|
||||||
|
// console.log(values);
|
||||||
|
// console.log(nodes, edges);
|
||||||
|
// handleOk(values);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</DynamicForm.Root>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -13,14 +13,14 @@ export enum TypesWithArray {
|
|||||||
String = 'string',
|
String = 'string',
|
||||||
Number = 'number',
|
Number = 'number',
|
||||||
Boolean = 'boolean',
|
Boolean = 'boolean',
|
||||||
// Object = 'object',
|
Object = 'object',
|
||||||
// ArrayString = 'array<string>',
|
ArrayString = 'array<string>',
|
||||||
// ArrayNumber = 'array<number>',
|
ArrayNumber = 'array<number>',
|
||||||
// ArrayBoolean = 'array<boolean>',
|
ArrayBoolean = 'array<boolean>',
|
||||||
// ArrayObject = 'array<object>',
|
ArrayObject = 'array<object>',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GobalFormFields = [
|
export const GlobalFormFields = [
|
||||||
{
|
{
|
||||||
label: t('flow.name'),
|
label: t('flow.name'),
|
||||||
name: 'name',
|
name: 'name',
|
||||||
@ -50,11 +50,11 @@ export const GobalFormFields = [
|
|||||||
label: t('flow.description'),
|
label: t('flow.description'),
|
||||||
name: 'description',
|
name: 'description',
|
||||||
placeholder: t('flow.variableDescription'),
|
placeholder: t('flow.variableDescription'),
|
||||||
type: 'textarea',
|
type: FormFieldType.Textarea,
|
||||||
},
|
},
|
||||||
] as FormFieldConfig[];
|
] as FormFieldConfig[];
|
||||||
|
|
||||||
export const GobalVariableFormDefaultValues = {
|
export const GlobalVariableFormDefaultValues = {
|
||||||
name: '',
|
name: '',
|
||||||
type: TypesWithArray.String,
|
type: TypesWithArray.String,
|
||||||
value: '',
|
value: '',
|
||||||
@ -65,9 +65,9 @@ export const TypeMaps = {
|
|||||||
[TypesWithArray.String]: FormFieldType.Textarea,
|
[TypesWithArray.String]: FormFieldType.Textarea,
|
||||||
[TypesWithArray.Number]: FormFieldType.Number,
|
[TypesWithArray.Number]: FormFieldType.Number,
|
||||||
[TypesWithArray.Boolean]: FormFieldType.Checkbox,
|
[TypesWithArray.Boolean]: FormFieldType.Checkbox,
|
||||||
// [TypesWithArray.Object]: FormFieldType.Textarea,
|
[TypesWithArray.Object]: FormFieldType.Textarea,
|
||||||
// [TypesWithArray.ArrayString]: FormFieldType.Textarea,
|
[TypesWithArray.ArrayString]: FormFieldType.Textarea,
|
||||||
// [TypesWithArray.ArrayNumber]: FormFieldType.Textarea,
|
[TypesWithArray.ArrayNumber]: FormFieldType.Textarea,
|
||||||
// [TypesWithArray.ArrayBoolean]: FormFieldType.Textarea,
|
[TypesWithArray.ArrayBoolean]: FormFieldType.Textarea,
|
||||||
// [TypesWithArray.ArrayObject]: FormFieldType.Textarea,
|
[TypesWithArray.ArrayObject]: FormFieldType.Textarea,
|
||||||
};
|
};
|
||||||
41
web/src/pages/agent/gobal-variable-sheet/hooks/use-form.tsx
Normal file
41
web/src/pages/agent/gobal-variable-sheet/hooks/use-form.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { useFetchAgent } from '@/hooks/use-agent-request';
|
||||||
|
import { GlobalVariableType } from '@/interfaces/database/agent';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { FieldValues } from 'react-hook-form';
|
||||||
|
import { useSaveGraph } from '../../hooks/use-save-graph';
|
||||||
|
import { TypesWithArray } from '../constant';
|
||||||
|
|
||||||
|
export const useHandleForm = () => {
|
||||||
|
const { data, refetch } = useFetchAgent();
|
||||||
|
const { saveGraph, loading } = useSaveGraph();
|
||||||
|
const handleObjectData = (value: any) => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(value);
|
||||||
|
} catch (error) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleSubmit = useCallback(async (fieldValue: FieldValues) => {
|
||||||
|
const param = {
|
||||||
|
...(data.dsl?.variables || {}),
|
||||||
|
[fieldValue.name]: {
|
||||||
|
...fieldValue,
|
||||||
|
value:
|
||||||
|
fieldValue.type === TypesWithArray.Object ||
|
||||||
|
fieldValue.type === TypesWithArray.ArrayObject
|
||||||
|
? handleObjectData(fieldValue.value)
|
||||||
|
: fieldValue.value,
|
||||||
|
},
|
||||||
|
} as Record<string, GlobalVariableType>;
|
||||||
|
|
||||||
|
const res = await saveGraph(undefined, {
|
||||||
|
globalVariables: param,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.code === 0) {
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { handleSubmit, loading };
|
||||||
|
};
|
||||||
@ -0,0 +1,246 @@
|
|||||||
|
import { BlockButton, Button } from '@/components/ui/button';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { Segmented } from '@/components/ui/segmented';
|
||||||
|
import { Editor } from '@monaco-editor/react';
|
||||||
|
import { t } from 'i18next';
|
||||||
|
import { Trash2, X } from 'lucide-react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { FieldValues } from 'react-hook-form';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { TypesWithArray } from '../constant';
|
||||||
|
|
||||||
|
export const useObjectFields = () => {
|
||||||
|
const booleanRender = useCallback(
|
||||||
|
(field: FieldValues, className?: string) => {
|
||||||
|
const fieldValue = field.value ? true : false;
|
||||||
|
return (
|
||||||
|
<Segmented
|
||||||
|
options={
|
||||||
|
[
|
||||||
|
{ value: true, label: 'True' },
|
||||||
|
{ value: false, label: 'False' },
|
||||||
|
] as any
|
||||||
|
}
|
||||||
|
sizeType="sm"
|
||||||
|
value={fieldValue}
|
||||||
|
onChange={field.onChange}
|
||||||
|
className={className}
|
||||||
|
itemClassName="justify-center flex-1"
|
||||||
|
></Segmented>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const objectRender = useCallback((field: FieldValues) => {
|
||||||
|
const fieldValue =
|
||||||
|
typeof field.value === 'object'
|
||||||
|
? JSON.stringify(field.value, null, 2)
|
||||||
|
: JSON.stringify({}, null, 2);
|
||||||
|
console.log('object-render-field', field, fieldValue);
|
||||||
|
return (
|
||||||
|
<Editor
|
||||||
|
height={200}
|
||||||
|
defaultLanguage="json"
|
||||||
|
theme="vs-dark"
|
||||||
|
value={fieldValue}
|
||||||
|
onChange={field.onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const objectValidate = useCallback((value: any) => {
|
||||||
|
try {
|
||||||
|
if (!JSON.parse(value)) {
|
||||||
|
throw new Error(t('knowledgeDetails.formatTypeError'));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(t('knowledgeDetails.formatTypeError'));
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const arrayStringRender = useCallback((field: FieldValues, type = 'text') => {
|
||||||
|
const values = Array.isArray(field.value)
|
||||||
|
? field.value
|
||||||
|
: [type === 'number' ? 0 : ''];
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{values?.map((item: any, index: number) => (
|
||||||
|
<div key={index} className="flex gap-1 items-center">
|
||||||
|
<Input
|
||||||
|
type={type}
|
||||||
|
value={item}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newValues = [...values];
|
||||||
|
newValues[index] = e.target.value;
|
||||||
|
field.onChange(newValues);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant={'secondary'}
|
||||||
|
onClick={() => {
|
||||||
|
const newValues = [...values];
|
||||||
|
newValues.splice(index, 1);
|
||||||
|
field.onChange(newValues);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Trash2 />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<BlockButton
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
field.onChange([...field.value, '']);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('flow.add')}
|
||||||
|
</BlockButton>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const arrayBooleanRender = useCallback(
|
||||||
|
(field: FieldValues) => {
|
||||||
|
// const values = field.value || [false];
|
||||||
|
const values = Array.isArray(field.value) ? field.value : [false];
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-1 flex-wrap ">
|
||||||
|
{values?.map((item: any, index: number) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="flex gap-1 items-center bg-bg-card rounded-lg border-[0.5px] border-border-button"
|
||||||
|
>
|
||||||
|
{booleanRender(
|
||||||
|
{
|
||||||
|
value: item,
|
||||||
|
onChange: (value) => {
|
||||||
|
values[index] = !!value;
|
||||||
|
field.onChange(values);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'bg-transparent',
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
variant={'transparent'}
|
||||||
|
className="border-none py-0 px-1"
|
||||||
|
onClick={() => {
|
||||||
|
const newValues = [...values];
|
||||||
|
newValues.splice(index, 1);
|
||||||
|
field.onChange(newValues);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<X />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<BlockButton
|
||||||
|
className="w-auto"
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
field.onChange([...field.value, false]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('flow.add')}
|
||||||
|
</BlockButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[booleanRender],
|
||||||
|
);
|
||||||
|
|
||||||
|
const arrayNumberRender = useCallback(
|
||||||
|
(field: FieldValues) => {
|
||||||
|
return arrayStringRender(field, 'number');
|
||||||
|
},
|
||||||
|
[arrayStringRender],
|
||||||
|
);
|
||||||
|
|
||||||
|
const arrayValidate = useCallback((value: any, type: string = 'string') => {
|
||||||
|
if (!Array.isArray(value) || !value.every((item) => typeof item === type)) {
|
||||||
|
throw new Error(t('flow.formatTypeError'));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const arrayStringValidate = useCallback(
|
||||||
|
(value: any) => {
|
||||||
|
return arrayValidate(value, 'string');
|
||||||
|
},
|
||||||
|
[arrayValidate],
|
||||||
|
);
|
||||||
|
|
||||||
|
const arrayNumberValidate = useCallback(
|
||||||
|
(value: any) => {
|
||||||
|
return arrayValidate(value, 'number');
|
||||||
|
},
|
||||||
|
[arrayValidate],
|
||||||
|
);
|
||||||
|
|
||||||
|
const arrayBooleanValidate = useCallback(
|
||||||
|
(value: any) => {
|
||||||
|
return arrayValidate(value, 'boolean');
|
||||||
|
},
|
||||||
|
[arrayValidate],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleRender = (value: TypesWithArray) => {
|
||||||
|
switch (value) {
|
||||||
|
case TypesWithArray.Boolean:
|
||||||
|
return booleanRender;
|
||||||
|
case TypesWithArray.Object:
|
||||||
|
case TypesWithArray.ArrayObject:
|
||||||
|
return objectRender;
|
||||||
|
case TypesWithArray.ArrayString:
|
||||||
|
return arrayStringRender;
|
||||||
|
case TypesWithArray.ArrayNumber:
|
||||||
|
return arrayNumberRender;
|
||||||
|
case TypesWithArray.ArrayBoolean:
|
||||||
|
return arrayBooleanRender;
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleCustomValidate = (value: TypesWithArray) => {
|
||||||
|
switch (value) {
|
||||||
|
case TypesWithArray.Object:
|
||||||
|
case TypesWithArray.ArrayObject:
|
||||||
|
return objectValidate;
|
||||||
|
case TypesWithArray.ArrayString:
|
||||||
|
return arrayStringValidate;
|
||||||
|
case TypesWithArray.ArrayNumber:
|
||||||
|
return arrayNumberValidate;
|
||||||
|
case TypesWithArray.ArrayBoolean:
|
||||||
|
return arrayBooleanValidate;
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleCustomSchema = (value: TypesWithArray) => {
|
||||||
|
switch (value) {
|
||||||
|
case TypesWithArray.ArrayString:
|
||||||
|
return z.array(z.string());
|
||||||
|
case TypesWithArray.ArrayNumber:
|
||||||
|
return z.array(z.number());
|
||||||
|
case TypesWithArray.ArrayBoolean:
|
||||||
|
return z.array(z.boolean());
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
objectRender,
|
||||||
|
objectValidate,
|
||||||
|
arrayStringRender,
|
||||||
|
arrayStringValidate,
|
||||||
|
arrayNumberRender,
|
||||||
|
booleanRender,
|
||||||
|
arrayBooleanRender,
|
||||||
|
arrayNumberValidate,
|
||||||
|
arrayBooleanValidate,
|
||||||
|
handleRender,
|
||||||
|
handleCustomValidate,
|
||||||
|
handleCustomSchema,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,12 +1,6 @@
|
|||||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||||
import {
|
import { FormFieldConfig } from '@/components/dynamic-form';
|
||||||
DynamicForm,
|
|
||||||
DynamicFormRef,
|
|
||||||
FormFieldConfig,
|
|
||||||
FormFieldType,
|
|
||||||
} from '@/components/dynamic-form';
|
|
||||||
import { BlockButton, Button } from '@/components/ui/button';
|
import { BlockButton, Button } from '@/components/ui/button';
|
||||||
import { Modal } from '@/components/ui/modal/modal';
|
|
||||||
import {
|
import {
|
||||||
Sheet,
|
Sheet,
|
||||||
SheetContent,
|
SheetContent,
|
||||||
@ -19,117 +13,65 @@ import { GlobalVariableType } from '@/interfaces/database/agent';
|
|||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { Trash2 } from 'lucide-react';
|
import { Trash2 } from 'lucide-react';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { FieldValues } from 'react-hook-form';
|
import { FieldValues } from 'react-hook-form';
|
||||||
import { useSaveGraph } from '../hooks/use-save-graph';
|
import { useSaveGraph } from '../hooks/use-save-graph';
|
||||||
|
import { AddVariableModal } from './component/add-variable-modal';
|
||||||
import {
|
import {
|
||||||
GobalFormFields,
|
GlobalFormFields,
|
||||||
GobalVariableFormDefaultValues,
|
GlobalVariableFormDefaultValues,
|
||||||
TypeMaps,
|
TypeMaps,
|
||||||
TypesWithArray,
|
TypesWithArray,
|
||||||
} from './contant';
|
} from './constant';
|
||||||
|
import { useObjectFields } from './hooks/use-object-fields';
|
||||||
|
|
||||||
export type IGobalParamModalProps = {
|
export type IGlobalParamModalProps = {
|
||||||
data: any;
|
data: any;
|
||||||
hideModal: (open: boolean) => void;
|
hideModal: (open: boolean) => void;
|
||||||
};
|
};
|
||||||
export const GobalParamSheet = (props: IGobalParamModalProps) => {
|
export const GlobalParamSheet = (props: IGlobalParamModalProps) => {
|
||||||
const { hideModal } = props;
|
const { hideModal } = props;
|
||||||
const { data, refetch } = useFetchAgent();
|
const { data, refetch } = useFetchAgent();
|
||||||
const [fields, setFields] = useState<FormFieldConfig[]>(GobalFormFields);
|
|
||||||
const { visible, showModal, hideModal: hideAddModal } = useSetModalState();
|
const { visible, showModal, hideModal: hideAddModal } = useSetModalState();
|
||||||
|
const [fields, setFields] = useState<FormFieldConfig[]>(GlobalFormFields);
|
||||||
const [defaultValues, setDefaultValues] = useState<FieldValues>(
|
const [defaultValues, setDefaultValues] = useState<FieldValues>(
|
||||||
GobalVariableFormDefaultValues,
|
GlobalVariableFormDefaultValues,
|
||||||
);
|
);
|
||||||
const formRef = useRef<DynamicFormRef>(null);
|
const { handleCustomValidate, handleCustomSchema, handleRender } =
|
||||||
|
useObjectFields();
|
||||||
|
const { saveGraph } = useSaveGraph();
|
||||||
|
|
||||||
const handleFieldUpdate = (
|
const handleDeleteGlobalVariable = async (key: string) => {
|
||||||
fieldName: string,
|
|
||||||
updatedField: Partial<FormFieldConfig>,
|
|
||||||
) => {
|
|
||||||
setFields((prevFields) =>
|
|
||||||
prevFields.map((field) =>
|
|
||||||
field.name === fieldName ? { ...field, ...updatedField } : field,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const typefileld = fields.find((item) => item.name === 'type');
|
|
||||||
|
|
||||||
if (typefileld) {
|
|
||||||
typefileld.onChange = (value) => {
|
|
||||||
// setWatchType(value);
|
|
||||||
handleFieldUpdate('value', {
|
|
||||||
type: TypeMaps[value as keyof typeof TypeMaps],
|
|
||||||
});
|
|
||||||
const values = formRef.current?.getValues();
|
|
||||||
setTimeout(() => {
|
|
||||||
switch (value) {
|
|
||||||
case TypesWithArray.Boolean:
|
|
||||||
setDefaultValues({ ...values, value: false });
|
|
||||||
break;
|
|
||||||
case TypesWithArray.Number:
|
|
||||||
setDefaultValues({ ...values, value: 0 });
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
setDefaultValues({ ...values, value: '' });
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}, [fields]);
|
|
||||||
|
|
||||||
const { saveGraph, loading } = useSaveGraph();
|
|
||||||
|
|
||||||
const handleSubmit = async (value: FieldValues) => {
|
|
||||||
const param = {
|
|
||||||
...(data.dsl?.variables || {}),
|
|
||||||
[value.name]: value,
|
|
||||||
} as Record<string, GlobalVariableType>;
|
|
||||||
|
|
||||||
const res = await saveGraph(undefined, {
|
|
||||||
gobalVariables: param,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.code === 0) {
|
|
||||||
refetch();
|
|
||||||
}
|
|
||||||
hideAddModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteGobalVariable = async (key: string) => {
|
|
||||||
const param = {
|
const param = {
|
||||||
...(data.dsl?.variables || {}),
|
...(data.dsl?.variables || {}),
|
||||||
} as Record<string, GlobalVariableType>;
|
} as Record<string, GlobalVariableType>;
|
||||||
delete param[key];
|
delete param[key];
|
||||||
const res = await saveGraph(undefined, {
|
const res = await saveGraph(undefined, {
|
||||||
gobalVariables: param,
|
globalVariables: param,
|
||||||
});
|
});
|
||||||
console.log('delete gobal variable-->', res);
|
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
refetch();
|
refetch();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditGobalVariable = (item: FieldValues) => {
|
const handleEditGlobalVariable = (item: FieldValues) => {
|
||||||
fields.forEach((field) => {
|
const newFields = fields.map((field) => {
|
||||||
if (field.name === 'value') {
|
let newField = field;
|
||||||
switch (item.type) {
|
newField.render = undefined;
|
||||||
// [TypesWithArray.String]: FormFieldType.Textarea,
|
newField.schema = undefined;
|
||||||
// [TypesWithArray.Number]: FormFieldType.Number,
|
newField.customValidate = undefined;
|
||||||
// [TypesWithArray.Boolean]: FormFieldType.Checkbox,
|
if (newField.name === 'value') {
|
||||||
case TypesWithArray.Boolean:
|
newField = {
|
||||||
field.type = FormFieldType.Checkbox;
|
...newField,
|
||||||
break;
|
type: TypeMaps[item.type as keyof typeof TypeMaps],
|
||||||
case TypesWithArray.Number:
|
render: handleRender(item.type),
|
||||||
field.type = FormFieldType.Number;
|
customValidate: handleCustomValidate(item.type),
|
||||||
break;
|
schema: handleCustomSchema(item.type),
|
||||||
default:
|
};
|
||||||
field.type = FormFieldType.Textarea;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return newField;
|
||||||
});
|
});
|
||||||
|
setFields(newFields);
|
||||||
setDefaultValues(item);
|
setDefaultValues(item);
|
||||||
showModal();
|
showModal();
|
||||||
};
|
};
|
||||||
@ -149,8 +91,8 @@ export const GobalParamSheet = (props: IGobalParamModalProps) => {
|
|||||||
<div className="px-5 pb-5">
|
<div className="px-5 pb-5">
|
||||||
<BlockButton
|
<BlockButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setFields(GobalFormFields);
|
setFields(GlobalFormFields);
|
||||||
setDefaultValues(GobalVariableFormDefaultValues);
|
setDefaultValues(GlobalVariableFormDefaultValues);
|
||||||
showModal();
|
showModal();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -167,7 +109,7 @@ export const GobalParamSheet = (props: IGobalParamModalProps) => {
|
|||||||
key={key}
|
key={key}
|
||||||
className="flex items-center gap-3 min-h-14 justify-between px-5 py-3 border border-border-default rounded-lg hover:bg-bg-card group"
|
className="flex items-center gap-3 min-h-14 justify-between px-5 py-3 border border-border-default rounded-lg hover:bg-bg-card group"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleEditGobalVariable(item);
|
handleEditGlobalVariable(item);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
@ -177,13 +119,23 @@ export const GobalParamSheet = (props: IGobalParamModalProps) => {
|
|||||||
{item.type}
|
{item.type}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
{![
|
||||||
<span className="text-text-primary">{item.value}</span>
|
TypesWithArray.Object,
|
||||||
</div>
|
TypesWithArray.ArrayObject,
|
||||||
|
TypesWithArray.ArrayString,
|
||||||
|
TypesWithArray.ArrayNumber,
|
||||||
|
TypesWithArray.ArrayBoolean,
|
||||||
|
].includes(item.type as TypesWithArray) && (
|
||||||
|
<div>
|
||||||
|
<span className="text-text-primary">
|
||||||
|
{item.value}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<ConfirmDeleteDialog
|
<ConfirmDeleteDialog
|
||||||
onOk={() => handleDeleteGobalVariable(key)}
|
onOk={() => handleDeleteGlobalVariable(key)}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
variant={'secondary'}
|
variant={'secondary'}
|
||||||
@ -201,40 +153,14 @@ export const GobalParamSheet = (props: IGobalParamModalProps) => {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</SheetContent>
|
</SheetContent>
|
||||||
<Modal
|
<AddVariableModal
|
||||||
title={t('flow.add') + t('flow.conversationVariable')}
|
visible={visible}
|
||||||
open={visible}
|
hideModal={hideAddModal}
|
||||||
onCancel={hideAddModal}
|
fields={fields}
|
||||||
showfooter={false}
|
setFields={setFields}
|
||||||
>
|
defaultValues={defaultValues}
|
||||||
<DynamicForm.Root
|
setDefaultValues={setDefaultValues}
|
||||||
ref={formRef}
|
/>
|
||||||
fields={fields}
|
|
||||||
onSubmit={(data) => {
|
|
||||||
console.log(data);
|
|
||||||
}}
|
|
||||||
defaultValues={defaultValues}
|
|
||||||
onFieldUpdate={handleFieldUpdate}
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-end w-full gap-2">
|
|
||||||
<DynamicForm.CancelButton
|
|
||||||
handleCancel={() => {
|
|
||||||
hideAddModal?.();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<DynamicForm.SavingButton
|
|
||||||
submitLoading={loading || false}
|
|
||||||
buttonText={t('common.ok')}
|
|
||||||
submitFunc={(values: FieldValues) => {
|
|
||||||
handleSubmit(values);
|
|
||||||
// console.log(values);
|
|
||||||
// console.log(nodes, edges);
|
|
||||||
// handleOk(values);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</DynamicForm.Root>
|
|
||||||
</Modal>
|
|
||||||
</Sheet>
|
</Sheet>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { RAGFlowNodeType } from '@/interfaces/database/flow';
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { Operator } from '../constant';
|
import { Operator } from '../constant';
|
||||||
import useGraphStore from '../store';
|
import useGraphStore from '../store';
|
||||||
import { buildDslComponentsByGraph, buildDslGobalVariables } from '../utils';
|
import { buildDslComponentsByGraph, buildDslGlobalVariables } from '../utils';
|
||||||
|
|
||||||
export const useBuildDslData = () => {
|
export const useBuildDslData = () => {
|
||||||
const { data } = useFetchAgent();
|
const { data } = useFetchAgent();
|
||||||
@ -13,7 +13,7 @@ export const useBuildDslData = () => {
|
|||||||
const buildDslData = useCallback(
|
const buildDslData = useCallback(
|
||||||
(
|
(
|
||||||
currentNodes?: RAGFlowNodeType[],
|
currentNodes?: RAGFlowNodeType[],
|
||||||
otherParam?: { gobalVariables: Record<string, GlobalVariableType> },
|
otherParam?: { globalVariables: Record<string, GlobalVariableType> },
|
||||||
) => {
|
) => {
|
||||||
const nodesToProcess = currentNodes ?? nodes;
|
const nodesToProcess = currentNodes ?? nodes;
|
||||||
|
|
||||||
@ -41,13 +41,13 @@ export const useBuildDslData = () => {
|
|||||||
data.dsl.components,
|
data.dsl.components,
|
||||||
);
|
);
|
||||||
|
|
||||||
const gobalVariables = buildDslGobalVariables(
|
const globalVariables = buildDslGlobalVariables(
|
||||||
data.dsl,
|
data.dsl,
|
||||||
otherParam?.gobalVariables,
|
otherParam?.globalVariables,
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
...data.dsl,
|
...data.dsl,
|
||||||
...gobalVariables,
|
...globalVariables,
|
||||||
graph: { nodes: filteredNodes, edges: filteredEdges },
|
graph: { nodes: filteredNodes, edges: filteredEdges },
|
||||||
components: dslComponents,
|
components: dslComponents,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -21,7 +21,7 @@ export const useSaveGraph = (showMessage: boolean = true) => {
|
|||||||
const saveGraph = useCallback(
|
const saveGraph = useCallback(
|
||||||
async (
|
async (
|
||||||
currentNodes?: RAGFlowNodeType[],
|
currentNodes?: RAGFlowNodeType[],
|
||||||
otherParam?: { gobalVariables: Record<string, GlobalVariableType> },
|
otherParam?: { globalVariables: Record<string, GlobalVariableType> },
|
||||||
) => {
|
) => {
|
||||||
return setAgent({
|
return setAgent({
|
||||||
id,
|
id,
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import { useParams } from 'umi';
|
|||||||
import AgentCanvas from './canvas';
|
import AgentCanvas from './canvas';
|
||||||
import { DropdownProvider } from './canvas/context';
|
import { DropdownProvider } from './canvas/context';
|
||||||
import { Operator } from './constant';
|
import { Operator } from './constant';
|
||||||
import { GobalParamSheet } from './gobal-variable-sheet';
|
import { GlobalParamSheet } from './gobal-variable-sheet';
|
||||||
import { useCancelCurrentDataflow } from './hooks/use-cancel-dataflow';
|
import { useCancelCurrentDataflow } from './hooks/use-cancel-dataflow';
|
||||||
import { useHandleExportJsonFile } from './hooks/use-export-json';
|
import { useHandleExportJsonFile } from './hooks/use-export-json';
|
||||||
import { useFetchDataOnMount } from './hooks/use-fetch-data';
|
import { useFetchDataOnMount } from './hooks/use-fetch-data';
|
||||||
@ -126,9 +126,9 @@ export default function Agent() {
|
|||||||
} = useSetModalState();
|
} = useSetModalState();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
visible: gobalParamSheetVisible,
|
visible: globalParamSheetVisible,
|
||||||
showModal: showGobalParamSheet,
|
showModal: showGlobalParamSheet,
|
||||||
hideModal: hideGobalParamSheet,
|
hideModal: hideGlobalParamSheet,
|
||||||
} = useSetModalState();
|
} = useSetModalState();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -216,7 +216,7 @@ export default function Agent() {
|
|||||||
</ButtonLoading>
|
</ButtonLoading>
|
||||||
<ButtonLoading
|
<ButtonLoading
|
||||||
variant={'secondary'}
|
variant={'secondary'}
|
||||||
onClick={() => showGobalParamSheet()}
|
onClick={() => showGlobalParamSheet()}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
>
|
>
|
||||||
<MessageSquareCode /> {t('flow.conversationVariable')}
|
<MessageSquareCode /> {t('flow.conversationVariable')}
|
||||||
@ -314,11 +314,11 @@ export default function Agent() {
|
|||||||
loading={pipelineRunning}
|
loading={pipelineRunning}
|
||||||
></PipelineRunSheet>
|
></PipelineRunSheet>
|
||||||
)}
|
)}
|
||||||
{gobalParamSheetVisible && (
|
{globalParamSheetVisible && (
|
||||||
<GobalParamSheet
|
<GlobalParamSheet
|
||||||
data={{}}
|
data={{}}
|
||||||
hideModal={hideGobalParamSheet}
|
hideModal={hideGlobalParamSheet}
|
||||||
></GobalParamSheet>
|
></GlobalParamSheet>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -348,30 +348,30 @@ export const buildDslComponentsByGraph = (
|
|||||||
return components;
|
return components;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const buildDslGobalVariables = (
|
export const buildDslGlobalVariables = (
|
||||||
dsl: DSL,
|
dsl: DSL,
|
||||||
gobalVariables?: Record<string, GlobalVariableType>,
|
globalVariables?: Record<string, GlobalVariableType>,
|
||||||
) => {
|
) => {
|
||||||
if (!gobalVariables) {
|
if (!globalVariables) {
|
||||||
return { globals: dsl.globals, variables: dsl.variables || {} };
|
return { globals: dsl.globals, variables: dsl.variables || {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
let gobalVariablesTemp: Record<string, any> = {};
|
let globalVariablesTemp: Record<string, any> = {};
|
||||||
let gobalSystem: Record<string, any> = {};
|
let globalSystem: Record<string, any> = {};
|
||||||
Object.keys(dsl.globals)?.forEach((key) => {
|
Object.keys(dsl.globals)?.forEach((key) => {
|
||||||
if (key.indexOf('sys') > -1) {
|
if (key.indexOf('sys') > -1) {
|
||||||
gobalSystem[key] = dsl.globals[key];
|
globalSystem[key] = dsl.globals[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Object.keys(gobalVariables).forEach((key) => {
|
Object.keys(globalVariables).forEach((key) => {
|
||||||
gobalVariablesTemp['env.' + key] = gobalVariables[key].value;
|
globalVariablesTemp['env.' + key] = globalVariables[key].value;
|
||||||
});
|
});
|
||||||
|
|
||||||
const gobalVariablesResult = {
|
const globalVariablesResult = {
|
||||||
...gobalSystem,
|
...globalSystem,
|
||||||
...gobalVariablesTemp,
|
...globalVariablesTemp,
|
||||||
};
|
};
|
||||||
return { globals: gobalVariablesResult, variables: gobalVariables };
|
return { globals: globalVariablesResult, variables: globalVariables };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const receiveMessageError = (res: any) =>
|
export const receiveMessageError = (res: any) =>
|
||||||
|
|||||||
@ -7,11 +7,14 @@ import {
|
|||||||
FormMessage,
|
FormMessage,
|
||||||
} from '@/components/ui/form';
|
} from '@/components/ui/form';
|
||||||
import { Radio } from '@/components/ui/radio';
|
import { Radio } from '@/components/ui/radio';
|
||||||
|
import { Spin } from '@/components/ui/spin';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
import { useFormContext } from 'react-hook-form';
|
import { useFormContext } from 'react-hook-form';
|
||||||
import {
|
import {
|
||||||
|
useHandleKbEmbedding,
|
||||||
useHasParsedDocument,
|
useHasParsedDocument,
|
||||||
useSelectChunkMethodList,
|
useSelectChunkMethodList,
|
||||||
useSelectEmbeddingModelOptions,
|
useSelectEmbeddingModelOptions,
|
||||||
@ -62,11 +65,17 @@ export function ChunkMethodItem(props: IProps) {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export function EmbeddingModelItem({ line = 1, isEdit = true }: IProps) {
|
export function EmbeddingModelItem({ line = 1, isEdit }: IProps) {
|
||||||
const { t } = useTranslate('knowledgeConfiguration');
|
const { t } = useTranslate('knowledgeConfiguration');
|
||||||
const form = useFormContext();
|
const form = useFormContext();
|
||||||
const embeddingModelOptions = useSelectEmbeddingModelOptions();
|
const embeddingModelOptions = useSelectEmbeddingModelOptions();
|
||||||
|
const { handleChange } = useHandleKbEmbedding();
|
||||||
const disabled = useHasParsedDocument(isEdit);
|
const disabled = useHasParsedDocument(isEdit);
|
||||||
|
const oldValue = useMemo(() => {
|
||||||
|
const embdStr = form.getValues('embd_id');
|
||||||
|
return embdStr || '';
|
||||||
|
}, [form]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FormField
|
<FormField
|
||||||
@ -93,14 +102,33 @@ export function EmbeddingModelItem({ line = 1, isEdit = true }: IProps) {
|
|||||||
className={cn('text-muted-foreground', { 'w-3/4': line === 1 })}
|
className={cn('text-muted-foreground', { 'w-3/4': line === 1 })}
|
||||||
>
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectWithSearch
|
<Spin
|
||||||
onChange={field.onChange}
|
spinning={loading}
|
||||||
value={field.value}
|
className={cn(' rounded-lg after:bg-bg-base', {
|
||||||
options={embeddingModelOptions}
|
'opacity-20': loading,
|
||||||
disabled={isEdit ? disabled : false}
|
})}
|
||||||
placeholder={t('embeddingModelPlaceholder')}
|
>
|
||||||
triggerClassName="!bg-bg-base"
|
<SelectWithSearch
|
||||||
/>
|
onChange={async (value) => {
|
||||||
|
field.onChange(value);
|
||||||
|
if (isEdit && disabled) {
|
||||||
|
setLoading(true);
|
||||||
|
const res = await handleChange({
|
||||||
|
embed_id: value,
|
||||||
|
callback: field.onChange,
|
||||||
|
});
|
||||||
|
if (res.code !== 0) {
|
||||||
|
field.onChange(oldValue);
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
value={field.value}
|
||||||
|
options={embeddingModelOptions}
|
||||||
|
placeholder={t('embeddingModelPlaceholder')}
|
||||||
|
triggerClassName="!bg-bg-base"
|
||||||
|
/>
|
||||||
|
</Spin>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -88,7 +88,7 @@ export function GeneralForm() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<PermissionFormField></PermissionFormField>
|
<PermissionFormField></PermissionFormField>
|
||||||
<EmbeddingModelItem></EmbeddingModelItem>
|
<EmbeddingModelItem isEdit={true}></EmbeddingModelItem>
|
||||||
<PageRankFormField></PageRankFormField>
|
<PageRankFormField></PageRankFormField>
|
||||||
|
|
||||||
<TagItems></TagItems>
|
<TagItems></TagItems>
|
||||||
|
|||||||
@ -4,10 +4,12 @@ import { useSetModalState } from '@/hooks/common-hooks';
|
|||||||
import { useSelectLlmOptionsByModelType } from '@/hooks/llm-hooks';
|
import { useSelectLlmOptionsByModelType } from '@/hooks/llm-hooks';
|
||||||
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
|
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
|
||||||
import { useSelectParserList } from '@/hooks/user-setting-hooks';
|
import { useSelectParserList } from '@/hooks/user-setting-hooks';
|
||||||
|
import kbService from '@/services/knowledge-service';
|
||||||
import { useIsFetching } from '@tanstack/react-query';
|
import { useIsFetching } from '@tanstack/react-query';
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { UseFormReturn } from 'react-hook-form';
|
import { UseFormReturn } from 'react-hook-form';
|
||||||
|
import { useParams, useSearchParams } from 'umi';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { formSchema } from './form-schema';
|
import { formSchema } from './form-schema';
|
||||||
|
|
||||||
@ -98,3 +100,22 @@ export const useRenameKnowledgeTag = () => {
|
|||||||
showTagRenameModal: handleShowTagRenameModal,
|
showTagRenameModal: handleShowTagRenameModal,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useHandleKbEmbedding = () => {
|
||||||
|
const { id } = useParams();
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
const knowledgeBaseId = searchParams.get('id') || id;
|
||||||
|
const handleChange = useCallback(
|
||||||
|
async ({ embed_id }: { embed_id: string }) => {
|
||||||
|
const res = await kbService.checkEmbedding({
|
||||||
|
kb_id: knowledgeBaseId,
|
||||||
|
embd_id: embed_id,
|
||||||
|
});
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
[knowledgeBaseId],
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
handleChange,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@ -47,6 +47,7 @@ const {
|
|||||||
traceGraphRag,
|
traceGraphRag,
|
||||||
runRaptor,
|
runRaptor,
|
||||||
traceRaptor,
|
traceRaptor,
|
||||||
|
check_embedding,
|
||||||
} = api;
|
} = api;
|
||||||
|
|
||||||
const methods = {
|
const methods = {
|
||||||
@ -214,6 +215,11 @@ const methods = {
|
|||||||
url: api.pipelineRerun,
|
url: api.pipelineRerun,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
checkEmbedding: {
|
||||||
|
url: check_embedding,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const kbService = registerServer<keyof typeof methods>(methods, request);
|
const kbService = registerServer<keyof typeof methods>(methods, request);
|
||||||
|
|||||||
@ -49,6 +49,8 @@ export default {
|
|||||||
llm_tools: `${api_host}/plugin/llm_tools`,
|
llm_tools: `${api_host}/plugin/llm_tools`,
|
||||||
|
|
||||||
// knowledge base
|
// knowledge base
|
||||||
|
|
||||||
|
check_embedding: `${api_host}/kb/check_embedding`,
|
||||||
kb_list: `${api_host}/kb/list`,
|
kb_list: `${api_host}/kb/list`,
|
||||||
create_kb: `${api_host}/kb/create`,
|
create_kb: `${api_host}/kb/create`,
|
||||||
update_kb: `${api_host}/kb/update`,
|
update_kb: `${api_host}/kb/update`,
|
||||||
|
|||||||
Reference in New Issue
Block a user