From 2446e03dfcb6039e5b2e091a5bc43d069e9b4a8e Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Thu, 18 Jul 2024 14:08:41 +0800 Subject: [PATCH] System template (#2082) * feat: system plugin (#2024) * add plugin cost & change plugin avatar (#2030) * add plugin cost & change plugin avatar * add author * feat: duckduckgo plugin * duckduck search * perf: templates select system plugin * perf: system plugin avatar * feat: duckduck plugins * doc * perf: plugin classify * perf: icon avatar component * perf: system template avatar --------- Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com> --- .../zh-cn/docs/development/upgrading/468.md | 2 +- packages/global/core/plugin/type.d.ts | 2 +- packages/global/core/workflow/constants.ts | 3 + .../global/core/workflow/runtime/type.d.ts | 3 +- .../core/workflow/template/system/aiChat.ts | 2 +- .../template/system/assignedAnswer.ts | 2 +- .../template/system/classifyQuestion/index.ts | 2 +- .../template/system/contextExtract/index.ts | 2 +- .../template/system/customFeedback.ts | 2 +- .../workflow/template/system/datasetConcat.ts | 2 +- .../workflow/template/system/datasetSearch.ts | 2 +- .../core/workflow/template/system/http468.ts | 2 +- .../workflow/template/system/ifElse/index.ts | 2 +- .../core/workflow/template/system/laf.ts | 2 +- .../workflow/template/system/pluginInput.ts | 2 +- .../workflow/template/system/pluginOutput.ts | 2 +- .../template/system/queryExtension.ts | 2 +- .../workflow/template/system/runApp/index.ts | 2 +- .../workflow/template/system/sandbox/index.ts | 2 +- .../core/workflow/template/system/stopTool.ts | 2 +- .../workflow/template/system/systemConfig.ts | 2 +- .../workflow/template/system/textEditor.ts | 2 +- .../core/workflow/template/system/tools.ts | 2 +- .../template/system/variableUpdate/index.tsx | 2 +- .../workflow/template/system/workflowStart.ts | 2 +- packages/global/core/workflow/type/index.d.ts | 12 + packages/global/core/workflow/type/node.d.ts | 3 +- packages/plugins/package.json | 1 + packages/plugins/register.ts | 135 ++++++--- .../plugins/src/duckduckgo/search/index.ts | 47 ++++ .../src/duckduckgo/search/template.json | 260 ++++++++++++++++++ .../plugins/src/duckduckgo/searchImg/index.ts | 46 ++++ .../src/duckduckgo/searchImg/template.json | 260 ++++++++++++++++++ .../src/duckduckgo/searchNews/index.ts | 47 ++++ .../src/duckduckgo/searchNews/template.json | 260 ++++++++++++++++++ .../src/duckduckgo/searchVideo/index.ts | 47 ++++ .../src/duckduckgo/searchVideo/template.json | 260 ++++++++++++++++++ packages/plugins/src/duckduckgo/template.json | 17 ++ packages/plugins/src/fetchUrl/template.json | 2 +- packages/plugins/src/getTime/template.json | 4 +- .../plugins/src/mathExprVal/template.json | 2 +- packages/plugins/type.d.ts | 6 +- .../service/core/app/plugin/controller.ts | 22 +- packages/service/core/app/plugin/utils.ts | 21 ++ .../core/workflow/dispatch/chat/oneapi.ts | 141 +++++----- .../core/workflow/dispatch/plugin/run.ts | 27 +- .../core/workflow/dispatch/tools/http468.ts | 4 +- .../service/support/permission/app/auth.ts | 21 ++ .../web/components/common}/Avatar/index.tsx | 9 +- .../web/components/common/Icon/constants.ts | 40 +++ .../icons/core/workflow/template/FileRead.svg | 10 + .../icons/core/workflow/template/aiChat.svg | 10 + .../icons/core/workflow/template/codeRun.svg | 10 + .../core/workflow/template/customFeedback.svg | 10 + .../core/workflow/template/datasetConcat.svg | 10 + .../core/workflow/template/datasetSearch.svg | 13 + .../core/workflow/template/duckduckgo.svg | 1 + .../core/workflow/template/extractJson.svg | 11 + .../icons/core/workflow/template/fetchUrl.svg | 10 + .../icons/core/workflow/template/getTime.svg | 12 + .../core/workflow/template/httpRequest.svg | 10 + .../icons/core/workflow/template/ifelse.svg | 10 + .../core/workflow/template/lafDispatch.svg | 10 + .../icons/core/workflow/template/mathCall.svg | 10 + .../core/workflow/template/pluginOutput.svg | 13 + .../core/workflow/template/queryExtension.svg | 10 + .../workflow/template/questionClassify.svg | 12 + .../icons/core/workflow/template/reply.svg | 10 + .../icons/core/workflow/template/runApp.svg | 13 + .../icons/core/workflow/template/stopTool.svg | 10 + .../core/workflow/template/systemConfig.svg | 10 + .../core/workflow/template/textConcat.svg | 11 + .../icons/core/workflow/template/toolCall.svg | 13 + .../core/workflow/template/variableUpdate.svg | 12 + .../core/workflow/template/workflowStart.svg | 10 + .../common/Icon/icons/plugins/textEditor.svg | 1 + .../web/components/common/MyModal/index.tsx | 17 +- .../components/common/Tabs/LightRowTabs.tsx | 10 +- packages/web/core/workflow/constants.ts | 10 + packages/web/i18n/en/app.json | 4 + packages/web/i18n/en/common.json | 8 +- packages/web/i18n/zh/app.json | 4 + packages/web/i18n/zh/common.json | 8 +- pnpm-lock.yaml | 31 +++ .../app/public/imgs/app/inputGuide-icon.svg | 2 +- .../app/public/imgs/app/nextQuestion-icon.svg | 2 +- projects/app/public/imgs/app/welcome-icon.svg | 2 +- .../app/public/imgs/workflow/fetchUrl.svg | 5 +- .../public/imgs/workflow/getCurrentTime.svg | 11 +- .../app/public/imgs/workflow/mathExprEval.svg | 5 +- projects/app/src/components/Layout/navbar.tsx | 2 +- .../src/components/Select/AIModelSelector.tsx | 2 +- .../common/Modal/EditResourceModal.tsx | 2 +- .../common/folder/SelectOneResource.tsx | 2 +- .../core/ai/SettingLLMModel/index.tsx | 2 +- .../core/app/DatasetSelectModal.tsx | 2 +- .../ChatBox/components/ChatAvatar.tsx | 2 +- .../components/SelectMarkCollection.tsx | 2 +- .../core/chat/components/AIResponseBox.tsx | 8 +- .../chat/components/WholeResponseModal.tsx | 21 +- .../permission/ConfigPerModal/index.tsx | 2 +- .../MemberManager/AddMemberModal.tsx | 4 +- .../permission/MemberManager/ManageModal.tsx | 2 +- .../MemberManager/MemberListCard.tsx | 2 +- .../user/team/TeamManageModal/TeamList.tsx | 2 +- .../components/EditInfoModal.tsx | 2 +- .../components/MemberTable.tsx | 2 +- .../PermissionManage/AddManager.tsx | 2 +- .../components/PermissionManage/index.tsx | 2 +- .../support/user/team/TeamMenu/index.tsx | 2 +- .../user/team/UpdateInviteModal/index.tsx | 2 +- .../app/src/pages/account/components/Info.tsx | 2 +- .../pages/account/components/UsageTable.tsx | 2 +- .../app/plugin/getSystemPluginTemplates.ts | 46 +++- .../app/src/pages/api/core/app/plugin/path.ts | 35 +++ .../pages/app/detail/components/InfoModal.tsx | 2 +- .../detail/components/SimpleApp/AppCard.tsx | 2 +- .../detail/components/SimpleApp/EditForm.tsx | 24 +- .../SimpleApp/components/ToolSelectModal.tsx | 169 ++++++++---- .../app/detail/components/Workflow/Header.tsx | 1 - .../components/WorkflowComponents/AppCard.tsx | 2 +- .../Flow/NodeTemplatesModal.tsx | 192 ++++++++----- .../Flow/nodes/render/NodeCard.tsx | 4 +- .../RenderInput/templates/Reference.tsx | 6 +- .../RenderInput/templates/SelectApp.tsx | 2 +- .../RenderInput/templates/SelectDataset.tsx | 2 +- .../pages/app/list/components/CreateModal.tsx | 4 +- .../list/components/HttpPluginEditModal.tsx | 2 +- .../src/pages/app/list/components/List.tsx | 2 +- .../src/pages/chat/components/ChatHeader.tsx | 2 +- .../chat/components/ChatHistorySlider.tsx | 2 +- .../app/src/pages/chat/components/Empty.tsx | 2 +- .../src/pages/chat/components/SliderApps.tsx | 2 +- .../pages/dataset/detail/components/Info.tsx | 2 +- .../dataset/detail/components/Slider.tsx | 2 +- .../dataset/list/component/CreateModal.tsx | 2 +- .../src/pages/dataset/list/component/List.tsx | 2 +- .../dataset/list/component/MoveModal.tsx | 2 +- projects/app/src/web/core/app/api/app.ts | 7 +- projects/app/src/web/core/app/api/plugin.ts | 11 +- projects/app/src/web/core/app/templates.ts | 92 +++---- projects/app/src/web/core/workflow/utils.ts | 1 + 142 files changed, 2393 insertions(+), 431 deletions(-) create mode 100644 packages/plugins/src/duckduckgo/search/index.ts create mode 100644 packages/plugins/src/duckduckgo/search/template.json create mode 100644 packages/plugins/src/duckduckgo/searchImg/index.ts create mode 100644 packages/plugins/src/duckduckgo/searchImg/template.json create mode 100644 packages/plugins/src/duckduckgo/searchNews/index.ts create mode 100644 packages/plugins/src/duckduckgo/searchNews/template.json create mode 100644 packages/plugins/src/duckduckgo/searchVideo/index.ts create mode 100644 packages/plugins/src/duckduckgo/searchVideo/template.json create mode 100644 packages/plugins/src/duckduckgo/template.json create mode 100644 packages/service/core/app/plugin/utils.ts rename {projects/app/src/components => packages/web/components/common}/Avatar/index.tsx (68%) create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/FileRead.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/aiChat.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/codeRun.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/customFeedback.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/datasetConcat.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/datasetSearch.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/duckduckgo.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/extractJson.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/fetchUrl.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/getTime.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/httpRequest.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/ifelse.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/lafDispatch.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/mathCall.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/pluginOutput.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/queryExtension.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/questionClassify.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/reply.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/runApp.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/stopTool.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/systemConfig.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/textConcat.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/toolCall.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/variableUpdate.svg create mode 100644 packages/web/components/common/Icon/icons/core/workflow/template/workflowStart.svg create mode 100644 packages/web/components/common/Icon/icons/plugins/textEditor.svg create mode 100644 projects/app/src/pages/api/core/app/plugin/path.ts diff --git a/docSite/content/zh-cn/docs/development/upgrading/468.md b/docSite/content/zh-cn/docs/development/upgrading/468.md index 1b579ab0b91..6df28919be7 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/468.md +++ b/docSite/content/zh-cn/docs/development/upgrading/468.md @@ -77,7 +77,7 @@ docker-compose up -d 商业版用户需要执行一个初始化,格式化团队信息。 -发起 1 个 HTTP 请求 ({{rootkey}} 替换成环境变量里的 `rootkey`,{{host}} 替换成自己域名) +发起 1 个 HTTP 请求 ({{rootkey}} 替换成环境变量里的 `rootkey`,{{host}} 替换成商业版域名) ```bash curl --location --request POST 'https://{{host}}/api/init/v468' \ diff --git a/packages/global/core/plugin/type.d.ts b/packages/global/core/plugin/type.d.ts index 361df1cf5ac..38215640e4e 100644 --- a/packages/global/core/plugin/type.d.ts +++ b/packages/global/core/plugin/type.d.ts @@ -32,7 +32,7 @@ export type PluginItemSchema = { export type PluginTemplateType = PluginRuntimeType & { author?: string; id: string; - source: `${PluginSourceEnum}`; + source: PluginSourceEnum; templateType: FlowNodeTemplateType['templateType']; intro: string; version: string; diff --git a/packages/global/core/workflow/constants.ts b/packages/global/core/workflow/constants.ts index 7df5f06a751..62e11b5ffea 100644 --- a/packages/global/core/workflow/constants.ts +++ b/packages/global/core/workflow/constants.ts @@ -4,6 +4,9 @@ export enum FlowNodeTemplateTypeEnum { function = 'function', tools = 'tools', + search = 'search', + multimodal = 'multimodal', + other = 'other', teamApp = 'teamApp' } diff --git a/packages/global/core/workflow/runtime/type.d.ts b/packages/global/core/workflow/runtime/type.d.ts index a3c944335f9..6022bbb2bbc 100644 --- a/packages/global/core/workflow/runtime/type.d.ts +++ b/packages/global/core/workflow/runtime/type.d.ts @@ -67,11 +67,12 @@ export type RuntimeNodeItemType = { }; export type PluginRuntimeType = { + id: string; teamId?: string; name: string; avatar: string; showStatus?: boolean; - isTool?: boolean; + currentCost?: number; nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[]; }; diff --git a/packages/global/core/workflow/template/system/aiChat.ts b/packages/global/core/workflow/template/system/aiChat.ts index 45e8f3120d6..e100e39fd06 100644 --- a/packages/global/core/workflow/template/system/aiChat.ts +++ b/packages/global/core/workflow/template/system/aiChat.ts @@ -26,7 +26,7 @@ export const AiChatModule: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.chatNode, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/AI.png', + avatar: 'core/workflow/template/aiChat', name: 'AI 对话', intro: 'AI 大模型对话', showStatus: true, diff --git a/packages/global/core/workflow/template/system/assignedAnswer.ts b/packages/global/core/workflow/template/system/assignedAnswer.ts index 5a8998eecdb..6850eb58496 100644 --- a/packages/global/core/workflow/template/system/assignedAnswer.ts +++ b/packages/global/core/workflow/template/system/assignedAnswer.ts @@ -13,7 +13,7 @@ export const AssignedAnswerModule: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.answerNode, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/reply.png', + avatar: 'core/workflow/template/reply', name: '指定回复', intro: '该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。', diff --git a/packages/global/core/workflow/template/system/classifyQuestion/index.ts b/packages/global/core/workflow/template/system/classifyQuestion/index.ts index 8a587fa10b5..7d378fbab51 100644 --- a/packages/global/core/workflow/template/system/classifyQuestion/index.ts +++ b/packages/global/core/workflow/template/system/classifyQuestion/index.ts @@ -25,7 +25,7 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.classifyQuestion, sourceHandle: getHandleConfig(false, false, false, false), targetHandle: getHandleConfig(true, false, true, true), - avatar: '/imgs/workflow/cq.png', + avatar: 'core/workflow/template/questionClassify', name: '问题分类', intro: `根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题`, showStatus: true, diff --git a/packages/global/core/workflow/template/system/contextExtract/index.ts b/packages/global/core/workflow/template/system/contextExtract/index.ts index 146fd6740a5..4b6eb42d646 100644 --- a/packages/global/core/workflow/template/system/contextExtract/index.ts +++ b/packages/global/core/workflow/template/system/contextExtract/index.ts @@ -20,7 +20,7 @@ export const ContextExtractModule: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.contentExtract, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/extract.png', + avatar: 'core/workflow/template/extractJson', name: '文本内容提取', intro: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等', showStatus: true, diff --git a/packages/global/core/workflow/template/system/customFeedback.ts b/packages/global/core/workflow/template/system/customFeedback.ts index cd7374ef649..fb8740c2806 100644 --- a/packages/global/core/workflow/template/system/customFeedback.ts +++ b/packages/global/core/workflow/template/system/customFeedback.ts @@ -13,7 +13,7 @@ export const CustomFeedbackNode: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.customFeedback, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/customFeedback.svg', + avatar: 'core/workflow/template/customFeedback', name: '自定义反馈', intro: '该模块被触发时,会给当前的对话记录增加一条反馈。可用于自动记录对话效果等。', version: '486', diff --git a/packages/global/core/workflow/template/system/datasetConcat.ts b/packages/global/core/workflow/template/system/datasetConcat.ts index 7355eb48c89..2b608cad3e4 100644 --- a/packages/global/core/workflow/template/system/datasetConcat.ts +++ b/packages/global/core/workflow/template/system/datasetConcat.ts @@ -37,7 +37,7 @@ export const DatasetConcatModule: FlowNodeTemplateType = { templateType: FlowNodeTemplateTypeEnum.other, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/concat.svg', + avatar: 'core/workflow/template/datasetConcat', name: '知识库搜索引用合并', intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。', showStatus: false, diff --git a/packages/global/core/workflow/template/system/datasetSearch.ts b/packages/global/core/workflow/template/system/datasetSearch.ts index caacb90523f..1e4f18a60da 100644 --- a/packages/global/core/workflow/template/system/datasetSearch.ts +++ b/packages/global/core/workflow/template/system/datasetSearch.ts @@ -23,7 +23,7 @@ export const DatasetSearchModule: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.datasetSearchNode, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/db.png', + avatar: 'core/workflow/template/datasetSearch', name: '知识库搜索', intro: Dataset_SEARCH_DESC, showStatus: true, diff --git a/packages/global/core/workflow/template/system/http468.ts b/packages/global/core/workflow/template/system/http468.ts index 5a980fd8a1b..c7846f7868f 100644 --- a/packages/global/core/workflow/template/system/http468.ts +++ b/packages/global/core/workflow/template/system/http468.ts @@ -20,7 +20,7 @@ export const HttpNode468: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.httpRequest468, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/http.png', + avatar: 'core/workflow/template/httpRequest', name: 'HTTP 请求', intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)', showStatus: true, diff --git a/packages/global/core/workflow/template/system/ifElse/index.ts b/packages/global/core/workflow/template/system/ifElse/index.ts index 39b7b41202b..1da8dcb3268 100644 --- a/packages/global/core/workflow/template/system/ifElse/index.ts +++ b/packages/global/core/workflow/template/system/ifElse/index.ts @@ -18,7 +18,7 @@ export const IfElseNode: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.ifElseNode, sourceHandle: getHandleConfig(false, false, false, false), targetHandle: getHandleConfig(true, false, true, true), - avatar: '/imgs/workflow/ifElse.svg', + avatar: 'core/workflow/template/ifelse', name: '判断器', intro: '根据一定的条件,执行不同的分支。', showStatus: true, diff --git a/packages/global/core/workflow/template/system/laf.ts b/packages/global/core/workflow/template/system/laf.ts index 4e05c54bfcb..e5466bc6d2d 100644 --- a/packages/global/core/workflow/template/system/laf.ts +++ b/packages/global/core/workflow/template/system/laf.ts @@ -26,7 +26,7 @@ export const LafModule: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.lafModule, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/laf.png', + avatar: 'core/workflow/template/lafDispatch', name: 'Laf 函数调用(测试)', intro: '可以调用Laf账号下的云函数。', showStatus: true, diff --git a/packages/global/core/workflow/template/system/pluginInput.ts b/packages/global/core/workflow/template/system/pluginInput.ts index 2a0478ff0d1..27fce9013ea 100644 --- a/packages/global/core/workflow/template/system/pluginInput.ts +++ b/packages/global/core/workflow/template/system/pluginInput.ts @@ -11,7 +11,7 @@ export const PluginInputModule: FlowNodeTemplateType = { targetHandle: getHandleConfig(false, false, false, false), unique: true, forbidDelete: true, - avatar: '/imgs/workflow/input.png', + avatar: 'core/workflow/template/workflowStart', name: '插件输入', intro: '可以配置插件需要哪些输入,利用这些输入来运行插件', showStatus: false, diff --git a/packages/global/core/workflow/template/system/pluginOutput.ts b/packages/global/core/workflow/template/system/pluginOutput.ts index 023a0972a6e..1d2e98bc990 100644 --- a/packages/global/core/workflow/template/system/pluginOutput.ts +++ b/packages/global/core/workflow/template/system/pluginOutput.ts @@ -11,7 +11,7 @@ export const PluginOutputModule: FlowNodeTemplateType = { targetHandle: getHandleConfig(false, false, false, true), unique: true, forbidDelete: true, - avatar: '/imgs/workflow/output.png', + avatar: 'core/workflow/template/pluginOutput', name: '自定义插件输出', intro: '自定义配置外部输出,使用插件时,仅暴露自定义配置的输出', showStatus: false, diff --git a/packages/global/core/workflow/template/system/queryExtension.ts b/packages/global/core/workflow/template/system/queryExtension.ts index 356b1737f4e..6f4358fef4f 100644 --- a/packages/global/core/workflow/template/system/queryExtension.ts +++ b/packages/global/core/workflow/template/system/queryExtension.ts @@ -24,7 +24,7 @@ export const AiQueryExtension: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.queryExtension, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/cfr.svg', + avatar: 'core/workflow/template/queryExtension', name: '问题优化', intro: '使用问题优化功能,可以提高知识库连续对话时搜索的精度。使用该功能后,会先利用 AI 根据上下文构建一个或多个新的检索词,这些检索词更利于进行知识库搜索。该模块已内置在知识库搜索模块中,如果您仅进行一次知识库搜索,可直接使用知识库内置的补全功能。', diff --git a/packages/global/core/workflow/template/system/runApp/index.ts b/packages/global/core/workflow/template/system/runApp/index.ts index ccbfc5c827b..2d30a28ecb5 100644 --- a/packages/global/core/workflow/template/system/runApp/index.ts +++ b/packages/global/core/workflow/template/system/runApp/index.ts @@ -19,7 +19,7 @@ export const RunAppModule: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.runApp, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/app.png', + avatar: 'core/workflow/template/runApp', name: '应用调用', intro: '可以选择一个其他应用进行调用', showStatus: true, diff --git a/packages/global/core/workflow/template/system/sandbox/index.ts b/packages/global/core/workflow/template/system/sandbox/index.ts index 36e2f2867ea..cd8bb00fb4b 100644 --- a/packages/global/core/workflow/template/system/sandbox/index.ts +++ b/packages/global/core/workflow/template/system/sandbox/index.ts @@ -21,7 +21,7 @@ export const CodeNode: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.code, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/code.svg', + avatar: 'core/workflow/template/codeRun', name: '代码运行', intro: '执行一段简单的脚本代码,通常用于进行复杂的数据处理。', showStatus: true, diff --git a/packages/global/core/workflow/template/system/stopTool.ts b/packages/global/core/workflow/template/system/stopTool.ts index 8499db6bdd9..c930c1419bd 100644 --- a/packages/global/core/workflow/template/system/stopTool.ts +++ b/packages/global/core/workflow/template/system/stopTool.ts @@ -9,7 +9,7 @@ export const StopToolNode: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.stopTool, sourceHandle: getHandleConfig(false, false, false, false), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/toolStop.svg', + avatar: 'core/workflow/template/stopTool', name: '工具调用终止', intro: '该模块需配置工具调用使用。当该模块被执行时,本次工具调用将会强制结束,并且不再调用AI针对工具调用结果回答问题。', diff --git a/packages/global/core/workflow/template/system/systemConfig.ts b/packages/global/core/workflow/template/system/systemConfig.ts index 31836f3a5f3..b037b8f8b1a 100644 --- a/packages/global/core/workflow/template/system/systemConfig.ts +++ b/packages/global/core/workflow/template/system/systemConfig.ts @@ -9,7 +9,7 @@ export const SystemConfigNode: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.systemConfig, sourceHandle: getHandleConfig(false, false, false, false), targetHandle: getHandleConfig(false, false, false, false), - avatar: '/imgs/workflow/userGuide.png', + avatar: 'core/workflow/template/systemConfig', name: '系统配置', intro: '可以配置应用的系统参数。', unique: true, diff --git a/packages/global/core/workflow/template/system/textEditor.ts b/packages/global/core/workflow/template/system/textEditor.ts index b9f630a7a69..fa157e439b9 100644 --- a/packages/global/core/workflow/template/system/textEditor.ts +++ b/packages/global/core/workflow/template/system/textEditor.ts @@ -19,7 +19,7 @@ export const TextEditorNode: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.textEditor, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/textEditor.svg', + avatar: 'core/workflow/template/textConcat', name: '文本拼接', intro: '可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。', version: '486', diff --git a/packages/global/core/workflow/template/system/tools.ts b/packages/global/core/workflow/template/system/tools.ts index c3a043983b9..5ff9f6a4e76 100644 --- a/packages/global/core/workflow/template/system/tools.ts +++ b/packages/global/core/workflow/template/system/tools.ts @@ -26,7 +26,7 @@ export const ToolModule: FlowNodeTemplateType = { templateType: FlowNodeTemplateTypeEnum.ai, sourceHandle: getHandleConfig(true, true, false, true), targetHandle: getHandleConfig(true, true, false, true), - avatar: '/imgs/workflow/tool.svg', + avatar: 'core/workflow/template/toolCall', name: '工具调用', intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。', showStatus: true, diff --git a/packages/global/core/workflow/template/system/variableUpdate/index.tsx b/packages/global/core/workflow/template/system/variableUpdate/index.tsx index 1d7e4936090..1ef323cb264 100644 --- a/packages/global/core/workflow/template/system/variableUpdate/index.tsx +++ b/packages/global/core/workflow/template/system/variableUpdate/index.tsx @@ -13,7 +13,7 @@ export const VariableUpdateNode: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.variableUpdate, sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), - avatar: '/imgs/workflow/variable.png', + avatar: 'core/workflow/template/variableUpdate', name: '变量更新', intro: '可以更新指定节点的输出值或更新全局变量', showStatus: false, diff --git a/packages/global/core/workflow/template/system/workflowStart.ts b/packages/global/core/workflow/template/system/workflowStart.ts index 4eaae7f01f8..d07870a734f 100644 --- a/packages/global/core/workflow/template/system/workflowStart.ts +++ b/packages/global/core/workflow/template/system/workflowStart.ts @@ -14,7 +14,7 @@ export const WorkflowStart: FlowNodeTemplateType = { flowNodeType: FlowNodeTypeEnum.workflowStart, sourceHandle: getHandleConfig(false, true, false, false), targetHandle: getHandleConfig(false, false, false, false), - avatar: '/imgs/workflow/userChatInput.svg', + avatar: 'core/workflow/template/workflowStart', name: '流程开始', intro: '', forbidDelete: true, diff --git a/packages/global/core/workflow/type/index.d.ts b/packages/global/core/workflow/type/index.d.ts index 07031270c11..0ac8a810167 100644 --- a/packages/global/core/workflow/type/index.d.ts +++ b/packages/global/core/workflow/type/index.d.ts @@ -42,17 +42,29 @@ export type WorkflowTemplateType = { workflow: WorkflowTemplateBasicType; }; + // template market export type TemplateMarketItemType = WorkflowTemplateType & { tags?: { id: string; label: string }[]; }; + // system plugin export type SystemPluginTemplateItemType = WorkflowTemplateType & { templateType: FlowNodeTemplateTypeEnum; isTool?: boolean; + // commercial plugin config originCost: number; // n points/one time currentCost: number; + isActive?: boolean; + inputConfig?: { + // Render config input form. Find the corresponding node and replace the variable directly + key: string; + label: string; + description: string; + value?: any; + }[]; + workflow: WorkflowTemplateBasicType; }; diff --git a/packages/global/core/workflow/type/node.d.ts b/packages/global/core/workflow/type/node.d.ts index 745df557ef5..e14255b280e 100644 --- a/packages/global/core/workflow/type/node.d.ts +++ b/packages/global/core/workflow/type/node.d.ts @@ -70,7 +70,7 @@ export type FlowNodeTemplateType = FlowNodeCommonType & { export type NodeTemplateListItemType = { id: string; // 系统节点-系统节点的 id, 系统插件-插件的 id,团队应用的 id flowNodeType: FlowNodeTypeEnum; // render node card - parentId?: string; + parentId?: ParentIdType; isFolder?: boolean; templateType: FlowNodeTemplateTypeEnum; avatar?: string; @@ -79,6 +79,7 @@ export type NodeTemplateListItemType = { isTool?: boolean; author?: string; unique?: boolean; // 唯一的 + currentCost?: number; // 当前积分消耗 }; export type NodeTemplateListType = { diff --git a/packages/plugins/package.json b/packages/plugins/package.json index 03c90737b97..0c232b2e77a 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -2,6 +2,7 @@ "name": "@fastgpt/plugins", "version": "1.0.0", "dependencies": { + "duck-duck-scrape": "^2.2.5", "expr-eval": "^2.0.2" }, "devDependencies": { diff --git a/packages/plugins/register.ts b/packages/plugins/register.ts index bb8f1f74459..c9d4e1c4877 100644 --- a/packages/plugins/register.ts +++ b/packages/plugins/register.ts @@ -1,57 +1,122 @@ import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants'; -import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants'; -import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant'; import { SystemPluginResponseType } from './type'; -import { NodeTemplateListItemType } from '@fastgpt/global/core/workflow/type/node'; -import { isProduction } from '../service/common/system/constants'; +import { FastGPTProUrl, isProduction } from '../service/common/system/constants'; +import { GET, POST } from '@fastgpt/service/common/api/plusRequest'; +import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type'; -let list = ['getTime', 'fetchUrl', 'mathExprVal']; +let list = [ + 'getTime', + 'fetchUrl', + 'mathExprVal', + 'duckduckgo', + 'duckduckgo/search', + 'duckduckgo/searchImg', + 'duckduckgo/searchNews', + 'duckduckgo/searchVideo' +]; +/* Get plugins */ export const getCommunityPlugins = () => { - if (isProduction && global.communitySystemPlugins) return global.communitySystemPlugins; + return list.map((name) => { + const config = require(`./src/${name}/template.json`); - global.communitySystemPlugins = list.map((name) => ({ - ...require(`./src/${name}/template.json`), - id: `${PluginSourceEnum.community}-${name}` - })); + const isFolder = list.find((item) => item.startsWith(`${name}/`)); - return global.communitySystemPlugins; + const parentIdList = name.split('/').slice(0, -1); + const parentId = + parentIdList.length > 0 ? `${PluginSourceEnum.community}-${parentIdList.join('/')}` : null; + + return { + ...config, + id: `${PluginSourceEnum.community}-${name}`, + isFolder, + parentId, + isActive: true + }; + }); +}; +const getCommercialPlugins = () => { + return GET('/core/app/plugin/getSystemPlugins'); }; +export const getSystemPluginTemplates = async () => { + if (isProduction && global.systemPlugins) return global.systemPlugins; + + try { + global.systemPlugins = []; + global.systemPlugins = FastGPTProUrl ? await getCommercialPlugins() : getCommunityPlugins(); -export const getCommunityPluginsTemplateList = () => { - return getCommunityPlugins().map((plugin) => ({ - id: plugin.id, - templateType: plugin.templateType ?? FlowNodeTemplateTypeEnum.other, - flowNodeType: FlowNodeTypeEnum.pluginModule, - avatar: plugin.avatar, - name: plugin.name, - intro: plugin.intro, - isTool: plugin.isTool - })); + return global.systemPlugins; + } catch (error) { + //@ts-ignore + global.systemPlugins = undefined; + return Promise.reject(error); + } }; export const getCommunityCb = async () => { - if (isProduction && global.communitySystemPluginCb) return global.communitySystemPluginCb; - // Do not modify the following code const loadModule = async (name: string) => { const module = await import(`./src/${name}/index`); return module.default; }; - const result = await Promise.all( - list.map(async (name) => ({ - name, - cb: await loadModule(name) - })) + const result = ( + await Promise.all( + list.map(async (name) => { + try { + return { + name, + cb: await loadModule(name) + }; + } catch (error) {} + }) + ) + ).filter(Boolean) as { + name: string; + cb: any; + }[]; + + return result.reduce SystemPluginResponseType>>( + (acc, { name, cb }) => { + acc[name] = cb; + return acc; + }, + {} ); +}; +const getCommercialCb = async () => { + const plugins = await getSystemPluginTemplates(); + const result = plugins.map((plugin) => { + const name = plugin.id.split('-')[1]; + + return { + name, + cb: (e: any) => + POST>('/core/app/plugin/run', { + pluginName: name, + data: e + }) + }; + }); - global.communitySystemPluginCb = result.reduce< - Record SystemPluginResponseType> - >((acc, { name, cb }) => { - acc[name] = cb; - return acc; - }, {}); + return result.reduce SystemPluginResponseType>>( + (acc, { name, cb }) => { + acc[name] = cb; + return acc; + }, + {} + ); +}; +export const getSystemPluginCb = async () => { + if (isProduction && global.systemPluginCb) return global.systemPluginCb; - return global.communitySystemPluginCb; + try { + global.systemPluginCb = {}; + global.systemPluginCb = FastGPTProUrl ? await getCommercialCb() : await getCommunityCb(); + return global.systemPluginCb; + } catch (error) { + //@ts-ignore + global.systemPluginCb = undefined; + return Promise.reject(error); + } }; diff --git a/packages/plugins/src/duckduckgo/search/index.ts b/packages/plugins/src/duckduckgo/search/index.ts new file mode 100644 index 00000000000..0d93404a1bb --- /dev/null +++ b/packages/plugins/src/duckduckgo/search/index.ts @@ -0,0 +1,47 @@ +import { search, SafeSearchType } from 'duck-duck-scrape'; +import { delay } from '@fastgpt/global/common/system/utils'; +import { addLog } from '@fastgpt/service/common/system/log'; + +type Props = { + query: string; +}; + +// Response type same as HTTP outputs +type Response = Promise<{ + result: string; +}>; + +const main = async (props: Props, retry = 3): Response => { + const { query } = props; + try { + const searchResults = await search(query, { + safeSearch: SafeSearchType.STRICT, + time: 'y' + }); + + const result = searchResults.results + .map((item) => ({ + title: item.title, + link: item.url, + snippet: item.description + })) + .slice(0, 10); + + return { + result: JSON.stringify(result) + }; + } catch (error) { + if (retry <= 0) { + return { + result: 'Failed to fetch data' + }; + } + + addLog.warn('DuckDuckGo error', { error }); + + await delay(Math.random() * 2000); + return main(props, retry - 1); + } +}; + +export default main; diff --git a/packages/plugins/src/duckduckgo/search/template.json b/packages/plugins/src/duckduckgo/search/template.json new file mode 100644 index 00000000000..35b283cd7d1 --- /dev/null +++ b/packages/plugins/src/duckduckgo/search/template.json @@ -0,0 +1,260 @@ +{ + "author": "FastGPT", + "version": "486", + "name": "DuckDuckGo 网络搜索", + "avatar": "core/workflow/template/duckduckgo", + "intro": "使用 DuckDuckGo 进行网络搜索", + "showStatus": true, + "weight": 10, + + "isTool": true, + "templateType": "search", + + "workflow": { + "nodes": [ + { + "nodeId": "pluginInput", + "name": "自定义插件输入", + "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", + "avatar": "/imgs/workflow/input.png", + "flowNodeType": "pluginInput", + "showStatus": false, + "position": { + "x": 393.68844551739926, + "y": -58.80666875994541 + }, + "version": "481", + "inputs": [ + { + "renderTypeList": ["reference"], + "selectedTypeIndex": 0, + "valueType": "string", + "canEdit": true, + "key": "query", + "label": "query", + "description": "检索词", + "required": true, + "toolDescription": "检索词" + } + ], + "outputs": [ + { + "id": "query", + "valueType": "string", + "key": "query", + "label": "query", + "type": "hidden" + } + ] + }, + { + "nodeId": "pluginOutput", + "name": "自定义插件输出", + "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", + "avatar": "/imgs/workflow/output.png", + "flowNodeType": "pluginOutput", + "showStatus": false, + "position": { + "x": 1795.6509902691012, + "y": -47.04550785550961 + }, + "version": "481", + "inputs": [ + { + "renderTypeList": ["reference"], + "valueType": "string", + "canEdit": true, + "key": "result", + "label": "result", + "description": " 检索结果", + "value": ["hjnVuJAOwyXV", "lEyy5QqyIBrK"] + } + ], + "outputs": [] + }, + { + "nodeId": "hjnVuJAOwyXV", + "name": "HTTP 请求", + "intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)", + "avatar": "/imgs/workflow/http.png", + "flowNodeType": "httpRequest468", + "showStatus": true, + "position": { + "x": 1054.6774638324207, + "y": -403.06127656499825 + }, + "version": "481", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": ["addInputParam"], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "core.module.input.description.HTTP Dynamic Input", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + } + }, + { + "key": "system_httpMethod", + "renderTypeList": ["custom"], + "valueType": "string", + "label": "", + "value": "POST", + "required": true + }, + { + "key": "system_httpReqUrl", + "renderTypeList": ["hidden"], + "valueType": "string", + "label": "", + "description": "core.module.input.description.Http Request Url", + "placeholder": "https://api.ai.com/getInventory", + "required": false, + "value": "duckduckgo/search" + }, + { + "key": "system_httpHeader", + "renderTypeList": ["custom"], + "valueType": "any", + "value": [], + "label": "", + "description": "core.module.input.description.Http Request Header", + "placeholder": "core.module.input.description.Http Request Header", + "required": false + }, + { + "key": "system_httpParams", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false + }, + { + "key": "system_httpJsonBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": "{\n \"query\": \"{{query}}\"\n}", + "label": "", + "required": false + }, + { + "renderTypeList": ["reference"], + "valueType": "string", + "canEdit": true, + "key": "query", + "label": "query", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + }, + "required": true, + "value": ["pluginInput", "query"] + } + ], + "outputs": [ + { + "id": "system_addOutputParam", + "key": "system_addOutputParam", + "type": "dynamic", + "valueType": "dynamic", + "label": "", + "customFieldConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": false + } + }, + { + "id": "error", + "key": "error", + "label": "请求错误", + "description": "HTTP请求错误信息,成功时返回空", + "valueType": "object", + "type": "static" + }, + { + "id": "httpRawResponse", + "key": "httpRawResponse", + "label": "原始响应", + "required": true, + "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", + "valueType": "any", + "type": "static" + }, + { + "id": "lEyy5QqyIBrK", + "valueType": "string", + "type": "dynamic", + "key": "result", + "label": "result" + } + ] + } + ], + "edges": [ + { + "source": "pluginInput", + "target": "hjnVuJAOwyXV", + "sourceHandle": "pluginInput-source-right", + "targetHandle": "hjnVuJAOwyXV-target-left" + }, + { + "source": "hjnVuJAOwyXV", + "target": "pluginOutput", + "sourceHandle": "hjnVuJAOwyXV-source-right", + "targetHandle": "pluginOutput-target-left" + } + ] + } +} diff --git a/packages/plugins/src/duckduckgo/searchImg/index.ts b/packages/plugins/src/duckduckgo/searchImg/index.ts new file mode 100644 index 00000000000..a49bd3136d5 --- /dev/null +++ b/packages/plugins/src/duckduckgo/searchImg/index.ts @@ -0,0 +1,46 @@ +import { searchImages, SafeSearchType } from 'duck-duck-scrape'; +import { delay } from '@fastgpt/global/common/system/utils'; +import { addLog } from '@fastgpt/service/common/system/log'; + +type Props = { + query: string; +}; + +// Response type same as HTTP outputs +type Response = Promise<{ + result: string; +}>; + +const main = async (props: Props, retry = 3): Response => { + const { query } = props; + + try { + const searchResults = await searchImages(query, { + safeSearch: SafeSearchType.STRICT + }); + + const result = searchResults.results + .map((item) => ({ + title: item.title, + image: item.image + })) + .slice(0, 10); + + return { + result: JSON.stringify(result) + }; + } catch (error) { + if (retry <= 0) { + return { + result: 'Failed to fetch data' + }; + } + + addLog.warn('DuckDuckGo error', { error }); + + await delay(Math.random() * 2000); + return main(props, retry - 1); + } +}; + +export default main; diff --git a/packages/plugins/src/duckduckgo/searchImg/template.json b/packages/plugins/src/duckduckgo/searchImg/template.json new file mode 100644 index 00000000000..28b3e0cc166 --- /dev/null +++ b/packages/plugins/src/duckduckgo/searchImg/template.json @@ -0,0 +1,260 @@ +{ + "author": "FastGPT", + "version": "486", + "name": "DuckDuckGo 图片搜索", + "avatar": "core/workflow/template/duckduckgo", + "intro": "使用 DuckDuckGo 进行图片搜索", + "showStatus": true, + "weight": 10, + + "isTool": true, + "templateType": "search", + + "workflow": { + "nodes": [ + { + "nodeId": "pluginInput", + "name": "自定义插件输入", + "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", + "avatar": "/imgs/workflow/input.png", + "flowNodeType": "pluginInput", + "showStatus": false, + "position": { + "x": 393.68844551739926, + "y": -58.80666875994541 + }, + "version": "481", + "inputs": [ + { + "renderTypeList": ["reference"], + "selectedTypeIndex": 0, + "valueType": "string", + "canEdit": true, + "key": "query", + "label": "query", + "description": "检索词", + "required": true, + "toolDescription": "检索词" + } + ], + "outputs": [ + { + "id": "query", + "valueType": "string", + "key": "query", + "label": "query", + "type": "hidden" + } + ] + }, + { + "nodeId": "pluginOutput", + "name": "自定义插件输出", + "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", + "avatar": "/imgs/workflow/output.png", + "flowNodeType": "pluginOutput", + "showStatus": false, + "position": { + "x": 1795.6509902691012, + "y": -47.04550785550961 + }, + "version": "481", + "inputs": [ + { + "renderTypeList": ["reference"], + "valueType": "string", + "canEdit": true, + "key": "result", + "label": "result", + "description": " 检索结果", + "value": ["hjnVuJAOwyXV", "lEyy5QqyIBrK"] + } + ], + "outputs": [] + }, + { + "nodeId": "hjnVuJAOwyXV", + "name": "HTTP 请求", + "intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)", + "avatar": "/imgs/workflow/http.png", + "flowNodeType": "httpRequest468", + "showStatus": true, + "position": { + "x": 1054.6774638324207, + "y": -403.06127656499825 + }, + "version": "481", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": ["addInputParam"], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "core.module.input.description.HTTP Dynamic Input", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + } + }, + { + "key": "system_httpMethod", + "renderTypeList": ["custom"], + "valueType": "string", + "label": "", + "value": "POST", + "required": true + }, + { + "key": "system_httpReqUrl", + "renderTypeList": ["hidden"], + "valueType": "string", + "label": "", + "description": "core.module.input.description.Http Request Url", + "placeholder": "https://api.ai.com/getInventory", + "required": false, + "value": "duckduckgo/searchImg" + }, + { + "key": "system_httpHeader", + "renderTypeList": ["custom"], + "valueType": "any", + "value": [], + "label": "", + "description": "core.module.input.description.Http Request Header", + "placeholder": "core.module.input.description.Http Request Header", + "required": false + }, + { + "key": "system_httpParams", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false + }, + { + "key": "system_httpJsonBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": "{\n \"query\": \"{{query}}\"\n}", + "label": "", + "required": false + }, + { + "renderTypeList": ["reference"], + "valueType": "string", + "canEdit": true, + "key": "query", + "label": "query", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + }, + "required": true, + "value": ["pluginInput", "query"] + } + ], + "outputs": [ + { + "id": "system_addOutputParam", + "key": "system_addOutputParam", + "type": "dynamic", + "valueType": "dynamic", + "label": "", + "customFieldConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": false + } + }, + { + "id": "error", + "key": "error", + "label": "请求错误", + "description": "HTTP请求错误信息,成功时返回空", + "valueType": "object", + "type": "static" + }, + { + "id": "httpRawResponse", + "key": "httpRawResponse", + "label": "原始响应", + "required": true, + "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", + "valueType": "any", + "type": "static" + }, + { + "id": "lEyy5QqyIBrK", + "valueType": "string", + "type": "dynamic", + "key": "result", + "label": "result" + } + ] + } + ], + "edges": [ + { + "source": "pluginInput", + "target": "hjnVuJAOwyXV", + "sourceHandle": "pluginInput-source-right", + "targetHandle": "hjnVuJAOwyXV-target-left" + }, + { + "source": "hjnVuJAOwyXV", + "target": "pluginOutput", + "sourceHandle": "hjnVuJAOwyXV-source-right", + "targetHandle": "pluginOutput-target-left" + } + ] + } +} diff --git a/packages/plugins/src/duckduckgo/searchNews/index.ts b/packages/plugins/src/duckduckgo/searchNews/index.ts new file mode 100644 index 00000000000..99a2af03007 --- /dev/null +++ b/packages/plugins/src/duckduckgo/searchNews/index.ts @@ -0,0 +1,47 @@ +import { searchNews, SafeSearchType } from 'duck-duck-scrape'; +import { delay } from '@fastgpt/global/common/system/utils'; +import { addLog } from '@fastgpt/service/common/system/log'; + +type Props = { + query: string; +}; + +// Response type same as HTTP outputs +type Response = Promise<{ + result: string; +}>; + +const main = async (props: Props, retry = 3): Response => { + const { query } = props; + + try { + const searchResults = await searchNews(query, { + safeSearch: SafeSearchType.STRICT + }); + + const result = searchResults.results + .map((item) => ({ + title: item.title, + excerpt: item.excerpt, + url: item.url + })) + .slice(0, 10); + + return { + result: JSON.stringify(result) + }; + } catch (error) { + if (retry <= 0) { + return { + result: 'Failed to fetch data' + }; + } + + addLog.warn('DuckDuckGo error', { error }); + + await delay(Math.random() * 2000); + return main(props, retry - 1); + } +}; + +export default main; diff --git a/packages/plugins/src/duckduckgo/searchNews/template.json b/packages/plugins/src/duckduckgo/searchNews/template.json new file mode 100644 index 00000000000..a1b85975905 --- /dev/null +++ b/packages/plugins/src/duckduckgo/searchNews/template.json @@ -0,0 +1,260 @@ +{ + "author": "FastGPT", + "version": "486", + "name": "DuckDuckGo 新闻检索", + "avatar": "core/workflow/template/duckduckgo", + "intro": "使用 DuckDuckGo 进行新闻检索", + "showStatus": true, + "weight": 10, + + "isTool": true, + "templateType": "search", + + "workflow": { + "nodes": [ + { + "nodeId": "pluginInput", + "name": "自定义插件输入", + "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", + "avatar": "/imgs/workflow/input.png", + "flowNodeType": "pluginInput", + "showStatus": false, + "position": { + "x": 393.68844551739926, + "y": -58.80666875994541 + }, + "version": "481", + "inputs": [ + { + "renderTypeList": ["reference"], + "selectedTypeIndex": 0, + "valueType": "string", + "canEdit": true, + "key": "query", + "label": "query", + "description": "检索词", + "required": true, + "toolDescription": "检索词" + } + ], + "outputs": [ + { + "id": "query", + "valueType": "string", + "key": "query", + "label": "query", + "type": "hidden" + } + ] + }, + { + "nodeId": "pluginOutput", + "name": "自定义插件输出", + "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", + "avatar": "/imgs/workflow/output.png", + "flowNodeType": "pluginOutput", + "showStatus": false, + "position": { + "x": 1795.6509902691012, + "y": -47.04550785550961 + }, + "version": "481", + "inputs": [ + { + "renderTypeList": ["reference"], + "valueType": "string", + "canEdit": true, + "key": "result", + "label": "result", + "description": " 检索结果", + "value": ["hjnVuJAOwyXV", "lEyy5QqyIBrK"] + } + ], + "outputs": [] + }, + { + "nodeId": "hjnVuJAOwyXV", + "name": "HTTP 请求", + "intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)", + "avatar": "/imgs/workflow/http.png", + "flowNodeType": "httpRequest468", + "showStatus": true, + "position": { + "x": 1054.6774638324207, + "y": -403.06127656499825 + }, + "version": "481", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": ["addInputParam"], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "core.module.input.description.HTTP Dynamic Input", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + } + }, + { + "key": "system_httpMethod", + "renderTypeList": ["custom"], + "valueType": "string", + "label": "", + "value": "POST", + "required": true + }, + { + "key": "system_httpReqUrl", + "renderTypeList": ["hidden"], + "valueType": "string", + "label": "", + "description": "core.module.input.description.Http Request Url", + "placeholder": "https://api.ai.com/getInventory", + "required": false, + "value": "duckduckgo/searchNews" + }, + { + "key": "system_httpHeader", + "renderTypeList": ["custom"], + "valueType": "any", + "value": [], + "label": "", + "description": "core.module.input.description.Http Request Header", + "placeholder": "core.module.input.description.Http Request Header", + "required": false + }, + { + "key": "system_httpParams", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false + }, + { + "key": "system_httpJsonBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": "{\n \"query\": \"{{query}}\"\n}", + "label": "", + "required": false + }, + { + "renderTypeList": ["reference"], + "valueType": "string", + "canEdit": true, + "key": "query", + "label": "query", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + }, + "required": true, + "value": ["pluginInput", "query"] + } + ], + "outputs": [ + { + "id": "system_addOutputParam", + "key": "system_addOutputParam", + "type": "dynamic", + "valueType": "dynamic", + "label": "", + "customFieldConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": false + } + }, + { + "id": "error", + "key": "error", + "label": "请求错误", + "description": "HTTP请求错误信息,成功时返回空", + "valueType": "object", + "type": "static" + }, + { + "id": "httpRawResponse", + "key": "httpRawResponse", + "label": "原始响应", + "required": true, + "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", + "valueType": "any", + "type": "static" + }, + { + "id": "lEyy5QqyIBrK", + "valueType": "string", + "type": "dynamic", + "key": "result", + "label": "result" + } + ] + } + ], + "edges": [ + { + "source": "pluginInput", + "target": "hjnVuJAOwyXV", + "sourceHandle": "pluginInput-source-right", + "targetHandle": "hjnVuJAOwyXV-target-left" + }, + { + "source": "hjnVuJAOwyXV", + "target": "pluginOutput", + "sourceHandle": "hjnVuJAOwyXV-source-right", + "targetHandle": "pluginOutput-target-left" + } + ] + } +} diff --git a/packages/plugins/src/duckduckgo/searchVideo/index.ts b/packages/plugins/src/duckduckgo/searchVideo/index.ts new file mode 100644 index 00000000000..ba0fe5b9e46 --- /dev/null +++ b/packages/plugins/src/duckduckgo/searchVideo/index.ts @@ -0,0 +1,47 @@ +import { searchVideos, SafeSearchType } from 'duck-duck-scrape'; +import { delay } from '@fastgpt/global/common/system/utils'; +import { addLog } from '@fastgpt/service/common/system/log'; + +type Props = { + query: string; +}; + +// Response type same as HTTP outputs +type Response = Promise<{ + result: string; +}>; + +const main = async (props: Props, retry = 3): Response => { + const { query } = props; + + try { + const searchResults = await searchVideos(query, { + safeSearch: SafeSearchType.STRICT + }); + + const result = searchResults.results + .map((item) => ({ + title: item.title, + description: item.description, + url: item.url + })) + .slice(0, 10); + + return { + result: JSON.stringify(result) + }; + } catch (error) { + if (retry <= 0) { + return { + result: 'Failed to fetch data' + }; + } + + addLog.warn('DuckDuckGo error', { error }); + + await delay(Math.random() * 2000); + return main(props, retry - 1); + } +}; + +export default main; diff --git a/packages/plugins/src/duckduckgo/searchVideo/template.json b/packages/plugins/src/duckduckgo/searchVideo/template.json new file mode 100644 index 00000000000..9ab2181e36a --- /dev/null +++ b/packages/plugins/src/duckduckgo/searchVideo/template.json @@ -0,0 +1,260 @@ +{ + "author": "FastGPT", + "version": "486", + "name": "DuckDuckGo 视频搜索", + "avatar": "core/workflow/template/duckduckgo", + "intro": "使用 DuckDuckGo 进行视频搜索", + "showStatus": true, + "weight": 10, + + "isTool": true, + "templateType": "search", + + "workflow": { + "nodes": [ + { + "nodeId": "pluginInput", + "name": "自定义插件输入", + "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", + "avatar": "/imgs/workflow/input.png", + "flowNodeType": "pluginInput", + "showStatus": false, + "position": { + "x": 393.68844551739926, + "y": -58.80666875994541 + }, + "version": "481", + "inputs": [ + { + "renderTypeList": ["reference"], + "selectedTypeIndex": 0, + "valueType": "string", + "canEdit": true, + "key": "query", + "label": "query", + "description": "检索词", + "required": true, + "toolDescription": "检索词" + } + ], + "outputs": [ + { + "id": "query", + "valueType": "string", + "key": "query", + "label": "query", + "type": "hidden" + } + ] + }, + { + "nodeId": "pluginOutput", + "name": "自定义插件输出", + "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", + "avatar": "/imgs/workflow/output.png", + "flowNodeType": "pluginOutput", + "showStatus": false, + "position": { + "x": 1795.6509902691012, + "y": -47.04550785550961 + }, + "version": "481", + "inputs": [ + { + "renderTypeList": ["reference"], + "valueType": "string", + "canEdit": true, + "key": "result", + "label": "result", + "description": " 检索结果", + "value": ["hjnVuJAOwyXV", "lEyy5QqyIBrK"] + } + ], + "outputs": [] + }, + { + "nodeId": "hjnVuJAOwyXV", + "name": "HTTP 请求", + "intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)", + "avatar": "/imgs/workflow/http.png", + "flowNodeType": "httpRequest468", + "showStatus": true, + "position": { + "x": 1054.6774638324207, + "y": -403.06127656499825 + }, + "version": "481", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": ["addInputParam"], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "core.module.input.description.HTTP Dynamic Input", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + } + }, + { + "key": "system_httpMethod", + "renderTypeList": ["custom"], + "valueType": "string", + "label": "", + "value": "POST", + "required": true + }, + { + "key": "system_httpReqUrl", + "renderTypeList": ["hidden"], + "valueType": "string", + "label": "", + "description": "core.module.input.description.Http Request Url", + "placeholder": "https://api.ai.com/getInventory", + "required": false, + "value": "duckduckgo/searchVideo" + }, + { + "key": "system_httpHeader", + "renderTypeList": ["custom"], + "valueType": "any", + "value": [], + "label": "", + "description": "core.module.input.description.Http Request Header", + "placeholder": "core.module.input.description.Http Request Header", + "required": false + }, + { + "key": "system_httpParams", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false + }, + { + "key": "system_httpJsonBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": "{\n \"query\": \"{{query}}\"\n}", + "label": "", + "required": false + }, + { + "renderTypeList": ["reference"], + "valueType": "string", + "canEdit": true, + "key": "query", + "label": "query", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + }, + "required": true, + "value": ["pluginInput", "query"] + } + ], + "outputs": [ + { + "id": "system_addOutputParam", + "key": "system_addOutputParam", + "type": "dynamic", + "valueType": "dynamic", + "label": "", + "customFieldConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": false + } + }, + { + "id": "error", + "key": "error", + "label": "请求错误", + "description": "HTTP请求错误信息,成功时返回空", + "valueType": "object", + "type": "static" + }, + { + "id": "httpRawResponse", + "key": "httpRawResponse", + "label": "原始响应", + "required": true, + "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", + "valueType": "any", + "type": "static" + }, + { + "id": "lEyy5QqyIBrK", + "valueType": "string", + "type": "dynamic", + "key": "result", + "label": "result" + } + ] + } + ], + "edges": [ + { + "source": "pluginInput", + "target": "hjnVuJAOwyXV", + "sourceHandle": "pluginInput-source-right", + "targetHandle": "hjnVuJAOwyXV-target-left" + }, + { + "source": "hjnVuJAOwyXV", + "target": "pluginOutput", + "sourceHandle": "hjnVuJAOwyXV-source-right", + "targetHandle": "pluginOutput-target-left" + } + ] + } +} diff --git a/packages/plugins/src/duckduckgo/template.json b/packages/plugins/src/duckduckgo/template.json new file mode 100644 index 00000000000..0e70509a0d9 --- /dev/null +++ b/packages/plugins/src/duckduckgo/template.json @@ -0,0 +1,17 @@ +{ + "author": "FastGPT", + "version": "486", + "name": "DuckDuckGo服务", + "avatar": "core/workflow/template/duckduckgo", + "intro": "DuckDuckGo 服务", + "showStatus": false, + "weight": 10, + + "isTool": true, + "templateType": "tools", + + "workflow": { + "nodes": [], + "edges": [] + } +} diff --git a/packages/plugins/src/fetchUrl/template.json b/packages/plugins/src/fetchUrl/template.json index 324bcc74542..5f8b359c1bf 100644 --- a/packages/plugins/src/fetchUrl/template.json +++ b/packages/plugins/src/fetchUrl/template.json @@ -2,7 +2,7 @@ "author": "FastGPT", "version": "486", "name": "网页内容抓取", - "avatar": "/imgs/workflow/fetchUrl.svg", + "avatar": "core/workflow/template/fetchUrl", "intro": "可获取一个网页链接内容,并以 Markdown 格式输出,仅支持获取静态网站。", "showStatus": true, "weight": 10, diff --git a/packages/plugins/src/getTime/template.json b/packages/plugins/src/getTime/template.json index 51352918eb3..6f87f66f9cf 100644 --- a/packages/plugins/src/getTime/template.json +++ b/packages/plugins/src/getTime/template.json @@ -1,9 +1,9 @@ { - "author": "FastGPT Team", + "author": "FastGPT", "version": "481", "templateType": "tools", "name": "获取当前时间", - "avatar": "/imgs/workflow/getCurrentTime.svg", + "avatar": "core/workflow/template/getTime", "intro": "获取用户当前时区的时间。", "showStatus": false, "isTool": true, diff --git a/packages/plugins/src/mathExprVal/template.json b/packages/plugins/src/mathExprVal/template.json index 846261ce84e..5cc829301a4 100644 --- a/packages/plugins/src/mathExprVal/template.json +++ b/packages/plugins/src/mathExprVal/template.json @@ -2,7 +2,7 @@ "author": "FastGPT", "version": "486", "name": "数学公式执行", - "avatar": "/imgs/workflow/mathExprEval.svg", + "avatar": "core/workflow/template/mathCall", "intro": "用于执行数学表达式的工具,通过 js 的 expr-eval 库运行表达式并返回结果。", "showStatus": false, "weight": 10, diff --git a/packages/plugins/type.d.ts b/packages/plugins/type.d.ts index 28252f5281a..271e8e1ca0a 100644 --- a/packages/plugins/type.d.ts +++ b/packages/plugins/type.d.ts @@ -1,7 +1,9 @@ +import { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d'; import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type'; + export type SystemPluginResponseType = Promise>; declare global { - var communitySystemPlugins: SystemPluginTemplateItemType[]; - var communitySystemPluginCb: Record SystemPluginResponseType>; + var systemPlugins: SystemPluginTemplateItemType[]; + var systemPluginCb: Record SystemPluginResponseType>; } diff --git a/packages/service/core/app/plugin/controller.ts b/packages/service/core/app/plugin/controller.ts index 1536388fafc..ea69a878671 100644 --- a/packages/service/core/app/plugin/controller.ts +++ b/packages/service/core/app/plugin/controller.ts @@ -9,7 +9,7 @@ import { getNanoid } from '@fastgpt/global/common/string/tools'; import { cloneDeep } from 'lodash'; import { MongoApp } from '../schema'; import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type'; -import { getCommunityPlugins } from '@fastgpt/plugins/register'; +import { getSystemPluginTemplates } from '@fastgpt/plugins/register'; /* plugin id rule: @@ -28,7 +28,7 @@ export async function splitCombinePluginId(id: string) { }; } - const [source, pluginId] = id.split('-') as [`${PluginSourceEnum}`, string]; + const [source, pluginId] = id.split('-') as [PluginSourceEnum, string]; if (!source || !pluginId) return Promise.reject('pluginId not found'); return { source, pluginId: id }; @@ -39,14 +39,6 @@ const getPluginTemplateById = async ( ): Promise => { const { source, pluginId } = await splitCombinePluginId(id); - if (source === PluginSourceEnum.community) { - const item = [...global.communityPlugins, ...getCommunityPlugins()].find( - (plugin) => plugin.id === pluginId - ); - if (!item) return Promise.reject('plugin not found'); - - return cloneDeep(item); - } if (source === PluginSourceEnum.personal) { const item = await MongoApp.findById(id).lean(); if (!item) return Promise.reject('plugin not found'); @@ -68,8 +60,14 @@ const getPluginTemplateById = async ( originCost: 0, currentCost: 0 }; + } else { + const item = [...global.communityPlugins, ...(await getSystemPluginTemplates())].find( + (plugin) => plugin.id === pluginId + ); + if (!item) return Promise.reject('plugin not found'); + + return cloneDeep(item); } - return Promise.reject('plugin not found'); }; /* format plugin modules to plugin preview module */ @@ -98,10 +96,12 @@ export async function getPluginRuntimeById(id: string): Promise { + const { source } = await splitCombinePluginId(plugin.id); + + if (source === PluginSourceEnum.commercial) { + return plugin.currentCost ?? 0; + } + + return childrenUsage.reduce((sum, item) => sum + (item.totalPoints || 0), 0); +}; diff --git a/packages/service/core/workflow/dispatch/chat/oneapi.ts b/packages/service/core/workflow/dispatch/chat/oneapi.ts index 20737ecd1b2..299f7683a8f 100644 --- a/packages/service/core/workflow/dispatch/chat/oneapi.ts +++ b/packages/service/core/workflow/dispatch/chat/oneapi.ts @@ -161,70 +161,86 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise { - if (res && stream) { - // sse response - const { answer } = await streamResponse({ - res, - detail, - stream: response, - requestBody - }); - - return { - answerText: answer - }; - } else { - const unStreamResponse = response as ChatCompletion; - const answer = unStreamResponse.choices?.[0]?.message?.content || ''; - - return { - answerText: answer - }; - } - })(); + try { + const response = await ai.chat.completions.create(requestBody, { + headers: { + Accept: 'application/json, text/plain, */*' + } + }); - const completeMessages = filterMessages.concat({ - role: ChatCompletionRequestMessageRoleEnum.Assistant, - content: answerText - }); - const chatCompleteMessages = GPTMessages2Chats(completeMessages); + const { answerText } = await (async () => { + if (res && stream) { + // sse response + const { answer } = await streamResponse({ + res, + detail, + stream: response + }); + + if (!answer) { + throw new Error('LLM model response empty'); + } + + return { + answerText: answer + }; + } else { + const unStreamResponse = response as ChatCompletion; + const answer = unStreamResponse.choices?.[0]?.message?.content || ''; + + return { + answerText: answer + }; + } + })(); - const tokens = await countMessagesTokens(chatCompleteMessages); - const { totalPoints, modelName } = formatModelChars2Points({ - model, - tokens, - modelType: ModelTypeEnum.llm - }); + const completeMessages = filterMessages.concat({ + role: ChatCompletionRequestMessageRoleEnum.Assistant, + content: answerText + }); + const chatCompleteMessages = GPTMessages2Chats(completeMessages); - return { - answerText, - [DispatchNodeResponseKeyEnum.nodeResponse]: { - totalPoints: user.openaiAccount?.key ? 0 : totalPoints, - model: modelName, + const tokens = await countMessagesTokens(chatCompleteMessages); + const { totalPoints, modelName } = formatModelChars2Points({ + model, tokens, - query: `${userChatInput}`, - maxToken: max_tokens, - historyPreview: getHistoryPreview(chatCompleteMessages), - contextTotalLen: completeMessages.length - }, - [DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [ - { - moduleName: name, + modelType: ModelTypeEnum.llm + }); + + return { + answerText, + [DispatchNodeResponseKeyEnum.nodeResponse]: { totalPoints: user.openaiAccount?.key ? 0 : totalPoints, model: modelName, - tokens - } - ], - [DispatchNodeResponseKeyEnum.toolResponses]: answerText, - history: chatCompleteMessages - }; + tokens, + query: `${userChatInput}`, + maxToken: max_tokens, + historyPreview: getHistoryPreview(chatCompleteMessages), + contextTotalLen: completeMessages.length + }, + [DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [ + { + moduleName: name, + totalPoints: user.openaiAccount?.key ? 0 : totalPoints, + model: modelName, + tokens + } + ], + [DispatchNodeResponseKeyEnum.toolResponses]: answerText, + history: chatCompleteMessages + }; + } catch (error) { + addLog.warn(`LLM response error`, { + baseUrl: user.openaiAccount?.baseUrl, + requestBody + }); + + if (user.openaiAccount?.baseUrl) { + return Promise.reject(`您的 OpenAI key 出错了: ${JSON.stringify(requestBody)}`); + } + + return Promise.reject(error); + } }; async function filterQuote({ @@ -334,13 +350,11 @@ async function getMaxTokens({ async function streamResponse({ res, detail, - stream, - requestBody + stream }: { res: NextApiResponse; detail: boolean; stream: StreamChatType; - requestBody: Record; }) { const write = responseWriteController({ res, @@ -364,10 +378,5 @@ async function streamResponse({ }); } - if (!answer) { - addLog.info(`LLM model response empty`, requestBody); - return Promise.reject('core.chat.Chat API is error or undefined'); - } - return { answer }; } diff --git a/packages/service/core/workflow/dispatch/plugin/run.ts b/packages/service/core/workflow/dispatch/plugin/run.ts index 416a2a35613..c88406af257 100644 --- a/packages/service/core/workflow/dispatch/plugin/run.ts +++ b/packages/service/core/workflow/dispatch/plugin/run.ts @@ -2,7 +2,7 @@ import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/ import { dispatchWorkFlow } from '../index'; import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant'; import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants'; -import { getPluginRuntimeById, splitCombinePluginId } from '../../../app/plugin/controller'; +import { getPluginRuntimeById } from '../../../app/plugin/controller'; import { getDefaultEntryNodeIds, initWorkflowEdgeStatus, @@ -10,9 +10,9 @@ import { } from '@fastgpt/global/core/workflow/runtime/utils'; import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type'; import { updateToolInputValue } from '../agent/runTool/utils'; -import { authAppByTmbId } from '../../../../support/permission/app/auth'; +import { authPluginByTmbId } from '../../../../support/permission/app/auth'; import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant'; -import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants'; +import { computedPluginUsage } from '../../../app/plugin/utils'; type RunPluginProps = ModuleDispatchProps<{ [key: string]: any; @@ -33,14 +33,12 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise sum + (item.totalPoints || 0), 0), + totalPoints: usagePoints, pluginOutput: output?.pluginOutput, pluginDetail: mode === 'test' && plugin.teamId === teamId @@ -96,8 +96,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise sum + (item.totalPoints || 0), 0), - model: plugin.name, + totalPoints: usagePoints, tokens: 0 } ], diff --git a/packages/service/core/workflow/dispatch/tools/http468.ts b/packages/service/core/workflow/dispatch/tools/http468.ts index d2ff91d66f0..534d2dffd9f 100644 --- a/packages/service/core/workflow/dispatch/tools/http468.ts +++ b/packages/service/core/workflow/dispatch/tools/http468.ts @@ -16,7 +16,7 @@ import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/ty import { getErrText } from '@fastgpt/global/common/error/utils'; import { responseWrite } from '../../../../common/response'; import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils'; -import { getCommunityCb } from '@fastgpt/plugins/register'; +import { getSystemPluginCb } from '@fastgpt/plugins/register'; type PropsArrType = { key: string; @@ -121,7 +121,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise { - const communityPluginCb = await getCommunityCb(); + const communityPluginCb = await getSystemPluginCb(); if (communityPluginCb[httpReqUrl]) { const pluginResult = await communityPluginCb[httpReqUrl](requestBody); return { diff --git a/packages/service/support/permission/app/auth.ts b/packages/service/support/permission/app/auth.ts index bc0c4d38494..4a08c16005b 100644 --- a/packages/service/support/permission/app/auth.ts +++ b/packages/service/support/permission/app/auth.ts @@ -12,6 +12,27 @@ import { AuthResponseType } from '../type/auth.d'; import { PermissionValueType } from '@fastgpt/global/support/permission/type'; import { AppFolderTypeList } from '@fastgpt/global/core/app/constants'; import { ParentIdType } from '@fastgpt/global/common/parentFolder/type'; +import { splitCombinePluginId } from '../../../core/app/plugin/controller'; +import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants'; + +export const authPluginByTmbId = async ({ + tmbId, + appId, + per +}: { + tmbId: string; + appId: string; + per: PermissionValueType; +}) => { + const { source } = await splitCombinePluginId(appId); + if (source === PluginSourceEnum.personal) { + await authAppByTmbId({ + appId, + tmbId, + per + }); + } +}; export const authAppByTmbId = async ({ tmbId, diff --git a/projects/app/src/components/Avatar/index.tsx b/packages/web/components/common/Avatar/index.tsx similarity index 68% rename from projects/app/src/components/Avatar/index.tsx rename to packages/web/components/common/Avatar/index.tsx index a5d96e26f2b..4546d6d6a89 100644 --- a/projects/app/src/components/Avatar/index.tsx +++ b/packages/web/components/common/Avatar/index.tsx @@ -2,9 +2,16 @@ import React from 'react'; import { Image } from '@chakra-ui/react'; import type { ImageProps } from '@chakra-ui/react'; import { LOGO_ICON } from '@fastgpt/global/common/system/constants'; +import MyIcon from '../Icon'; +import { iconPaths } from '../Icon/constants'; const Avatar = ({ w = '30px', src, ...props }: ImageProps) => { - return ( + // @ts-ignore + const isIcon = !!iconPaths[src as any]; + + return isIcon ? ( + + ) : ( import('./icons/core/workflow/runSkip.svg'), 'core/workflow/runSuccess': () => import('./icons/core/workflow/runSuccess.svg'), 'core/workflow/running': () => import('./icons/core/workflow/running.svg'), + 'core/workflow/template/FileRead': () => import('./icons/core/workflow/template/FileRead.svg'), + 'core/workflow/template/aiChat': () => import('./icons/core/workflow/template/aiChat.svg'), + 'core/workflow/template/codeRun': () => import('./icons/core/workflow/template/codeRun.svg'), + 'core/workflow/template/customFeedback': () => + import('./icons/core/workflow/template/customFeedback.svg'), + 'core/workflow/template/datasetConcat': () => + import('./icons/core/workflow/template/datasetConcat.svg'), + 'core/workflow/template/datasetSearch': () => + import('./icons/core/workflow/template/datasetSearch.svg'), + 'core/workflow/template/duckduckgo': () => + import('./icons/core/workflow/template/duckduckgo.svg'), + 'core/workflow/template/extractJson': () => + import('./icons/core/workflow/template/extractJson.svg'), + 'core/workflow/template/fetchUrl': () => import('./icons/core/workflow/template/fetchUrl.svg'), + 'core/workflow/template/getTime': () => import('./icons/core/workflow/template/getTime.svg'), + 'core/workflow/template/httpRequest': () => + import('./icons/core/workflow/template/httpRequest.svg'), + 'core/workflow/template/ifelse': () => import('./icons/core/workflow/template/ifelse.svg'), + 'core/workflow/template/lafDispatch': () => + import('./icons/core/workflow/template/lafDispatch.svg'), + 'core/workflow/template/mathCall': () => import('./icons/core/workflow/template/mathCall.svg'), + 'core/workflow/template/pluginOutput': () => + import('./icons/core/workflow/template/pluginOutput.svg'), + 'core/workflow/template/queryExtension': () => + import('./icons/core/workflow/template/queryExtension.svg'), + 'core/workflow/template/questionClassify': () => + import('./icons/core/workflow/template/questionClassify.svg'), + 'core/workflow/template/reply': () => import('./icons/core/workflow/template/reply.svg'), + 'core/workflow/template/runApp': () => import('./icons/core/workflow/template/runApp.svg'), + 'core/workflow/template/stopTool': () => import('./icons/core/workflow/template/stopTool.svg'), + 'core/workflow/template/systemConfig': () => + import('./icons/core/workflow/template/systemConfig.svg'), + 'core/workflow/template/textConcat': () => + import('./icons/core/workflow/template/textConcat.svg'), + 'core/workflow/template/toolCall': () => import('./icons/core/workflow/template/toolCall.svg'), + 'core/workflow/template/variableUpdate': () => + import('./icons/core/workflow/template/variableUpdate.svg'), + 'core/workflow/template/workflowStart': () => + import('./icons/core/workflow/template/workflowStart.svg'), 'core/workflow/versionHistories': () => import('./icons/core/workflow/versionHistories.svg'), date: () => import('./icons/date.svg'), delete: () => import('./icons/delete.svg'), @@ -206,6 +245,7 @@ export const iconPaths = { 'phoneTabbar/me': () => import('./icons/phoneTabbar/me.svg'), 'phoneTabbar/tool': () => import('./icons/phoneTabbar/tool.svg'), 'phoneTabbar/toolFill': () => import('./icons/phoneTabbar/toolFill.svg'), + 'plugins/textEditor': () => import('./icons/plugins/textEditor.svg'), 'price/bg': () => import('./icons/price/bg.svg'), 'price/right': () => import('./icons/price/right.svg'), save: () => import('./icons/save.svg'), diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/FileRead.svg b/packages/web/components/common/Icon/icons/core/workflow/template/FileRead.svg new file mode 100644 index 00000000000..966b1aa54cb --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/FileRead.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/aiChat.svg b/packages/web/components/common/Icon/icons/core/workflow/template/aiChat.svg new file mode 100644 index 00000000000..c852f45d7fc --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/aiChat.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/codeRun.svg b/packages/web/components/common/Icon/icons/core/workflow/template/codeRun.svg new file mode 100644 index 00000000000..b6e9779bc6d --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/codeRun.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/customFeedback.svg b/packages/web/components/common/Icon/icons/core/workflow/template/customFeedback.svg new file mode 100644 index 00000000000..517b88e19f9 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/customFeedback.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/datasetConcat.svg b/packages/web/components/common/Icon/icons/core/workflow/template/datasetConcat.svg new file mode 100644 index 00000000000..680d1e2cb3e --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/datasetConcat.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/datasetSearch.svg b/packages/web/components/common/Icon/icons/core/workflow/template/datasetSearch.svg new file mode 100644 index 00000000000..7127308b473 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/datasetSearch.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/duckduckgo.svg b/packages/web/components/common/Icon/icons/core/workflow/template/duckduckgo.svg new file mode 100644 index 00000000000..3ab30101c21 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/duckduckgo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/extractJson.svg b/packages/web/components/common/Icon/icons/core/workflow/template/extractJson.svg new file mode 100644 index 00000000000..63426bbe8e8 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/extractJson.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/fetchUrl.svg b/packages/web/components/common/Icon/icons/core/workflow/template/fetchUrl.svg new file mode 100644 index 00000000000..d91c05df081 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/fetchUrl.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/getTime.svg b/packages/web/components/common/Icon/icons/core/workflow/template/getTime.svg new file mode 100644 index 00000000000..3a70e9f49a8 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/getTime.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/httpRequest.svg b/packages/web/components/common/Icon/icons/core/workflow/template/httpRequest.svg new file mode 100644 index 00000000000..ac7b79fd872 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/httpRequest.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/ifelse.svg b/packages/web/components/common/Icon/icons/core/workflow/template/ifelse.svg new file mode 100644 index 00000000000..f6a8dae00ca --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/ifelse.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/lafDispatch.svg b/packages/web/components/common/Icon/icons/core/workflow/template/lafDispatch.svg new file mode 100644 index 00000000000..89a94778e05 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/lafDispatch.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/mathCall.svg b/packages/web/components/common/Icon/icons/core/workflow/template/mathCall.svg new file mode 100644 index 00000000000..e389218b4c1 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/mathCall.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/pluginOutput.svg b/packages/web/components/common/Icon/icons/core/workflow/template/pluginOutput.svg new file mode 100644 index 00000000000..a5b9ca0b7b5 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/pluginOutput.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/queryExtension.svg b/packages/web/components/common/Icon/icons/core/workflow/template/queryExtension.svg new file mode 100644 index 00000000000..691161c3b12 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/queryExtension.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/questionClassify.svg b/packages/web/components/common/Icon/icons/core/workflow/template/questionClassify.svg new file mode 100644 index 00000000000..7e817735b19 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/questionClassify.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/reply.svg b/packages/web/components/common/Icon/icons/core/workflow/template/reply.svg new file mode 100644 index 00000000000..142bc9f5108 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/reply.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/runApp.svg b/packages/web/components/common/Icon/icons/core/workflow/template/runApp.svg new file mode 100644 index 00000000000..1f3b1ad5e41 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/runApp.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/stopTool.svg b/packages/web/components/common/Icon/icons/core/workflow/template/stopTool.svg new file mode 100644 index 00000000000..216381e4350 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/stopTool.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/systemConfig.svg b/packages/web/components/common/Icon/icons/core/workflow/template/systemConfig.svg new file mode 100644 index 00000000000..b1f010d9f59 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/systemConfig.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/textConcat.svg b/packages/web/components/common/Icon/icons/core/workflow/template/textConcat.svg new file mode 100644 index 00000000000..3b44b470d78 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/textConcat.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/toolCall.svg b/packages/web/components/common/Icon/icons/core/workflow/template/toolCall.svg new file mode 100644 index 00000000000..575bb2b5de9 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/toolCall.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/variableUpdate.svg b/packages/web/components/common/Icon/icons/core/workflow/template/variableUpdate.svg new file mode 100644 index 00000000000..9fed569cfe7 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/variableUpdate.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/core/workflow/template/workflowStart.svg b/packages/web/components/common/Icon/icons/core/workflow/template/workflowStart.svg new file mode 100644 index 00000000000..4cd6718fe84 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/workflow/template/workflowStart.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/plugins/textEditor.svg b/packages/web/components/common/Icon/icons/plugins/textEditor.svg new file mode 100644 index 00000000000..bee20bf70ef --- /dev/null +++ b/packages/web/components/common/Icon/icons/plugins/textEditor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/web/components/common/MyModal/index.tsx b/packages/web/components/common/MyModal/index.tsx index 3f707575ba7..b38b440148e 100644 --- a/packages/web/components/common/MyModal/index.tsx +++ b/packages/web/components/common/MyModal/index.tsx @@ -12,6 +12,7 @@ import { import MyIcon from '../Icon'; import MyBox from '../MyBox'; import { useSystem } from '../../../hooks/useSystem'; +import Avatar from '../Avatar'; export interface MyModalProps extends ModalContentProps { iconSrc?: string; @@ -68,14 +69,18 @@ const MyModal = ({ > {iconSrc && ( <> - {iconSrc.startsWith('/') ? ( - - ) : ( - - )} + )} - {title} + + {title} + {onClose && ( diff --git a/packages/web/components/common/Tabs/LightRowTabs.tsx b/packages/web/components/common/Tabs/LightRowTabs.tsx index 110dc128e7a..069d290dc67 100644 --- a/packages/web/components/common/Tabs/LightRowTabs.tsx +++ b/packages/web/components/common/Tabs/LightRowTabs.tsx @@ -2,7 +2,7 @@ import React, { useMemo } from 'react'; import { Box, Flex, Grid, Image } from '@chakra-ui/react'; import type { FlexProps, GridProps } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; -import MyIcon from '../Icon'; +import Avatar from '../Avatar'; type Props = Omit & { list: { icon?: string; label: string | React.ReactNode; value: ValueType }[]; @@ -81,14 +81,10 @@ const LightRowTabs = ({ > {item.icon && ( <> - {item.icon.startsWith('/') ? ( - {''} - ) : ( - - )} + )} - {typeof item.label === 'string' ? t(item.label as any) : item.label} + {typeof item.label === 'string' ? t(item.label as any) : item.label} ))} diff --git a/packages/web/core/workflow/constants.ts b/packages/web/core/workflow/constants.ts index bfebc1c9bfd..6124f1e2742 100644 --- a/packages/web/core/workflow/constants.ts +++ b/packages/web/core/workflow/constants.ts @@ -18,6 +18,16 @@ export const workflowNodeTemplateList = (t: TFunction): NodeTemplateListType => label: t('common:core.module.template.Tool module'), list: [] }, + { + type: FlowNodeTemplateTypeEnum.search, + label: t('core.workflow.template.Search'), + list: [] + }, + { + type: FlowNodeTemplateTypeEnum.multimodal, + label: t('core.workflow.template.Multimodal'), + list: [] + }, { type: FlowNodeTemplateTypeEnum.other, label: t('common:common.Other'), diff --git a/packages/web/i18n/en/app.json b/packages/web/i18n/en/app.json index e8993ccbdb7..b17c41ec84f 100644 --- a/packages/web/i18n/en/app.json +++ b/packages/web/i18n/en/app.json @@ -40,6 +40,7 @@ "My Apps": "My Apps", "Output Field Settings": "Output Field Settings", "Paste Config": "Paste Config", + "Plugin cost per times": "{{cost}}/per time", "Plugin dispatch": "Plugins", "Plugin dispatch tip": "It is up to the model to decide which plug-ins to add additional capabilities to. If the plug-in is selected, the knowledge base call is also treated as a special plug-in.", "Publish channel": "Publish channel", @@ -60,6 +61,9 @@ "has new version": "has new version" } }, + "common": { + "Plugin cost per times": "{{cost}} points/times" + }, "module": { "Combine Modules": "Combine Modules", "Confirm Sync": "The template will be updated to the latest template configuration. Fields that do not exist in the template will be deleted (including all custom fields). You are advised to make a copy of the node and then update the original node version.", diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index 3b14a9bd658..29d02e54044 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -1046,9 +1046,11 @@ "plugin": { "Custom headers": "Custom headers", "Delete http plugin": "Confirm to delete this group of HTTP plugins? This will delete all plugins in the directory.", + "Free": "The plugin requires no points~", "Get Plugin Module Detail Failed": "Plugin loading failed", "Http plugin intro placeholder": "For display only, no actual effect", - "Intro placeholder": "If this plugin is used as a tool, this introduction will be used as a prompt." + "Intro placeholder": "If this plugin is used as a tool, this introduction will be used as a prompt.", + "cost": "Plugin cost: " }, "shareChat": { "Init Error": "Failed to initialize chat dialog", @@ -1117,6 +1119,10 @@ "OnRevert version confirm": "Confirm to revert to this version? It will save the configuration of the version being edited and create a new published version for the reverted version.", "histories": "Publishing records" }, + "template": { + "Multimodal": "Multimodal", + "Search": "Search" + }, "tool": { "Handle": "Tool connector", "Select Tool": "Select tool" diff --git a/packages/web/i18n/zh/app.json b/packages/web/i18n/zh/app.json index d4832be8559..09f00921990 100644 --- a/packages/web/i18n/zh/app.json +++ b/packages/web/i18n/zh/app.json @@ -39,6 +39,7 @@ "My Apps": "我的应用", "Output Field Settings": "输出字段编辑", "Paste Config": "粘贴配置", + "Plugin cost per times": "{{cost}}/次", "Plugin dispatch": "插件调用", "Plugin dispatch tip": "给模型附加额外的能力,具体调用哪些插件,将由模型自主决定。\n若选择了插件,知识库调用将自动作为一个特殊的插件。", "Publish channel": "发布渠道", @@ -59,6 +60,9 @@ "has new version": "有新版本" } }, + "common": { + "Plugin cost per times": "{{cost}}积分/次" + }, "module": { "Combine Modules": "组合模块", "Confirm Sync": "将会更新至最新的模板配置,不存在模板中的字段将会被删除(包括所有自定义字段),建议您先复制一份节点,再更新原来节点的版本。", diff --git a/packages/web/i18n/zh/common.json b/packages/web/i18n/zh/common.json index c7d1e84ea26..7e0cf82a8a5 100644 --- a/packages/web/i18n/zh/common.json +++ b/packages/web/i18n/zh/common.json @@ -1055,9 +1055,11 @@ "plugin": { "Custom headers": "自定义请求头", "Delete http plugin": "确认删除该组 HTTP 插件?会删除该目录下所有插件。", + "Free": "该插件无需积分消耗~", "Get Plugin Module Detail Failed": "加载插件异常", "Http plugin intro placeholder": "仅做展示,无实际效果", - "Intro placeholder": "如果该插件作为工具被调用,则会使用该介绍作为提示词。" + "Intro placeholder": "如果该插件作为工具被调用,则会使用该介绍作为提示词。", + "cost": "积分消耗:" }, "shareChat": { "Init Error": "初始化对话框失败", @@ -1126,6 +1128,10 @@ "OnRevert version confirm": "确认回退至该版本?会为您保存编辑中版本的配置,并为回退版本创建一个新的发布版本。", "histories": "发布记录" }, + "template": { + "Multimodal": "多模态", + "Search": "搜索" + }, "tool": { "Handle": "工具连接器", "Select Tool": "选择工具" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 817c589b76a..4104fb11a35 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,6 +81,9 @@ importers: packages/plugins: dependencies: + duck-duck-scrape: + specifier: ^2.2.5 + version: 2.2.5 expr-eval: specifier: ^2.0.2 version: 2.0.2 @@ -4692,6 +4695,9 @@ packages: domutils@3.1.0: resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + duck-duck-scrape@2.2.5: + resolution: {integrity: sha512-RTu/Ag5LhgD/j1l2zVGCwTINBoEYCffl58nMoBjtXWJG8tTex72h3gxpDjAr8jVqFaBvhgASNKTUsE31JeqYgw==} + duck@0.1.12: resolution: {integrity: sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==} @@ -5425,6 +5431,9 @@ packages: hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + html-entities@2.5.2: + resolution: {integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -6642,6 +6651,11 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + needle@3.3.1: + resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} + engines: {node: '>= 4.4.x'} + hasBin: true + negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -7579,6 +7593,9 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + sax@1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} @@ -13553,6 +13570,11 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 + duck-duck-scrape@2.2.5: + dependencies: + html-entities: 2.5.2 + needle: 3.3.1 + duck@0.1.12: dependencies: underscore: 1.13.6 @@ -14603,6 +14625,8 @@ snapshots: dependencies: react-is: 16.13.1 + html-entities@2.5.2: {} + html-escaper@2.0.2: {} html-parse-stringify@3.0.1: @@ -16206,6 +16230,11 @@ snapshots: natural-compare@1.4.0: {} + needle@3.3.1: + dependencies: + iconv-lite: 0.6.3 + sax: 1.4.1 + negotiator@0.6.3: {} neo-async@2.6.2: {} @@ -17268,6 +17297,8 @@ snapshots: immutable: 4.3.6 source-map-js: 1.2.0 + sax@1.4.1: {} + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 diff --git a/projects/app/public/imgs/app/inputGuide-icon.svg b/projects/app/public/imgs/app/inputGuide-icon.svg index beeb3727699..d9929dcac94 100644 --- a/projects/app/public/imgs/app/inputGuide-icon.svg +++ b/projects/app/public/imgs/app/inputGuide-icon.svg @@ -1,4 +1,4 @@ - + diff --git a/projects/app/public/imgs/app/nextQuestion-icon.svg b/projects/app/public/imgs/app/nextQuestion-icon.svg index 846196f9fe7..8a921eafe14 100644 --- a/projects/app/public/imgs/app/nextQuestion-icon.svg +++ b/projects/app/public/imgs/app/nextQuestion-icon.svg @@ -1,4 +1,4 @@ - + diff --git a/projects/app/public/imgs/app/welcome-icon.svg b/projects/app/public/imgs/app/welcome-icon.svg index b8fbf3f031d..cfc1a0838b3 100644 --- a/projects/app/public/imgs/app/welcome-icon.svg +++ b/projects/app/public/imgs/app/welcome-icon.svg @@ -1,4 +1,4 @@ - + diff --git a/projects/app/public/imgs/workflow/fetchUrl.svg b/projects/app/public/imgs/workflow/fetchUrl.svg index d034e6eba0a..d75c79a38c6 100644 --- a/projects/app/public/imgs/workflow/fetchUrl.svg +++ b/projects/app/public/imgs/workflow/fetchUrl.svg @@ -1 +1,4 @@ - \ No newline at end of file + + +🌐 + diff --git a/projects/app/public/imgs/workflow/getCurrentTime.svg b/projects/app/public/imgs/workflow/getCurrentTime.svg index bce53c3fe72..5eb4f81b568 100644 --- a/projects/app/public/imgs/workflow/getCurrentTime.svg +++ b/projects/app/public/imgs/workflow/getCurrentTime.svg @@ -1,7 +1,4 @@ - - - - \ No newline at end of file + + + + diff --git a/projects/app/public/imgs/workflow/mathExprEval.svg b/projects/app/public/imgs/workflow/mathExprEval.svg index 959ed176fd3..866b6ed6de7 100644 --- a/projects/app/public/imgs/workflow/mathExprEval.svg +++ b/projects/app/public/imgs/workflow/mathExprEval.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/projects/app/src/components/Layout/navbar.tsx b/projects/app/src/components/Layout/navbar.tsx index c1d42cb3bf3..f2785673fd6 100644 --- a/projects/app/src/components/Layout/navbar.tsx +++ b/projects/app/src/components/Layout/navbar.tsx @@ -6,7 +6,7 @@ import { useChatStore } from '@/web/core/chat/context/storeChat'; import { HUMAN_ICON } from '@fastgpt/global/common/system/constants'; import NextLink from 'next/link'; import Badge from '../Badge'; -import Avatar from '../Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { useTranslation } from 'next-i18next'; import { useSystemStore } from '@/web/common/system/useSystemStore'; diff --git a/projects/app/src/components/Select/AIModelSelector.tsx b/projects/app/src/components/Select/AIModelSelector.tsx index 5792763f942..0c93ff4e253 100644 --- a/projects/app/src/components/Select/AIModelSelector.tsx +++ b/projects/app/src/components/Select/AIModelSelector.tsx @@ -7,7 +7,7 @@ import { AI_POINT_USAGE_CARD_ROUTE } from '@/web/support/wallet/sub/constants'; import MySelect, { SelectProps } from '@fastgpt/web/components/common/MySelect'; import { HUGGING_FACE_ICON, LOGO_ICON } from '@fastgpt/global/common/system/constants'; import { Box, Flex } from '@chakra-ui/react'; -import Avatar from '../Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; type Props = SelectProps & { diff --git a/projects/app/src/components/common/Modal/EditResourceModal.tsx b/projects/app/src/components/common/Modal/EditResourceModal.tsx index 5a1362e4e9b..ce88d869745 100644 --- a/projects/app/src/components/common/Modal/EditResourceModal.tsx +++ b/projects/app/src/components/common/Modal/EditResourceModal.tsx @@ -10,7 +10,7 @@ import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants' import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; import { getErrText } from '@fastgpt/global/common/error/utils'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { useToast } from '@fastgpt/web/hooks/useToast'; export type EditResourceInfoFormType = { diff --git a/projects/app/src/components/common/folder/SelectOneResource.tsx b/projects/app/src/components/common/folder/SelectOneResource.tsx index d231e37e440..2448088795c 100644 --- a/projects/app/src/components/common/folder/SelectOneResource.tsx +++ b/projects/app/src/components/common/folder/SelectOneResource.tsx @@ -7,7 +7,7 @@ import { } from '@fastgpt/global/common/parentFolder/type'; import MyIcon from '@fastgpt/web/components/common/Icon'; import Loading from '@fastgpt/web/components/common/MyLoading'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useMemoizedFn } from 'ahooks'; import { FolderImgUrl } from '@fastgpt/global/common/file/image/constants'; diff --git a/projects/app/src/components/core/ai/SettingLLMModel/index.tsx b/projects/app/src/components/core/ai/SettingLLMModel/index.tsx index dc13393dd54..e73e6f60caf 100644 --- a/projects/app/src/components/core/ai/SettingLLMModel/index.tsx +++ b/projects/app/src/components/core/ai/SettingLLMModel/index.tsx @@ -4,7 +4,7 @@ import { LLMModelTypeEnum, llmModelTypeFilterMap } from '@fastgpt/global/core/ai import { Box, Button, Flex, css, useDisclosure } from '@chakra-ui/react'; import type { SettingAIDataType } from '@fastgpt/global/core/app/type.d'; import AISettingModal from '@/components/core/ai/AISettingModal'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { HUGGING_FACE_ICON } from '@fastgpt/global/common/system/constants'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import { useTranslation } from 'next-i18next'; diff --git a/projects/app/src/components/core/app/DatasetSelectModal.tsx b/projects/app/src/components/core/app/DatasetSelectModal.tsx index 5129ec88ec9..418d19fe224 100644 --- a/projects/app/src/components/core/app/DatasetSelectModal.tsx +++ b/projects/app/src/components/core/app/DatasetSelectModal.tsx @@ -10,7 +10,7 @@ import { Grid, Divider } from '@chakra-ui/react'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import type { SelectedDatasetType } from '@fastgpt/global/core/workflow/api.d'; import { useToast } from '@fastgpt/web/hooks/useToast'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatAvatar.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatAvatar.tsx index a0faa371185..56ba48acf46 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatAvatar.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatAvatar.tsx @@ -1,4 +1,4 @@ -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { Box } from '@chakra-ui/react'; import { useTheme } from '@chakra-ui/system'; import React from 'react'; diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/SelectMarkCollection.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/SelectMarkCollection.tsx index 1ae5dc90061..925db604eb4 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/SelectMarkCollection.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/SelectMarkCollection.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { ModalBody, useTheme, ModalFooter, Button, Box, Card, Flex, Grid } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants'; import DatasetSelectModal, { useDatasetSelect } from '@/components/core/dataset/SelectModal'; diff --git a/projects/app/src/components/core/chat/components/AIResponseBox.tsx b/projects/app/src/components/core/chat/components/AIResponseBox.tsx index e01251331b2..770f202545d 100644 --- a/projects/app/src/components/core/chat/components/AIResponseBox.tsx +++ b/projects/app/src/components/core/chat/components/AIResponseBox.tsx @@ -15,7 +15,7 @@ import { } from '@fastgpt/global/core/chat/type'; import React from 'react'; import MyIcon from '@fastgpt/web/components/common/Icon'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; type props = { value: UserChatItemValueItemType | AIChatItemValueItemType; @@ -81,12 +81,14 @@ ${JSON.stringify(questionGuides)}`; borderWidth={'1px'} borderColor={'myGray.200'} boxShadow={'1'} + pl={3} + pr={2.5} _hover={{ bg: 'auto' }} > - - + + {tool.toolName} {isChatting && !tool.response && } diff --git a/projects/app/src/components/core/chat/components/WholeResponseModal.tsx b/projects/app/src/components/core/chat/components/WholeResponseModal.tsx index dfdac7e665e..62e8ba00a53 100644 --- a/projects/app/src/components/core/chat/components/WholeResponseModal.tsx +++ b/projects/app/src/components/core/chat/components/WholeResponseModal.tsx @@ -12,6 +12,7 @@ import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants'; import { formatNumber } from '@fastgpt/global/common/math/tools'; import { useI18n } from '@/web/context/I18n'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; +import Avatar from '@fastgpt/web/components/common/Avatar'; function RowRender({ children, @@ -125,18 +126,18 @@ export const ResponseBox = React.memo(function ResponseBox({ () => response.map((item, i) => ({ label: ( - - + item.moduleType === template.flowNodeType) ?.avatar } alt={''} - w={['14px', '16px']} + w={'1.25rem'} + borderRadius={'sm'} /> - {t(item.moduleName as any)} + {t(item.moduleName as any)} ), value: `${i}` @@ -334,7 +335,9 @@ export const ResponseBox = React.memo(function ResponseBox({ + + + } /> )} @@ -350,7 +353,11 @@ export const ResponseBox = React.memo(function ResponseBox({ {activeModule?.toolDetail && activeModule?.toolDetail.length > 0 && ( } + rawDom={ + + + + } /> )} diff --git a/projects/app/src/components/support/permission/ConfigPerModal/index.tsx b/projects/app/src/components/support/permission/ConfigPerModal/index.tsx index b4cf7066905..2cab7ee6097 100644 --- a/projects/app/src/components/support/permission/ConfigPerModal/index.tsx +++ b/projects/app/src/components/support/permission/ConfigPerModal/index.tsx @@ -4,7 +4,7 @@ import { useTranslation } from 'next-i18next'; import { PermissionValueType } from '@fastgpt/global/support/permission/type'; import CollaboratorContextProvider, { MemberManagerInputPropsType } from '../MemberManager/context'; import { Box, Button, Flex, HStack, ModalBody } from '@chakra-ui/react'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import DefaultPermissionList from '../DefaultPerList'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; diff --git a/projects/app/src/components/support/permission/MemberManager/AddMemberModal.tsx b/projects/app/src/components/support/permission/MemberManager/AddMemberModal.tsx index 1f93951ed05..c1ef73f36d8 100644 --- a/projects/app/src/components/support/permission/MemberManager/AddMemberModal.tsx +++ b/projects/app/src/components/support/permission/MemberManager/AddMemberModal.tsx @@ -14,7 +14,7 @@ import { import MyModal from '@fastgpt/web/components/common/MyModal'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { useContextSelector } from 'use-context-selector'; -import MyAvatar from '@/components/Avatar'; +import MyAvatar from '@fastgpt/web/components/common/Avatar'; import { useMemo, useState } from 'react'; import PermissionSelect from './PermissionSelect'; import PermissionTags from './PermissionTags'; @@ -23,7 +23,7 @@ import { useUserStore } from '@/web/support/user/useUserStore'; import { getTeamMembers } from '@/web/support/user/team/api'; import MyBox from '@fastgpt/web/components/common/MyBox'; import { ChevronDownIcon } from '@chakra-ui/icons'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useTranslation } from 'next-i18next'; diff --git a/projects/app/src/components/support/permission/MemberManager/ManageModal.tsx b/projects/app/src/components/support/permission/MemberManager/ManageModal.tsx index 609553a5093..ff8af158a04 100644 --- a/projects/app/src/components/support/permission/MemberManager/ManageModal.tsx +++ b/projects/app/src/components/support/permission/MemberManager/ManageModal.tsx @@ -15,7 +15,7 @@ import React from 'react'; import { useContextSelector } from 'use-context-selector'; import PermissionSelect from './PermissionSelect'; import PermissionTags from './PermissionTags'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { CollaboratorContext } from './context'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest'; diff --git a/projects/app/src/components/support/permission/MemberManager/MemberListCard.tsx b/projects/app/src/components/support/permission/MemberManager/MemberListCard.tsx index 09aa927090c..c9de309dfb2 100644 --- a/projects/app/src/components/support/permission/MemberManager/MemberListCard.tsx +++ b/projects/app/src/components/support/permission/MemberManager/MemberListCard.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { useContextSelector } from 'use-context-selector'; import { CollaboratorContext } from './context'; import Tag, { TagProps } from '@fastgpt/web/components/common/Tag'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { useTranslation } from 'next-i18next'; export type MemberListCardProps = BoxProps & { tagStyle?: Omit }; diff --git a/projects/app/src/components/support/user/team/TeamManageModal/TeamList.tsx b/projects/app/src/components/support/user/team/TeamManageModal/TeamList.tsx index a6eedc7052a..c9b020af892 100644 --- a/projects/app/src/components/support/user/team/TeamManageModal/TeamList.tsx +++ b/projects/app/src/components/support/user/team/TeamManageModal/TeamList.tsx @@ -1,5 +1,5 @@ import { Box, Button, Flex, IconButton, Text } from '@chakra-ui/react'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { useTranslation } from 'next-i18next'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant'; diff --git a/projects/app/src/components/support/user/team/TeamManageModal/components/EditInfoModal.tsx b/projects/app/src/components/support/user/team/TeamManageModal/components/EditInfoModal.tsx index 0b5ba657c25..416c120cb38 100644 --- a/projects/app/src/components/support/user/team/TeamManageModal/components/EditInfoModal.tsx +++ b/projects/app/src/components/support/user/team/TeamManageModal/components/EditInfoModal.tsx @@ -9,7 +9,7 @@ import { useRequest } from '@fastgpt/web/hooks/useRequest'; import MyModal from '@fastgpt/web/components/common/MyModal'; import { Box, Button, Flex, Input, ModalBody, ModalFooter } from '@chakra-ui/react'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { postCreateTeam, putUpdateTeam } from '@/web/support/user/team/api'; import { CreateTeamProps } from '@fastgpt/global/support/user/team/controller.d'; import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants'; diff --git a/projects/app/src/components/support/user/team/TeamManageModal/components/MemberTable.tsx b/projects/app/src/components/support/user/team/TeamManageModal/components/MemberTable.tsx index b5879d08cc3..ded51b07e9a 100644 --- a/projects/app/src/components/support/user/team/TeamManageModal/components/MemberTable.tsx +++ b/projects/app/src/components/support/user/team/TeamManageModal/components/MemberTable.tsx @@ -1,4 +1,4 @@ -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { Box, diff --git a/projects/app/src/components/support/user/team/TeamManageModal/components/PermissionManage/AddManager.tsx b/projects/app/src/components/support/user/team/TeamManageModal/components/PermissionManage/AddManager.tsx index 48405a25b64..561befec510 100644 --- a/projects/app/src/components/support/user/team/TeamManageModal/components/PermissionManage/AddManager.tsx +++ b/projects/app/src/components/support/user/team/TeamManageModal/components/PermissionManage/AddManager.tsx @@ -12,7 +12,7 @@ import { InputGroup, InputLeftElement } from '@chakra-ui/react'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyModal from '@fastgpt/web/components/common/MyModal'; import React, { useMemo, useState } from 'react'; import { useTranslation } from 'next-i18next'; diff --git a/projects/app/src/components/support/user/team/TeamManageModal/components/PermissionManage/index.tsx b/projects/app/src/components/support/user/team/TeamManageModal/components/PermissionManage/index.tsx index 9acfb911faa..e8d0438e259 100644 --- a/projects/app/src/components/support/user/team/TeamManageModal/components/PermissionManage/index.tsx +++ b/projects/app/src/components/support/user/team/TeamManageModal/components/PermissionManage/index.tsx @@ -3,7 +3,7 @@ import { Box, Button, Flex, Tag, TagLabel, useDisclosure } from '@chakra-ui/reac import { useTranslation } from 'next-i18next'; import { useContextSelector } from 'use-context-selector'; import MyIcon from '@fastgpt/web/components/common/Icon'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { delMemberPermission } from '@/web/support/user/team/api'; import { useUserStore } from '@/web/support/user/useUserStore'; diff --git a/projects/app/src/components/support/user/team/TeamMenu/index.tsx b/projects/app/src/components/support/user/team/TeamMenu/index.tsx index 2bfee82e0d9..61ab1440f50 100644 --- a/projects/app/src/components/support/user/team/TeamMenu/index.tsx +++ b/projects/app/src/components/support/user/team/TeamMenu/index.tsx @@ -6,7 +6,7 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import dynamic from 'next/dynamic'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useToast } from '@fastgpt/web/hooks/useToast'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; const TeamManageModal = dynamic(() => import('../TeamManageModal')); diff --git a/projects/app/src/components/support/user/team/UpdateInviteModal/index.tsx b/projects/app/src/components/support/user/team/UpdateInviteModal/index.tsx index 49e75f4faea..455fc53ac4a 100644 --- a/projects/app/src/components/support/user/team/UpdateInviteModal/index.tsx +++ b/projects/app/src/components/support/user/team/UpdateInviteModal/index.tsx @@ -13,7 +13,7 @@ import { import { useQuery } from '@tanstack/react-query'; import { getTeamList, updateInviteResult } from '@/web/support/user/team/api'; import { TeamMemberStatusEnum } from '@fastgpt/global/support/user/team/constant'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { useToast } from '@fastgpt/web/hooks/useToast'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; diff --git a/projects/app/src/pages/account/components/Info.tsx b/projects/app/src/pages/account/components/Info.tsx index db78f0576db..de76fcc927d 100644 --- a/projects/app/src/pages/account/components/Info.tsx +++ b/projects/app/src/pages/account/components/Info.tsx @@ -23,7 +23,7 @@ import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; import { compressImgFileAndUpload } from '@/web/common/file/controller'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useTranslation } from 'next-i18next'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyIcon from '@fastgpt/web/components/common/Icon'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import { useRouter } from 'next/router'; diff --git a/projects/app/src/pages/account/components/UsageTable.tsx b/projects/app/src/pages/account/components/UsageTable.tsx index 39850c845b6..2af918dad47 100644 --- a/projects/app/src/pages/account/components/UsageTable.tsx +++ b/projects/app/src/pages/account/components/UsageTable.tsx @@ -27,7 +27,7 @@ import { useTranslation } from 'next-i18next'; import { useQuery } from '@tanstack/react-query'; import { useUserStore } from '@/web/support/user/useUserStore'; import { getTeamMembers } from '@/web/support/user/team/api'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MySelect from '@fastgpt/web/components/common/MySelect'; import { formatNumber } from '@fastgpt/global/common/math/tools'; import EmptyTip from '@fastgpt/web/components/common/EmptyTip'; diff --git a/projects/app/src/pages/api/core/app/plugin/getSystemPluginTemplates.ts b/projects/app/src/pages/api/core/app/plugin/getSystemPluginTemplates.ts index 8257459425e..60a05a1db46 100644 --- a/projects/app/src/pages/api/core/app/plugin/getSystemPluginTemplates.ts +++ b/projects/app/src/pages/api/core/app/plugin/getSystemPluginTemplates.ts @@ -1,26 +1,46 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; +import type { NextApiResponse } from 'next'; import { authCert } from '@fastgpt/service/support/permission/auth/common'; import { NodeTemplateListItemType } from '@fastgpt/global/core/workflow/type/node.d'; import { NextAPI } from '@/service/middleware/entry'; -import { getCommunityPluginsTemplateList } from '@fastgpt/plugins/register'; +import { getSystemPluginTemplates } from '@fastgpt/plugins/register'; +import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants'; +import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant'; +import { ParentIdType } from '@fastgpt/global/common/parentFolder/type'; +import { ApiRequestProps } from '@fastgpt/service/type/next'; + +export type GetSystemPluginTemplatesQuery = { + parentId: ParentIdType; +}; async function handler( - req: NextApiRequest, + req: ApiRequestProps<{}, GetSystemPluginTemplatesQuery>, res: NextApiResponse ): Promise { await authCert({ req, authToken: true }); - // const data: NodeTemplateListItemType[] = - // global.communityPlugins?.map((plugin) => ({ - // id: plugin.id, - // templateType: plugin.templateType ?? FlowNodeTemplateTypeEnum.other, - // flowNodeType: FlowNodeTypeEnum.pluginModule, - // avatar: plugin.avatar, - // name: plugin.name, - // intro: plugin.intro - // })) || []; + const { parentId } = req.query; + + const formatParentId = parentId || null; - return getCommunityPluginsTemplateList(); + return getSystemPluginTemplates().then((res) => + res + // Just show the active plugins + .filter((item) => item.isActive) + .map((plugin) => ({ + id: plugin.id, + isFolder: plugin.isFolder, + parentId: plugin.parentId, + templateType: plugin.templateType ?? FlowNodeTemplateTypeEnum.other, + flowNodeType: FlowNodeTypeEnum.pluginModule, + avatar: plugin.avatar, + name: plugin.name, + intro: plugin.intro, + isTool: plugin.isTool, + currentCost: plugin.currentCost, + author: plugin.author + })) + .filter((item) => item.parentId === formatParentId) + ); } export default NextAPI(handler); diff --git a/projects/app/src/pages/api/core/app/plugin/path.ts b/projects/app/src/pages/api/core/app/plugin/path.ts new file mode 100644 index 00000000000..77217d1ed27 --- /dev/null +++ b/projects/app/src/pages/api/core/app/plugin/path.ts @@ -0,0 +1,35 @@ +import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next'; +import { NextAPI } from '@/service/middleware/entry'; +import { ParentIdType, ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type'; +import { getSystemPluginTemplates } from '@fastgpt/plugins/register'; + +export type pathQuery = { + parentId: ParentIdType; +}; + +export type pathBody = {}; + +export type pathResponse = Promise; + +async function handler( + req: ApiRequestProps, + res: ApiResponseType +): Promise { + const { parentId } = req.query; + + if (!parentId) return []; + + const plugins = await getSystemPluginTemplates(); + const plugin = plugins.find((item) => item.id === parentId); + + if (!plugin) return []; + + return [ + { + parentId: plugin.id, + parentName: plugin.name + } + ]; +} + +export default NextAPI(handler); diff --git a/projects/app/src/pages/app/detail/components/InfoModal.tsx b/projects/app/src/pages/app/detail/components/InfoModal.tsx index 2bdc37a2048..bfbae9ad873 100644 --- a/projects/app/src/pages/app/detail/components/InfoModal.tsx +++ b/projects/app/src/pages/app/detail/components/InfoModal.tsx @@ -16,7 +16,7 @@ import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; import { compressImgFileAndUpload } from '@/web/common/file/controller'; import { getErrText } from '@fastgpt/global/common/error/utils'; import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyModal from '@fastgpt/web/components/common/MyModal'; import { useTranslation } from 'next-i18next'; import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants'; diff --git a/projects/app/src/pages/app/detail/components/SimpleApp/AppCard.tsx b/projects/app/src/pages/app/detail/components/SimpleApp/AppCard.tsx index 74c94224139..06e756d9351 100644 --- a/projects/app/src/pages/app/detail/components/SimpleApp/AppCard.tsx +++ b/projects/app/src/pages/app/detail/components/SimpleApp/AppCard.tsx @@ -13,7 +13,7 @@ import { import { useRouter } from 'next/router'; import { AppSchema } from '@fastgpt/global/core/app/type.d'; import { useTranslation } from 'next-i18next'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyIcon from '@fastgpt/web/components/common/Icon'; import TagsEditModal from '../TagsEditModal'; import { useSystemStore } from '@/web/common/system/useSystemStore'; diff --git a/projects/app/src/pages/app/detail/components/SimpleApp/EditForm.tsx b/projects/app/src/pages/app/detail/components/SimpleApp/EditForm.tsx index 58948f15c7f..fd2205e64b3 100644 --- a/projects/app/src/pages/app/detail/components/SimpleApp/EditForm.tsx +++ b/projects/app/src/pages/app/detail/components/SimpleApp/EditForm.tsx @@ -18,7 +18,7 @@ import { useDatasetStore } from '@/web/core/dataset/store/dataset'; import dynamic from 'next/dynamic'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; -import Avatar from '@/components/Avatar'; +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'; @@ -242,8 +242,15 @@ const EditForm = ({ }) } > - - + + {item.name} @@ -292,8 +299,15 @@ const EditForm = ({ borderColor: 'primary.300' }} > - - + + {item.name} void }) const { data: templates = [], loading: isLoading } = useRequest2( async () => { if (templateType === TemplateTypeEnum.systemPlugin) { - return (await getSystemPlugTemplates()).filter( + return (await getSystemPlugTemplates(parentId)).filter( (item) => item.isTool && item.name.toLowerCase().includes(searchKey.toLowerCase()) ); } else if (templateType === TemplateTypeEnum.teamPlugin) { @@ -82,10 +88,20 @@ const ToolSelectModal = ({ onClose, ...props }: Props & { onClose: () => void }) } ); - const { data: paths = [] } = useRequest2(() => getAppFolderPath(parentId), { - manual: false, - refreshDeps: [parentId] - }); + const { data: paths = [] } = useRequest2( + () => { + if (templateType === TemplateTypeEnum.teamPlugin) return getAppFolderPath(parentId); + return getSystemPluginPaths(parentId); + }, + { + manual: false, + refreshDeps: [parentId] + } + ); + + useEffect(() => { + setParentId(''); + }, [templateType, searchKey]); return ( void }) {/* route components */} - {templateType === TemplateTypeEnum.teamPlugin && !searchKey && parentId && ( + {!searchKey && parentId && ( void }) templates={templates} isLoadingData={isLoading} setParentId={setParentId} + showCost={templateType === TemplateTypeEnum.systemPlugin} {...props} /> @@ -160,13 +177,16 @@ const RenderList = React.memo(function RenderList({ isLoadingData, onAddTool, onRemoveTool, - setParentId + setParentId, + showCost }: Props & { templates: NodeTemplateListItemType[]; isLoadingData: boolean; setParentId: React.Dispatch>; + showCost?: boolean; }) { const { t } = useTranslation(); + const { appT } = useI18n(); const [configTool, setConfigTool] = useState(); const onCloseConfigTool = useCallback(() => setConfigTool(undefined), []); @@ -195,57 +215,90 @@ const RenderList = React.memo(function RenderList({ const selected = selectedTools.some((tool) => tool.pluginId === item.id); return ( - + + + + {t(item.name as any)} + + + + {t(item.intro as any) || t('common:core.workflow.Not intro')} + + {showCost && ( + <> + + + {t('common:core.plugin.cost')} + + {item.currentCost && item.currentCost > 0 + ? t('app:Plugin cost per times', { cost: item.currentCost }) + : t('common:core.plugin.Free')} + + + + )} + + } > - - - {t(item.name as any)} - {item.intro && ( - - {t(item.intro as any)} + + + + + {t(item.name as any)} + + {showCost && ( + + {item.author ? `by ${item.author}` : `by 匿名大佬`} )} - - {selected ? ( - } - onClick={() => onRemoveTool(item)} - > - {t('common:common.Remove')} - - ) : item.isFolder ? ( - - ) : ( - } - isLoading={isLoading} - onClick={() => onClickAdd(item)} - > - {t('common:common.Add')} - - )} - + {selected ? ( + } + onClick={() => onRemoveTool(item)} + > + {t('common:common.Remove')} + + ) : item.isFolder ? ( + + ) : ( + } + isLoading={isLoading} + onClick={() => onClickAdd(item)} + > + {t('common:common.Add')} + + )} + + ); })} {!!configTool && ( diff --git a/projects/app/src/pages/app/detail/components/Workflow/Header.tsx b/projects/app/src/pages/app/detail/components/Workflow/Header.tsx index e1d9b6ff989..af3e1db6381 100644 --- a/projects/app/src/pages/app/detail/components/Workflow/Header.tsx +++ b/projects/app/src/pages/app/detail/components/Workflow/Header.tsx @@ -10,7 +10,6 @@ import { WorkflowContext, getWorkflowStore } from '../WorkflowComponents/context import { useInterval } from 'ahooks'; import { AppContext, TabEnum } from '../context'; import RouteTab from '../RouteTab'; -import { useSystemStore } from '@/web/common/system/useSystemStore'; import PopoverConfirm from '@fastgpt/web/components/common/MyPopover/PopoverConfirm'; import { useRouter } from 'next/router'; diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/AppCard.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/AppCard.tsx index cf44628c9a8..9e05cc21d3a 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/AppCard.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/AppCard.tsx @@ -4,7 +4,7 @@ import { useContextSelector } from 'use-context-selector'; import { AppContext, TabEnum } from '../context'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import { useTranslation } from 'next-i18next'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyMenu from '@fastgpt/web/components/common/MyMenu'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { useI18n } from '@/web/context/I18n'; diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx index 028467ef684..3e08934d1d3 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx @@ -1,17 +1,30 @@ -import React, { useCallback, useMemo, useState } from 'react'; -import { Box, Flex, IconButton, Input, InputGroup, InputLeftElement, css } from '@chakra-ui/react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { + Box, + Divider, + Flex, + IconButton, + Input, + InputGroup, + InputLeftElement, + css +} from '@chakra-ui/react'; import type { NodeTemplateListItemType, NodeTemplateListType } from '@fastgpt/global/core/workflow/type/node.d'; import { useViewport, XYPosition } from 'reactflow'; import { useSystemStore } from '@/web/common/system/useSystemStore'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { nodeTemplate2FlowNode } from '@/web/core/workflow/utils'; import { useTranslation } from 'next-i18next'; import EmptyTip from '@fastgpt/web/components/common/EmptyTip'; import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant'; -import { getPreviewPluginNode, getSystemPlugTemplates } from '@/web/core/app/api/plugin'; +import { + getPreviewPluginNode, + getSystemPlugTemplates, + getSystemPluginPaths +} from '@/web/core/app/api/plugin'; import { useToast } from '@fastgpt/web/hooks/useToast'; import { getErrText } from '@fastgpt/global/common/error/utils'; import { workflowNodeTemplateList } from '@fastgpt/web/core/workflow/constants'; @@ -40,6 +53,7 @@ type ModuleTemplateListProps = { }; type RenderListProps = { templates: NodeTemplateListItemType[]; + type: TemplateTypeEnum; onClose: () => void; parentId: ParentIdType; setParentId: React.Dispatch>; @@ -51,7 +65,7 @@ enum TemplateTypeEnum { 'teamPlugin' = 'teamPlugin' } -const sliderWidth = 390; +const sliderWidth = 420; const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => { const { t } = useTranslation(); @@ -104,7 +118,7 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => { refreshDeps: [basicNodeTemplates, nodeList, hasToolNode, templateType, searchKey, parentId] } ); - const { data: teamApps, loading: isLoadingTeamApp } = useRequest2( + const { data: teamAndSystemApps, loading: isLoadingTeamApp } = useRequest2( async () => { if (templateType === TemplateTypeEnum.teamPlugin) { return getTeamPlugTemplates({ @@ -113,6 +127,9 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => { type: [AppTypeEnum.folder, AppTypeEnum.httpPlugin, AppTypeEnum.plugin] }).then((res) => res.filter((app) => app.id !== appId)); } + if (templateType === TemplateTypeEnum.systemPlugin) { + return getSystemPlugTemplates(parentId); + } }, { manual: false, @@ -120,29 +137,28 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => { refreshDeps: [templateType, searchKey, parentId] } ); - const { data: systemPlugins, loading: isLoadingSystemPlugins } = useRequest2( - async () => { - if (templateType === TemplateTypeEnum.systemPlugin) { - return getSystemPlugTemplates(); - } + + const isLoading = isLoadingTeamApp; + const templates = useMemo( + () => basicNodes || teamAndSystemApps || [], + [basicNodes, teamAndSystemApps] + ); + + useEffect(() => { + setParentId(''); + }, [templateType, searchKey]); + + const { data: paths = [] } = useRequest2( + () => { + if (templateType === TemplateTypeEnum.teamPlugin) return getAppFolderPath(parentId); + return getSystemPluginPaths(parentId); }, { manual: false, - refreshDeps: [templateType] + refreshDeps: [parentId] } ); - const isLoading = isLoadingTeamApp || isLoadingSystemPlugins; - const templates = useMemo( - () => basicNodes || teamApps || systemPlugins || [], - [basicNodes, systemPlugins, teamApps] - ); - - const { data: paths = [] } = useRequest2(() => getAppFolderPath(parentId), { - manual: false, - refreshDeps: [parentId] - }); - const Render = useMemo(() => { return ( <> @@ -154,6 +170,7 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => { left={0} bottom={0} w={`${sliderWidth}px`} + maxW={'100%'} onClick={onClose} fontSize={'sm'} /> @@ -176,30 +193,35 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => { userSelect={'none'} overflow={isOpen ? 'none' : 'hidden'} > + {/* Header */} + {/* Tabs */} - setTemplateType(e as TemplateTypeEnum)} - /> + + setTemplateType(e as TemplateTypeEnum)} + /> + {/* close icon */} { onClick={onClose} /> + {/* Search */} {templateType === TemplateTypeEnum.teamPlugin && ( @@ -238,14 +261,19 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => { )} - {templateType === TemplateTypeEnum.teamPlugin && !searchKey && parentId && ( - - - - )} + {/* paths */} + {(templateType === TemplateTypeEnum.teamPlugin || + templateType === TemplateTypeEnum.systemPlugin) && + !searchKey && + parentId && ( + + + + )} - {item.label && ( + {item.label && formatTemplates.length > 1 && ( - + {t(item.label as any)} @@ -385,27 +416,43 @@ const RenderList = React.memo(function RenderList({ key={template.id} placement={'right'} label={ - + - + {t(template.name as any)} {t(template.intro as any) || t('common:core.workflow.Not intro')} + {isSystemPlugin && ( + <> + + + {t('common:core.plugin.cost')} + + {template.currentCost && template.currentCost > 0 + ? t('app:Plugin cost per times', { + cost: template.currentCost + }) + : t('common:core.plugin.Free')} + + + + )} } > - + {t(template.name as any)} + {template.author && ( + + {`by ${template.author}`} + + )} ))} @@ -452,7 +510,17 @@ const RenderList = React.memo(function RenderList({ ); - }, [appT, formatTemplates, isPc, onAddNode, onClose, setParentId, t, templates.length]); + }, [ + appT, + formatTemplates, + isPc, + isSystemPlugin, + onAddNode, + onClose, + setParentId, + t, + templates.length + ]); return Render; }); diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx index dc6f0332e9a..4ab4853db0e 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Box, Button, Card, Flex } from '@chakra-ui/react'; import MyIcon from '@fastgpt/web/components/common/Icon'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import type { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node.d'; import { useTranslation } from 'next-i18next'; import { useEditTitle } from '@/web/common/hooks/useEditTitle'; @@ -137,7 +137,7 @@ const NodeCard = (props: Props) => { {/* avatar and name */} - + {t(name as any)} diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Reference.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Reference.tsx index af5a17a5b45..5ae2f304454 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Reference.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Reference.tsx @@ -19,7 +19,7 @@ import { AppContext } from '@/pages/app/detail/components/context'; const MultipleRowSelect = dynamic( () => import('@fastgpt/web/components/common/MySelect/MultipleRowSelect') ); -const Avatar = dynamic(() => import('@/components/Avatar')); +const Avatar = dynamic(() => import('@fastgpt/web/components/common/Avatar')); type SelectProps = { value?: ReferenceValueProps; @@ -120,8 +120,8 @@ export const useReference = ({ return { label: ( - - {t(node.name as any)} + + {t(node.name as any)} ), value: node.nodeId, diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectApp.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectApp.tsx index c350f88f0a7..e7516be9ab8 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectApp.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectApp.tsx @@ -2,7 +2,7 @@ import React, { useMemo } from 'react'; import type { RenderInputProps } from '../type'; import { Box, Button, useDisclosure } from '@chakra-ui/react'; import { SelectAppItemType } from '@fastgpt/global/core/workflow/template/system/runApp/type'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import SelectAppModal from '../../../../SelectAppModal'; import { useTranslation } from 'next-i18next'; import { useContextSelector } from 'use-context-selector'; diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDataset.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDataset.tsx index 9c4dec1ab01..9b9b6f2d15c 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDataset.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDataset.tsx @@ -3,7 +3,7 @@ import type { RenderInputProps } from '../type'; import { Box, Button, Flex, Grid, useDisclosure, useTheme } from '@chakra-ui/react'; import { useDatasetStore } from '@/web/core/dataset/store/dataset'; import { SelectedDatasetType } from '@fastgpt/global/core/workflow/api'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants'; diff --git a/projects/app/src/pages/app/list/components/CreateModal.tsx b/projects/app/src/pages/app/list/components/CreateModal.tsx index 28842f51b6c..eb74fb5a587 100644 --- a/projects/app/src/pages/app/list/components/CreateModal.tsx +++ b/projects/app/src/pages/app/list/components/CreateModal.tsx @@ -20,7 +20,7 @@ import { useRouter } from 'next/router'; import { simpleBotTemplates, workflowTemplates, pluginTemplates } from '@/web/core/app/templates'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useRequest } from '@fastgpt/web/hooks/useRequest'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import MyModal from '@fastgpt/web/components/common/MyModal'; import { useTranslation } from 'next-i18next'; @@ -195,7 +195,7 @@ const CreateModal = ({ onClose, type }: { type: CreateAppType; onClose: () => vo }} > - + {t(item.name as any)} diff --git a/projects/app/src/pages/app/list/components/HttpPluginEditModal.tsx b/projects/app/src/pages/app/list/components/HttpPluginEditModal.tsx index 87b3a4e12ae..e1e68b93192 100644 --- a/projects/app/src/pages/app/list/components/HttpPluginEditModal.tsx +++ b/projects/app/src/pages/app/list/components/HttpPluginEditModal.tsx @@ -21,7 +21,7 @@ import { compressImgFileAndUpload } from '@/web/common/file/controller'; import { getErrText } from '@fastgpt/global/common/error/utils'; import { useToast } from '@fastgpt/web/hooks/useToast'; import { useRequest } from '@fastgpt/web/hooks/useRequest'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import { useTranslation } from 'next-i18next'; import { HttpPluginImgUrl, MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants'; diff --git a/projects/app/src/pages/app/list/components/List.tsx b/projects/app/src/pages/app/list/components/List.tsx index 294d362a343..70a9f29a03c 100644 --- a/projects/app/src/pages/app/list/components/List.tsx +++ b/projects/app/src/pages/app/list/components/List.tsx @@ -4,7 +4,7 @@ import { useRouter } from 'next/router'; import { delAppById, putAppById, resumeInheritPer } from '@/web/core/app/api'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import MyIcon from '@fastgpt/web/components/common/Icon'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import PermissionIconText from '@/components/support/permission/IconText'; import { useI18n } from '@/web/context/I18n'; import EmptyTip from '@fastgpt/web/components/common/EmptyTip'; diff --git a/projects/app/src/pages/chat/components/ChatHeader.tsx b/projects/app/src/pages/chat/components/ChatHeader.tsx index 838cd9cde4c..8804d1e3cbc 100644 --- a/projects/app/src/pages/chat/components/ChatHeader.tsx +++ b/projects/app/src/pages/chat/components/ChatHeader.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Flex, useTheme, Box } from '@chakra-ui/react'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import MyIcon from '@fastgpt/web/components/common/Icon'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import ToolMenu from './ToolMenu'; import type { ChatItemType } from '@fastgpt/global/core/chat/type'; import { useTranslation } from 'next-i18next'; diff --git a/projects/app/src/pages/chat/components/ChatHistorySlider.tsx b/projects/app/src/pages/chat/components/ChatHistorySlider.tsx index 5591f1b416b..578c7fc3fb9 100644 --- a/projects/app/src/pages/chat/components/ChatHistorySlider.tsx +++ b/projects/app/src/pages/chat/components/ChatHistorySlider.tsx @@ -3,7 +3,7 @@ import { Box, Button, Flex, useTheme, IconButton } from '@chakra-ui/react'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useEditTitle } from '@/web/common/hooks/useEditTitle'; import { useRouter } from 'next/router'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { useTranslation } from 'next-i18next'; diff --git a/projects/app/src/pages/chat/components/Empty.tsx b/projects/app/src/pages/chat/components/Empty.tsx index b0e67b2fc7a..31746b08f4f 100644 --- a/projects/app/src/pages/chat/components/Empty.tsx +++ b/projects/app/src/pages/chat/components/Empty.tsx @@ -4,7 +4,7 @@ import { useMarkdown } from '@/web/common/hooks/useMarkdown'; import dynamic from 'next/dynamic'; const Markdown = dynamic(() => import('@/components/Markdown')); -const Avatar = dynamic(() => import('@/components/Avatar')); +const Avatar = dynamic(() => import('@fastgpt/web/components/common/Avatar')); const Empty = ({ showChatProblem, diff --git a/projects/app/src/pages/chat/components/SliderApps.tsx b/projects/app/src/pages/chat/components/SliderApps.tsx index 051b6c44a87..1c1e3474c08 100644 --- a/projects/app/src/pages/chat/components/SliderApps.tsx +++ b/projects/app/src/pages/chat/components/SliderApps.tsx @@ -3,7 +3,7 @@ import { Flex, Box, IconButton, HStack } from '@chakra-ui/react'; import { useRouter } from 'next/router'; import { useTranslation } from 'next-i18next'; import MyIcon from '@fastgpt/web/components/common/Icon'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { AppListItemType } from '@fastgpt/global/core/app/type'; import MyDivider from '@fastgpt/web/components/common/MyDivider'; import MyPopover from '@fastgpt/web/components/common/MyPopover/index'; diff --git a/projects/app/src/pages/dataset/detail/components/Info.tsx b/projects/app/src/pages/dataset/detail/components/Info.tsx index ae39fb938d6..b5098350dae 100644 --- a/projects/app/src/pages/dataset/detail/components/Info.tsx +++ b/projects/app/src/pages/dataset/detail/components/Info.tsx @@ -8,7 +8,7 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import { useForm } from 'react-hook-form'; import { compressImgFileAndUpload } from '@/web/common/file/controller'; import type { DatasetItemType } from '@fastgpt/global/core/dataset/type.d'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import { useTranslation } from 'next-i18next'; import { useSystemStore } from '@/web/common/system/useSystemStore'; diff --git a/projects/app/src/pages/dataset/detail/components/Slider.tsx b/projects/app/src/pages/dataset/detail/components/Slider.tsx index 0862bb7956a..3014d971c7e 100644 --- a/projects/app/src/pages/dataset/detail/components/Slider.tsx +++ b/projects/app/src/pages/dataset/detail/components/Slider.tsx @@ -2,7 +2,7 @@ import React, { useCallback } from 'react'; import { useTranslation } from 'next-i18next'; import { Box, Flex, IconButton, useTheme, Progress } from '@chakra-ui/react'; import { useSystemStore } from '@/web/common/system/useSystemStore'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { DatasetTypeMap } from '@fastgpt/global/core/dataset/constants'; import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag'; import MyIcon from '@fastgpt/web/components/common/Icon'; diff --git a/projects/app/src/pages/dataset/list/component/CreateModal.tsx b/projects/app/src/pages/dataset/list/component/CreateModal.tsx index c580767f8d0..ddc10523bcf 100644 --- a/projects/app/src/pages/dataset/list/component/CreateModal.tsx +++ b/projects/app/src/pages/dataset/list/component/CreateModal.tsx @@ -8,7 +8,7 @@ import { useToast } from '@fastgpt/web/hooks/useToast'; import { useRouter } from 'next/router'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useRequest } from '@fastgpt/web/hooks/useRequest'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import MyModal from '@fastgpt/web/components/common/MyModal'; import { postCreateDataset } from '@/web/core/dataset/api'; diff --git a/projects/app/src/pages/dataset/list/component/List.tsx b/projects/app/src/pages/dataset/list/component/List.tsx index 465ecbd981d..bf93ef2c2d3 100644 --- a/projects/app/src/pages/dataset/list/component/List.tsx +++ b/projects/app/src/pages/dataset/list/component/List.tsx @@ -8,7 +8,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon'; import { useRouter } from 'next/router'; import PermissionIconText from '@/components/support/permission/IconText'; import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { DatasetItemType } from '@fastgpt/global/core/dataset/type'; diff --git a/projects/app/src/pages/dataset/list/component/MoveModal.tsx b/projects/app/src/pages/dataset/list/component/MoveModal.tsx index fd4a3872543..d2f748fa4bf 100644 --- a/projects/app/src/pages/dataset/list/component/MoveModal.tsx +++ b/projects/app/src/pages/dataset/list/component/MoveModal.tsx @@ -10,7 +10,7 @@ import { useTheme, Grid } from '@chakra-ui/react'; -import Avatar from '@/components/Avatar'; +import Avatar from '@fastgpt/web/components/common/Avatar'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import MyModal from '@fastgpt/web/components/common/MyModal'; import MyIcon from '@fastgpt/web/components/common/Icon'; diff --git a/projects/app/src/web/core/app/api/app.ts b/projects/app/src/web/core/app/api/app.ts index 90d6eb02531..6ce023aa2e6 100644 --- a/projects/app/src/web/core/app/api/app.ts +++ b/projects/app/src/web/core/app/api/app.ts @@ -12,8 +12,11 @@ import type { copyAppQuery, copyAppResponse } from '@/pages/api/core/app/copy'; export const postCreateAppFolder = (data: CreateAppFolderBody) => POST('/core/app/folder/create', data); -export const getAppFolderPath = (parentId: ParentIdType) => - GET(`/core/app/folder/path`, { parentId }); +export const getAppFolderPath = (parentId: ParentIdType) => { + if (!parentId) return Promise.resolve([]); + + return GET(`/core/app/folder/path`, { parentId }); +}; /* detail */ export const postTransition2Workflow = (data: transitionWorkflowBody) => diff --git a/projects/app/src/web/core/app/api/plugin.ts b/projects/app/src/web/core/app/api/plugin.ts index 3055233cd02..dd94701f3bd 100644 --- a/projects/app/src/web/core/app/api/plugin.ts +++ b/projects/app/src/web/core/app/api/plugin.ts @@ -11,6 +11,7 @@ import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant'; import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants'; import type { GetPreviewNodeQuery } from '@/pages/api/core/app/plugin/getPreviewNode'; import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; +import { ParentIdType, ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type'; /* ============ team plugin ============== */ export const getTeamPlugTemplates = (data?: ListAppBody) => @@ -30,8 +31,14 @@ export const getTeamPlugTemplates = (data?: ListAppBody) => })) ); -export const getSystemPlugTemplates = () => - GET('/core/app/plugin/getSystemPluginTemplates'); +/* ============ system plugin ============== */ +export const getSystemPlugTemplates = (parentId: ParentIdType) => + GET('/core/app/plugin/getSystemPluginTemplates', { parentId }); + +export const getSystemPluginPaths = (parentId: ParentIdType) => { + if (!parentId) return Promise.resolve([]); + return GET('/core/app/plugin/path', { parentId }); +}; export const getPreviewPluginNode = (data: GetPreviewNodeQuery) => GET('/core/app/plugin/getPreviewNode', data); diff --git a/projects/app/src/web/core/app/templates.ts b/projects/app/src/web/core/app/templates.ts index a8d58af78d5..cfec8b621d3 100644 --- a/projects/app/src/web/core/app/templates.ts +++ b/projects/app/src/web/core/app/templates.ts @@ -22,7 +22,7 @@ type TemplateType = (AppItemType & { export const simpleBotTemplates: TemplateType = [ { id: 'simpleChat', - avatar: '/imgs/workflow/AI.png', + avatar: 'core/workflow/template/aiChat', name: '简易机器人', intro: '一个极其简单的 AI 应用,你可以绑定知识库或工具。', type: AppTypeEnum.simple, @@ -31,7 +31,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: 'userGuide', name: '系统配置', intro: '可以配置应用的系统参数', - avatar: '/imgs/workflow/userGuide.png', + avatar: 'core/workflow/template/systemConfig', flowNodeType: FlowNodeTypeEnum.systemConfig, position: { x: 531.2422736065552, @@ -94,7 +94,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: '448745', name: '流程开始', intro: '', - avatar: '/imgs/workflow/userChatInput.svg', + avatar: 'core/workflow/template/workflowStart', flowNodeType: FlowNodeTypeEnum.workflowStart, position: { x: 558.4082376415505, @@ -125,7 +125,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: 'loOvhld2ZTKa', name: 'AI 对话', intro: 'AI 大模型对话', - avatar: '/imgs/workflow/AI.png', + avatar: 'core/workflow/template/aiChat', flowNodeType: FlowNodeTypeEnum.chatNode, showStatus: true, position: { @@ -252,7 +252,7 @@ export const simpleBotTemplates: TemplateType = [ }, { id: 'chatGuide', - avatar: '/imgs/workflow/userGuide.png', + avatar: 'core/workflow/template/systemConfig', name: '对话引导 + 变量', intro: '可以在对话开始发送一段提示,或者让用户填写一些内容,作为本次对话的变量', type: AppTypeEnum.simple, @@ -261,7 +261,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: 'userGuide', name: '系统配置', intro: '可以配置应用的系统参数', - avatar: '/imgs/workflow/userGuide.png', + avatar: 'core/workflow/template/systemConfig', flowNodeType: FlowNodeTypeEnum.systemConfig, position: { x: 496.57560693988853, @@ -341,7 +341,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: '448745', name: '流程开始', intro: '', - avatar: '/imgs/workflow/userChatInput.svg', + avatar: 'core/workflow/template/workflowStart', flowNodeType: FlowNodeTypeEnum.workflowStart, position: { x: 558.4082376415505, @@ -372,7 +372,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: 'loOvhld2ZTKa', name: 'AI 对话', intro: 'AI 大模型对话', - avatar: '/imgs/workflow/AI.png', + avatar: 'core/workflow/template/aiChat', flowNodeType: FlowNodeTypeEnum.chatNode, showStatus: true, position: { @@ -499,7 +499,7 @@ export const simpleBotTemplates: TemplateType = [ }, { id: 'simpleDatasetChat', - avatar: '/imgs/workflow/db.png', + avatar: 'core/workflow/template/datasetSearch', name: '知识库+对话引导', intro: '每次提问时进行一次知识库搜索,将搜索结果注入 LLM 模型进行参考回答', type: AppTypeEnum.simple, @@ -508,7 +508,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: 'userGuide', name: '系统配置', intro: '可以配置应用的系统参数', - avatar: '/imgs/workflow/userGuide.png', + avatar: 'core/workflow/template/systemConfig', flowNodeType: FlowNodeTypeEnum.systemConfig, position: { x: 531.2422736065552, @@ -571,7 +571,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: 'workflowStartNodeId', name: '流程开始', intro: '', - avatar: '/imgs/workflow/userChatInput.svg', + avatar: 'core/workflow/template/workflowStart', flowNodeType: FlowNodeTypeEnum.workflowStart, position: { x: 558.4082376415505, @@ -602,7 +602,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: '7BdojPlukIQw', name: 'AI 对话', intro: 'AI 大模型对话', - avatar: '/imgs/workflow/AI.png', + avatar: 'core/workflow/template/aiChat', flowNodeType: FlowNodeTypeEnum.chatNode, showStatus: true, position: { @@ -722,7 +722,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: 'iKBoX2vIzETU', name: '知识库搜索', intro: '调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容', - avatar: '/imgs/workflow/db.png', + avatar: 'core/workflow/template/datasetSearch', flowNodeType: FlowNodeTypeEnum.datasetSearchNode, showStatus: true, position: { @@ -827,7 +827,7 @@ export const simpleBotTemplates: TemplateType = [ }, { id: 'toolChat', - avatar: '/imgs/workflow/history.png', + avatar: 'core/workflow/template/getTime', name: '知道时间的机器人', intro: '通过挂载时间插件,让模型获取当前最新时间', type: AppTypeEnum.simple, @@ -836,7 +836,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: 'userGuide', name: '系统配置', intro: '可以配置应用的系统参数', - avatar: '/imgs/workflow/userGuide.png', + avatar: 'core/workflow/template/systemConfig', flowNodeType: FlowNodeTypeEnum.systemConfig, position: { x: 531.2422736065552, @@ -850,7 +850,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: 'workflowStartNodeId', name: '流程开始', intro: '', - avatar: '/imgs/workflow/userChatInput.svg', + avatar: 'core/workflow/template/workflowStart', flowNodeType: FlowNodeTypeEnum.workflowStart, position: { x: 558.4082376415505, @@ -881,7 +881,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: 'jrWPV9', name: '工具调用', intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。', - avatar: '/imgs/workflow/tool.svg', + avatar: 'core/workflow/template/toolCall', flowNodeType: FlowNodeTypeEnum.tools, showStatus: true, position: { @@ -963,7 +963,7 @@ export const simpleBotTemplates: TemplateType = [ nodeId: 'zBxjo5', name: '获取当前时间', intro: '获取用户当前时区的时间。', - avatar: '/imgs/workflow/getCurrentTime.svg', + avatar: 'core/workflow/template/getTime', flowNodeType: 'pluginModule', showStatus: false, position: { @@ -1021,7 +1021,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'userGuide', name: '系统配置', intro: '可以配置应用的系统参数', - avatar: '/imgs/workflow/userGuide.png', + avatar: 'core/workflow/template/systemConfig', flowNodeType: 'userGuide', position: { x: 531.2422736065552, @@ -1084,7 +1084,7 @@ export const workflowTemplates: TemplateType = [ nodeId: '448745', name: '流程开始', intro: '', - avatar: '/imgs/workflow/userChatInput.svg', + avatar: 'core/workflow/template/workflowStart', flowNodeType: 'workflowStart', position: { x: 558.4082376415505, @@ -1115,7 +1115,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'loOvhld2ZTKa', name: '第一轮翻译', intro: 'AI 大模型对话', - avatar: '/imgs/workflow/AI.png', + avatar: 'core/workflow/template/aiChat', flowNodeType: 'chatNode', showStatus: true, position: { @@ -1235,7 +1235,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'w0oBbQ3YJHye', name: '代码运行', intro: '执行一段简单的脚本代码,通常用于进行复杂的数据处理。', - avatar: '/imgs/workflow/code.svg', + avatar: 'core/workflow/template/codeRun', flowNodeType: 'code', showStatus: true, position: { @@ -1348,7 +1348,7 @@ export const workflowTemplates: TemplateType = [ name: '指定回复', intro: '该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。', - avatar: '/imgs/workflow/reply.png', + avatar: 'core/workflow/template/reply', flowNodeType: 'answerNode', position: { x: 3798.4479531204515, @@ -1374,7 +1374,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'gBDvemE4FBhp', name: '文本拼接', intro: '可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。', - avatar: '/imgs/workflow/textEditor.svg', + avatar: 'core/workflow/template/textConcat', flowNodeType: 'textEditor', position: { x: 1031.371061396644, @@ -1463,7 +1463,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'bcqtxqxE2R6o', name: '合并输出结果', intro: '可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。', - avatar: '/imgs/workflow/textEditor.svg', + avatar: 'core/workflow/template/textConcat', flowNodeType: 'textEditor', position: { x: 3113.6227559936665, @@ -1593,7 +1593,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'userGuide', name: '系统配置', intro: '可以配置应用的系统参数', - avatar: '/imgs/workflow/userGuide.png', + avatar: 'core/workflow/template/systemConfig', flowNodeType: 'userGuide', position: { x: 262.2732338817093, @@ -1656,7 +1656,7 @@ export const workflowTemplates: TemplateType = [ nodeId: '448745', name: '流程开始', intro: '', - avatar: '/imgs/workflow/userChatInput.svg', + avatar: 'core/workflow/template/workflowStart', flowNodeType: 'workflowStart', position: { x: 295.8944548701009, @@ -1687,7 +1687,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'NOgbnBzUwDgT', name: '工具调用', intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。', - avatar: '/imgs/workflow/tool.svg', + avatar: 'core/workflow/template/toolCall', flowNodeType: 'tools', showStatus: true, position: { @@ -1769,7 +1769,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'GMELVPxHfpg5', name: 'HTTP 请求', intro: '调用谷歌搜索,查询相关内容', - avatar: '/imgs/workflow/http.png', + avatar: 'core/workflow/template/httpRequest', flowNodeType: 'httpRequest468', showStatus: true, position: { @@ -1914,7 +1914,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'poIbrrA8aiR0', name: '代码运行', intro: '执行一段简单的脚本代码,通常用于进行复杂的数据处理。', - avatar: '/imgs/workflow/code.svg', + avatar: 'core/workflow/template/codeRun', flowNodeType: 'code', showStatus: true, position: { @@ -2032,7 +2032,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'userGuide', name: '系统配置', intro: '可以配置应用的系统参数', - avatar: '/imgs/workflow/userGuide.png', + avatar: 'core/workflow/template/systemConfig', flowNodeType: 'userGuide', position: { x: 531.2422736065552, @@ -2095,7 +2095,7 @@ export const workflowTemplates: TemplateType = [ nodeId: '448745', name: '流程开始', intro: '', - avatar: '/imgs/workflow/userChatInput.svg', + avatar: 'core/workflow/template/workflowStart', flowNodeType: 'workflowStart', position: { x: 532.1275542407774, @@ -2126,7 +2126,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'tMyUnRL5jIrC', name: 'HTTP 请求', intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)', - avatar: '/imgs/workflow/http.png', + avatar: 'core/workflow/template/httpRequest', flowNodeType: 'httpRequest468', showStatus: true, position: { @@ -2291,7 +2291,7 @@ export const workflowTemplates: TemplateType = [ name: '指定回复', intro: '该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。', - avatar: '/imgs/workflow/reply.png', + avatar: 'core/workflow/template/reply', flowNodeType: 'answerNode', position: { x: 2204.4609372615846, @@ -2317,7 +2317,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'vEXJF8pQ8eOv', name: '文本拼接', intro: '可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。', - avatar: '/imgs/workflow/textEditor.svg', + avatar: 'core/workflow/template/textConcat', flowNodeType: 'textEditor', position: { x: 1544.8821308368042, @@ -2426,7 +2426,7 @@ export const workflowTemplates: TemplateType = [ }, { id: 'CQ', - avatar: '/imgs/workflow/cq.png', + avatar: 'core/workflow/template/questionClassify', name: '问题分类 + 知识库', intro: '先对用户的问题进行分类,再根据不同类型问题,执行不同的操作', type: AppTypeEnum.workflow, @@ -2435,7 +2435,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'userGuide', name: '系统配置', intro: '可以配置应用的系统参数', - avatar: '/imgs/workflow/userGuide.png', + avatar: 'core/workflow/template/systemConfig', flowNodeType: FlowNodeTypeEnum.systemConfig, position: { x: 531.2422736065552, @@ -2498,7 +2498,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'workflowStartNodeId', name: '流程开始', intro: '', - avatar: '/imgs/workflow/userChatInput.svg', + avatar: 'core/workflow/template/workflowStart', flowNodeType: FlowNodeTypeEnum.workflowStart, position: { x: 558.4082376415505, @@ -2529,7 +2529,7 @@ export const workflowTemplates: TemplateType = [ nodeId: '7BdojPlukIQw', name: 'AI 对话', intro: 'AI 大模型对话', - avatar: '/imgs/workflow/AI.png', + avatar: 'core/workflow/template/aiChat', flowNodeType: FlowNodeTypeEnum.chatNode, showStatus: true, position: { @@ -2650,7 +2650,7 @@ export const workflowTemplates: TemplateType = [ name: '问题分类', intro: '根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题', - avatar: '/imgs/workflow/cq.png', + avatar: 'core/workflow/template/questionClassify', flowNodeType: FlowNodeTypeEnum.classifyQuestion, showStatus: true, position: { @@ -2732,7 +2732,7 @@ export const workflowTemplates: TemplateType = [ name: '指定回复', intro: '该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。', - avatar: '/imgs/workflow/reply.png', + avatar: 'core/workflow/template/reply', flowNodeType: FlowNodeTypeEnum.answerNode, position: { x: 1874.9167551056487, @@ -2757,7 +2757,7 @@ export const workflowTemplates: TemplateType = [ nodeId: 'MNMMMIjjWyMU', name: '知识库搜索', intro: '调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容', - avatar: '/imgs/workflow/db.png', + avatar: 'core/workflow/template/datasetSearch', flowNodeType: FlowNodeTypeEnum.datasetSearchNode, showStatus: true, position: { @@ -2883,7 +2883,7 @@ export const workflowTemplates: TemplateType = [ export const pluginTemplates: TemplateType = [ { id: 'plugin-simple', - avatar: '/imgs/workflow/AI.png', + avatar: 'core/workflow/template/aiChat', name: '默认模板', intro: '标准的插件初始模板', type: AppTypeEnum.plugin, @@ -2891,7 +2891,7 @@ export const pluginTemplates: TemplateType = [ { nodeId: 'pluginInput', name: '自定义插件输入', - avatar: '/imgs/workflow/input.png', + avatar: 'core/workflow/template/workflowStart', flowNodeType: FlowNodeTypeEnum.pluginInput, showStatus: false, position: { @@ -2930,7 +2930,7 @@ export const pluginTemplates: TemplateType = [ nodeId: 'pluginInput', name: '自定义插件输入', intro: '自定义配置外部输入,使用插件时,仅暴露自定义配置的输入', - avatar: '/imgs/workflow/input.png', + avatar: 'core/workflow/template/workflowStart', flowNodeType: 'pluginInput', showStatus: false, position: { @@ -3015,7 +3015,7 @@ export const pluginTemplates: TemplateType = [ nodeId: 'rKBYGQuYefae', name: 'HTTP 请求', intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)', - avatar: '/imgs/workflow/http.png', + avatar: 'core/workflow/template/httpRequest', flowNodeType: 'httpRequest468', showStatus: true, position: { diff --git a/projects/app/src/web/core/workflow/utils.ts b/projects/app/src/web/core/workflow/utils.ts index cdca446b642..0a54c6b93d3 100644 --- a/projects/app/src/web/core/workflow/utils.ts +++ b/projects/app/src/web/core/workflow/utils.ts @@ -84,6 +84,7 @@ export const storeNode2FlowNode = ({ const nodeItem: FlowNodeItemType = { ...template, ...storeNode, + avatar: template.avatar ?? storeNode.avatar, version: storeNode.version ?? template.version ?? defaultNodeVersion, /*