import { type FC, type ReactNode, useEffect, useRef, useState, forwardRef, useImperativeHandle } from 'react'; import clsx from 'clsx' import { useTranslation } from 'react-i18next' import { useParams } from 'react-router-dom'; import { Row, Col, Space, Form, Input, Switch, Button, App, Spin } from 'antd' import Chat from './components/Chat' import RbCard from '@/components/RbCard/Card' import Card from './components/Card' import ModelConfigModal from './components/ModelConfigModal' import type { ModelConfigModalRef, ChatData, Config, ModelConfig, AgentRef, KnowledgeBase, KnowledgeConfig, Variable, MemoryConfig, } from './types' import type { Model } from '@/views/ModelManagement/types' import { getModelList } from '@/api/models'; import { saveAgentConfig } from '@/api/application' import Knowledge from './components/Knowledge' import VariableList from './components/VariableList' import { getApplicationConfig } from '@/api/application' import { getKnowledgeBaseList } from '@/api/knowledgeBase' import { memoryConfigListUrl } from '@/api/memory' import CustomSelect from '@/components/CustomSelect' const DescWrapper: FC<{desc: string, className?: string}> = ({desc, className}) => { return (
{desc}
) } const LabelWrapper: FC<{title: string, className?: string; children?: ReactNode}> = ({title, className, children}) => { return (
{title} {children}
) } const SwitchWrapper: FC<{ title: string, desc: string, name: string }> = ({ title, desc, name }) => { const { t } = useTranslation(); return (
) } const SelectWrapper: FC<{ title: string, desc: string, name: string, url: string }> = ({ title, desc, name, url }) => { const { t } = useTranslation(); return ( <> ) } const Agent = forwardRef((_props, ref) => { const { t } = useTranslation() const { id } = useParams(); const { message } = App.useApp() const [form] = Form.useForm() const [loading, setLoading] = useState(false) const [data, setData] = useState(null); const modelConfigModalRef = useRef(null) const [modelList, setModelList] = useState([]) const [defaultModel, setDefaultModel] = useState(null) const [chatList, setChatList] = useState([]) const [formData, setFormData] = useState<{ default_model_config_id?: string, model_parameters?: Config['model_parameters'], } | null>(null) const values = Form.useWatch<{ memoryEnabled: boolean; memory_content?: string | number; webSearch: boolean; } & Config>([], form) const [knowledgeConfig, setKnowledgeConfig] = useState({ knowledge_bases: [] }) const [variableList, setVariableList] = useState([]) const [isSave, setIsSave] = useState(false) const initialized = useRef(false) // 初始化完成标记 useEffect(() => { if (data && values && formData) { initialized.current = true } }, [data, values, formData]) useEffect(() => { if (!initialized.current) return if (isSave) return setIsSave(true) }, [knowledgeConfig]) useEffect(() => { if (!initialized.current) return if (isSave) return setIsSave(true) }, [variableList]) useEffect(() => { if (!initialized.current) return if (isSave) return setIsSave(true) }, [formData]) useEffect(() => { if (!initialized.current) return if (isSave) return setIsSave(true) }, [values]) useEffect(() => { getModels() getData() }, []) const getData = () => { setLoading(true) getApplicationConfig(id as string).then(res => { const response = res as Config setData(response) const { memory, tools } = response form.setFieldsValue({ ...response, memoryEnabled: memory?.enabled || false, memory_content: memory?.memory_content ? Number(memory?.memory_content) : undefined, webSearch: tools?.web_search?.enabled || false, }) setFormData({ default_model_config_id: response.default_model_config_id, model_parameters: response.model_parameters || {}, }) if (response?.knowledge_retrieval?.knowledge_bases?.length) { getDefaultKnowledgeList(response) } }).finally(() => { setLoading(false) }) } const getDefaultKnowledgeList = (data: Config) => { if (!data || !data.knowledge_retrieval || !data.knowledge_retrieval?.knowledge_bases?.length) { return } const initialList = [...(data?.knowledge_retrieval?.knowledge_bases || [])] getKnowledgeBaseList(undefined, { kb_ids: initialList.map(vo => vo.kb_id).join(','), page: 1, pagesize: 100, }) .then(res => { const list = res.items || [] const knowledge_bases: KnowledgeBase[] = list.map(item => { const filterItem = initialList.find(vo => vo.kb_id === item.id) return { ...item, ...filterItem } }) setData((prev) => { prev = prev as Config const knowledge_retrieval: KnowledgeConfig = { ...(prev?.knowledge_retrieval || {}), knowledge_bases: [...knowledge_bases] } return { ...(prev || {}), knowledge_retrieval } }) }) } const refresh = (vo: ModelConfig, type: 'model' | 'chat') => { if (type === 'model') { const { default_model_config_id, ...rest } = vo form.setFieldsValue({ default_model_config_id, model_parameters: {...rest} }) setFormData((prevState) => { const prev = prevState as Config return { ...(prev || {}), default_model_config_id, model_parameters: {...rest} }; }) if (default_model_config_id === formData?.default_model_config_id) { setChatList([{ label: vo.label || '', model_config_id: default_model_config_id || '', model_parameters: {...rest}, list: [] }]) } } else if (type === 'chat') { if (chatList.length >= 4) { message.warning(t('application.maxChatCount')) return } const { label, default_model_config_id, ...reset } = vo setChatList((prev: ChatData[]) => { const newChatItem: ChatData = { label, model_config_id: default_model_config_id || '', model_parameters: {...reset}, list: [] }; return [ ...(prev || []).map(item => ({ ...item, list: [] })), newChatItem ]; }) } } const handleModelConfig = () => { modelConfigModalRef.current?.handleOpen('model') } const handleClearDebugging = () => { setChatList([]) } // 保存Agent配置 const handleSave = (flag = true) => { if (!isSave || !data) return Promise.resolve() const { memoryEnabled, memory_content, webSearch, ...rest } = values const { knowledge_bases = [], ...knowledgeRest } = knowledgeConfig || {} // 从原数据中获取memory的其他必要属性 const originalMemory = data.memory || ({} as MemoryConfig) const params: Config = { ...data, ...rest, ...(formData || {}), memory: { ...originalMemory, enabled: memoryEnabled, memory_content: memory_content ? String(memory_content) : '', max_history: originalMemory.max_history || '', }, variables: variableList || [], knowledge_retrieval: knowledge_bases.length > 0 ? { ...data.knowledge_retrieval, ...knowledgeRest, knowledge_bases: knowledge_bases.map(item => ({ kb_id: item.id, ...(item.config || {}) })) } as KnowledgeConfig : null, tools: { web_search: { enabled: webSearch, config: { web_search: webSearch } } } } return new Promise((resolve, reject) => { saveAgentConfig(data.app_id, params) .then(() => { if (flag) { message.success(t('common.saveSuccess')) } setIsSave(false) resolve(true) }).catch(error => { reject(error) }) }) } const getModels = () => { const requests = [getModelList({ type: 'llm', pagesize: 100, page: 1 }), getModelList({ type: 'chat', pagesize: 100, page: 1 })] Promise.all(requests) .then(responses => { const [chatRes, modelRes] = responses as { items: Model[] }[] const chatList = chatRes.items || [] const modelList = modelRes.items || [] setModelList([...chatList, ...modelList]) }) } const handleAddModel = () => { modelConfigModalRef.current?.handleOpen('chat') } useEffect(() => { if (formData?.default_model_config_id && modelList.length > 0) { const filterValue = modelList.find(item => item.id === formData.default_model_config_id) setDefaultModel(filterValue as Model | null) setChatList([{ label: filterValue?.name || '', model_config_id: filterValue?.id || '', model_parameters: {...(filterValue?.config || {})} as unknown as ModelConfig, list: [] }]) } }, [modelList, formData?.default_model_config_id]) useImperativeHandle(ref, () => ({ handleSave })) return ( <> {loading && }
{/* 提示词 */}
{t('application.configuration')} ({t('application.configurationDesc')})
{/* 知识库 */} {/* 记忆配置 */} {/* 变量配置 */} {/* 工具配置 */} {/* */}
{t('application.debuggingAndPreview')}
); }); export default Agent;