refactor: agent config refactor
This commit is contained in:
@@ -658,8 +658,8 @@ export const zh = {
|
|||||||
priority: '结构化整合',
|
priority: '结构化整合',
|
||||||
addTool: '添加工具',
|
addTool: '添加工具',
|
||||||
tool: '工具',
|
tool: '工具',
|
||||||
|
variableConfig: '配置变量'
|
||||||
},
|
},
|
||||||
// 角色管理相关翻译
|
|
||||||
role: {
|
role: {
|
||||||
roleManagement: '角色管理',
|
roleManagement: '角色管理',
|
||||||
roleId: '角色ID',
|
roleId: '角色ID',
|
||||||
|
|||||||
@@ -13,26 +13,25 @@ import type {
|
|||||||
Config,
|
Config,
|
||||||
ModelConfig,
|
ModelConfig,
|
||||||
AgentRef,
|
AgentRef,
|
||||||
KnowledgeBase,
|
|
||||||
KnowledgeConfig,
|
|
||||||
Variable,
|
|
||||||
MemoryConfig,
|
MemoryConfig,
|
||||||
AiPromptModalRef,
|
AiPromptModalRef,
|
||||||
Source,
|
Source,
|
||||||
ToolOption
|
ChatVariableConfigModalRef
|
||||||
} from './types'
|
} from './types'
|
||||||
|
import type { Variable } from './components/VariableList/types'
|
||||||
|
import type { KnowledgeConfig } from './components/Knowledge/types'
|
||||||
import type { Model } from '@/views/ModelManagement/types'
|
import type { Model } from '@/views/ModelManagement/types'
|
||||||
import { getModelList } from '@/api/models';
|
import { getModelList } from '@/api/models';
|
||||||
import { saveAgentConfig } from '@/api/application'
|
import { saveAgentConfig } from '@/api/application'
|
||||||
import Knowledge from './components/Knowledge'
|
import Knowledge from './components/Knowledge/Knowledge'
|
||||||
import VariableList from './components/VariableList'
|
import VariableList from './components/VariableList/VariableList'
|
||||||
import { getApplicationConfig } from '@/api/application'
|
import { getApplicationConfig } from '@/api/application'
|
||||||
import { getKnowledgeBaseList } from '@/api/knowledgeBase'
|
|
||||||
import { memoryConfigListUrl } from '@/api/memory'
|
import { memoryConfigListUrl } from '@/api/memory'
|
||||||
import CustomSelect from '@/components/CustomSelect'
|
import CustomSelect from '@/components/CustomSelect'
|
||||||
import aiPrompt from '@/assets/images/application/aiPrompt.png'
|
import aiPrompt from '@/assets/images/application/aiPrompt.png'
|
||||||
import AiPromptModal from './components/AiPromptModal'
|
import AiPromptModal from './components/AiPromptModal'
|
||||||
import ToolList from './components/ToolList'
|
import ToolList from './components/ToolList/ToolList'
|
||||||
|
import ChatVariableConfigModal from './components/ChatVariableConfigModal';
|
||||||
|
|
||||||
const DescWrapper: FC<{desc: string, className?: string}> = ({desc, className}) => {
|
const DescWrapper: FC<{desc: string, className?: string}> = ({desc, className}) => {
|
||||||
return (
|
return (
|
||||||
@@ -66,7 +65,7 @@ const SwitchWrapper: FC<{ title: string, desc?: string, name: string | string[];
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const SelectWrapper: FC<{ title: string, desc: string, name: string, url: string }> = ({ title, desc, name, url }) => {
|
const SelectWrapper: FC<{ title: string, desc: string, name: string | string[], url: string }> = ({ title, desc, name, url }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -77,6 +76,7 @@ const SelectWrapper: FC<{ title: string, desc: string, name: string, url: string
|
|||||||
className="rb:mb-0!"
|
className="rb:mb-0!"
|
||||||
>
|
>
|
||||||
<CustomSelect
|
<CustomSelect
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
url={url}
|
url={url}
|
||||||
hasAll={false}
|
hasAll={false}
|
||||||
valueKey='config_id'
|
valueKey='config_id'
|
||||||
@@ -99,54 +99,22 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
const [modelList, setModelList] = useState<Model[]>([])
|
const [modelList, setModelList] = useState<Model[]>([])
|
||||||
const [defaultModel, setDefaultModel] = useState<Model | null>(null)
|
const [defaultModel, setDefaultModel] = useState<Model | null>(null)
|
||||||
const [chatList, setChatList] = useState<ChatData[]>([])
|
const [chatList, setChatList] = useState<ChatData[]>([])
|
||||||
const [formData, setFormData] = useState<{
|
const values = Form.useWatch<Config>([], form)
|
||||||
default_model_config_id?: string,
|
|
||||||
model_parameters?: Config['model_parameters'],
|
|
||||||
tools: ToolOption[],
|
|
||||||
} | null>(null)
|
|
||||||
const values = Form.useWatch<{
|
|
||||||
memoryEnabled: boolean;
|
|
||||||
memory_content?: string | number;
|
|
||||||
} & Config>([], form)
|
|
||||||
|
|
||||||
const [knowledgeConfig, setKnowledgeConfig] = useState<KnowledgeConfig>({ knowledge_bases: [] })
|
|
||||||
const [variableList, setVariableList] = useState<Variable[]>([])
|
|
||||||
const [isSave, setIsSave] = useState(false)
|
const [isSave, setIsSave] = useState(false)
|
||||||
const initialized = useRef(false)
|
const initialized = useRef(false)
|
||||||
const [toolList, setToolList] = useState<ToolOption[]>([])
|
|
||||||
|
|
||||||
// 初始化完成标记
|
// 初始化完成标记
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data && values && formData) {
|
if (data) {
|
||||||
initialized.current = true
|
initialized.current = true
|
||||||
}
|
}
|
||||||
}, [data, values, formData])
|
}, [data])
|
||||||
|
|
||||||
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(() => {
|
useEffect(() => {
|
||||||
if (!initialized.current) return
|
if (!initialized.current) return
|
||||||
if (isSave) return
|
if (isSave) return
|
||||||
setIsSave(true)
|
setIsSave(true)
|
||||||
}, [values])
|
}, [values])
|
||||||
useEffect(() => {
|
|
||||||
if (!initialized.current) return
|
|
||||||
if (isSave) return
|
|
||||||
setIsSave(true)
|
|
||||||
}, [toolList])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getModels()
|
getModels()
|
||||||
@@ -157,68 +125,19 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
setLoading(true)
|
setLoading(true)
|
||||||
getApplicationConfig(id as string).then(res => {
|
getApplicationConfig(id as string).then(res => {
|
||||||
const response = res as Config
|
const response = res as Config
|
||||||
setData({
|
let allTools = Array.isArray(response.tools) ? response.tools : []
|
||||||
...response,
|
|
||||||
tools: Array.isArray(response.tools) ? response.tools : []
|
|
||||||
})
|
|
||||||
const { memory, tools } = response
|
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
...response,
|
...response,
|
||||||
memoryEnabled: memory?.enabled || false,
|
tools: allTools
|
||||||
memory_content: memory?.memory_content ? Number(memory?.memory_content) : undefined,
|
|
||||||
tools: Array.isArray(tools) ? tools : []
|
|
||||||
})
|
})
|
||||||
setFormData({
|
setData({
|
||||||
default_model_config_id: response.default_model_config_id,
|
...response,
|
||||||
model_parameters: response.model_parameters || {},
|
tools: allTools
|
||||||
tools: Array.isArray(tools) ? tools : []
|
|
||||||
})
|
})
|
||||||
if (response?.knowledge_retrieval?.knowledge_bases?.length) {
|
|
||||||
getDefaultKnowledgeList(response)
|
|
||||||
}
|
|
||||||
if (response?.tools?.length) {
|
|
||||||
setToolList(response?.tools)
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
setLoading(false)
|
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
|
|
||||||
}
|
|
||||||
})
|
|
||||||
setKnowledgeConfig(prev => ({
|
|
||||||
...prev,
|
|
||||||
knowledge_bases: [...knowledge_bases]
|
|
||||||
}))
|
|
||||||
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: Source) => {
|
const refresh = (vo: ModelConfig, type: Source) => {
|
||||||
if (type === 'model') {
|
if (type === 'model') {
|
||||||
@@ -227,15 +146,7 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
default_model_config_id,
|
default_model_config_id,
|
||||||
model_parameters: {...rest}
|
model_parameters: {...rest}
|
||||||
})
|
})
|
||||||
setFormData((prevState) => {
|
if (default_model_config_id === values?.default_model_config_id) {
|
||||||
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([{
|
setChatList([{
|
||||||
label: vo.label || '',
|
label: vo.label || '',
|
||||||
model_config_id: default_model_config_id || '',
|
model_config_id: default_model_config_id || '',
|
||||||
@@ -279,24 +190,20 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
// 保存Agent配置
|
// 保存Agent配置
|
||||||
const handleSave = (flag = true) => {
|
const handleSave = (flag = true) => {
|
||||||
if (!isSave || !data) return Promise.resolve()
|
if (!isSave || !data) return Promise.resolve()
|
||||||
const { memoryEnabled, memory_content, ...rest } = values
|
const { memory, knowledge_retrieval, tools, ...rest } = values
|
||||||
const { knowledge_bases = [], ...knowledgeRest } = knowledgeConfig || {}
|
const { knowledge_bases = [], ...knowledgeRest } = knowledge_retrieval || {}
|
||||||
|
const { memory_content } = memory || {}
|
||||||
|
|
||||||
// 从原数据中获取memory的其他必要属性
|
// 从原数据中获取memory的其他必要属性
|
||||||
const originalMemory = data.memory || ({} as MemoryConfig)
|
const originalMemory = data.memory || ({} as MemoryConfig)
|
||||||
|
|
||||||
const params: Config = {
|
const params: Config = {
|
||||||
...data,
|
...data,
|
||||||
...rest,
|
...rest,
|
||||||
...(formData || {}),
|
|
||||||
memory: {
|
memory: {
|
||||||
...originalMemory,
|
...originalMemory,
|
||||||
enabled: memoryEnabled,
|
...memory,
|
||||||
memory_content: memory_content ? String(memory_content) : '',
|
memory_content: memory_content ? String(memory_content) : '',
|
||||||
max_history: originalMemory.max_history || '',
|
|
||||||
},
|
},
|
||||||
variables: variableList || [],
|
|
||||||
knowledge_retrieval: knowledge_bases.length > 0 ? {
|
knowledge_retrieval: knowledge_bases.length > 0 ? {
|
||||||
...data.knowledge_retrieval,
|
...data.knowledge_retrieval,
|
||||||
...knowledgeRest,
|
...knowledgeRest,
|
||||||
@@ -305,14 +212,12 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
...(item.config || {})
|
...(item.config || {})
|
||||||
}))
|
}))
|
||||||
} as KnowledgeConfig : null,
|
} as KnowledgeConfig : null,
|
||||||
tools: toolList.map(vo => ({
|
tools: tools.map(vo => ({
|
||||||
tool_id: vo.tool_id,
|
tool_id: vo.tool_id,
|
||||||
operation: vo.operation,
|
operation: vo.operation,
|
||||||
enabled: vo.enabled
|
enabled: vo.enabled
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('params', rest, params)
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
saveAgentConfig(data.app_id, params)
|
saveAgentConfig(data.app_id, params)
|
||||||
@@ -338,8 +243,8 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
modelConfigModalRef.current?.handleOpen('chat')
|
modelConfigModalRef.current?.handleOpen('chat')
|
||||||
}
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (formData?.default_model_config_id && modelList.length > 0) {
|
if (values?.default_model_config_id && modelList.length > 0) {
|
||||||
const filterValue = modelList.find(item => item.id === formData.default_model_config_id)
|
const filterValue = modelList.find(item => item.id === values.default_model_config_id)
|
||||||
setDefaultModel(filterValue as Model | null)
|
setDefaultModel(filterValue as Model | null)
|
||||||
setChatList([{
|
setChatList([{
|
||||||
label: filterValue?.name || '',
|
label: filterValue?.name || '',
|
||||||
@@ -348,7 +253,7 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
list: []
|
list: []
|
||||||
}])
|
}])
|
||||||
}
|
}
|
||||||
}, [modelList, formData?.default_model_config_id])
|
}, [modelList, values?.default_model_config_id])
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
handleSave
|
handleSave
|
||||||
@@ -360,8 +265,31 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
}
|
}
|
||||||
const updatePrompt = (value: string) => {
|
const updatePrompt = (value: string) => {
|
||||||
form.setFieldValue('system_prompt', value)
|
form.setFieldValue('system_prompt', value)
|
||||||
|
const variables = value.match(/\{\{([^}]+)\}\}/g)?.map(match => match.slice(2, -2)) || []
|
||||||
|
const uniqueVariables = [...new Set(variables)]
|
||||||
|
const newVariableList: Variable[] = uniqueVariables.map((name, index) => ({
|
||||||
|
index,
|
||||||
|
type: 'text',
|
||||||
|
name,
|
||||||
|
display_name: name,
|
||||||
|
required: false
|
||||||
|
}))
|
||||||
|
updateVariableList(newVariableList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateVariableList = (list: Variable[]) => {
|
||||||
|
form.setFieldValue('variables', [...list])
|
||||||
|
setChatVariables([...list])
|
||||||
|
}
|
||||||
|
const chatVariableConfigModalRef = useRef<ChatVariableConfigModalRef>(null)
|
||||||
|
const [chatVariables, setChatVariables] = useState<Variable[]>([])
|
||||||
|
const handleOpenVariableConfig = () => {
|
||||||
|
chatVariableConfigModalRef.current?.handleOpen(chatVariables)
|
||||||
|
}
|
||||||
|
const handleSaveChatVariable = (values: Variable[]) => {
|
||||||
|
setChatVariables(values)
|
||||||
|
}
|
||||||
|
console.log('values', values)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{loading && <Spin fullscreen></Spin>}
|
{loading && <Spin fullscreen></Spin>}
|
||||||
@@ -379,8 +307,9 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
<Form form={form}>
|
<Form form={form}>
|
||||||
|
<Form.Item name="default_model_config_id" hidden noStyle></Form.Item>
|
||||||
|
<Form.Item name="model_parameters" hidden noStyle></Form.Item>
|
||||||
<Space size={16} direction="vertical" style={{ width: '100%' }}>
|
<Space size={16} direction="vertical" style={{ width: '100%' }}>
|
||||||
{/* 提示词 */}
|
|
||||||
<Card title={t('application.promptConfiguration')}>
|
<Card title={t('application.promptConfiguration')}>
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:mb-2.75">
|
<div className="rb:flex rb:items-center rb:justify-between rb:mb-2.75">
|
||||||
<div className="rb:font-medium rb:leading-5">
|
<div className="rb:font-medium rb:leading-5">
|
||||||
@@ -406,36 +335,31 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* 知识库 */}
|
<Form.Item name="knowledge_retrieval" noStyle>
|
||||||
<Knowledge
|
<Knowledge />
|
||||||
data={data?.knowledge_retrieval || { knowledge_bases: [] }}
|
</Form.Item>
|
||||||
onUpdate={setKnowledgeConfig}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* 记忆配置 */}
|
{/* 记忆配置 */}
|
||||||
<Card title={t('application.memoryConfiguration')}>
|
<Card title={t('application.memoryConfiguration')}>
|
||||||
<Space size={24} direction='vertical' style={{ width: '100%' }}>
|
<Space size={24} direction='vertical' style={{ width: '100%' }}>
|
||||||
<SwitchWrapper title="dialogueHistoricalMemory" desc="dialogueHistoricalMemoryDesc" name="memoryEnabled" />
|
<SwitchWrapper title="dialogueHistoricalMemory" desc="dialogueHistoricalMemoryDesc" name={['memory', 'enabled']} />
|
||||||
<SelectWrapper
|
<SelectWrapper
|
||||||
title="selectMemoryContent"
|
title="selectMemoryContent"
|
||||||
desc="selectMemoryContentDesc"
|
desc="selectMemoryContentDesc"
|
||||||
name="memory_content"
|
name={['memory', 'memory_content']}
|
||||||
url={memoryConfigListUrl}
|
url={memoryConfigListUrl}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* 变量配置 */}
|
<Form.Item name="variables">
|
||||||
<VariableList
|
<VariableList />
|
||||||
data={data?.variables}
|
</Form.Item>
|
||||||
onUpdate={setVariableList}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* 工具配置 */}
|
{/* 工具配置 */}
|
||||||
<ToolList
|
<Form.Item name="tools">
|
||||||
data={data?.tools || []}
|
<ToolList />
|
||||||
onUpdate={setToolList}
|
</Form.Item>
|
||||||
/>
|
|
||||||
</Space>
|
</Space>
|
||||||
</Form>
|
</Form>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -444,6 +368,9 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
{t('application.debuggingAndPreview')}
|
{t('application.debuggingAndPreview')}
|
||||||
|
|
||||||
<Space size={10}>
|
<Space size={10}>
|
||||||
|
<Button type="primary" ghost onClick={handleOpenVariableConfig}>
|
||||||
|
{t('application.variableConfig')}
|
||||||
|
</Button>
|
||||||
<Button type="primary" ghost onClick={handleAddModel}>
|
<Button type="primary" ghost onClick={handleAddModel}>
|
||||||
+ {t('application.addModel')}
|
+ {t('application.addModel')}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -463,7 +390,7 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
|
|
||||||
<ModelConfigModal
|
<ModelConfigModal
|
||||||
modelList={modelList}
|
modelList={modelList}
|
||||||
data={formData as Config}
|
data={values}
|
||||||
ref={modelConfigModalRef}
|
ref={modelConfigModalRef}
|
||||||
refresh={refresh}
|
refresh={refresh}
|
||||||
/>
|
/>
|
||||||
@@ -472,6 +399,10 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
|
|||||||
defaultModel={defaultModel}
|
defaultModel={defaultModel}
|
||||||
refresh={updatePrompt}
|
refresh={updatePrompt}
|
||||||
/>
|
/>
|
||||||
|
<ChatVariableConfigModal
|
||||||
|
ref={chatVariableConfigModalRef}
|
||||||
|
refresh={handleSaveChatVariable}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,18 +3,21 @@ import RbCard from '@/components/RbCard/Card'
|
|||||||
|
|
||||||
interface CardProps {
|
interface CardProps {
|
||||||
title?: string | ReactNode;
|
title?: string | ReactNode;
|
||||||
|
subTitle?: string | ReactNode;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
extra?: ReactNode;
|
extra?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Card: FC<CardProps> = ({
|
const Card: FC<CardProps> = ({
|
||||||
title,
|
title,
|
||||||
|
subTitle,
|
||||||
children,
|
children,
|
||||||
extra,
|
extra,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<RbCard
|
<RbCard
|
||||||
title={title}
|
title={title}
|
||||||
|
subTitle={subTitle}
|
||||||
extra={extra}
|
extra={extra}
|
||||||
headerType="borderL"
|
headerType="borderL"
|
||||||
headerClassName="rb:before:bg-[#155EEF]! rb:before:h-[19px]"
|
headerClassName="rb:before:bg-[#155EEF]! rb:before:h-[19px]"
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||||
|
import { Form, Input, InputNumber } from 'antd';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import type { ChatVariableConfigModalRef } from '../types'
|
||||||
|
import type { Variable } from './VariableList/types'
|
||||||
|
import RbModal from '@/components/RbModal'
|
||||||
|
|
||||||
|
interface VariableEditModalProps {
|
||||||
|
refresh: (values: Variable[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChatVariableConfigModal = forwardRef<ChatVariableConfigModalRef, VariableEditModalProps>(({
|
||||||
|
refresh,
|
||||||
|
}, ref) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const [form] = Form.useForm<{variables: Variable[]}>();
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [initialValues, setInitialValues] = useState<Variable[]>([])
|
||||||
|
|
||||||
|
// 封装取消方法,添加关闭弹窗逻辑
|
||||||
|
const handleClose = () => {
|
||||||
|
setVisible(false);
|
||||||
|
form.resetFields();
|
||||||
|
setLoading(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOpen = (values: Variable[]) => {
|
||||||
|
console.log('values', values)
|
||||||
|
setVisible(true);
|
||||||
|
form.setFieldsValue({variables: values})
|
||||||
|
setInitialValues([...values])
|
||||||
|
};
|
||||||
|
// 封装保存方法,添加提交逻辑
|
||||||
|
const handleSave = () => {
|
||||||
|
form.validateFields().then((values) => {
|
||||||
|
refresh([
|
||||||
|
...(values?.variables ?? []),
|
||||||
|
])
|
||||||
|
handleClose()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露给父组件的方法
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
handleOpen,
|
||||||
|
handleClose
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log(form.getFieldValue('variables'))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RbModal
|
||||||
|
title={t('application.variableConfig')}
|
||||||
|
open={visible}
|
||||||
|
onCancel={handleClose}
|
||||||
|
okText={t('common.save')}
|
||||||
|
onOk={handleSave}
|
||||||
|
confirmLoading={loading}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
layout="horizontal"
|
||||||
|
scrollToFirstError={{ behavior: 'instant', block: 'end', focus: true }}
|
||||||
|
>
|
||||||
|
<Form.List name="variables">
|
||||||
|
{(fields) => (
|
||||||
|
<>
|
||||||
|
{fields.map(({ name }, index) => {
|
||||||
|
const field = initialValues[index]
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
key={name}
|
||||||
|
name={[name, 'value']}
|
||||||
|
label={`${field.name}·${field.display_name}`}
|
||||||
|
rules={[
|
||||||
|
{ required: field.required, message: t('common.pleaseEnter') },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
field.type === 'text' && <Input placeholder={t('common.pleaseEnter')} />
|
||||||
|
}
|
||||||
|
{
|
||||||
|
field.type === 'number' && <InputNumber placeholder={t('common.pleaseEnter')} className="rb:w-full!" onChange={(value) => form.setFieldValue(['variables', name, 'value'], value)} />
|
||||||
|
}
|
||||||
|
{
|
||||||
|
field.type === 'paragraph' && <Input.TextArea placeholder={t('common.pleaseEnter')} />
|
||||||
|
}
|
||||||
|
</Form.Item>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Form.List>
|
||||||
|
</Form>
|
||||||
|
</RbModal>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ChatVariableConfigModal;
|
||||||
@@ -2,7 +2,6 @@ import { type FC, useRef, useState, useEffect } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Space, Button, List } from 'antd'
|
import { Space, Button, List } from 'antd'
|
||||||
import knowledgeEmpty from '@/assets/images/application/knowledgeEmpty.svg'
|
import knowledgeEmpty from '@/assets/images/application/knowledgeEmpty.svg'
|
||||||
import Card from './Card'
|
|
||||||
import type {
|
import type {
|
||||||
KnowledgeConfigForm,
|
KnowledgeConfigForm,
|
||||||
KnowledgeConfig,
|
KnowledgeConfig,
|
||||||
@@ -11,14 +10,16 @@ import type {
|
|||||||
KnowledgeModalRef,
|
KnowledgeModalRef,
|
||||||
KnowledgeConfigModalRef,
|
KnowledgeConfigModalRef,
|
||||||
KnowledgeGlobalConfigModalRef,
|
KnowledgeGlobalConfigModalRef,
|
||||||
} from '../types'
|
} from './types'
|
||||||
import Empty from '@/components/Empty'
|
import Empty from '@/components/Empty'
|
||||||
import KnowledgeListModal from './KnowledgeListModal'
|
import KnowledgeListModal from './KnowledgeListModal'
|
||||||
import KnowledgeConfigModal from './KnowledgeConfigModal'
|
import KnowledgeConfigModal from './KnowledgeConfigModal'
|
||||||
import KnowledgeGlobalConfigModal from './KnowledgeGlobalConfigModal'
|
import KnowledgeGlobalConfigModal from './KnowledgeGlobalConfigModal'
|
||||||
import Tag from '@/components/Tag'
|
import Tag from '@/components/Tag'
|
||||||
|
import { getKnowledgeBaseList } from '@/api/knowledgeBase'
|
||||||
|
import Card from '../Card'
|
||||||
|
|
||||||
const Knowledge: FC<{data: KnowledgeConfig; onUpdate: (config: KnowledgeConfig) => void}> = ({data, onUpdate}) => {
|
const Knowledge: FC<{value?: KnowledgeConfig; onChange?: (config: KnowledgeConfig) => void}> = ({value = {knowledge_bases: []}, onChange}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const knowledgeModalRef = useRef<KnowledgeModalRef>(null)
|
const knowledgeModalRef = useRef<KnowledgeModalRef>(null)
|
||||||
const knowledgeConfigModalRef = useRef<KnowledgeConfigModalRef>(null)
|
const knowledgeConfigModalRef = useRef<KnowledgeConfigModalRef>(null)
|
||||||
@@ -27,12 +28,31 @@ const Knowledge: FC<{data: KnowledgeConfig; onUpdate: (config: KnowledgeConfig)
|
|||||||
const [editConfig, setEditConfig] = useState<KnowledgeConfig>({} as KnowledgeConfig)
|
const [editConfig, setEditConfig] = useState<KnowledgeConfig>({} as KnowledgeConfig)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (value && JSON.stringify(value) !== JSON.stringify(editConfig)) {
|
||||||
setEditConfig({ ...(data || {}) })
|
setEditConfig({ ...(value || {}) })
|
||||||
const knowledge_bases = [...(data.knowledge_bases || [])]
|
const knowledge_bases = [...(value.knowledge_bases || [])]
|
||||||
setKnowledgeList(knowledge_bases)
|
|
||||||
|
// 检查是否有knowledge_bases缺少name字段
|
||||||
|
const basesWithoutName = knowledge_bases.filter(base => !base.name)
|
||||||
|
if (basesWithoutName.length > 0) {
|
||||||
|
// 调用接口获取完整的知识库信息
|
||||||
|
getKnowledgeBaseList().then(res => {
|
||||||
|
const fullBases = knowledge_bases.map(base => {
|
||||||
|
if (!base.name) {
|
||||||
|
const fullBase = res.items.find((item: any) => item.id === base.kb_id)
|
||||||
|
return fullBase ? { ...base, ...fullBase } : base
|
||||||
|
}
|
||||||
|
return base
|
||||||
|
})
|
||||||
|
setKnowledgeList(fullBases)
|
||||||
|
}).catch(() => {
|
||||||
|
setKnowledgeList(knowledge_bases)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setKnowledgeList(knowledge_bases)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [data])
|
}, [value])
|
||||||
|
|
||||||
const handleKnowledgeConfig = () => {
|
const handleKnowledgeConfig = () => {
|
||||||
knowledgeGlobalConfigModalRef.current?.handleOpen()
|
knowledgeGlobalConfigModalRef.current?.handleOpen()
|
||||||
@@ -43,7 +63,7 @@ const Knowledge: FC<{data: KnowledgeConfig; onUpdate: (config: KnowledgeConfig)
|
|||||||
const handleDeleteKnowledge = (id: string) => {
|
const handleDeleteKnowledge = (id: string) => {
|
||||||
const list = knowledgeList.filter(item => item.id !== id)
|
const list = knowledgeList.filter(item => item.id !== id)
|
||||||
setKnowledgeList([...list])
|
setKnowledgeList([...list])
|
||||||
onUpdate({
|
onChange && onChange({
|
||||||
...editConfig,
|
...editConfig,
|
||||||
knowledge_bases: [...list],
|
knowledge_bases: [...list],
|
||||||
})
|
})
|
||||||
@@ -65,7 +85,7 @@ const Knowledge: FC<{data: KnowledgeConfig; onUpdate: (config: KnowledgeConfig)
|
|||||||
list = [...values as KnowledgeBase[]]
|
list = [...values as KnowledgeBase[]]
|
||||||
}
|
}
|
||||||
setKnowledgeList([...list])
|
setKnowledgeList([...list])
|
||||||
onUpdate({
|
onChange && onChange({
|
||||||
...editConfig,
|
...editConfig,
|
||||||
knowledge_bases: [...list],
|
knowledge_bases: [...list],
|
||||||
})
|
})
|
||||||
@@ -77,14 +97,14 @@ const Knowledge: FC<{data: KnowledgeConfig; onUpdate: (config: KnowledgeConfig)
|
|||||||
config: {...values as KnowledgeConfigForm}
|
config: {...values as KnowledgeConfigForm}
|
||||||
}
|
}
|
||||||
setKnowledgeList([...list])
|
setKnowledgeList([...list])
|
||||||
onUpdate({
|
onChange && onChange({
|
||||||
...editConfig,
|
...editConfig,
|
||||||
knowledge_bases: [...list],
|
knowledge_bases: [...list],
|
||||||
})
|
})
|
||||||
} else if (type === 'rerankerConfig') {
|
} else if (type === 'rerankerConfig') {
|
||||||
const rerankerValues = values as RerankerConfig
|
const rerankerValues = values as RerankerConfig
|
||||||
setEditConfig(prev => ({ ...prev, ...rerankerValues }))
|
setEditConfig(prev => ({ ...prev, ...rerankerValues }))
|
||||||
onUpdate({
|
onChange && onChange({
|
||||||
...editConfig,
|
...editConfig,
|
||||||
...rerankerValues,
|
...rerankerValues,
|
||||||
reranker_id: rerankerValues.rerank_model ? rerankerValues.reranker_id : undefined,
|
reranker_id: rerankerValues.rerank_model ? rerankerValues.reranker_id : undefined,
|
||||||
@@ -93,55 +113,54 @@ const Knowledge: FC<{data: KnowledgeConfig; onUpdate: (config: KnowledgeConfig)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={t('application.knowledgeBaseAssociation')}
|
title={t('application.knowledgeBaseAssociation')}
|
||||||
extra={
|
extra={
|
||||||
<Button style={{padding: '0 8px', height: '24px'}} onClick={() => handleKnowledgeConfig()}>{t('application.globalConfig')}</Button>
|
<Space>
|
||||||
|
<Button style={{ padding: '0 8px', height: '24px' }} onClick={handleKnowledgeConfig}>{t('workflow.config.knowledge-retrieval.recallConfig')}</Button>
|
||||||
|
<Button style={{ padding: '0 8px', height: '24px' }} onClick={handleAddKnowledge}>+</Button>
|
||||||
|
</Space>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:mb-3">
|
|
||||||
<div className="rb:font-medium rb:leading-5">{t('application.associatedKnowledgeBase')}</div>
|
|
||||||
<Button style={{padding: '0 8px', height: '24px'}} onClick={handleAddKnowledge}>+{t('application.addKnowledgeBase')}</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{knowledgeList.length === 0
|
{knowledgeList.length === 0
|
||||||
? <Empty url={knowledgeEmpty} size={88} subTitle={t('application.knowledgeEmpty')} />
|
? <Empty url={knowledgeEmpty} size={88} subTitle={t('application.knowledgeEmpty')} />
|
||||||
:
|
:
|
||||||
<List
|
<List
|
||||||
grid={{ gutter: 12, column: 1 }}
|
grid={{ gutter: 12, column: 1 }}
|
||||||
dataSource={knowledgeList}
|
dataSource={knowledgeList}
|
||||||
renderItem={(item) => (
|
renderItem={(item) => {
|
||||||
<List.Item>
|
if (!item.id) return null
|
||||||
<div key={item.id} className="rb:flex rb:items-center rb:justify-between rb:p-[12px_16px] rb:bg-[#FBFDFF] rb:border rb:border-[#DFE4ED] rb:rounded-lg">
|
return (
|
||||||
<div className="rb:font-medium rb:leading-4">
|
<List.Item>
|
||||||
{item.name}
|
<div key={item.id} className="rb:flex rb:items-center rb:justify-between rb:p-[12px_16px] rb:bg-[#FBFDFF] rb:border rb:border-[#DFE4ED] rb:rounded-lg">
|
||||||
<Tag color={item.status === 1 ? 'success' : item.status === 0 ? 'default' : 'error'} className="rb:ml-2">
|
<div className="rb:font-medium rb:leading-4">
|
||||||
{item.status === 1 ? t('common.enable') : item.status === 0 ? t('common.disabled') : t('common.deleted')}
|
{item.name}
|
||||||
</Tag>
|
<Tag color={item.status === 1 ? 'success' : item.status === 0 ? 'default' : 'error'} className="rb:ml-2">
|
||||||
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-5">{t('application.contains', {include_count: item.doc_num})}</div>
|
{item.status === 1 ? t('common.enable') : item.status === 0 ? t('common.disabled') : t('common.deleted')}
|
||||||
|
</Tag>
|
||||||
|
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-5">{t('application.contains', {include_count: item.doc_num})}</div>
|
||||||
|
</div>
|
||||||
|
<Space size={12}>
|
||||||
|
<div
|
||||||
|
className="rb:w-6 rb:h-6 rb:cursor-pointer rb:bg-[url('@/assets/images/editBorder.svg')] rb:hover:bg-[url('@/assets/images/editBg.svg')]"
|
||||||
|
onClick={() => handleEditKnowledge(item)}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
className="rb:w-6 rb:h-6 rb:cursor-pointer rb:bg-[url('@/assets/images/deleteBorder.svg')] rb:hover:bg-[url('@/assets/images/deleteBg.svg')]"
|
||||||
|
onClick={() => handleDeleteKnowledge(item.id)}
|
||||||
|
></div>
|
||||||
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
<Space size={12}>
|
</List.Item>
|
||||||
<div
|
)
|
||||||
className="rb:w-6 rb:h-6 rb:cursor-pointer rb:bg-[url('@/assets/images/editBorder.svg')] rb:hover:bg-[url('@/assets/images/editBg.svg')]"
|
}}
|
||||||
onClick={() => handleEditKnowledge(item)}
|
|
||||||
></div>
|
|
||||||
<div
|
|
||||||
className="rb:w-6 rb:h-6 rb:cursor-pointer rb:bg-[url('@/assets/images/deleteBorder.svg')] rb:hover:bg-[url('@/assets/images/deleteBg.svg')]"
|
|
||||||
onClick={() => handleDeleteKnowledge(item.id)}
|
|
||||||
></div>
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
</List.Item>
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
{/* 全局设置 */}
|
|
||||||
<KnowledgeGlobalConfigModal
|
<KnowledgeGlobalConfigModal
|
||||||
data={editConfig}
|
data={editConfig}
|
||||||
ref={knowledgeGlobalConfigModalRef}
|
ref={knowledgeGlobalConfigModalRef}
|
||||||
refresh={refresh}
|
refresh={refresh}
|
||||||
/>
|
/>
|
||||||
{/* 知识库列表 */}
|
|
||||||
<KnowledgeListModal
|
<KnowledgeListModal
|
||||||
ref={knowledgeModalRef}
|
ref={knowledgeModalRef}
|
||||||
selectedList={knowledgeList}
|
selectedList={knowledgeList}
|
||||||
@@ -2,7 +2,7 @@ import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
|||||||
import { Form, Select, InputNumber } from 'antd';
|
import { Form, Select, InputNumber } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { KnowledgeConfigModalRef, KnowledgeBase, KnowledgeConfigForm } from '../types'
|
import type { KnowledgeConfigModalRef, KnowledgeBase, KnowledgeConfigForm, RetrieveType } from './types'
|
||||||
import RbModal from '@/components/RbModal'
|
import RbModal from '@/components/RbModal'
|
||||||
import RbSlider from '@/components/RbSlider'
|
import RbSlider from '@/components/RbSlider'
|
||||||
import { formatDateTime } from '@/utils/format';
|
import { formatDateTime } from '@/utils/format';
|
||||||
@@ -12,7 +12,7 @@ const FormItem = Form.Item;
|
|||||||
interface KnowledgeConfigModalProps {
|
interface KnowledgeConfigModalProps {
|
||||||
refresh: (values: KnowledgeConfigForm, type: 'knowledgeConfig') => void;
|
refresh: (values: KnowledgeConfigForm, type: 'knowledgeConfig') => void;
|
||||||
}
|
}
|
||||||
const retrieveTypes = ['participle', 'semantic', 'hybrid']
|
const retrieveTypes: RetrieveType[] = ['participle', 'semantic', 'hybrid']
|
||||||
|
|
||||||
const KnowledgeConfigModal = forwardRef<KnowledgeConfigModalRef, KnowledgeConfigModalProps>(({
|
const KnowledgeConfigModal = forwardRef<KnowledgeConfigModalRef, KnowledgeConfigModalProps>(({
|
||||||
refresh,
|
refresh,
|
||||||
@@ -33,8 +33,11 @@ const KnowledgeConfigModal = forwardRef<KnowledgeConfigModalRef, KnowledgeConfig
|
|||||||
|
|
||||||
const handleOpen = (data: KnowledgeBase) => {
|
const handleOpen = (data: KnowledgeBase) => {
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
retrieve_type: retrieveTypes[0],
|
retrieve_type: data?.config?.retrieve_type || retrieveTypes[0],
|
||||||
kb_id: data.id,
|
kb_id: data.id,
|
||||||
|
top_k: data?.config?.top_k || 5,
|
||||||
|
similarity_threshold: data?.config?.similarity_threshold || 0.5,
|
||||||
|
vector_similarity_weight: data?.config?.vector_similarity_weight || 0.5,
|
||||||
...(data || {}),
|
...(data || {}),
|
||||||
...(data?.config || {}),
|
...(data?.config || {}),
|
||||||
})
|
})
|
||||||
@@ -62,12 +65,10 @@ const KnowledgeConfigModal = forwardRef<KnowledgeConfigModalRef, KnowledgeConfig
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (values?.retrieve_type) {
|
if (values?.retrieve_type) {
|
||||||
const initialValues = Object.keys(values).map(key => {
|
const fieldsToReset = Object.keys(values).filter(key =>
|
||||||
return {
|
key !== 'kb_id' && key !== 'retrieve_type'
|
||||||
[key as keyof KnowledgeConfigForm]: (key === 'kb_id' || key === 'retrieve_type') ? values[key] : undefined
|
) as (keyof KnowledgeConfigForm)[];
|
||||||
}
|
form.resetFields(fieldsToReset);
|
||||||
})
|
|
||||||
form.resetFields(initialValues)
|
|
||||||
}
|
}
|
||||||
}, [values?.retrieve_type])
|
}, [values?.retrieve_type])
|
||||||
|
|
||||||
@@ -84,12 +85,12 @@ const KnowledgeConfigModal = forwardRef<KnowledgeConfigModalRef, KnowledgeConfig
|
|||||||
layout="vertical"
|
layout="vertical"
|
||||||
>
|
>
|
||||||
{data && (
|
{data && (
|
||||||
<div className="rb:mb-[24px] rb:flex rb:items-center rb:justify-between rb:border rb:rounded-[8px] rb:p-[17px_16px] rb:cursor-pointer rb:bg-[#F0F3F8] rb:border-[#DFE4ED] rb:text-[#212332]">
|
<div className="rb:mb-6 rb:flex rb:items-center rb:justify-between rb:border rb:rounded-lg rb:p-[17px_16px] rb:cursor-pointer rb:bg-[#F0F3F8] rb:border-[#DFE4ED] rb:text-[#212332]">
|
||||||
<div className="rb:text-[16px] rb:leading-[22px]">
|
<div className="rb:text-[16px] rb:leading-5.5">
|
||||||
{data.name}
|
{data.name}
|
||||||
<div className="rb:text-[12px] rb:leading-[16px] rb:text-[#5B6167] rb:mt-[8px]">{t('application.contains', {include_count: data.doc_num})}</div>
|
<div className="rb:text-[12px] rb:leading-4 rb:text-[#5B6167] rb:mt-2">{t('application.contains', {include_count: data.doc_num})}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="rb:text-[12px] rb:leading-[16px] rb:text-[#5B6167]">{formatDateTime(data.updated_at, 'YYYY-MM-DD HH:mm:ss')}</div>
|
<div className="rb:text-[12px] rb:leading-4 rb:text-[#5B6167]">{formatDateTime(data.updated_at, 'YYYY-MM-DD HH:mm:ss')}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<FormItem name="kb_id" hidden />
|
<FormItem name="kb_id" hidden />
|
||||||
@@ -114,8 +115,14 @@ const KnowledgeConfigModal = forwardRef<KnowledgeConfigModalRef, KnowledgeConfig
|
|||||||
label={t('application.top_k')}
|
label={t('application.top_k')}
|
||||||
rules={[{ required: true, message: t('common.pleaseEnter') }]}
|
rules={[{ required: true, message: t('common.pleaseEnter') }]}
|
||||||
extra={t('application.top_k_desc')}
|
extra={t('application.top_k_desc')}
|
||||||
|
initialValue={5}
|
||||||
>
|
>
|
||||||
<InputNumber style={{ width: '100%' }} />
|
<InputNumber
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
min={1}
|
||||||
|
max={20}
|
||||||
|
onChange={(value) => form.setFieldValue('top_k', value)}
|
||||||
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
{/* 语义相似度阈值 similarity_threshold */}
|
{/* 语义相似度阈值 similarity_threshold */}
|
||||||
{values?.retrieve_type === 'semantic' && (
|
{values?.retrieve_type === 'semantic' && (
|
||||||
@@ -123,6 +130,7 @@ const KnowledgeConfigModal = forwardRef<KnowledgeConfigModalRef, KnowledgeConfig
|
|||||||
name="similarity_threshold"
|
name="similarity_threshold"
|
||||||
label={t('application.similarity_threshold')}
|
label={t('application.similarity_threshold')}
|
||||||
extra={t('application.similarity_threshold_desc')}
|
extra={t('application.similarity_threshold_desc')}
|
||||||
|
initialValue={0.5}
|
||||||
>
|
>
|
||||||
<RbSlider
|
<RbSlider
|
||||||
max={1.0}
|
max={1.0}
|
||||||
@@ -137,6 +145,7 @@ const KnowledgeConfigModal = forwardRef<KnowledgeConfigModalRef, KnowledgeConfig
|
|||||||
name="vector_similarity_weight"
|
name="vector_similarity_weight"
|
||||||
label={t('application.vector_similarity_weight')}
|
label={t('application.vector_similarity_weight')}
|
||||||
extra={t('application.vector_similarity_weight_desc')}
|
extra={t('application.vector_similarity_weight_desc')}
|
||||||
|
initialValue={0.5}
|
||||||
>
|
>
|
||||||
<RbSlider
|
<RbSlider
|
||||||
max={1.0}
|
max={1.0}
|
||||||
@@ -152,6 +161,7 @@ const KnowledgeConfigModal = forwardRef<KnowledgeConfigModalRef, KnowledgeConfig
|
|||||||
name="similarity_threshold"
|
name="similarity_threshold"
|
||||||
label={t('application.similarity_threshold')}
|
label={t('application.similarity_threshold')}
|
||||||
extra={t('application.similarity_threshold_desc1')}
|
extra={t('application.similarity_threshold_desc1')}
|
||||||
|
initialValue={0.5}
|
||||||
>
|
>
|
||||||
<RbSlider
|
<RbSlider
|
||||||
max={1.0}
|
max={1.0}
|
||||||
@@ -163,6 +173,7 @@ const KnowledgeConfigModal = forwardRef<KnowledgeConfigModalRef, KnowledgeConfig
|
|||||||
name="vector_similarity_weight"
|
name="vector_similarity_weight"
|
||||||
label={t('application.vector_similarity_weight')}
|
label={t('application.vector_similarity_weight')}
|
||||||
extra={t('application.vector_similarity_weight_desc1')}
|
extra={t('application.vector_similarity_weight_desc1')}
|
||||||
|
initialValue={0.5}
|
||||||
>
|
>
|
||||||
<RbSlider
|
<RbSlider
|
||||||
max={1.0}
|
max={1.0}
|
||||||
@@ -2,7 +2,7 @@ import { forwardRef, useImperativeHandle, useState, useEffect } from 'react';
|
|||||||
import { Form, InputNumber, Switch } from 'antd';
|
import { Form, InputNumber, Switch } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { RerankerConfig, KnowledgeGlobalConfigModalRef } from '../types'
|
import type { RerankerConfig, KnowledgeGlobalConfigModalRef } from './types'
|
||||||
import RbModal from '@/components/RbModal'
|
import RbModal from '@/components/RbModal'
|
||||||
import CustomSelect from '@/components/CustomSelect'
|
import CustomSelect from '@/components/CustomSelect'
|
||||||
import { getModelListUrl } from '@/api/models'
|
import { getModelListUrl } from '@/api/models'
|
||||||
@@ -71,18 +71,18 @@ const KnowledgeGlobalConfigModal = forwardRef<KnowledgeGlobalConfigModalRef, Kno
|
|||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
>
|
>
|
||||||
<div className="rb:text-[#5B6167] rb:mb-[24px]">{t('application.globalConfigDesc')}</div>
|
<div className="rb:text-[#5B6167] rb:mb-6">{t('application.globalConfigDesc')}</div>
|
||||||
|
|
||||||
{/* 结果重排 */}
|
{/* 结果重排 */}
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:my-[24px]">
|
<div className="rb:flex rb:items-center rb:justify-between rb:my-6">
|
||||||
<div className="rb:text-[14px] rb:font-medium rb:leading-[20px]">
|
<div className="rb:text-[14px] rb:font-medium rb:leading-5">
|
||||||
{t('application.rerankModel')}
|
{t('application.rerankModel')}
|
||||||
<div className="rb:mt-[4px] rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-[16px]">{t('application.rerankModelDesc')}</div>
|
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4">{t('application.rerankModelDesc')}</div>
|
||||||
</div>
|
</div>
|
||||||
<FormItem
|
<FormItem
|
||||||
name="rerank_model"
|
name="rerank_model"
|
||||||
valuePropName="checked"
|
valuePropName="checked"
|
||||||
className="rb:mb-[0px]!"
|
className="rb:mb-0!"
|
||||||
>
|
>
|
||||||
<Switch />
|
<Switch />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
@@ -110,7 +110,12 @@ const KnowledgeGlobalConfigModal = forwardRef<KnowledgeGlobalConfigModalRef, Kno
|
|||||||
rules={[{ required: true, message: t('common.pleaseEnter') }]}
|
rules={[{ required: true, message: t('common.pleaseEnter') }]}
|
||||||
extra={t('application.reranker_top_k_desc')}
|
extra={t('application.reranker_top_k_desc')}
|
||||||
>
|
>
|
||||||
<InputNumber style={{ width: '100%' }} min={1} max={20} />
|
<InputNumber
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
min={1}
|
||||||
|
max={20}
|
||||||
|
onChange={(value) => form.setFieldValue('reranker_top_k', value)}
|
||||||
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</>}
|
</>}
|
||||||
</Form>
|
</Form>
|
||||||
@@ -2,7 +2,7 @@ import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
|||||||
import { Space, List } from 'antd';
|
import { Space, List } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import type { KnowledgeModalRef, KnowledgeBase } from '../types'
|
import type { KnowledgeModalRef, KnowledgeBase } from './types'
|
||||||
import type { KnowledgeBaseListItem } from '@/views/KnowledgeBase/types'
|
import type { KnowledgeBaseListItem } from '@/views/KnowledgeBase/types'
|
||||||
import RbModal from '@/components/RbModal'
|
import RbModal from '@/components/RbModal'
|
||||||
import { getKnowledgeBaseList } from '@/api/knowledgeBase'
|
import { getKnowledgeBaseList } from '@/api/knowledgeBase'
|
||||||
@@ -39,12 +39,13 @@ const KnowledgeListModal = forwardRef<KnowledgeModalRef, KnowledgeModalProps>(({
|
|||||||
setQuery({})
|
setQuery({})
|
||||||
setSelectedIds([])
|
setSelectedIds([])
|
||||||
setSelectedRows([])
|
setSelectedRows([])
|
||||||
getList()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getList()
|
if (visible) {
|
||||||
}, [query.keywords])
|
getList()
|
||||||
|
}
|
||||||
|
}, [query.keywords, visible])
|
||||||
const getList = () => {
|
const getList = () => {
|
||||||
getKnowledgeBaseList(undefined, {
|
getKnowledgeBaseList(undefined, {
|
||||||
...query,
|
...query,
|
||||||
@@ -124,15 +125,15 @@ const KnowledgeListModal = forwardRef<KnowledgeModalRef, KnowledgeModalProps>(({
|
|||||||
dataSource={filterList}
|
dataSource={filterList}
|
||||||
renderItem={(item: KnowledgeBase) => (
|
renderItem={(item: KnowledgeBase) => (
|
||||||
<List.Item>
|
<List.Item>
|
||||||
<div key={item.id} className={clsx("rb:flex rb:items-center rb:justify-between rb:border rb:rounded-[8px] rb:p-[17px_16px] rb:cursor-pointer rb:hover:bg-[#F0F3F8]", {
|
<div key={item.id} className={clsx("rb:flex rb:items-center rb:justify-between rb:border rb:rounded-lg rb:p-[17px_16px] rb:cursor-pointer rb:hover:bg-[#F0F3F8]", {
|
||||||
"rb:bg-[rgba(21,94,239,0.06)] rb:border-[#155EEF] rb:text-[#155EEF]": selectedIds.includes(item.id),
|
"rb:bg-[rgba(21,94,239,0.06)] rb:border-[#155EEF] rb:text-[#155EEF]": selectedIds.includes(item.id),
|
||||||
"rb:border-[#DFE4ED] rb:text-[#212332]": !selectedIds.includes(item.id),
|
"rb:border-[#DFE4ED] rb:text-[#212332]": !selectedIds.includes(item.id),
|
||||||
})} onClick={() => handleSelect(item)}>
|
})} onClick={() => handleSelect(item)}>
|
||||||
<div className="rb:text-[16px] rb:leading-[22px]">
|
<div className="rb:text-[16px] rb:leading-5.5">
|
||||||
{item.name}
|
{item.name}
|
||||||
<div className="rb:text-[12px] rb:leading-[16px] rb:text-[#5B6167] rb:mt-[8px]">{t('application.contains', {include_count: item.doc_num})}</div>
|
<div className="rb:text-[12px] rb:leading-4 rb:text-[#5B6167] rb:mt-2">{t('application.contains', {include_count: item.doc_num})}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="rb:text-[12px] rb:leading-[16px] rb:text-[#5B6167]">{formatDateTime(item.created_at, 'YYYY-MM-DD HH:mm:ss')}</div>
|
<div className="rb:text-[12px] rb:leading-4 rb:text-[#5B6167]">{formatDateTime(item.created_at, 'YYYY-MM-DD HH:mm:ss')}</div>
|
||||||
</div>
|
</div>
|
||||||
</List.Item>
|
</List.Item>
|
||||||
)}
|
)}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import type { KnowledgeBaseListItem } from '@/views/KnowledgeBase/types'
|
||||||
|
export interface RerankerConfig {
|
||||||
|
rerank_model?: boolean | undefined;
|
||||||
|
reranker_id?: string | undefined;
|
||||||
|
reranker_top_k?: number | undefined;
|
||||||
|
}
|
||||||
|
export type RetrieveType = 'participle' | 'semantic' | 'hybrid'
|
||||||
|
export interface KnowledgeConfigForm {
|
||||||
|
kb_id?: string;
|
||||||
|
similarity_threshold?: number;
|
||||||
|
vector_similarity_weight?: number;
|
||||||
|
top_k?: number;
|
||||||
|
retrieve_type?: RetrieveType;
|
||||||
|
}
|
||||||
|
export interface KnowledgeBase extends KnowledgeBaseListItem, KnowledgeConfigForm {
|
||||||
|
config?: KnowledgeConfigForm
|
||||||
|
}
|
||||||
|
export interface KnowledgeConfig extends RerankerConfig {
|
||||||
|
knowledge_bases: KnowledgeBase[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface KnowledgeConfigModalRef {
|
||||||
|
handleOpen: (data: KnowledgeBase) => void;
|
||||||
|
}
|
||||||
|
export interface KnowledgeGlobalConfigModalRef {
|
||||||
|
handleOpen: () => void;
|
||||||
|
}
|
||||||
|
export interface KnowledgeModalRef {
|
||||||
|
handleOpen: (config?: KnowledgeConfig[]) => void;
|
||||||
|
}
|
||||||
@@ -1,22 +1,22 @@
|
|||||||
import { type FC, useRef, useState, useEffect } from 'react'
|
import { type FC, useRef, useState, useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Space, Button, List, Switch } from 'antd'
|
import { Space, Button, List, Switch } from 'antd'
|
||||||
import Card from './Card'
|
import Card from '../Card'
|
||||||
import type {
|
import type {
|
||||||
ToolModalRef,
|
ToolModalRef,
|
||||||
ToolOption
|
ToolOption
|
||||||
} from '../types'
|
} from './types'
|
||||||
import Empty from '@/components/Empty'
|
import Empty from '@/components/Empty'
|
||||||
import ToolModal from './ToolModal'
|
import ToolModal from './ToolModal'
|
||||||
import { getToolMethods, getToolDetail } from '@/api/tools'
|
import { getToolMethods, getToolDetail } from '@/api/tools'
|
||||||
|
|
||||||
const ToolList: FC<{ data: ToolOption[]; onUpdate: (config: ToolOption[]) => void}> = ({data, onUpdate}) => {
|
const ToolList: FC<{ value?: ToolOption[]; onChange?: (config: ToolOption[]) => void}> = ({value, onChange}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const toolModalRef = useRef<ToolModalRef>(null)
|
const toolModalRef = useRef<ToolModalRef>(null)
|
||||||
const [toolList, setToolList] = useState<ToolOption[]>([])
|
const [toolList, setToolList] = useState<ToolOption[]>([])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (value) {
|
||||||
const processedData = data.map(async (item) => {
|
const processedData = value.map(async (item) => {
|
||||||
if (!item.label && item.tool_id) {
|
if (!item.label && item.tool_id) {
|
||||||
try {
|
try {
|
||||||
const [toolDetail, methods] = await Promise.all([
|
const [toolDetail, methods] = await Promise.all([
|
||||||
@@ -77,7 +77,7 @@ const ToolList: FC<{ data: ToolOption[]; onUpdate: (config: ToolOption[]) => voi
|
|||||||
|
|
||||||
Promise.all(processedData).then(setToolList)
|
Promise.all(processedData).then(setToolList)
|
||||||
}
|
}
|
||||||
}, [data])
|
}, [value])
|
||||||
|
|
||||||
const handleAddTool = () => {
|
const handleAddTool = () => {
|
||||||
toolModalRef.current?.handleOpen()
|
toolModalRef.current?.handleOpen()
|
||||||
@@ -85,12 +85,12 @@ const ToolList: FC<{ data: ToolOption[]; onUpdate: (config: ToolOption[]) => voi
|
|||||||
const updateTools = (tool: ToolOption) => {
|
const updateTools = (tool: ToolOption) => {
|
||||||
const list = [...toolList, tool]
|
const list = [...toolList, tool]
|
||||||
setToolList(list)
|
setToolList(list)
|
||||||
onUpdate(list)
|
onChange && onChange(list)
|
||||||
}
|
}
|
||||||
const handleDeleteTool = (index: number) => {
|
const handleDeleteTool = (index: number) => {
|
||||||
const list = toolList.filter((_item, idx) => idx !== index)
|
const list = toolList.filter((_item, idx) => idx !== index)
|
||||||
setToolList([...list])
|
setToolList([...list])
|
||||||
onUpdate(list)
|
onChange && onChange(list)
|
||||||
}
|
}
|
||||||
const handleChangeEnabled = (index: number) => {
|
const handleChangeEnabled = (index: number) => {
|
||||||
const list = toolList.map((item, idx) => {
|
const list = toolList.map((item, idx) => {
|
||||||
@@ -103,7 +103,7 @@ const ToolList: FC<{ data: ToolOption[]; onUpdate: (config: ToolOption[]) => voi
|
|||||||
return item
|
return item
|
||||||
})
|
})
|
||||||
setToolList([...list])
|
setToolList([...list])
|
||||||
onUpdate(list)
|
onChange && onChange(list)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
@@ -112,7 +112,6 @@ const ToolList: FC<{ data: ToolOption[]; onUpdate: (config: ToolOption[]) => voi
|
|||||||
<Button style={{ padding: '0 8px', height: '24px' }} onClick={handleAddTool}>+{t('application.addTool')}</Button>
|
<Button style={{ padding: '0 8px', height: '24px' }} onClick={handleAddTool}>+{t('application.addTool')}</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
||||||
{toolList.length === 0
|
{toolList.length === 0
|
||||||
? <Empty size={88} />
|
? <Empty size={88} />
|
||||||
:
|
:
|
||||||
26
web/src/views/ApplicationConfig/components/ToolList/types.ts
Normal file
26
web/src/views/ApplicationConfig/components/ToolList/types.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export interface ToolOption {
|
||||||
|
value?: string | number | null;
|
||||||
|
label?: React.ReactNode;
|
||||||
|
description?: string;
|
||||||
|
children?: ToolOption[];
|
||||||
|
isLeaf?: boolean;
|
||||||
|
method_id?: string;
|
||||||
|
operation?: string;
|
||||||
|
parameters?: Parameter[];
|
||||||
|
tool_id?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
export interface Parameter {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
description: string;
|
||||||
|
required: boolean;
|
||||||
|
default: any;
|
||||||
|
enum: null | string[];
|
||||||
|
minimum: number;
|
||||||
|
maximum: number;
|
||||||
|
pattern: null | string;
|
||||||
|
}
|
||||||
|
export interface ToolModalRef {
|
||||||
|
handleOpen: () => void;
|
||||||
|
}
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
import { type FC, useRef, useState, useEffect } from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { Space, Button, Switch } from 'antd'
|
|
||||||
import variablesEmpty from '@/assets/images/application/variablesEmpty.svg'
|
|
||||||
import Card from './Card'
|
|
||||||
import Table from '@/components/Table';
|
|
||||||
import type { Variable, VariableEditModalRef } from '../types'
|
|
||||||
import Empty from '@/components/Empty'
|
|
||||||
import VariableEditModal from './VariableEditModal'
|
|
||||||
|
|
||||||
interface VariableListProps {
|
|
||||||
data?: Variable[];
|
|
||||||
onUpdate: (data: Variable[]) => void;
|
|
||||||
}
|
|
||||||
const VariableList: FC<VariableListProps> = ({data = [], onUpdate}) => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const variableEditModalRef = useRef<VariableEditModalRef>(null)
|
|
||||||
const [variableList, setVariableList] = useState<Variable[]>([])
|
|
||||||
const [maxIndex, setMaxIndex] = useState(0)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!data || data.length === 0) return
|
|
||||||
const list = data.map((item, index) => ({
|
|
||||||
...item,
|
|
||||||
index
|
|
||||||
}))
|
|
||||||
setVariableList(list)
|
|
||||||
onUpdate(list)
|
|
||||||
setMaxIndex(list.length)
|
|
||||||
}, [data])
|
|
||||||
|
|
||||||
const handleAddVariable = () => {
|
|
||||||
variableEditModalRef.current?.handleOpen()
|
|
||||||
}
|
|
||||||
const handleSaveVariable = (value: Variable) => {
|
|
||||||
if (value.index !== undefined && value.index >= 0) {
|
|
||||||
const index = variableList.findIndex(item => item.index === value.index)
|
|
||||||
if (index !== -1) {
|
|
||||||
const newData = [...variableList]
|
|
||||||
newData[index] = value
|
|
||||||
setVariableList([...newData])
|
|
||||||
onUpdate([...newData])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const list = [...variableList, {
|
|
||||||
index: maxIndex + 1,
|
|
||||||
...value
|
|
||||||
}]
|
|
||||||
setVariableList(list)
|
|
||||||
onUpdate([...list])
|
|
||||||
setMaxIndex(maxIndex + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const handleDeleteVariable = (index: number) => {
|
|
||||||
const list = variableList.filter((_, i) => i !== index)
|
|
||||||
setVariableList(list)
|
|
||||||
onUpdate([...list])
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Card title={t('application.variableConfiguration')}>
|
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:mb-[11px]">
|
|
||||||
<div className="rb:font-medium rb:leading-[20px]">
|
|
||||||
{t('application.VariableManagement')}
|
|
||||||
<span className="rb:font-regular rb:text-[12px] rb:text-[#5B6167]"> ({t('application.VariableManagementDesc')})</span>
|
|
||||||
</div>
|
|
||||||
<Button style={{padding: '0 8px', height: '24px'}} onClick={handleAddVariable}>+{t('application.addVariables')}</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* List */}
|
|
||||||
{variableList.length > 0
|
|
||||||
? (
|
|
||||||
<div className="rb:mt-[12px]">
|
|
||||||
<Table
|
|
||||||
rowKey="index"
|
|
||||||
pagination={false}
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: t('application.variableType'),
|
|
||||||
dataIndex: 'type',
|
|
||||||
key: 'type',
|
|
||||||
render: (type) => t(`application.${type}`)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('application.variableKey'),
|
|
||||||
dataIndex: 'name',
|
|
||||||
key: 'name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('application.variableName'),
|
|
||||||
dataIndex: 'display_name',
|
|
||||||
key: 'display_name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('application.optional'),
|
|
||||||
dataIndex: 'required',
|
|
||||||
key: 'required',
|
|
||||||
render: (required) => <Switch checked={!required} disabled />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('common.operation'),
|
|
||||||
key: 'action',
|
|
||||||
render: (_, record, index: number) => (
|
|
||||||
<Space size="middle">
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => variableEditModalRef.current?.handleOpen(record as Variable)}
|
|
||||||
>
|
|
||||||
{t('common.edit')}
|
|
||||||
</Button>
|
|
||||||
<Button type="link" danger onClick={() => handleDeleteVariable(index)}>
|
|
||||||
{t('common.delete')}
|
|
||||||
</Button>
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
initialData={variableList as unknown as Record<string, unknown>[]}
|
|
||||||
emptySize={88}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
: <Empty url={variablesEmpty} size={88} subTitle={t('application.variablesEmpty')} />
|
|
||||||
}
|
|
||||||
<VariableEditModal
|
|
||||||
ref={variableEditModalRef}
|
|
||||||
refreshTable={handleSaveVariable}
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default VariableList
|
|
||||||
@@ -2,7 +2,7 @@ import { forwardRef, useImperativeHandle, useState } from 'react';
|
|||||||
import { Form, Input } from 'antd';
|
import { Form, Input } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { ApiExtensionModalData, ApiExtensionModalRef } from '../types'
|
import type { ApiExtensionModalData, ApiExtensionModalRef } from './types'
|
||||||
import RbModal from '@/components/RbModal'
|
import RbModal from '@/components/RbModal'
|
||||||
|
|
||||||
const FormItem = Form.Item;
|
const FormItem = Form.Item;
|
||||||
@@ -2,7 +2,7 @@ import { forwardRef, useImperativeHandle, useState, useRef } from 'react';
|
|||||||
import { Form, Input, Select, InputNumber, Checkbox, Tag, Divider, Button } from 'antd';
|
import { Form, Input, Select, InputNumber, Checkbox, Tag, Divider, Button } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { ApiExtensionModalRef, Variable, VariableEditModalRef } from '../types'
|
import type { ApiExtensionModalRef, Variable, VariableEditModalRef } from './types'
|
||||||
import RbModal from '@/components/RbModal'
|
import RbModal from '@/components/RbModal'
|
||||||
import SortableList from '@/components/SortableList'
|
import SortableList from '@/components/SortableList'
|
||||||
import ApiExtensionModal from './ApiExtensionModal'
|
import ApiExtensionModal from './ApiExtensionModal'
|
||||||
@@ -137,7 +137,14 @@ const VariableEditModal = forwardRef<VariableEditModalRef, VariableEditModalProp
|
|||||||
{ pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, message: t('application.invalidVariableName') },
|
{ pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, message: t('application.invalidVariableName') },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input placeholder={t('common.enter')} />
|
<Input
|
||||||
|
placeholder={t('common.enter')}
|
||||||
|
onBlur={(e) => {
|
||||||
|
if (!form.getFieldValue('display_name')) {
|
||||||
|
form.setFieldValue('display_name', e.target.value)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
{/* 显示名称 */}
|
{/* 显示名称 */}
|
||||||
<FormItem
|
<FormItem
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
import { type FC, useRef } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { Space, Button, Switch, Form } from 'antd'
|
||||||
|
import variablesEmpty from '@/assets/images/application/variablesEmpty.svg'
|
||||||
|
import Card from '../Card'
|
||||||
|
import Table from '@/components/Table';
|
||||||
|
import type { Variable, VariableEditModalRef } from './types'
|
||||||
|
import Empty from '@/components/Empty'
|
||||||
|
import VariableEditModal from './VariableEditModal'
|
||||||
|
|
||||||
|
interface VariableListProps {
|
||||||
|
value?: Variable[];
|
||||||
|
onChange?: (value: Variable[]) => void;
|
||||||
|
}
|
||||||
|
const VariableList: FC<VariableListProps> = ({value = [], onChange}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const variableEditModalRef = useRef<VariableEditModalRef>(null)
|
||||||
|
|
||||||
|
const handleAddVariable = () => {
|
||||||
|
variableEditModalRef.current?.handleOpen()
|
||||||
|
}
|
||||||
|
const handleSaveVariable = (variable: Variable) => {
|
||||||
|
const newList = [...(value || [])]
|
||||||
|
if (variable.index !== undefined && variable.index >= 0) {
|
||||||
|
const index = newList.findIndex(item => item.index === variable.index)
|
||||||
|
if (index !== -1) {
|
||||||
|
newList[index] = variable
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newList.push({ ...variable, index: Date.now() })
|
||||||
|
}
|
||||||
|
onChange?.(newList)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
title={<>
|
||||||
|
{t('application.variableConfiguration')}
|
||||||
|
<span className="rb:font-regular rb:text-[12px] rb:text-[#5B6167]"> ({t('application.VariableManagementDesc')})</span>
|
||||||
|
</>}
|
||||||
|
extra={<Button style={{ padding: '0 8px', height: '24px' }} onClick={handleAddVariable}>+ {t('application.addVariables')}</Button>}
|
||||||
|
>
|
||||||
|
<Form.List name="variables" initialValue={value}>
|
||||||
|
{(fields, { remove }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{fields.length > 0 ? (
|
||||||
|
<div className="rb:mt-3">
|
||||||
|
<Table
|
||||||
|
rowKey="index"
|
||||||
|
pagination={false}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
title: t('application.variableType'),
|
||||||
|
dataIndex: 'type',
|
||||||
|
key: 'type',
|
||||||
|
render: (type) => t(`application.${type}`)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('application.variableKey'),
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('application.variableName'),
|
||||||
|
dataIndex: 'display_name',
|
||||||
|
key: 'display_name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('application.optional'),
|
||||||
|
dataIndex: 'required',
|
||||||
|
key: 'required',
|
||||||
|
render: (required) => <Switch checked={!required} disabled />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('common.operation'),
|
||||||
|
key: 'action',
|
||||||
|
render: (_, record, index: number) => (
|
||||||
|
<Space size="middle">
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
onClick={() => variableEditModalRef.current?.handleOpen(record as Variable)}
|
||||||
|
>
|
||||||
|
{t('common.edit')}
|
||||||
|
</Button>
|
||||||
|
<Button type="link" danger onClick={() => remove(index)}>
|
||||||
|
{t('common.delete')}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
initialData={value as unknown as Record<string, unknown>[]}
|
||||||
|
emptySize={88}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Empty url={variablesEmpty} size={88} subTitle={t('application.variablesEmpty')} />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</Form.List>
|
||||||
|
<VariableEditModal
|
||||||
|
ref={variableEditModalRef}
|
||||||
|
refreshTable={handleSaveVariable}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default VariableList
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
export interface Variable {
|
||||||
|
index?: number;
|
||||||
|
name: string;
|
||||||
|
display_name: string;
|
||||||
|
type: string;
|
||||||
|
required: boolean;
|
||||||
|
max_length?: number;
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
key?: string;
|
||||||
|
default_value?: string;
|
||||||
|
options?: string[];
|
||||||
|
api_extension?: string;
|
||||||
|
hidden?: boolean;
|
||||||
|
value?: any;
|
||||||
|
}
|
||||||
|
export interface VariableEditModalRef {
|
||||||
|
handleOpen: (values?: Variable) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiExtensionModalData {
|
||||||
|
name: string;
|
||||||
|
apiEndpoint: string;
|
||||||
|
apiKey: string;
|
||||||
|
}
|
||||||
|
export interface ApiExtensionModalRef {
|
||||||
|
handleOpen: () => void;
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import type { KnowledgeBaseListItem } from '@/views/KnowledgeBase/types'
|
import type { KnowledgeConfig } from './components/Knowledge/types'
|
||||||
|
import type { Variable } from './components/VariableList/types'
|
||||||
|
import type { ToolOption } from './components/ToolList/types'
|
||||||
import type { ChatItem } from '@/components/Chat/types'
|
import type { ChatItem } from '@/components/Chat/types'
|
||||||
import type { GraphRef } from '@/views/Workflow/types';
|
import type { GraphRef } from '@/views/Workflow/types';
|
||||||
import type { ApiKey } from '@/views/ApiKeyManagement/types'
|
import type { ApiKey } from '@/views/ApiKeyManagement/types'
|
||||||
@@ -14,55 +16,6 @@ export interface ModelConfig {
|
|||||||
n: number;
|
n: number;
|
||||||
stop?: string;
|
stop?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************** 知识库相关 ******************/
|
|
||||||
export interface RerankerConfig {
|
|
||||||
rerank_model?: boolean | undefined;
|
|
||||||
reranker_id?: string | undefined;
|
|
||||||
reranker_top_k?: number | undefined;
|
|
||||||
}
|
|
||||||
export interface KnowledgeConfigForm {
|
|
||||||
kb_id?: string;
|
|
||||||
similarity_threshold?: number;
|
|
||||||
vector_similarity_weight?: number;
|
|
||||||
top_k?: number;
|
|
||||||
retrieve_type?: 'participle' | 'semantic' | 'hybrid';
|
|
||||||
}
|
|
||||||
export interface KnowledgeBase extends KnowledgeBaseListItem, KnowledgeConfigForm {
|
|
||||||
config?: KnowledgeConfigForm
|
|
||||||
}
|
|
||||||
export interface KnowledgeConfig extends RerankerConfig {
|
|
||||||
knowledge_bases: KnowledgeBase[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface KnowledgeConfigModalRef {
|
|
||||||
handleOpen: (data: KnowledgeBase) => void;
|
|
||||||
}
|
|
||||||
export interface KnowledgeGlobalConfigModalRef {
|
|
||||||
handleOpen: () => void;
|
|
||||||
}
|
|
||||||
/*********** end 知识库相关 ******************/
|
|
||||||
|
|
||||||
/*************** 变量相关 ******************/
|
|
||||||
export interface Variable {
|
|
||||||
index?: number;
|
|
||||||
name: string;
|
|
||||||
display_name: string;
|
|
||||||
type: string;
|
|
||||||
required: boolean;
|
|
||||||
max_length?: number;
|
|
||||||
description?: string;
|
|
||||||
|
|
||||||
key: string;
|
|
||||||
default_value?: string;
|
|
||||||
options?: string[];
|
|
||||||
api_extension?: string;
|
|
||||||
hidden?: boolean;
|
|
||||||
}
|
|
||||||
export interface VariableEditModalRef {
|
|
||||||
handleOpen: (values?: Variable) => void;
|
|
||||||
}
|
|
||||||
/*********** end 变量相关 ******************/
|
|
||||||
export interface MemoryConfig {
|
export interface MemoryConfig {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
memory_content?: string;
|
memory_content?: string;
|
||||||
@@ -131,17 +84,6 @@ export interface ModelConfigModalData {
|
|||||||
export interface AiPromptModalRef {
|
export interface AiPromptModalRef {
|
||||||
handleOpen: () => void;
|
handleOpen: () => void;
|
||||||
}
|
}
|
||||||
export interface KnowledgeModalRef {
|
|
||||||
handleOpen: (config?: KnowledgeConfig[]) => void;
|
|
||||||
}
|
|
||||||
export interface ApiExtensionModalData {
|
|
||||||
name: string;
|
|
||||||
apiEndpoint: string;
|
|
||||||
apiKey: string;
|
|
||||||
}
|
|
||||||
export interface ApiExtensionModalRef {
|
|
||||||
handleOpen: () => void;
|
|
||||||
}
|
|
||||||
export interface ChatData {
|
export interface ChatData {
|
||||||
label?: string;
|
label?: string;
|
||||||
model_config_id?: string;
|
model_config_id?: string;
|
||||||
@@ -206,30 +148,6 @@ export interface AiPromptForm {
|
|||||||
message?: string;
|
message?: string;
|
||||||
current_prompt?: string;
|
current_prompt?: string;
|
||||||
}
|
}
|
||||||
export interface ToolModalRef {
|
export interface ChatVariableConfigModalRef {
|
||||||
handleOpen: () => void;
|
handleOpen: (values: Variable[]) => void;
|
||||||
}
|
|
||||||
|
|
||||||
export interface ToolOption {
|
|
||||||
value?: string | number | null;
|
|
||||||
label?: React.ReactNode;
|
|
||||||
description?: string;
|
|
||||||
children?: ToolOption[];
|
|
||||||
isLeaf?: boolean;
|
|
||||||
method_id?: string;
|
|
||||||
operation?: string;
|
|
||||||
parameters?: Parameter[];
|
|
||||||
tool_id?: string;
|
|
||||||
enabled?: boolean;
|
|
||||||
}
|
|
||||||
export interface Parameter {
|
|
||||||
name: string;
|
|
||||||
type: string;
|
|
||||||
description: string;
|
|
||||||
required: boolean;
|
|
||||||
default: any;
|
|
||||||
enum: null | string[];
|
|
||||||
minimum: number;
|
|
||||||
maximum: number;
|
|
||||||
pattern: null | string;
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user