From 0ea6d2ee3f4c9e85b5d53ed90183ebfb39e70af0 Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Thu, 11 Dec 2025 14:23:22 +0800 Subject: [PATCH] skill editor ui --- packages/global/core/app/agent/type.d.ts | 1 - packages/global/core/app/agent/type.ts | 6 + packages/global/core/app/type.d.ts | 14 + packages/global/core/app/utils.ts | 3 +- packages/global/core/chat/helperBot/type.ts | 9 +- packages/global/core/workflow/constants.ts | 1 + .../global/openapi/core/chat/helperBot/api.ts | 5 + .../core/chat/HelperBot/dispatch/index.ts | 4 +- .../HelperBot/dispatch/skillEditor/index.ts | 15 + .../chat/HelperBot/dispatch/topAgent/index.ts | 7 +- .../core/chat/HelperBot/dispatch/type.ts | 11 +- packages/web/i18n/en/app.json | 6 + packages/web/i18n/en/common.json | 1 + packages/web/i18n/zh-CN/app.json | 10 +- packages/web/i18n/zh-CN/common.json | 1 + packages/web/i18n/zh-Hant/app.json | 6 + packages/web/i18n/zh-Hant/common.json | 1 + .../components/core/chat/HelperBot/index.tsx | 2 +- .../app/detail/Edit/ChatAgent/Edit.tsx | 66 ++++- .../app/detail/Edit/ChatAgent/EditForm.tsx | 95 +++--- .../Edit/ChatAgent/SkillEdit/ChatTest.tsx | 59 ++++ .../Edit/ChatAgent/SkillEdit/EditForm.tsx | 274 ++++++++++++++++++ .../detail/Edit/ChatAgent/SkillEdit/Row.tsx | 88 ++++++ .../app/detail/Edit/ChatAgent/utils.ts | 51 +++- .../FormComponent/ToolSelector/ToolSelect.tsx | 72 ++--- .../ToolSelector/ToolSelectModal.tsx | 8 +- .../app/detail/Edit/SimpleApp/EditForm.tsx | 25 +- .../api/core/chat/helperBot/completions.ts | 5 +- 28 files changed, 734 insertions(+), 112 deletions(-) delete mode 100644 packages/global/core/app/agent/type.d.ts create mode 100644 packages/global/core/app/agent/type.ts create mode 100644 packages/service/core/chat/HelperBot/dispatch/skillEditor/index.ts create mode 100644 projects/app/src/pageComponents/app/detail/Edit/ChatAgent/SkillEdit/ChatTest.tsx create mode 100644 projects/app/src/pageComponents/app/detail/Edit/ChatAgent/SkillEdit/EditForm.tsx create mode 100644 projects/app/src/pageComponents/app/detail/Edit/ChatAgent/SkillEdit/Row.tsx diff --git a/packages/global/core/app/agent/type.d.ts b/packages/global/core/app/agent/type.d.ts deleted file mode 100644 index f220a8f3e..000000000 --- a/packages/global/core/app/agent/type.d.ts +++ /dev/null @@ -1 +0,0 @@ -export type AgentSubAppItemType = {}; diff --git a/packages/global/core/app/agent/type.ts b/packages/global/core/app/agent/type.ts new file mode 100644 index 000000000..2e2324937 --- /dev/null +++ b/packages/global/core/app/agent/type.ts @@ -0,0 +1,6 @@ +import { ObjectIdSchema } from '../../../../global/common/type/mongo'; +import { z } from 'zod'; + +export type AgentSubAppItemType = {}; + +/* ===== Dataset ==== */ diff --git a/packages/global/core/app/type.d.ts b/packages/global/core/app/type.d.ts index 08e7a8ca8..63113fc9c 100644 --- a/packages/global/core/app/type.d.ts +++ b/packages/global/core/app/type.d.ts @@ -100,6 +100,19 @@ export type AppDatasetSearchParamsType = { datasetSearchExtensionBg?: string; }; +/* ===== skill ===== */ +export type SkillEditType = { + id: string; + name: string; + description: string; + prompt: string; + dataset: { + list: SelectedDatasetType[]; + }; + selectedTools: SelectedToolItemType[]; + fileSelectConfig: AppFileSelectConfigType; +}; + export type SelectedToolItemType = FlowNodeTemplateType & { configStatus?: 'active' | 'waitingForConfig' | 'invalid'; }; @@ -126,6 +139,7 @@ export type AppFormEditFormType = { } & AppDatasetSearchParamsType; selectedTools: SelectedToolItemType[]; chatConfig: AppChatConfigType; + skills: SkillEditType[]; }; export type HttpToolConfigType = { diff --git a/packages/global/core/app/utils.ts b/packages/global/core/app/utils.ts index c9a796a29..a51f9d163 100644 --- a/packages/global/core/app/utils.ts +++ b/packages/global/core/app/utils.ts @@ -28,7 +28,8 @@ export const getDefaultAppForm = (): AppFormEditFormType => { datasetSearchExtensionBg: '' }, selectedTools: [], - chatConfig: {} + chatConfig: {}, + skills: [] }; }; diff --git a/packages/global/core/chat/helperBot/type.ts b/packages/global/core/chat/helperBot/type.ts index d027e71a4..505fd4a23 100644 --- a/packages/global/core/chat/helperBot/type.ts +++ b/packages/global/core/chat/helperBot/type.ts @@ -4,7 +4,8 @@ import { ChatRoleEnum } from '../constants'; import { UserChatItemSchema, SystemChatItemSchema, ToolModuleResponseItemSchema } from '../type'; export enum HelperBotTypeEnum { - topAgent = 'topAgent' + topAgent = 'topAgent', + skillEditor = 'skillEditor' } export const HelperBotTypeEnumSchema = z.enum(Object.values(HelperBotTypeEnum)); export type HelperBotTypeEnumType = z.infer; @@ -72,7 +73,7 @@ export type HelperBotChatItemSiteType = z.infer; + +// Skill editor +export const skillEditorParamsSchema = z.object({}); +export type SkillEditorParamsType = z.infer; diff --git a/packages/global/core/workflow/constants.ts b/packages/global/core/workflow/constants.ts index 4a73f8afd..bffa95f6d 100644 --- a/packages/global/core/workflow/constants.ts +++ b/packages/global/core/workflow/constants.ts @@ -172,6 +172,7 @@ export enum NodeInputKeyEnum { // agent subApps = 'subApps', + skills = 'skills', isAskAgent = 'isAskAgent', isPlanAgent = 'isPlanAgent', isConfirmPlanAgent = 'isConfirmPlanAgent', diff --git a/packages/global/openapi/core/chat/helperBot/api.ts b/packages/global/openapi/core/chat/helperBot/api.ts index 42c06622d..a6f31b717 100644 --- a/packages/global/openapi/core/chat/helperBot/api.ts +++ b/packages/global/openapi/core/chat/helperBot/api.ts @@ -3,6 +3,7 @@ import { type HelperBotChatItemSiteType, HelperBotTypeEnum, HelperBotTypeEnumSchema, + skillEditorParamsSchema, topAgentParamsSchema } from '../../../../core/chat/helperBot/type'; import { z } from 'zod'; @@ -58,6 +59,10 @@ export const HelperBotCompletionsParamsSchema = z.object({ z.object({ type: z.literal(HelperBotTypeEnum.topAgent), data: topAgentParamsSchema + }), + z.object({ + type: z.literal(HelperBotTypeEnum.skillEditor), + data: skillEditorParamsSchema }) ]) }); diff --git a/packages/service/core/chat/HelperBot/dispatch/index.ts b/packages/service/core/chat/HelperBot/dispatch/index.ts index 8f5719ba4..78fdc066e 100644 --- a/packages/service/core/chat/HelperBot/dispatch/index.ts +++ b/packages/service/core/chat/HelperBot/dispatch/index.ts @@ -1,6 +1,8 @@ import { HelperBotTypeEnum } from '@fastgpt/global/core/chat/helperBot/type'; import { dispatchTopAgent } from './topAgent'; +import { dispatchSkillEditor } from './skillEditor'; export const dispatchMap = { - [HelperBotTypeEnum.topAgent]: dispatchTopAgent + [HelperBotTypeEnum.topAgent]: dispatchTopAgent, + [HelperBotTypeEnum.skillEditor]: dispatchSkillEditor }; diff --git a/packages/service/core/chat/HelperBot/dispatch/skillEditor/index.ts b/packages/service/core/chat/HelperBot/dispatch/skillEditor/index.ts new file mode 100644 index 000000000..937bac3e5 --- /dev/null +++ b/packages/service/core/chat/HelperBot/dispatch/skillEditor/index.ts @@ -0,0 +1,15 @@ +import type { HelperBotDispatchParamsType, HelperBotDispatchResponseType } from '../type'; + +export const dispatchSkillEditor = async ( + props: HelperBotDispatchParamsType +): Promise => { + console.log(props, 22222); + return { + aiResponse: [], + usage: { + model: '', + inputTokens: 0, + outputTokens: 0 + } + }; +}; diff --git a/packages/service/core/chat/HelperBot/dispatch/topAgent/index.ts b/packages/service/core/chat/HelperBot/dispatch/topAgent/index.ts index 94fadb9a0..da75df3ed 100644 --- a/packages/service/core/chat/HelperBot/dispatch/topAgent/index.ts +++ b/packages/service/core/chat/HelperBot/dispatch/topAgent/index.ts @@ -9,11 +9,12 @@ import { generateResourceList } from './utils'; import { TopAgentFormDataSchema } from './type'; import { addLog } from '../../../../../common/system/log'; import { formatAIResponse } from '../utils'; +import type { TopAgentParamsType } from '@fastgpt/global/core/chat/helperBot/type'; export const dispatchTopAgent = async ( - props: HelperBotDispatchParamsType + props: HelperBotDispatchParamsType ): Promise => { - const { query, files, metadata, histories, workflowResponseWrite, user } = props; + const { query, files, data, histories, workflowResponseWrite, user } = props; const modelData = getLLMModel(); if (!modelData) { @@ -32,7 +33,7 @@ export const dispatchTopAgent = async ( }); const systemPrompt = getPrompt({ resourceList, - metadata: metadata.data + metadata: data }); const historyMessages = helperChats2GPTMessages({ diff --git a/packages/service/core/chat/HelperBot/dispatch/type.ts b/packages/service/core/chat/HelperBot/dispatch/type.ts index d6e8f2c72..edfbe6754 100644 --- a/packages/service/core/chat/HelperBot/dispatch/type.ts +++ b/packages/service/core/chat/HelperBot/dispatch/type.ts @@ -10,7 +10,7 @@ import { LocaleList } from '@fastgpt/global/common/i18n/type'; export const HelperBotDispatchParamsSchema = z.object({ query: z.string(), files: HelperBotCompletionsParamsSchema.shape.files, - metadata: HelperBotCompletionsParamsSchema.shape.metadata, + data: z.unknown(), // Allow any type, will be constrained by generic type parameter histories: z.array(HelperBotChatItemSchema), workflowResponseWrite: WorkflowResponseFnSchema, @@ -22,7 +22,14 @@ export const HelperBotDispatchParamsSchema = z.object({ lang: z.enum(LocaleList) }) }); -export type HelperBotDispatchParamsType = z.infer; + +type BaseHelperBotDispatchParamsType = z.infer; +export type HelperBotDispatchParamsType = Omit< + BaseHelperBotDispatchParamsType, + 'data' +> & { + data: T; +}; export const HelperBotDispatchResponseSchema = z.object({ aiResponse: z.array(AIChatItemValueItemSchema), diff --git a/packages/web/i18n/en/app.json b/packages/web/i18n/en/app.json index 673e31887..6990f5c0d 100644 --- a/packages/web/i18n/en/app.json +++ b/packages/web/i18n/en/app.json @@ -327,6 +327,12 @@ "show_templates": "Expand", "show_top_p_tip": "An alternative method of temperature sampling, called Nucleus sampling, the model considers the results of tokens with TOP_P probability mass quality. \nTherefore, 0.1 means that only tokens containing the highest probability quality are considered. \nThe default is 1.", "simple_tool_tips": "This tool contains special inputs and does not support being called by simple applications.", + "skill_description_placeholder": "Used to guide the Agent to select the skill for execution", + "skill_editor": "Skill-assisted generation", + "skill_empty_name": "Unnamed skill", + "skill_name_placeholder": "Please enter the skill description, for display only", + "skills": "Skills", + "skills_tip": "Model behavioral knowledge", "source_updateTime": "Update time", "space_to_expand_folder": "Press \"Space\" to expand the folder", "stop_sign": "Stop", diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index 632bafd65..16a4e4589 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -840,6 +840,7 @@ "delete_folder": "Delete Folder", "delete_success": "Deleted Successfully", "delete_warning": "Deletion Warning", + "descripton": "describe", "discount_coupon_used": "Coupon used:", "embedding_model_not_config": "No index model is detected", "enable_auth": "Enable authentication", diff --git a/packages/web/i18n/zh-CN/app.json b/packages/web/i18n/zh-CN/app.json index ad224211f..054370cca 100644 --- a/packages/web/i18n/zh-CN/app.json +++ b/packages/web/i18n/zh-CN/app.json @@ -157,6 +157,7 @@ "export_config_successful": "已复制配置,自动过滤部分敏感信息,请注意检查是否仍有敏感数据", "export_configs": "导出配置", "export_log_filename": "{{name}} 对话日志.csv", + "failed_tools": "失败的工具", "fastgpt_marketplace": "FastGPT 插件市场", "feedback_count": "用户反馈", "file_quote_link": "文件链接", @@ -340,6 +341,12 @@ "show_templates": "显示模板", "show_top_p_tip": "用温度采样的替代方法,称为Nucleus采样,该模型考虑了具有TOP_P概率质量质量的令牌的结果。因此,0.1表示仅考虑包含最高概率质量的令牌。默认为 1。", "simple_tool_tips": "该工具含有特殊输入,暂不支持被简易应用调用", + "skill_description_placeholder": "用于引导 Agent 选中该技能进行执行", + "skill_editor": "技能辅助生成", + "skill_empty_name": "未命名的技能", + "skill_name_placeholder": "请输入技能明,仅用于展示", + "skills": "技能", + "skills_tip": "模型的行为知识", "source_updateTime": "更新时间", "space_to_expand_folder": "按\"空格\"展开文件夹", "stop_sign": "停止序列", @@ -396,6 +403,7 @@ "tool_active_system_config_price_desc_folder": "需额外支付密钥价格,依据实际使用工具扣费。", "tool_detail": "工具详情", "tool_input_param_tip": "该工具正常运行需要配置相关信息", + "tool_load_failed": "部分工具加载失败", "tool_not_active": "该工具尚未激活", "tool_offset_tips": "该工具已无法使用,将中断应用运行,请立即替换", "tool_param_config": "参数配置", @@ -468,8 +476,6 @@ "toolkit_uninstalled": "未安装", "toolkit_update_failed": "更新失败", "toolkit_user_guide": "使用说明", - "tool_load_failed": "部分工具加载失败", - "failed_tools": "失败的工具", "tools": "工具", "tools_no_description": "这个工具没有介绍~", "tools_tip": "声明模型可用的工具,可以实现与外部系统交互等扩展能力", diff --git a/packages/web/i18n/zh-CN/common.json b/packages/web/i18n/zh-CN/common.json index 561bd079a..dc3dc3cce 100644 --- a/packages/web/i18n/zh-CN/common.json +++ b/packages/web/i18n/zh-CN/common.json @@ -845,6 +845,7 @@ "delete_folder": "删除文件夹", "delete_success": "删除成功", "delete_warning": "删除警告", + "descripton": "描述", "discount_coupon_used": "已使用优惠券:", "embedding_model_not_config": "检测到没有可用的索引模型", "enable_auth": "启用鉴权", diff --git a/packages/web/i18n/zh-Hant/app.json b/packages/web/i18n/zh-Hant/app.json index 799306e5c..60af81780 100644 --- a/packages/web/i18n/zh-Hant/app.json +++ b/packages/web/i18n/zh-Hant/app.json @@ -325,6 +325,12 @@ "show_templates": "顯示模板", "show_top_p_tip": "用溫度取樣的替代方法,稱為 Nucleus 取樣,該模型考慮了具有 TOP_P 機率質量質量的令牌的結果。\n因此,0.1 表示僅考慮包含最高機率質量的令牌。\n預設為 1。", "simple_tool_tips": "該工具含有特殊輸入,暫不支持被簡易應用調用", + "skill_description_placeholder": "用於引導 Agent 選中該技能進行執行", + "skill_editor": "技能輔助生成", + "skill_empty_name": "未命名的技能", + "skill_name_placeholder": "請輸入技能明,僅用於展示", + "skills": "技能", + "skills_tip": "模型的行為知識", "source_updateTime": "更新時間", "space_to_expand_folder": "按\"空格\"展開文件夾", "stop_sign": "停止序列", diff --git a/packages/web/i18n/zh-Hant/common.json b/packages/web/i18n/zh-Hant/common.json index cc8483b9b..d2b11ba2d 100644 --- a/packages/web/i18n/zh-Hant/common.json +++ b/packages/web/i18n/zh-Hant/common.json @@ -839,6 +839,7 @@ "delete_folder": "刪除資料夾", "delete_success": "刪除成功", "delete_warning": "刪除警告", + "descripton": "描述", "discount_coupon_used": "已使用優惠券:", "embedding_model_not_config": "偵測到沒有可用的索引模型", "enable_auth": "啟用鑑權", diff --git a/projects/app/src/components/core/chat/HelperBot/index.tsx b/projects/app/src/components/core/chat/HelperBot/index.tsx index 31d1d8619..76ba8a2fd 100644 --- a/projects/app/src/components/core/chat/HelperBot/index.tsx +++ b/projects/app/src/components/core/chat/HelperBot/index.tsx @@ -334,7 +334,7 @@ const ChatBox = ({ type, metadata, onApply, ...props }: HelperBotProps) => { name: item.name })), metadata: { - type: 'topAgent', + type, data: metadata } }, diff --git a/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/Edit.tsx b/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/Edit.tsx index 75307632f..60fa2dd04 100644 --- a/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/Edit.tsx +++ b/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/Edit.tsx @@ -1,16 +1,19 @@ import React, { useState } from 'react'; -import { Box } from '@chakra-ui/react'; +import { Box, Flex } from '@chakra-ui/react'; import ChatTest from './ChatTest'; import AppCard from '../FormComponent/AppCard'; import EditForm from './EditForm'; -import { type AppFormEditFormType } from '@fastgpt/global/core/app/type'; +import type { SkillEditType, AppFormEditFormType } from '@fastgpt/global/core/app/type'; import { cardStyles } from '../../constants'; - -import styles from '../FormComponent/styles.module.scss'; import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { type SimpleAppSnapshotType } from '../FormComponent/useSnapshots'; import { agentForm2AppWorkflow } from './utils'; +import styles from '../FormComponent/styles.module.scss'; +import dynamic from 'next/dynamic'; + +const SkillEditForm = dynamic(() => import('./SkillEdit/EditForm'), { ssr: false }); +const SKillChatTest = dynamic(() => import('./SkillEdit/ChatTest'), { ssr: false }); const Edit = ({ appForm, @@ -23,6 +26,7 @@ const Edit = ({ }) => { const { isPc } = useSystem(); const [renderEdit, setRenderEdit] = useState(true); + const [editSkill, setEditSkill] = useState(); return ( + {/* Top agent editor */} {renderEdit && ( - + setEditSkill(e)} + /> )} @@ -61,6 +71,52 @@ const Edit = ({ /> )} + + {/* Mask */} + {editSkill && ( + + )} + + {/* Skill editor */} + + {editSkill && ( + <> + + setEditSkill(undefined)} + setAppForm={setAppForm} + /> + + + + + + )} + ); }; diff --git a/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/EditForm.tsx b/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/EditForm.tsx index 0c598f93e..46b5e03a4 100644 --- a/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/EditForm.tsx +++ b/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/EditForm.tsx @@ -10,7 +10,7 @@ import { HStack, Input } from '@chakra-ui/react'; -import type { AppFormEditFormType } from '@fastgpt/global/core/app/type.d'; +import type { AppFormEditFormType, SkillEditType } from '@fastgpt/global/core/app/type.d'; import { useRouter } from 'next/router'; import { useTranslation } from 'next-i18next'; @@ -20,23 +20,17 @@ import Avatar from '@fastgpt/web/components/common/Avatar'; import MyIcon from '@fastgpt/web/components/common/Icon'; import VariableEdit from '@/components/core/app/VariableEdit'; import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor'; -import { formatEditorVariablePickerIcon } from '@fastgpt/global/core/workflow/utils'; import SearchParamsTip from '@/components/core/dataset/SearchParamsTip'; import SettingLLMModel from '@/components/core/ai/SettingLLMModel'; import { TTSTypeEnum } from '@/web/core/app/constants'; -import { workflowSystemVariables } from '@/web/core/app/utils'; import { useContextSelector } from 'use-context-selector'; import { AppContext } from '@/pageComponents/app/detail/context'; -import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; -import VariableTip from '@/components/common/Textarea/MyTextarea/VariableTip'; import { getWebLLMModel } from '@/web/common/system/utils'; import ToolSelect from '../FormComponent/ToolSelector/ToolSelect'; -import OptimizerPopover from '@/components/common/PromptEditor/OptimizerPopover'; -import type { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node'; -import { type SelectedToolItemType, useSkillManager } from './hooks/useSkillManager'; -import { useMemoEnhance } from '@fastgpt/web/hooks/useMemoEnhance'; +import SkillRow from './SkillEdit/Row'; import { cardStyles } from '../../constants'; +import { SmallAddIcon } from '@chakra-ui/icons'; const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal')); const DatasetParamsModal = dynamic(() => import('@/components/core/app/DatasetParamsModal')); @@ -56,10 +50,12 @@ const BoxStyles: BoxProps = { const EditForm = ({ appForm, - setAppForm + setAppForm, + onEditSkill }: { appForm: AppFormEditFormType; setAppForm: React.Dispatch>; + onEditSkill: (e: SkillEditType) => void; }) => { const theme = useTheme(); const router = useRouter(); @@ -80,26 +76,6 @@ const EditForm = ({ onClose: onCloseDatasetParams } = useDisclosure(); - const formatVariables = useMemo( - () => - formatEditorVariablePickerIcon([ - ...workflowSystemVariables.filter( - (variable) => - !['appId', 'chatId', 'responseChatItemId', 'histories'].includes(variable.key) - ), - ...(appForm.chatConfig.variables || []) - ]).map((item) => ({ - ...item, - label: t(item.label as any), - parent: { - id: 'VARIABLE_NODE_ID', - label: t('common:core.module.Variable'), - avatar: 'core/workflow/template/variable' - } - })), - [appForm.chatConfig.variables, t] - ); - const selectedModel = getWebLLMModel(appForm.aiSettings.model); const tokenLimit = useMemo(() => { return selectedModel?.quoteMaxToken || 3000; @@ -226,9 +202,44 @@ const EditForm = ({ + + { + setAppForm((state) => ({ + ...state, + skills: state.skills.filter((item) => item.id !== id) + })); + }} + /> + {/* tool choice */} - + { + setAppForm((state) => ({ + ...state, + selectedTools: [e, ...(state.selectedTools || [])] + })); + }} + onUpdateTool={(e) => { + setAppForm((state) => ({ + ...state, + selectedTools: + state.selectedTools?.map((item) => (item.id === e.id ? e : item)) || [] + })); + }} + onRemoveTool={(id) => { + setAppForm((state) => ({ + ...state, + selectedTools: state.selectedTools?.filter((item) => item.id !== id) || [] + })); + }} + /> {/* dataset */} @@ -239,17 +250,6 @@ const EditForm = ({ {t('app:dataset')} - + {appForm.dataset.datasets?.length > 0 && ( diff --git a/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/SkillEdit/ChatTest.tsx b/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/SkillEdit/ChatTest.tsx new file mode 100644 index 000000000..c00e810d0 --- /dev/null +++ b/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/SkillEdit/ChatTest.tsx @@ -0,0 +1,59 @@ +import { Box, Flex, IconButton } from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; +import React, { useMemo } from 'react'; +import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; +import MyIcon from '@fastgpt/web/components/common/Icon'; +import type { AppFormEditFormType, SkillEditType } from '@fastgpt/global/core/app/type'; +import { useContextSelector } from 'use-context-selector'; +import { AppContext } from '../../../context'; +import MyBox from '@fastgpt/web/components/common/MyBox'; +import { cardStyles } from '../../../constants'; +import HelperBot from '@/components/core/chat/HelperBot'; +import { HelperBotTypeEnum } from '@fastgpt/global/core/chat/helperBot/type'; +import { useToast } from '@fastgpt/web/hooks/useToast'; + +type Props = { + skill: SkillEditType; + setAppForm: React.Dispatch>; +}; +const ChatTest = ({ skill, setAppForm }: Props) => { + const { t } = useTranslation(); + const { toast } = useToast(); + + // 构建 SkillAgent metadata,从 appForm 中提取配置 + const skillAgentMetadata = useMemo(() => ({}), []); + + return ( + + + + {t('app:skill_editor')} + + + } + variant={'whiteDanger'} + borderRadius={'md'} + aria-label={'delete'} + onClick={(e) => { + e.stopPropagation(); + }} + /> + + + + { + console.log(e); + }} + /> + + + ); +}; + +export default React.memo(ChatTest); diff --git a/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/SkillEdit/EditForm.tsx b/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/SkillEdit/EditForm.tsx new file mode 100644 index 000000000..4c53f4f19 --- /dev/null +++ b/projects/app/src/pageComponents/app/detail/Edit/ChatAgent/SkillEdit/EditForm.tsx @@ -0,0 +1,274 @@ +import React, { useEffect, useMemo, useTransition } from 'react'; +import { + Box, + Flex, + Grid, + type BoxProps, + useTheme, + useDisclosure, + Button, + HStack, + Input, + IconButton, + Textarea +} from '@chakra-ui/react'; +import type { + AppFileSelectConfigType, + AppFormEditFormType, + SkillEditType +} from '@fastgpt/global/core/app/type.d'; +import { useRouter } from 'next/router'; +import { useTranslation } from 'next-i18next'; + +import dynamic from 'next/dynamic'; +import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; +import Avatar from '@fastgpt/web/components/common/Avatar'; +import MyIcon from '@fastgpt/web/components/common/Icon'; +import VariableEdit from '@/components/core/app/VariableEdit'; +import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor'; +import { formatEditorVariablePickerIcon } from '@fastgpt/global/core/workflow/utils'; +import SearchParamsTip from '@/components/core/dataset/SearchParamsTip'; +import SettingLLMModel from '@/components/core/ai/SettingLLMModel'; +import { TTSTypeEnum } from '@/web/core/app/constants'; +import { workflowSystemVariables } from '@/web/core/app/utils'; +import { useContextSelector } from 'use-context-selector'; +import { AppContext } from '@/pageComponents/app/detail/context'; +import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; +import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; +import VariableTip from '@/components/common/Textarea/MyTextarea/VariableTip'; +import { getWebLLMModel } from '@/web/common/system/utils'; +import ToolSelect from '../../FormComponent/ToolSelector/ToolSelect'; +import OptimizerPopover from '@/components/common/PromptEditor/OptimizerPopover'; +import type { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node'; +import { type SelectedToolItemType, useSkillManager } from '../hooks/useSkillManager'; +import { useMemoEnhance } from '@fastgpt/web/hooks/useMemoEnhance'; +import { cardStyles } from '../../../constants'; +import { defaultSkill as defaultEditSkill } from './Row'; +import { useForm } from 'react-hook-form'; +import type { LLMModelItemType } from '@fastgpt/global/core/ai/model.d'; +import { SmallAddIcon } from '@chakra-ui/icons'; +import { getNanoid } from '@fastgpt/global/common/string/tools'; + +const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal')); +const DatasetParamsModal = dynamic(() => import('@/components/core/app/DatasetParamsModal')); +const TTSSelect = dynamic(() => import('@/components/core/app/TTSSelect')); +const QGConfig = dynamic(() => import('@/components/core/app/QGConfig')); +const WhisperConfig = dynamic(() => import('@/components/core/app/WhisperConfig')); +const InputGuideConfig = dynamic(() => import('@/components/core/app/InputGuideConfig')); +const WelcomeTextConfig = dynamic(() => import('@/components/core/app/WelcomeTextConfig')); +const FileSelectConfig = dynamic(() => import('@/components/core/app/FileSelect')); + +const EditForm = ({ + model, + fileSelectConfig, + defaultSkill = defaultEditSkill, + onClose, + setAppForm +}: { + model: string; + fileSelectConfig?: AppFileSelectConfigType; + defaultSkill?: SkillEditType; + onClose: () => void; + setAppForm: React.Dispatch>; +}) => { + const theme = useTheme(); + const router = useRouter(); + const { t } = useTranslation(); + const [, startTst] = useTransition(); + + const selectedModel = getWebLLMModel(model); + + const { register, setValue, handleSubmit, reset, watch } = useForm({ + defaultValues: defaultSkill + }); + useEffect(() => { + reset(defaultSkill); + }, [defaultSkill, reset]); + + const name = watch('name'); + const prompt = watch('prompt'); + const selectedTools = watch('selectedTools'); + const selectDatasets = watch('dataset.list'); + + const { + isOpen: isOpenDatasetSelect, + onOpen: onOpenKbSelect, + onClose: onCloseKbSelect + } = useDisclosure(); + + const onSave = (e: SkillEditType) => { + setAppForm((state) => ({ + ...state, + skills: e.id + ? state.skills.map((item) => (item.id === e.id ? e : item)) + : [{ ...e, id: getNanoid(6) }, ...state.skills] + })); + onClose(); + }; + + return ( + <> + + {/* Header */} + + } + size={'smSquare'} + aria-label={''} + w={'32px'} + h={'32px'} + onClick={onClose} + /> + + {name || t('app:skill_empty_name')} + + + + + {/* Name */} + + + {t('common:Name')} + + + + {/* Desc */} + + + + {t('common:descripton')} + + + +