From 75af549c7f2a35bebaec3eb8dc40390e2e1d1753 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Fri, 20 Sep 2024 14:12:58 +0800 Subject: [PATCH] Plugin support select file (#2756) * feat: plugin support upload files (#2716) * feat: plugin support file upload * file history * fix history & chattest * chore: code * plugin config icon & file preview padding * perf: undefined fn * fix: plugin file numbers & plugin template add config (#2743) * perf: run plugin without human message (#2749) * perf: run plugin without human message * fix build * fix build * rename node * perf: ui * perf: plugin rerun with last params & plugin log add file (#2755) * perf: plugin run with last params & plugin log add file * delete console * perf: plugin refresh code * fix: ts --------- Co-authored-by: heheer --- .../zh-cn/docs/development/openapi/chat.md | 4 +- .../zh-cn/docs/development/upgrading/4811.md | 17 +- .../workflow/template/system/pluginOutput.ts | 2 +- packages/global/core/workflow/utils.ts | 28 ++ .../src/Doc2X/FileImg2text/template.json | 99 ++++-- .../src/Doc2X/FilePDF2text/template.json | 98 ++++-- .../src/Doc2X/URLImg2text/template.json | 101 ++++-- .../src/Doc2X/URLPDF2text/template.json | 98 ++++-- .../src/duckduckgo/search/template.json | 132 +++++--- .../src/duckduckgo/searchImg/template.json | 132 +++++--- .../src/duckduckgo/searchNews/template.json | 132 +++++--- .../src/duckduckgo/searchVideo/template.json | 132 +++++--- packages/plugins/src/feishu/template.json | 124 ++++++-- packages/plugins/src/fetchUrl/template.json | 4 +- packages/plugins/src/getTime/template.json | 4 +- .../plugins/src/mathExprVal/template.json | 2 +- .../core/workflow/dispatch/plugin/run.ts | 5 +- .../core/workflow/dispatch/plugin/runInput.ts | 16 +- packages/service/core/workflow/utils.ts | 23 -- .../web/components/common/Icon/constants.ts | 1 + .../common/Icon/icons/core/chat/imgSelect.svg | 4 + packages/web/i18n/en/app.json | 2 +- packages/web/i18n/en/chat.json | 11 +- packages/web/i18n/en/common.json | 8 +- packages/web/i18n/en/workflow.json | 8 +- packages/web/i18n/zh/app.json | 2 +- packages/web/i18n/zh/chat.json | 11 +- packages/web/i18n/zh/common.json | 10 +- packages/web/i18n/zh/workflow.json | 8 +- .../data/pluginTemplates/customFeedback.json | 4 +- .../data/pluginTemplates/getCurrentTime.json | 4 +- .../app/data/pluginTemplates/textEditor.json | 4 +- .../pluginTemplates/v1/customFeedback.json | 2 +- .../pluginTemplates/v1/getCurrentTime.json | 4 +- .../data/pluginTemplates/v1/textEditor.json | 4 +- .../app/data/pluginTemplates/v1/tfSwitch.json | 4 +- .../appMarketTemplates/flux/template.json | 96 ++++-- .../plugin-dalle/template.json | 96 ++++-- .../plugin-feishu/template.json | 221 ++++++++++--- .../src/components/core/app/FileSelect.tsx | 10 +- .../ChatContainer/ChatBox/Input/ChatInput.tsx | 298 ++---------------- .../chat/ChatContainer/ChatBox/Provider.tsx | 3 +- .../ChatBox/hooks/useFileUpload.tsx | 214 +++++++++++++ .../core/chat/ChatContainer/ChatBox/index.tsx | 3 +- .../core/chat/ChatContainer/ChatBox/type.d.ts | 1 + .../PluginRunBox/components/RenderInput.tsx | 183 ++++++++--- .../ChatContainer/PluginRunBox/context.tsx | 210 +++++++----- .../chat/ChatContainer/PluginRunBox/type.d.ts | 3 +- .../ChatContainer/components/FilePreview.tsx | 121 +++++++ .../core/chat/ChatContainer/useChat.ts | 8 +- .../app/src/pages/api/core/chat/chatTest.ts | 30 +- .../app/src/pages/api/v1/chat/completions.ts | 14 +- .../components/Logs/DetailLogsModal.tsx | 1 + .../Flow/hooks/useWorkflow.tsx | 10 +- .../nodes/NodePluginIO/NodePluginConfig.tsx | 54 ++++ .../Flow/nodes/NodePluginIO/PluginInput.tsx | 9 +- .../app/detail/components/useChatTest.tsx | 2 +- .../dataset/list/component/CreateModal.tsx | 1 - projects/app/src/web/core/app/templates.ts | 16 +- 59 files changed, 2013 insertions(+), 835 deletions(-) create mode 100644 packages/web/components/common/Icon/icons/core/chat/imgSelect.svg create mode 100644 projects/app/src/components/core/chat/ChatContainer/ChatBox/hooks/useFileUpload.tsx create mode 100644 projects/app/src/components/core/chat/ChatContainer/components/FilePreview.tsx diff --git a/docSite/content/zh-cn/docs/development/openapi/chat.md b/docSite/content/zh-cn/docs/development/openapi/chat.md index 53b8dc88fa1..4a336bb37b8 100644 --- a/docSite/content/zh-cn/docs/development/openapi/chat.md +++ b/docSite/content/zh-cn/docs/development/openapi/chat.md @@ -332,7 +332,7 @@ curl --location --request POST 'http://localhost:3000/api/v1/chat/completions' \ }, { "nodeId": "pluginOutput", - "moduleName": "自定义插件输出", + "moduleName": "插件输出", "moduleType": "pluginOutput", "totalPoints": 0, "pluginOutput": { @@ -430,7 +430,7 @@ event: answer data: [DONE] event: flowResponses -data: [{"nodeId":"fdDgXQ6SYn8v","moduleName":"AI 对话","moduleType":"chatNode","totalPoints":0.033,"model":"FastAI-3.5","tokens":33,"query":"你好","maxToken":2000,"historyPreview":[{"obj":"Human","value":"你好"},{"obj":"AI","value":"你好!有什么可以帮助你的吗?"}],"contextTotalLen":2,"runningTime":1.42},{"nodeId":"pluginOutput","moduleName":"自定义插件输出","moduleType":"pluginOutput","totalPoints":0,"pluginOutput":{"result":"你好!有什么可以帮助你的吗?"},"runningTime":0}] +data: [{"nodeId":"fdDgXQ6SYn8v","moduleName":"AI 对话","moduleType":"chatNode","totalPoints":0.033,"model":"FastAI-3.5","tokens":33,"query":"你好","maxToken":2000,"historyPreview":[{"obj":"Human","value":"你好"},{"obj":"AI","value":"你好!有什么可以帮助你的吗?"}],"contextTotalLen":2,"runningTime":1.42},{"nodeId":"pluginOutput","moduleName":"插件输出","moduleType":"pluginOutput","totalPoints":0,"pluginOutput":{"result":"你好!有什么可以帮助你的吗?"},"runningTime":0}] ``` {{< /markdownify >}} diff --git a/docSite/content/zh-cn/docs/development/upgrading/4811.md b/docSite/content/zh-cn/docs/development/upgrading/4811.md index 5c343ae5691..101e466fe16 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/4811.md +++ b/docSite/content/zh-cn/docs/development/upgrading/4811.md @@ -91,11 +91,12 @@ weight: 813 5. 新增 - 沙盒增加字符串转 base64 全局方法。 6. 新增 - 支持 Openai o1 模型,需增加模型的 `defaultConfig` 配置,覆盖 `temperature`、`max_tokens` 和 `stream`配置,o1 不支持 stream 模式, 详细可重新拉取 `config.json` 配置文件查看。 7. 新增 - AI 对话节点知识库引用,支持配置 role=system 和 role=user,已配置的过自定义提示词的节点将会保持 user 模式,其余用户将转成 system 模式。 -8. 优化 - 工作流嵌套层级限制 20 层,避免因编排不合理导致的无限死循环。 -9. 优化 - 工作流 handler 性能优化。 -10. 优化 - 工作流快捷键,避免调试测试时也会触发。 -11. 优化 - 流输出,切换 tab 时仍可以继续输出。 -12. 优化 - 完善外部文件知识库相关 API -13. 修复 - 知识库选择权限问题。 -14. 修复 - 空 chatId 发起对话,首轮携带用户选择时会异常。 -15. 修复 - createDataset 接口,intro 为赋值。 +8. 新增 - 插件支持上传系统文件。 +9. 优化 - 工作流嵌套层级限制 20 层,避免因编排不合理导致的无限死循环。 +10. 优化 - 工作流 handler 性能优化。 +11. 优化 - 工作流快捷键,避免调试测试时也会触发。 +12. 优化 - 流输出,切换 tab 时仍可以继续输出。 +13. 优化 - 完善外部文件知识库相关 API +14. 修复 - 知识库选择权限问题。 +15. 修复 - 空 chatId 发起对话,首轮携带用户选择时会异常。 +16. 修复 - createDataset 接口,intro 为赋值。 diff --git a/packages/global/core/workflow/template/system/pluginOutput.ts b/packages/global/core/workflow/template/system/pluginOutput.ts index 18e0b3bc878..cd05d15d8b5 100644 --- a/packages/global/core/workflow/template/system/pluginOutput.ts +++ b/packages/global/core/workflow/template/system/pluginOutput.ts @@ -13,7 +13,7 @@ export const PluginOutputModule: FlowNodeTemplateType = { unique: true, forbidDelete: true, avatar: 'core/workflow/template/pluginOutput', - name: i18nT('workflow:custom_plugin_output'), + name: i18nT('workflow:template.plugin_output'), intro: i18nT('workflow:intro_custom_plugin_output'), showStatus: false, version: '481', diff --git a/packages/global/core/workflow/utils.ts b/packages/global/core/workflow/utils.ts index 43661656d44..edabbf5f666 100644 --- a/packages/global/core/workflow/utils.ts +++ b/packages/global/core/workflow/utils.ts @@ -33,6 +33,11 @@ import { RuntimeNodeItemType } from './runtime/type'; import { getReferenceVariableValue } from './runtime/utils'; import { Input_Template_History, Input_Template_UserChatInput } from './template/input'; import { i18nT } from '../../../web/i18n/utils'; +import { RuntimeUserPromptType, UserChatItemType } from '../../core/chat/type'; +import { getNanoid } from '../../common/string/tools'; +import { ChatRoleEnum } from '../../core/chat/constants'; +import { runtimePrompt2ChatsValue } from '../../core/chat/adapt'; +import { getPluginRunContent } from '../../core/app/plugin/utils'; export const getHandleId = (nodeId: string, type: 'source' | 'target', key: string) => { return `${nodeId}-${type}-${key}`; @@ -395,3 +400,26 @@ export function replaceEditorVariable({ } return text || ''; } + +/* Get plugin runtime input user query */ +export const getPluginRunUserQuery = ({ + pluginInputs, + variables, + files = [] +}: { + pluginInputs: FlowNodeInputItemType[]; + variables: Record; + files?: RuntimeUserPromptType['files']; +}): UserChatItemType & { dataId: string } => { + return { + dataId: getNanoid(24), + obj: ChatRoleEnum.Human, + value: runtimePrompt2ChatsValue({ + text: getPluginRunContent({ + pluginInputs: pluginInputs, + variables + }), + files + }) + }; +}; diff --git a/packages/plugins/src/Doc2X/FileImg2text/template.json b/packages/plugins/src/Doc2X/FileImg2text/template.json index 9c877b83293..f47b89853b4 100644 --- a/packages/plugins/src/Doc2X/FileImg2text/template.json +++ b/packages/plugins/src/Doc2X/FileImg2text/template.json @@ -13,16 +13,30 @@ "workflow": { "nodes": [ + { + "nodeId": "pluginConfig", + "name": "common:core.module.template.system_config", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": -90.53591960393504, + "y": -17.580286776561252 + }, + "version": "4811", + "inputs": [], + "outputs": [] + }, { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", "showStatus": false, "position": { - "x": 362.9862638626885, - "y": 6.16353826540589 + "x": 368.6800424053505, + "y": -17.580286776561252 }, "version": "481", "inputs": [ @@ -107,14 +121,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 1661.4708279314577, - "y": 23.877720915480012 + "x": 1796.2235867744578, + "y": 6.419713223438748 }, "version": "481", "inputs": [ @@ -167,7 +181,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input", + "description": "common:core.module.input.description.HTTP Dynamic Input", "customInputConfig": { "selectValueTypeList": [ "string", @@ -178,6 +192,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -187,7 +202,9 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -195,17 +212,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "Doc2X/FileImg2text" + "value": "Doc2X/FileImg2text", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -213,9 +246,11 @@ "valueType": "any", "value": [], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -223,7 +258,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -231,7 +268,29 @@ "valueType": "any", "value": "{\n \"apikey\": \"{{apikey}}\",\n \"files\": {{files}},\n \"img_correction\": {{img_correction}},\n \"formula\": {{formula}}\n}", "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -249,6 +308,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -278,6 +338,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -307,6 +368,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -336,6 +398,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -354,7 +417,7 @@ { "id": "error", "key": "error", - "label": "请求错误", + "label": "workflow:request_error", "description": "HTTP请求错误信息,成功时返回空", "valueType": "object", "type": "static" @@ -362,8 +425,8 @@ { "id": "httpRawResponse", "key": "httpRawResponse", - "label": "原始响应", "required": true, + "label": "workflow:raw_response", "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", "valueType": "any", "type": "static" diff --git a/packages/plugins/src/Doc2X/FilePDF2text/template.json b/packages/plugins/src/Doc2X/FilePDF2text/template.json index afb7ab80052..575060c6bf7 100644 --- a/packages/plugins/src/Doc2X/FilePDF2text/template.json +++ b/packages/plugins/src/Doc2X/FilePDF2text/template.json @@ -13,16 +13,30 @@ "workflow": { "nodes": [ + { + "nodeId": "pluginConfig", + "name": "common:core.module.template.system_config", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": -30.474351356537454, + "y": -101.45216221730038 + }, + "version": "4811", + "inputs": [], + "outputs": [] + }, { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", "showStatus": false, "position": { - "x": 388.243055058894, - "y": -75.09744210499466 + "x": 407.2817920483865, + "y": -101.45216221730038 }, "version": "481", "inputs": [ @@ -88,14 +102,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 1649.7796447278438, - "y": -96.05331527115042 + "x": 1842.070888321717, + "y": -101.45216221730038 }, "version": "481", "inputs": [ @@ -148,7 +162,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input", + "description": "common:core.module.input.description.HTTP Dynamic Input", "customInputConfig": { "selectValueTypeList": [ "string", @@ -159,6 +173,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -168,7 +183,9 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -176,17 +193,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "Doc2X/FilePDF2text" + "value": "Doc2X/FilePDF2text", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -194,9 +227,11 @@ "valueType": "any", "value": [], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -204,7 +239,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -212,7 +249,29 @@ "valueType": "any", "value": "{\n \"apikey\": \"{{apikey}}\",\n \"files\": {{files}},\n \"ocr\": {{ocr}}\n}", "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -230,6 +289,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -259,6 +319,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -288,6 +349,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -306,7 +368,7 @@ { "id": "error", "key": "error", - "label": "请求错误", + "label": "workflow:request_error", "description": "HTTP请求错误信息,成功时返回空", "valueType": "object", "type": "static" @@ -314,8 +376,8 @@ { "id": "httpRawResponse", "key": "httpRawResponse", - "label": "原始响应", "required": true, + "label": "workflow:raw_response", "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", "valueType": "any", "type": "static" diff --git a/packages/plugins/src/Doc2X/URLImg2text/template.json b/packages/plugins/src/Doc2X/URLImg2text/template.json index 77bc4e23e79..f3ea27508fc 100644 --- a/packages/plugins/src/Doc2X/URLImg2text/template.json +++ b/packages/plugins/src/Doc2X/URLImg2text/template.json @@ -15,13 +15,13 @@ "nodes": [ { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", "showStatus": false, "position": { - "x": 388.243055058894, + "x": 353.91678143999377, "y": -75.09744210499466 }, "version": "481", @@ -107,14 +107,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 1654.8021754314786, - "y": -22.243376051504086 + "x": 1703.581616889916, + "y": -14.097442104994656 }, "version": "481", "inputs": [ @@ -147,8 +147,8 @@ "flowNodeType": "httpRequest468", "showStatus": true, "position": { - "x": 1081.967607938733, - "y": -426.08028677656125 + "x": 1000.6685388413375, + "y": -457.0974421049947 }, "version": "481", "inputs": [ @@ -158,7 +158,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input", + "description": "common:core.module.input.description.HTTP Dynamic Input", "customInputConfig": { "selectValueTypeList": [ "string", @@ -169,6 +169,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -178,7 +179,9 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -186,17 +189,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "Doc2X/URLImg2text" + "value": "Doc2X/URLImg2text", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -204,9 +223,11 @@ "valueType": "any", "value": [], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -214,7 +235,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -222,7 +245,29 @@ "valueType": "any", "value": "{\n \"apikey\": \"{{apikey}}\",\n \"url\": \"{{url}}\",\n \"img_correction\": {{img_correction}},\n \"formula\": {{formula}}\n}", "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -240,6 +285,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -269,6 +315,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -298,6 +345,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -327,6 +375,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -345,7 +394,7 @@ { "id": "error", "key": "error", - "label": "请求错误", + "label": "workflow:request_error", "description": "HTTP请求错误信息,成功时返回空", "valueType": "object", "type": "static" @@ -353,8 +402,8 @@ { "id": "httpRawResponse", "key": "httpRawResponse", - "label": "原始响应", "required": true, + "label": "workflow:raw_response", "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", "valueType": "any", "type": "static" @@ -401,6 +450,20 @@ "label": "success" } ] + }, + { + "nodeId": "sWEDDSeuI9ar", + "name": "系统配置", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": -117.03701176267538, + "y": -75.09744210499466 + }, + "version": "4811", + "inputs": [], + "outputs": [] } ], "edges": [ diff --git a/packages/plugins/src/Doc2X/URLPDF2text/template.json b/packages/plugins/src/Doc2X/URLPDF2text/template.json index f3613a279af..32db81c90c5 100644 --- a/packages/plugins/src/Doc2X/URLPDF2text/template.json +++ b/packages/plugins/src/Doc2X/URLPDF2text/template.json @@ -15,7 +15,7 @@ "nodes": [ { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", @@ -88,14 +88,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 1654.8021754314786, - "y": -22.243376051504086 + "x": 1665.6420513111314, + "y": -40.597442104994656 }, "version": "481", "inputs": [ @@ -128,8 +128,8 @@ "flowNodeType": "httpRequest468", "showStatus": true, "position": { - "x": 1081.967607938733, - "y": -426.08028677656125 + "x": 966.3422652224374, + "y": -446.5974421049947 }, "version": "481", "inputs": [ @@ -139,7 +139,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input", + "description": "common:core.module.input.description.HTTP Dynamic Input", "customInputConfig": { "selectValueTypeList": [ "string", @@ -150,6 +150,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -159,7 +160,9 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -167,17 +170,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "Doc2X/URLPDF2text" + "value": "Doc2X/URLPDF2text", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -185,9 +204,11 @@ "valueType": "any", "value": [], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -195,7 +216,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -203,7 +226,29 @@ "valueType": "any", "value": "{\n \"apikey\": \"{{apikey}}\",\n \"url\": \"{{url}}\",\n \"ocr\": {{ocr}}\n}", "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -221,6 +266,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -250,6 +296,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -279,6 +326,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -297,7 +345,7 @@ { "id": "error", "key": "error", - "label": "请求错误", + "label": "workflow:request_error", "description": "HTTP请求错误信息,成功时返回空", "valueType": "object", "type": "static" @@ -305,8 +353,8 @@ { "id": "httpRawResponse", "key": "httpRawResponse", - "label": "原始响应", "required": true, + "label": "workflow:raw_response", "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", "valueType": "any", "type": "static" @@ -353,6 +401,20 @@ "label": "success" } ] + }, + { + "nodeId": "rZmLfANEyyJe", + "name": "系统配置", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": -93.55061402342784, + "y": -55.907069101622824 + }, + "version": "4811", + "inputs": [], + "outputs": [] } ], "edges": [ diff --git a/packages/plugins/src/duckduckgo/search/template.json b/packages/plugins/src/duckduckgo/search/template.json index 37e648b5059..6176d55690f 100644 --- a/packages/plugins/src/duckduckgo/search/template.json +++ b/packages/plugins/src/duckduckgo/search/template.json @@ -14,14 +14,14 @@ "nodes": [ { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", - "avatar": "/imgs/workflow/input.png", + "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", "showStatus": false, "position": { - "x": 393.68844551739926, - "y": -58.80666875994541 + "x": 484.02074451450517, + "y": -79.06127656499825 }, "version": "481", "inputs": [ @@ -49,14 +49,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", - "avatar": "/imgs/workflow/output.png", + "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 1795.6509902691012, - "y": -47.04550785550961 + "x": 1759.5180706702588, + "y": -60.56127656499825 }, "version": "481", "inputs": [ @@ -76,7 +76,7 @@ "nodeId": "hjnVuJAOwyXV", "name": "HTTP 请求", "intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)", - "avatar": "/imgs/workflow/http.png", + "avatar": "core/workflow/template/httpRequest", "flowNodeType": "httpRequest468", "showStatus": true, "position": { @@ -91,7 +91,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input", + "description": "common:core.module.input.description.HTTP Dynamic Input", "customInputConfig": { "selectValueTypeList": [ "string", @@ -102,6 +102,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -111,7 +112,9 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -119,17 +122,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "duckduckgo/search" + "value": "duckduckgo/search", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -137,9 +156,11 @@ "valueType": "any", "value": [], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -147,7 +168,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -155,7 +178,29 @@ "valueType": "any", "value": "{\n \"query\": \"{{query}}\"\n}", "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -173,6 +218,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -188,6 +234,23 @@ } ], "outputs": [ + { + "id": "error", + "key": "error", + "label": "workflow:request_error", + "description": "HTTP请求错误信息,成功时返回空", + "valueType": "object", + "type": "static" + }, + { + "id": "httpRawResponse", + "key": "httpRawResponse", + "required": true, + "label": "workflow:raw_response", + "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", + "valueType": "any", + "type": "static" + }, { "id": "system_addOutputParam", "key": "system_addOutputParam", @@ -215,23 +278,6 @@ "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", @@ -240,6 +286,20 @@ "label": "result" } ] + }, + { + "nodeId": "f1mRh1D85H2D", + "name": "系统配置", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": -28.511358745511643, + "y": -103.56127656499825 + }, + "version": "4811", + "inputs": [], + "outputs": [] } ], "edges": [ diff --git a/packages/plugins/src/duckduckgo/searchImg/template.json b/packages/plugins/src/duckduckgo/searchImg/template.json index e8cd13d4aa2..e3ef73f6e34 100644 --- a/packages/plugins/src/duckduckgo/searchImg/template.json +++ b/packages/plugins/src/duckduckgo/searchImg/template.json @@ -14,14 +14,14 @@ "nodes": [ { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", - "avatar": "/imgs/workflow/input.png", + "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", "showStatus": false, "position": { - "x": 393.68844551739926, - "y": -58.80666875994541 + "x": 422.59478119647315, + "y": -79.06127656499825 }, "version": "481", "inputs": [ @@ -49,14 +49,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", - "avatar": "/imgs/workflow/output.png", + "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 1795.6509902691012, - "y": -47.04550785550961 + "x": 1777.58453046968, + "y": -60.56127656499825 }, "version": "481", "inputs": [ @@ -76,7 +76,7 @@ "nodeId": "hjnVuJAOwyXV", "name": "HTTP 请求", "intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)", - "avatar": "/imgs/workflow/http.png", + "avatar": "core/workflow/template/httpRequest", "flowNodeType": "httpRequest468", "showStatus": true, "position": { @@ -91,7 +91,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input", + "description": "common:core.module.input.description.HTTP Dynamic Input", "customInputConfig": { "selectValueTypeList": [ "string", @@ -102,6 +102,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -111,7 +112,9 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -119,17 +122,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "duckduckgo/searchImg" + "value": "duckduckgo/searchImg", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -137,9 +156,11 @@ "valueType": "any", "value": [], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -147,7 +168,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -155,7 +178,29 @@ "valueType": "any", "value": "{\n \"query\": \"{{query}}\"\n}", "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -173,6 +218,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -188,6 +234,23 @@ } ], "outputs": [ + { + "id": "error", + "key": "error", + "label": "workflow:request_error", + "description": "HTTP请求错误信息,成功时返回空", + "valueType": "object", + "type": "static" + }, + { + "id": "httpRawResponse", + "key": "httpRawResponse", + "required": true, + "label": "workflow:raw_response", + "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", + "valueType": "any", + "type": "static" + }, { "id": "system_addOutputParam", "key": "system_addOutputParam", @@ -215,23 +278,6 @@ "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", @@ -240,6 +286,20 @@ "label": "result" } ] + }, + { + "nodeId": "y3A7CnUp4VOH", + "name": "系统配置", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": -35.73794266528006, + "y": -103.56127656499825 + }, + "version": "4811", + "inputs": [], + "outputs": [] } ], "edges": [ diff --git a/packages/plugins/src/duckduckgo/searchNews/template.json b/packages/plugins/src/duckduckgo/searchNews/template.json index ccd66196ccc..83554adb675 100644 --- a/packages/plugins/src/duckduckgo/searchNews/template.json +++ b/packages/plugins/src/duckduckgo/searchNews/template.json @@ -14,14 +14,14 @@ "nodes": [ { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", - "avatar": "/imgs/workflow/input.png", + "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", "showStatus": false, "position": { - "x": 393.68844551739926, - "y": -58.80666875994541 + "x": 476.7941605947366, + "y": -79.06127656499825 }, "version": "481", "inputs": [ @@ -49,14 +49,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", - "avatar": "/imgs/workflow/output.png", + "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 1795.6509902691012, - "y": -47.04550785550961 + "x": 1761.324716650201, + "y": -60.56127656499825 }, "version": "481", "inputs": [ @@ -76,7 +76,7 @@ "nodeId": "hjnVuJAOwyXV", "name": "HTTP 请求", "intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)", - "avatar": "/imgs/workflow/http.png", + "avatar": "core/workflow/template/httpRequest", "flowNodeType": "httpRequest468", "showStatus": true, "position": { @@ -91,7 +91,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input", + "description": "common:core.module.input.description.HTTP Dynamic Input", "customInputConfig": { "selectValueTypeList": [ "string", @@ -102,6 +102,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -111,7 +112,9 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -119,17 +122,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "duckduckgo/searchNews" + "value": "duckduckgo/searchNews", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -137,9 +156,11 @@ "valueType": "any", "value": [], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -147,7 +168,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -155,7 +178,29 @@ "valueType": "any", "value": "{\n \"query\": \"{{query}}\"\n}", "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -173,6 +218,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -188,6 +234,23 @@ } ], "outputs": [ + { + "id": "error", + "key": "error", + "label": "workflow:request_error", + "description": "HTTP请求错误信息,成功时返回空", + "valueType": "object", + "type": "static" + }, + { + "id": "httpRawResponse", + "key": "httpRawResponse", + "required": true, + "label": "workflow:raw_response", + "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", + "valueType": "any", + "type": "static" + }, { "id": "system_addOutputParam", "key": "system_addOutputParam", @@ -215,23 +278,6 @@ "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", @@ -240,6 +286,20 @@ "label": "result" } ] + }, + { + "nodeId": "dG0Prv5FaR8e", + "name": "系统配置", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": -32.12465070539588, + "y": -103.56127656499825 + }, + "version": "4811", + "inputs": [], + "outputs": [] } ], "edges": [ diff --git a/packages/plugins/src/duckduckgo/searchVideo/template.json b/packages/plugins/src/duckduckgo/searchVideo/template.json index e62e148c30a..4891144f360 100644 --- a/packages/plugins/src/duckduckgo/searchVideo/template.json +++ b/packages/plugins/src/duckduckgo/searchVideo/template.json @@ -14,14 +14,14 @@ "nodes": [ { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", - "avatar": "/imgs/workflow/input.png", + "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", "showStatus": false, "position": { - "x": 393.68844551739926, - "y": -58.80666875994541 + "x": 429.8213651162415, + "y": -79.06127656499825 }, "version": "481", "inputs": [ @@ -49,14 +49,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", - "avatar": "/imgs/workflow/output.png", + "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 1795.6509902691012, - "y": -47.04550785550961 + "x": 1781.1978224295642, + "y": -60.56127656499825 }, "version": "481", "inputs": [ @@ -76,7 +76,7 @@ "nodeId": "hjnVuJAOwyXV", "name": "HTTP 请求", "intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)", - "avatar": "/imgs/workflow/http.png", + "avatar": "core/workflow/template/httpRequest", "flowNodeType": "httpRequest468", "showStatus": true, "position": { @@ -91,7 +91,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input", + "description": "common:core.module.input.description.HTTP Dynamic Input", "customInputConfig": { "selectValueTypeList": [ "string", @@ -102,6 +102,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -111,7 +112,9 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -119,17 +122,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "duckduckgo/searchVideo" + "value": "duckduckgo/searchVideo", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -137,9 +156,11 @@ "valueType": "any", "value": [], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -147,7 +168,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -155,7 +178,29 @@ "valueType": "any", "value": "{\n \"query\": \"{{query}}\"\n}", "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -173,6 +218,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -188,6 +234,23 @@ } ], "outputs": [ + { + "id": "error", + "key": "error", + "label": "workflow:request_error", + "description": "HTTP请求错误信息,成功时返回空", + "valueType": "object", + "type": "static" + }, + { + "id": "httpRawResponse", + "key": "httpRawResponse", + "required": true, + "label": "workflow:raw_response", + "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", + "valueType": "any", + "type": "static" + }, { "id": "system_addOutputParam", "key": "system_addOutputParam", @@ -215,23 +278,6 @@ "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", @@ -240,6 +286,20 @@ "label": "result" } ] + }, + { + "nodeId": "iyF6yGGXuyWn", + "name": "系统配置", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": -8.638252966148258, + "y": -103.56127656499825 + }, + "version": "4811", + "inputs": [], + "outputs": [] } ], "edges": [ diff --git a/packages/plugins/src/feishu/template.json b/packages/plugins/src/feishu/template.json index 8a01a3d5cdc..8728f579010 100644 --- a/packages/plugins/src/feishu/template.json +++ b/packages/plugins/src/feishu/template.json @@ -15,14 +15,14 @@ "nodes": [ { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", "showStatus": false, "position": { - "x": 156.37657136084977, - "y": 90.73380846709256 + "x": 194.3171058153904, + "y": 125.65095361549629 }, "version": "481", "inputs": [ @@ -68,14 +68,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 2110.7223589692912, - "y": 120.17602722162474 + "x": 2128.4279417147436, + "y": 170.6509536154963 }, "version": "481", "inputs": [ @@ -110,7 +110,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input", + "description": "common:core.module.input.description.HTTP Dynamic Input", "customInputConfig": { "selectValueTypeList": [ "string", @@ -121,6 +121,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -130,7 +131,9 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -138,17 +141,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "{{url}}" + "value": "{{url}}", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -156,9 +175,11 @@ "valueType": "any", "value": [], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -166,7 +187,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -174,7 +197,29 @@ "valueType": "any", "value": "{{content}}", "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -192,6 +237,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -221,6 +267,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -239,7 +286,7 @@ { "id": "error", "key": "error", - "label": "请求错误", + "label": "workflow:request_error", "description": "HTTP请求错误信息,成功时返回空", "valueType": "object", "type": "static" @@ -247,8 +294,8 @@ { "id": "httpRawResponse", "key": "httpRawResponse", - "label": "原始响应", "required": true, + "label": "workflow:raw_response", "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", "valueType": "any", "type": "static" @@ -290,8 +337,8 @@ "flowNodeType": "code", "showStatus": true, "position": { - "x": 805.8169457909617, - "y": -159.52218926716316 + "x": 833.6400043909581, + "y": -127.34904638450371 }, "version": "482", "inputs": [ @@ -301,7 +348,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "这些变量会作为代码的运行的输入参数", + "description": "workflow:these_variables_will_be_input_parameters_for_code_execution", "customInputConfig": { "selectValueTypeList": [ "string", @@ -312,6 +359,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -321,19 +369,25 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "codeType", "renderTypeList": ["hidden"], "label": "", - "value": "js" + "value": "js", + "debugLabel": "", + "toolDescription": "" }, { "key": "code", "renderTypeList": ["custom"], "label": "", - "value": "function main({data1}){\n try{\n const parseData = JSON.parse(data1)\n if(typeof parseData === 'object') {\n return parseData\n }\n return {\n \"msg_type\": \"text\",\n content: {\n \"text\": data1\n }\n }\n } catch(err) {\n return {\n \"msg_type\": \"text\",\n content: {\n \"text\": data1\n }\n }\n }\n}" + "value": "function main({data1}){\n try{\n const parseData = JSON.parse(data1)\n if(typeof parseData === 'object') {\n return parseData\n }\n return {\n \"msg_type\": \"text\",\n content: {\n \"text\": data1\n }\n }\n } catch(err) {\n return {\n \"msg_type\": \"text\",\n content: {\n \"text\": data1\n }\n }\n }\n}", + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -351,6 +405,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -369,14 +424,15 @@ { "id": "system_rawResponse", "key": "system_rawResponse", - "label": "完整响应数据", + "label": "workflow:full_response_data", "valueType": "object", - "type": "static" + "type": "static", + "description": "" }, { "id": "error", "key": "error", - "label": "运行错误", + "label": "workflow:execution_error", "description": "代码运行错误信息,成功时返回空", "valueType": "object", "type": "static" @@ -417,6 +473,20 @@ "label": "content" } ] + }, + { + "nodeId": "xDvVyZbQIrPg", + "name": "系统配置", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": -272.2181157945658, + "y": 125.65095361549629 + }, + "version": "4811", + "inputs": [], + "outputs": [] } ], "edges": [ diff --git a/packages/plugins/src/fetchUrl/template.json b/packages/plugins/src/fetchUrl/template.json index 47e63aa91b2..38700ad6a9e 100644 --- a/packages/plugins/src/fetchUrl/template.json +++ b/packages/plugins/src/fetchUrl/template.json @@ -14,7 +14,7 @@ "nodes": [ { "nodeId": "lmpb9v2lo2lk", - "name": "自定义插件输入", + "name": "插件开始", "intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入", "avatar": "/imgs/workflow/input.png", "flowNodeType": "pluginInput", @@ -48,7 +48,7 @@ }, { "nodeId": "i7uow4wj2wdp", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "/imgs/workflow/output.png", "flowNodeType": "pluginOutput", diff --git a/packages/plugins/src/getTime/template.json b/packages/plugins/src/getTime/template.json index 8560c8a3a87..a49d68617cf 100644 --- a/packages/plugins/src/getTime/template.json +++ b/packages/plugins/src/getTime/template.json @@ -12,7 +12,7 @@ "nodes": [ { "nodeId": "lmpb9v2lo2lk", - "name": "自定义插件输入", + "name": "插件开始", "intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入", "avatar": "/imgs/workflow/input.png", "flowNodeType": "pluginInput", @@ -27,7 +27,7 @@ }, { "nodeId": "i7uow4wj2wdp", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "/imgs/workflow/output.png", "flowNodeType": "pluginOutput", diff --git a/packages/plugins/src/mathExprVal/template.json b/packages/plugins/src/mathExprVal/template.json index e49005d7982..717915bc830 100644 --- a/packages/plugins/src/mathExprVal/template.json +++ b/packages/plugins/src/mathExprVal/template.json @@ -48,7 +48,7 @@ }, { "nodeId": "sowtxkCPjvb7", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "/imgs/workflow/output.png", "flowNodeType": "pluginOutput", diff --git a/packages/service/core/workflow/dispatch/plugin/run.ts b/packages/service/core/workflow/dispatch/plugin/run.ts index 0c0ec88a50c..4a43fcfe7e1 100644 --- a/packages/service/core/workflow/dispatch/plugin/run.ts +++ b/packages/service/core/workflow/dispatch/plugin/run.ts @@ -13,8 +13,9 @@ import { authPluginByTmbId } from '../../../../support/permission/app/auth'; import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant'; import { computedPluginUsage } from '../../../app/plugin/utils'; import { filterSystemVariables } from '../utils'; -import { getPluginRunUserQuery } from '../../utils'; import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt'; +import { getPluginRunUserQuery } from '@fastgpt/global/core/workflow/utils'; +import { getPluginInputsFromStoreNodes } from '@fastgpt/global/core/app/plugin/utils'; type RunPluginProps = ModuleDispatchProps<{ [key: string]: any; @@ -79,7 +80,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise; export const dispatchPluginInput = (props: PluginInputProps) => { - const { params } = props; + const { params, query } = props; + const { files } = chatValue2RuntimePrompt(query); - return params; + return { + ...params, + [DispatchNodeResponseKeyEnum.nodeResponse]: {}, + [NodeOutputKeyEnum.userFiles]: files + .map((item) => { + return item?.url ?? ''; + }) + .filter(Boolean) + }; }; diff --git a/packages/service/core/workflow/utils.ts b/packages/service/core/workflow/utils.ts index b7e0b1713ee..327cae65680 100644 --- a/packages/service/core/workflow/utils.ts +++ b/packages/service/core/workflow/utils.ts @@ -32,26 +32,3 @@ export const filterSearchResultsByMaxChars = async ( return results.length === 0 ? list.slice(0, 1) : results; }; - -/* Get plugin runtime input user query */ -export const getPluginRunUserQuery = ({ - nodes, - variables, - files = [] -}: { - nodes: StoreNodeItemType[]; - variables: Record; - files?: RuntimeUserPromptType['files']; -}): UserChatItemType & { dataId: string } => { - return { - dataId: getNanoid(24), - obj: ChatRoleEnum.Human, - value: runtimePrompt2ChatsValue({ - text: getPluginRunContent({ - pluginInputs: getPluginInputsFromStoreNodes(nodes), - variables - }), - files - }) - }; -}; diff --git a/packages/web/components/common/Icon/constants.ts b/packages/web/components/common/Icon/constants.ts index 00fd25f5a93..f0b593331b5 100644 --- a/packages/web/components/common/Icon/constants.ts +++ b/packages/web/components/common/Icon/constants.ts @@ -129,6 +129,7 @@ export const iconPaths = { 'core/chat/feedback/goodLight': () => import('./icons/core/chat/feedback/goodLight.svg'), 'core/chat/fileSelect': () => import('./icons/core/chat/fileSelect.svg'), 'core/chat/finishSpeak': () => import('./icons/core/chat/finishSpeak.svg'), + 'core/chat/imgSelect': () => import('./icons/core/chat/imgSelect.svg'), 'core/chat/quoteFill': () => import('./icons/core/chat/quoteFill.svg'), 'core/chat/quoteSign': () => import('./icons/core/chat/quoteSign.svg'), 'core/chat/recordFill': () => import('./icons/core/chat/recordFill.svg'), diff --git a/packages/web/components/common/Icon/icons/core/chat/imgSelect.svg b/packages/web/components/common/Icon/icons/core/chat/imgSelect.svg new file mode 100644 index 00000000000..e66bb8a536f --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/chat/imgSelect.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/packages/web/i18n/en/app.json b/packages/web/i18n/en/app.json index 05e6482798b..735555197af 100644 --- a/packages/web/i18n/en/app.json +++ b/packages/web/i18n/en/app.json @@ -191,4 +191,4 @@ "user_select": "User Selection", "user_select_tip": "This module can configure multiple options for selection during the dialogue. Different options can lead to different workflow branches." } -} +} \ No newline at end of file diff --git a/packages/web/i18n/en/chat.json b/packages/web/i18n/en/chat.json index 1c3ddf848cf..cb27f805da2 100644 --- a/packages/web/i18n/en/chat.json +++ b/packages/web/i18n/en/chat.json @@ -15,6 +15,8 @@ "delete_all_input_guide_confirm": "Are you sure you want to clear the input guide lexicon?", "empty_directory": "This directory is empty~", "file_amount_over": "Exceeded maximum file quantity {{max}}", + "file_input": "File input", + "file_input_tip": "You can obtain the link to the corresponding file through the \"File Link\" of the [Plug-in Start] node", "in_progress": "In Progress", "input_guide": "Input Guide", "input_guide_lexicon": "Lexicon", @@ -32,9 +34,12 @@ "response": { "node_inputs": "Node Inputs" }, - "select_file": "Select File", - "select_img": "Select Image", + "select": "Select", + "select_file": "Upload File", + "select_file_img": "Upload file / image", + "select_img": "Upload Image", "stream_output": "Stream Output", + "upload": "Upload", "view_citations": "View References", "web_site_sync": "Web Site Sync" -} +} \ No newline at end of file diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index 9d4004e0699..cf1a3fdac6e 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -810,7 +810,6 @@ "QueryExtension": { "placeholder": "For example:\nQuestions about the introduction and use of Python.\nThe current conversation is related to the game 'GTA5'." }, - "Quote prompt setting": "Quote Prompt Configuration", "Select app": "Select App", "Setting quote prompt": "Configure Quote Prompt", "Variable": "Global Variable", @@ -899,7 +898,6 @@ "empty_plugin": "Blank plugin", "empty_workflow": "Blank workflow", "http body placeholder": "Same syntax as Apifox", - "self_input": "Custom plug-in input", "self_output": "Custom plug-in output", "system_config": "System configuration", "system_config_info": "Can configure application system parameters", @@ -1384,10 +1382,6 @@ }, "tag_list": "Tag List", "team_tag": "Team Tag", - "template": { - "Quote Content Tip": "You can customize the structure of the quoted content to better adapt to different scenarios. You can use some variables to configure the template:\n{{q}} - Search content, {{a}} - Expected content, {{source}} - Source, {{sourceId}} - Source file name, {{index}} - The nth quote, they are all optional. Below is the default value:\n{{default}}", - "Quote Prompt Tip": "You can use {{quote}} to insert the quote content template, and use {{question}} to insert the question. Below is the default value:\n{{default}}" - }, "textarea_variable_picker_tip": "Enter \"/\" to select a variable", "tool_field": "Tool Field Parameter Configuration", "undefined_var": "Referenced an undefined variable, add it automatically?", @@ -1490,4 +1484,4 @@ "verification": "Verification", "xx_search_result": "{{key}} Search Results", "yes": "Yes" -} +} \ No newline at end of file diff --git a/packages/web/i18n/en/workflow.json b/packages/web/i18n/en/workflow.json index b2550741538..4032b87eb6a 100644 --- a/packages/web/i18n/en/workflow.json +++ b/packages/web/i18n/en/workflow.json @@ -2,7 +2,6 @@ "Array_element": "Array element", "Code": "Code", "Quote_prompt_setting": "Quote prompt", - "about_xxx_question": "Question regarding xxx", "add_new_input": "Add New Input", "append_application_reply_to_history_as_new_context": "Append the application's reply to the history as new context", "application_call": "Application Call", @@ -28,7 +27,6 @@ "create_link_error": "Error creating link", "custom_feedback": "Custom Feedback", "custom_input": "Custom Input", - "custom_plugin_output": "Custom Plugin Output", "dataset_quote_role": "Role", "dataset_quote_role_system_option_desc": "Historical records should be consistent first (recommended)", "dataset_quote_role_tip": "When set to System, the knowledge base reference content will be placed in the system message, which can ensure the continuity of the history record, but the constraint effect may not be good.\n\nWhen set to User, the knowledge base reference content will be placed in the user message, and the {{question}} variable location needs to be specified. \nIt will have a certain impact on the consistency of historical records, but usually the constraint effect is better.", @@ -57,7 +55,6 @@ "full_response_data": "Full Response Data", "greater_than": "Greater Than", "greater_than_or_equal_to": "Greater Than or Equal To", - "greeting": "Greeting", "http_raw_response_description": "Raw HTTP response. Only accepts string or JSON type response data.", "http_request": "HTTP Request", "http_request_error_info": "HTTP request error information, returns empty on success", @@ -105,7 +102,6 @@ "only_the_reference_type_is_supported": "Only reference type is supported", "optional_value_type": "Optional Value Type", "optional_value_type_tip": "You can specify one or more data types. When dynamically adding fields, users can only select the configured types.", - "other_questions": "Other Questions", "pan_priority": "Touchpad first", "pass_returned_object_as_output_to_next_nodes": "Pass the object returned in the code as output to the next nodes. The variable name needs to correspond to the return key.", "plugin": { @@ -148,6 +144,8 @@ "tool_call_intro": "Automatically select one or more functional blocks for calling through the AI model, or call plugins.", "workflow_start": "Workflow Start" }, + "template.plugin_output": "Plugin output", + "template.plugin_start": "Plugin start", "text_concatenation": "Text Concatenation", "text_content_extraction": "Text Content Extraction", "text_to_extract": "Text to Extract", @@ -167,4 +165,4 @@ "Team cloud": "Team Cloud", "exit_tips": "Your changes have not been saved. 'Exit directly' will not save your edits." } -} +} \ No newline at end of file diff --git a/packages/web/i18n/zh/app.json b/packages/web/i18n/zh/app.json index 2fe7b13f087..2db5ca983ea 100644 --- a/packages/web/i18n/zh/app.json +++ b/packages/web/i18n/zh/app.json @@ -191,4 +191,4 @@ "manage": "写权限基础上,可配置发布渠道、查看对话日志、分配该应用权限" } } -} +} \ No newline at end of file diff --git a/packages/web/i18n/zh/chat.json b/packages/web/i18n/zh/chat.json index add42805230..d6f87ae1426 100644 --- a/packages/web/i18n/zh/chat.json +++ b/packages/web/i18n/zh/chat.json @@ -15,6 +15,8 @@ "delete_all_input_guide_confirm": "确定要清空输入引导词库吗?", "empty_directory": "这个目录已经没东西可选了~", "file_amount_over": "超出最大文件数量 {{max}}", + "file_input": "系统文件", + "file_input_tip": "可通过【插件开始】节点的“文件链接”获取对应文件的链接", "in_progress": "进行中", "input_guide": "输入引导", "input_guide_lexicon": "词库", @@ -32,9 +34,12 @@ "response": { "node_inputs": "节点输入" }, - "select_file": "选择文件", - "select_img": "选择图片", + "select": "选择", + "select_file": "上传文件", + "select_file_img": "上传文件/图片", + "select_img": "上传图片", "stream_output": "流输出", + "upload": "上传", "view_citations": "查看引用", "web_site_sync": "Web站点同步" -} +} \ No newline at end of file diff --git a/packages/web/i18n/zh/common.json b/packages/web/i18n/zh/common.json index 63596d872d7..6c6f32b2d5a 100644 --- a/packages/web/i18n/zh/common.json +++ b/packages/web/i18n/zh/common.json @@ -810,7 +810,6 @@ "QueryExtension": { "placeholder": "例如:\n关于 Python 的介绍和使用等问题。\n当前对话与游戏《GTA5》有关。" }, - "Quote prompt setting": "引用提示词配置", "Select app": "选择应用", "Setting quote prompt": "配置引用提示词", "Variable": "全局变量", @@ -899,8 +898,7 @@ "empty_plugin": "空白插件", "empty_workflow": "空白工作流", "http body placeholder": "与 Apifox 相同的语法", - "self_input": "自定义插件输入", - "self_output": "自定义插件输出", + "self_output": "插件输出", "system_config": "系统配置", "system_config_info": "可以配置应用的系统参数", "work_start": "流程开始" @@ -1384,10 +1382,6 @@ }, "tag_list": "标签列表", "team_tag": "团队标签", - "template": { - "Quote Content Tip": "可以自定义引用内容的结构,以更好的适配不同场景。可以使用一些变量来进行模板配置:\n{{q}} - 检索内容,{{a}} - 预期内容,{{source}} - 来源,{{sourceId}} - 来源文件名,{{index}} - 第 n 个引用,他们都是可选的,下面是默认值:\n{{default}}", - "Quote Prompt Tip": "可以用 {{quote}} 来插入引用内容模板,使用 {{question}} 来插入问题。下面是默认值:\n{{default}}" - }, "textarea_variable_picker_tip": "输入\"/\"可选择变量", "tool_field": "工具字段参数配置", "undefined_var": "引用了未定义的变量,是否自动添加?", @@ -1490,4 +1484,4 @@ "verification": "验证", "xx_search_result": "{{key}} 的搜索结果", "yes": "是" -} +} \ No newline at end of file diff --git a/packages/web/i18n/zh/workflow.json b/packages/web/i18n/zh/workflow.json index 98e22700ad7..e66352981fb 100644 --- a/packages/web/i18n/zh/workflow.json +++ b/packages/web/i18n/zh/workflow.json @@ -2,7 +2,6 @@ "Array_element": "数组元素", "Code": "代码", "Quote_prompt_setting": "引用提示词配置", - "about_xxx_question": "关于 xxx 的问题", "add_new_input": "新增输入", "append_application_reply_to_history_as_new_context": "将该应用回复内容拼接到历史记录中,作为新的上下文返回", "application_call": "应用调用", @@ -28,7 +27,6 @@ "create_link_error": "创建链接异常", "custom_feedback": "自定义反馈", "custom_input": "自定义输入", - "custom_plugin_output": "自定义插件输出", "dataset_quote_role": "角色", "dataset_quote_role_system_option_desc": "历史记录连贯优先(推荐)", "dataset_quote_role_tip": "设置为 System 时,将会把知识库引用内容放置到 system 消息中,可以确保历史记录的连贯性,但约束效果可能不佳,需要多调试。\n设置为 User 时,将会把知识库引用内容放置到 user 消息中,并且需要指定 {{question}} 变量位置。会对历史记录连贯性有一定影响,但通常约束效果更优。", @@ -57,7 +55,6 @@ "full_response_data": "完整响应数据", "greater_than": "大于", "greater_than_or_equal_to": "大于等于", - "greeting": "打招呼", "http_raw_response_description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", "http_request": "HTTP 请求", "http_request_error_info": "HTTP请求错误信息,成功时返回空", @@ -111,7 +108,6 @@ "only_the_reference_type_is_supported": "仅支持引用类型", "optional_value_type": "可选的数据类型", "optional_value_type_tip": "可以指定 1 个或多个数据类型,用户在动态添加字段时,仅可选择配置的类型", - "other_questions": "其他问题", "pan_priority": "触摸板优先", "pass_returned_object_as_output_to_next_nodes": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key", "plugin": { @@ -154,6 +150,8 @@ "tool_call_intro": "通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。", "workflow_start": "流程开始" }, + "template.plugin_output": "插件输出", + "template.plugin_start": "插件开始", "text_concatenation": "文本拼接", "text_content_extraction": "文本内容提取", "text_to_extract": "需要提取的文本", @@ -173,4 +171,4 @@ "Team cloud": "团队云端", "exit_tips": "您的更改尚未保存,「直接退出」将不会保存您的编辑记录。" } -} +} \ No newline at end of file diff --git a/projects/app/data/pluginTemplates/customFeedback.json b/projects/app/data/pluginTemplates/customFeedback.json index 00eed7501ae..47733ee8d14 100644 --- a/projects/app/data/pluginTemplates/customFeedback.json +++ b/projects/app/data/pluginTemplates/customFeedback.json @@ -12,7 +12,7 @@ "nodes": [ { "nodeId": "lmpb9v2lo2lk", - "name": "自定义插件输入", + "name": "插件开始", "intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入", "avatar": "/imgs/workflow/input.png", "flowNodeType": "pluginInput", @@ -68,7 +68,7 @@ }, { "nodeId": "i7uow4wj2wdp", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "/imgs/workflow/output.png", "flowNodeType": "pluginOutput", diff --git a/projects/app/data/pluginTemplates/getCurrentTime.json b/projects/app/data/pluginTemplates/getCurrentTime.json index eac73b9d8c7..9968fab87c6 100644 --- a/projects/app/data/pluginTemplates/getCurrentTime.json +++ b/projects/app/data/pluginTemplates/getCurrentTime.json @@ -12,7 +12,7 @@ "nodes": [ { "nodeId": "lmpb9v2lo2lk", - "name": "自定义插件输入", + "name": "插件开始", "intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入", "avatar": "/imgs/workflow/input.png", "flowNodeType": "pluginInput", @@ -26,7 +26,7 @@ }, { "nodeId": "i7uow4wj2wdp", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "/imgs/workflow/output.png", "flowNodeType": "pluginOutput", diff --git a/projects/app/data/pluginTemplates/textEditor.json b/projects/app/data/pluginTemplates/textEditor.json index 23fb56564c5..b5291778780 100644 --- a/projects/app/data/pluginTemplates/textEditor.json +++ b/projects/app/data/pluginTemplates/textEditor.json @@ -14,7 +14,7 @@ "nodes": [ { "nodeId": "lmpb9v2lo2lk", - "name": "自定义插件输入", + "name": "插件开始", "intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入", "avatar": "/imgs/workflow/input.png", "flowNodeType": "pluginInput", @@ -71,7 +71,7 @@ }, { "nodeId": "i7uow4wj2wdp", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "/imgs/workflow/output.png", "flowNodeType": "pluginOutput", diff --git a/projects/app/data/pluginTemplates/v1/customFeedback.json b/projects/app/data/pluginTemplates/v1/customFeedback.json index 4cfb690b421..b4461d9d3c8 100644 --- a/projects/app/data/pluginTemplates/v1/customFeedback.json +++ b/projects/app/data/pluginTemplates/v1/customFeedback.json @@ -10,7 +10,7 @@ "modules": [ { "moduleId": "w90mfp", - "name": "自定义插件输入", + "name": "插件开始", "flowType": "pluginInput", "showStatus": false, "position": { diff --git a/projects/app/data/pluginTemplates/v1/getCurrentTime.json b/projects/app/data/pluginTemplates/v1/getCurrentTime.json index eb76a295fc2..2c7a4a24f2f 100644 --- a/projects/app/data/pluginTemplates/v1/getCurrentTime.json +++ b/projects/app/data/pluginTemplates/v1/getCurrentTime.json @@ -10,7 +10,7 @@ "modules": [ { "moduleId": "m8dupj", - "name": "自定义插件输入", + "name": "插件开始", "intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入", "avatar": "/imgs/module/input.png", "flowType": "pluginInput", @@ -48,7 +48,7 @@ }, { "moduleId": "bjsa7r", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "/imgs/module/output.png", "flowType": "pluginOutput", diff --git a/projects/app/data/pluginTemplates/v1/textEditor.json b/projects/app/data/pluginTemplates/v1/textEditor.json index 5559672dc4e..9ea905dc0fb 100644 --- a/projects/app/data/pluginTemplates/v1/textEditor.json +++ b/projects/app/data/pluginTemplates/v1/textEditor.json @@ -10,7 +10,7 @@ "modules": [ { "moduleId": "w90mfp", - "name": "自定义插件输入", + "name": "插件开始", "flowType": "pluginInput", "showStatus": false, "position": { @@ -94,7 +94,7 @@ }, { "moduleId": "tze1ju", - "name": "自定义插件输出", + "name": "插件输出", "flowType": "pluginOutput", "showStatus": false, "position": { diff --git a/projects/app/data/pluginTemplates/v1/tfSwitch.json b/projects/app/data/pluginTemplates/v1/tfSwitch.json index 610ec8275c4..6d3bd8ecaae 100644 --- a/projects/app/data/pluginTemplates/v1/tfSwitch.json +++ b/projects/app/data/pluginTemplates/v1/tfSwitch.json @@ -11,7 +11,7 @@ "modules": [ { "moduleId": "w90mfp", - "name": "自定义插件输入", + "name": "插件开始", "flowType": "pluginInput", "showStatus": false, "position": { @@ -78,7 +78,7 @@ }, { "moduleId": "tze1ju", - "name": "自定义插件输出", + "name": "插件输出", "flowType": "pluginOutput", "showStatus": false, "position": { diff --git a/projects/app/public/appMarketTemplates/flux/template.json b/projects/app/public/appMarketTemplates/flux/template.json index 2cc451c7c14..c8277f78f86 100644 --- a/projects/app/public/appMarketTemplates/flux/template.json +++ b/projects/app/public/appMarketTemplates/flux/template.json @@ -9,14 +9,14 @@ "nodes": [ { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", "showStatus": false, "position": { - "x": 351.2046235980429, - "y": -77.41739975794749 + "x": 503.3030871469042, + "y": -91.64434154072819 }, "version": "481", "inputs": [ @@ -44,14 +44,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 1983.6911708285384, - "y": -95.86447885674228 + "x": 1876.2082565873427, + "y": -110.14434154072819 }, "version": "481", "inputs": [ @@ -95,7 +95,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input", + "description": "common:core.module.input.description.HTTP Dynamic Input", "customInputConfig": { "selectValueTypeList": [ "string", @@ -106,6 +106,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -115,7 +116,9 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -123,17 +126,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "https://fal.run/fal-ai/flux-pro" + "value": "https://fal.run/fal-ai/flux-pro", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -147,9 +166,11 @@ } ], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -157,7 +178,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -165,7 +188,29 @@ "valueType": "any", "value": "{\n \"prompt\": \"{{prompt}}\",\n \"image_size\": \"landscape_4_3\",\n \"num_inference_steps\": 28,\n \"guidance_scale\": 3.5\n}", "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -183,6 +228,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -201,7 +247,7 @@ { "id": "error", "key": "error", - "label": "请求错误", + "label": "workflow:request_error", "description": "HTTP请求错误信息,成功时返回空", "valueType": "object", "type": "static" @@ -209,8 +255,8 @@ { "id": "httpRawResponse", "key": "httpRawResponse", - "label": "原始响应", "required": true, + "label": "workflow:raw_response", "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", "valueType": "any", "type": "static" @@ -250,6 +296,20 @@ "label": "images[0].url" } ] + }, + { + "nodeId": "lSYsc889IXDr", + "name": "系统配置", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": 45.52914573588026, + "y": -110.14434154072819 + }, + "version": "4811", + "inputs": [], + "outputs": [] } ], "edges": [ diff --git a/projects/app/public/appMarketTemplates/plugin-dalle/template.json b/projects/app/public/appMarketTemplates/plugin-dalle/template.json index cd0de0ab745..b253e6bec25 100644 --- a/projects/app/public/appMarketTemplates/plugin-dalle/template.json +++ b/projects/app/public/appMarketTemplates/plugin-dalle/template.json @@ -9,14 +9,14 @@ "nodes": [ { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", "showStatus": false, "position": { - "x": 412.7756423516722, - "y": -99.80686112290361 + "x": 421.97302886868476, + "y": -89.7785530936485 }, "version": "481", "inputs": [ @@ -44,14 +44,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 1822.7195641525896, - "y": -193.54601587659562 + "x": 1785.9300180845394, + "y": -108.2785530936485 }, "version": "481", "inputs": [ @@ -95,7 +95,7 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input", + "description": "common:core.module.input.description.HTTP Dynamic Input", "customInputConfig": { "selectValueTypeList": [ "string", @@ -106,6 +106,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -115,7 +116,9 @@ ], "showDescription": false, "showDefaultValue": true - } + }, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -123,17 +126,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "https://api.openai.com/v1/images/generations" + "value": "https://api.openai.com/v1/images/generations", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -147,9 +166,11 @@ } ], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -157,7 +178,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -165,7 +188,29 @@ "valueType": "any", "value": "{\n \"model\": \"dall-e-3\",\n \"prompt\": \"{{prompt}}\",\n \"n\": 1,\n \"size\": \"1024x1024\"\n}", "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "renderTypeList": ["reference"], @@ -183,6 +228,7 @@ "arrayNumber", "arrayBoolean", "arrayObject", + "arrayAny", "any", "chatHistory", "datasetQuote", @@ -201,7 +247,7 @@ { "id": "error", "key": "error", - "label": "请求错误", + "label": "workflow:request_error", "description": "HTTP请求错误信息,成功时返回空", "valueType": "object", "type": "static" @@ -209,8 +255,8 @@ { "id": "httpRawResponse", "key": "httpRawResponse", - "label": "原始响应", "required": true, + "label": "workflow:raw_response", "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", "valueType": "any", "type": "static" @@ -250,6 +296,20 @@ "label": "data[0].url" } ] + }, + { + "nodeId": "c7tRU2qAQoAf", + "name": "系统配置", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": -46.476647046261974, + "y": -89.7785530936485 + }, + "version": "4811", + "inputs": [], + "outputs": [] } ], "edges": [ diff --git a/projects/app/public/appMarketTemplates/plugin-feishu/template.json b/projects/app/public/appMarketTemplates/plugin-feishu/template.json index f8a9189ecbc..a10785c92a4 100644 --- a/projects/app/public/appMarketTemplates/plugin-feishu/template.json +++ b/projects/app/public/appMarketTemplates/plugin-feishu/template.json @@ -9,14 +9,14 @@ "nodes": [ { "nodeId": "pluginInput", - "name": "自定义插件输入", + "name": "插件开始", "intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入", "avatar": "core/workflow/template/workflowStart", "flowNodeType": "pluginInput", "showStatus": false, "position": { - "x": 517.5620777851774, - "y": -173.55711888178655 + "x": 535.7465806305546, + "y": -201.26482361861054 }, "version": "481", "inputs": [ @@ -79,14 +79,14 @@ }, { "nodeId": "pluginOutput", - "name": "自定义插件输出", + "name": "插件输出", "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", - "avatar": "/imgs/workflow/output.png", + "avatar": "core/workflow/template/pluginOutput", "flowNodeType": "pluginOutput", "showStatus": false, "position": { - "x": 1668.9410524554828, - "y": -153.47815316221283 + "x": 1776.027569211593, + "y": -58.264823618610535 }, "version": "481", "inputs": [], @@ -111,33 +111,30 @@ "valueType": "dynamic", "label": "", "required": false, - "description": "core.module.input.description.HTTP Dynamic Input" - }, - { - "key": "text", - "valueType": "string", - "label": "text", - "renderTypeList": ["reference"], - "description": "", - "canEdit": true, - "editField": { - "key": true, - "valueType": true - }, - "value": ["pluginInput", "p0m68Dv5KaIp"] - }, - { - "key": "url", - "valueType": "string", - "label": "url", - "renderTypeList": ["reference"], - "description": "", - "canEdit": true, - "editField": { - "key": true, - "valueType": true + "description": "common:core.module.input.description.HTTP Dynamic Input", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "arrayAny", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true }, - "value": ["pluginInput", "mv52BrPVE6bm"] + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpMethod", @@ -145,17 +142,33 @@ "valueType": "string", "label": "", "value": "POST", - "required": true + "required": true, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpTimeout", + "renderTypeList": ["custom"], + "valueType": "number", + "label": "", + "value": 30, + "min": 5, + "max": 600, + "required": true, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpReqUrl", "renderTypeList": ["hidden"], "valueType": "string", "label": "", - "description": "core.module.input.description.Http Request Url", + "description": "common:core.module.input.description.Http Request Url", "placeholder": "https://api.ai.com/getInventory", "required": false, - "value": "{{url}}" + "value": "{{url}}", + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpHeader", @@ -163,9 +176,11 @@ "valueType": "any", "value": [], "label": "", - "description": "core.module.input.description.Http Request Header", - "placeholder": "core.module.input.description.Http Request Header", - "required": false + "description": "common:core.module.input.description.Http Request Header", + "placeholder": "common:core.module.input.description.Http Request Header", + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpParams", @@ -173,7 +188,9 @@ "valueType": "any", "value": [], "label": "", - "required": false + "required": false, + "debugLabel": "", + "toolDescription": "" }, { "key": "system_httpJsonBody", @@ -181,25 +198,104 @@ "valueType": "any", "value": "{\r\n \"msg_type\": \"text\",\r\n \"content\": {\r\n \"text\": \"{{text}}\"\r\n }\r\n}", "label": "", - "required": false - } - ], - "outputs": [ + "required": false, + "debugLabel": "", + "toolDescription": "" + }, { - "id": "system_addOutputParam", - "key": "system_addOutputParam", - "type": "dynamic", - "valueType": "dynamic", + "key": "system_httpFormBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "system_httpContentType", + "renderTypeList": ["hidden"], + "valueType": "string", + "value": "json", + "label": "", + "required": false, + "debugLabel": "", + "toolDescription": "" + }, + { + "key": "text", + "valueType": "string", + "label": "text", + "renderTypeList": ["reference"], + "description": "", + "canEdit": true, "editField": { "key": true, "valueType": true + }, + "value": ["pluginInput", "p0m68Dv5KaIp"], + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "arrayAny", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true } }, + { + "key": "url", + "valueType": "string", + "label": "url", + "renderTypeList": ["reference"], + "description": "", + "canEdit": true, + "editField": { + "key": true, + "valueType": true + }, + "value": ["pluginInput", "mv52BrPVE6bm"], + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "arrayAny", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + } + } + ], + "outputs": [ { "id": "error", "key": "error", - "label": "请求错误", + "label": "workflow:request_error", "description": "HTTP请求错误信息,成功时返回空", "valueType": "object", "type": "static" @@ -207,13 +303,38 @@ { "id": "httpRawResponse", "key": "httpRawResponse", - "label": "原始响应", "required": true, + "label": "workflow:raw_response", "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", "valueType": "any", "type": "static" + }, + { + "id": "system_addOutputParam", + "key": "system_addOutputParam", + "type": "dynamic", + "valueType": "dynamic", + "label": "", + "editField": { + "key": true, + "valueType": true + } } ] + }, + { + "nodeId": "q3ccNXiZIHoS", + "name": "系统配置", + "intro": "", + "avatar": "core/workflow/template/systemConfig", + "flowNodeType": "pluginConfig", + "position": { + "x": 99.73879703925843, + "y": -201.26482361861054 + }, + "version": "4811", + "inputs": [], + "outputs": [] } ], "edges": [ diff --git a/projects/app/src/components/core/app/FileSelect.tsx b/projects/app/src/components/core/app/FileSelect.tsx index 2da1f25c2c5..a4b8ac1d861 100644 --- a/projects/app/src/components/core/app/FileSelect.tsx +++ b/projects/app/src/components/core/app/FileSelect.tsx @@ -8,7 +8,8 @@ import { useDisclosure, HStack, Switch, - ModalFooter + ModalFooter, + BoxProps } from '@chakra-ui/react'; import React, { useMemo } from 'react'; import { useTranslation } from 'next-i18next'; @@ -25,8 +26,9 @@ import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; const FileSelect = ({ forbidVision = false, value = defaultAppSelectFileConfig, - onChange -}: { + onChange, + ...labelStyle +}: Omit & { forbidVision?: boolean; value?: AppFileSelectConfigType; onChange: (e: AppFileSelectConfigType) => void; @@ -57,7 +59,7 @@ const FileSelect = ({ return ( - {t('app:file_upload')} + {t('app:file_upload')} diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/ChatInput.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/ChatInput.tsx index be7053cfca8..3cfc8b265d0 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/ChatInput.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/ChatInput.tsx @@ -1,34 +1,21 @@ import { useSpeech } from '@/web/common/hooks/useSpeech'; import { useSystemStore } from '@/web/common/system/useSystemStore'; -import { Box, CircularProgress, Flex, HStack, Image, Spinner, Textarea } from '@chakra-ui/react'; +import { Box, Flex, Spinner, Textarea } from '@chakra-ui/react'; import React, { useRef, useEffect, useCallback, useMemo } from 'react'; import { useTranslation } from 'next-i18next'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import MyIcon from '@fastgpt/web/components/common/Icon'; -import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; -import { uploadFile2DB } from '@/web/common/file/controller'; -import { ChatFileTypeEnum } from '@fastgpt/global/core/chat/constants'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; -import { - ChatBoxInputFormType, - ChatBoxInputType, - SendPromptFnType, - UserInputFileItemType -} from '../type'; +import { ChatBoxInputFormType, ChatBoxInputType, SendPromptFnType } from '../type'; import { textareaMinH } from '../constants'; -import { UseFormReturn, useFieldArray } from 'react-hook-form'; +import { UseFormReturn } from 'react-hook-form'; import { ChatBoxContext } from '../Provider'; import dynamic from 'next/dynamic'; import { useContextSelector } from 'use-context-selector'; -import { getNanoid } from '@fastgpt/global/common/string/tools'; import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { documentFileType } from '@fastgpt/global/common/file/constants'; -import { getFileIcon } from '@fastgpt/global/common/file/icon'; -import { useToast } from '@fastgpt/web/hooks/useToast'; -import { clone } from 'lodash'; -import { formatFileSize } from '@fastgpt/global/common/file/tools'; -import MyBox from '@fastgpt/web/components/common/MyBox'; -import { getErrText } from '@fastgpt/global/common/error/utils'; +import FilePreview from '../../components/FilePreview'; +import { useFileUpload } from '../hooks/useFileUpload'; import ComplianceTip from '@/components/common/ComplianceTip/index'; const InputGuideBox = dynamic(() => import('./InputGuideBox')); @@ -56,21 +43,10 @@ const ChatInput = ({ appId: string; }) => { const { isPc } = useSystem(); - const { toast } = useToast(); const { t } = useTranslation(); - const { feConfigs } = useSystemStore(); const { setValue, watch, control } = chatForm; const inputValue = watch('input'); - const { - update: updateFiles, - remove: removeFiles, - fields: fileList, - replace: replaceFiles - } = useFieldArray({ - control, - name: 'files' - }); const { chatId, @@ -82,86 +58,32 @@ const ChatInput = ({ fileSelectConfig } = useContextSelector(ChatBoxContext, (v) => v); + const { + File, + onOpenSelectFile, + fileList, + onSelectFile, + uploadFiles, + selectFileIcon, + selectFileLabel, + showSelectFile, + showSelectImg, + removeFiles, + replaceFiles + } = useFileUpload({ + outLinkAuthData, + chatId: chatId || '', + fileSelectConfig, + control + }); const havInput = !!inputValue || fileList.length > 0; const hasFileUploading = fileList.some((item) => !item.url); const canSendMessage = havInput && !hasFileUploading; - const showSelectFile = fileSelectConfig.canSelectFile; - const showSelectImg = fileSelectConfig.canSelectImg; - const maxSelectFiles = fileSelectConfig.maxFiles ?? 10; - const maxSize = (feConfigs?.uploadFileMaxSize || 1024) * 1024 * 1024; // nkb - const { icon: selectFileIcon, tooltip: selectFileTip } = useMemo(() => { - if (showSelectFile) { - return { - icon: 'core/chat/fileSelect', - tooltip: t('chat:select_file') - }; - } else if (showSelectImg) { - return { - icon: 'core/chat/fileSelect', - tooltip: t('chat:select_img') - }; - } - return {}; - }, [showSelectFile, showSelectImg, t]); - - /* file selector and upload */ - const { File, onOpen: onOpenSelectFile } = useSelectFile({ - fileType: `${showSelectImg ? 'image/*,' : ''} ${showSelectFile ? documentFileType : ''}`, - multiple: true, - maxCount: maxSelectFiles - }); // Upload files useRequest2( async () => { - const filterFiles = fileList.filter((item) => item.status === 0); - - if (filterFiles.length === 0) return; - - replaceFiles(fileList.map((item) => ({ ...item, status: 1 }))); - let errorFileIndex: number[] = []; - - await Promise.allSettled( - filterFiles.map(async (file) => { - const copyFile = clone(file); - copyFile.status = 1; - if (!copyFile.rawFile) return; - - try { - const fileIndex = fileList.findIndex((item) => item.id === file.id)!; - - // Start upload and update process - const { previewUrl } = await uploadFile2DB({ - file: copyFile.rawFile, - bucketName: 'chat', - outLinkAuthData, - metadata: { - chatId - }, - percentListen(e) { - copyFile.process = e; - if (!copyFile.url) { - updateFiles(fileIndex, copyFile); - } - } - }); - - // Update file url - copyFile.url = `${location.origin}${previewUrl}`; - updateFiles(fileIndex, copyFile); - } catch (error) { - errorFileIndex.push(fileList.findIndex((item) => item.id === file.id)!); - toast({ - status: 'warning', - title: t( - getErrText(error, t('common:error.upload_file_error_filename', { name: file.name })) - ) - }); - } - }) - ); - - removeFiles(errorFileIndex); + uploadFiles(); }, { manual: false, @@ -169,78 +91,6 @@ const ChatInput = ({ refreshDeps: [fileList, outLinkAuthData, chatId] } ); - const onSelectFile = useCallback( - async (files: File[]) => { - if (!files || files.length === 0) { - return; - } - // filter max files - if (fileList.length + files.length > maxSelectFiles) { - files = files.slice(0, maxSelectFiles - fileList.length); - toast({ - status: 'warning', - title: t('chat:file_amount_over', { max: maxSelectFiles }) - }); - } - - const filterFilesByMaxSize = files.filter((file) => file.size <= maxSize); - if (filterFilesByMaxSize.length < files.length) { - toast({ - status: 'warning', - title: t('file:some_file_size_exceeds_limit', { maxSize: formatFileSize(maxSize) }) - }); - } - - const loadFiles = await Promise.all( - filterFilesByMaxSize.map( - (file) => - new Promise((resolve, reject) => { - if (file.type.includes('image')) { - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = () => { - const item: UserInputFileItemType = { - id: getNanoid(6), - rawFile: file, - type: ChatFileTypeEnum.image, - name: file.name, - icon: reader.result as string, - status: 0 - }; - resolve(item); - }; - reader.onerror = () => { - reject(reader.error); - }; - } else { - resolve({ - id: getNanoid(6), - rawFile: file, - type: ChatFileTypeEnum.file, - name: file.name, - icon: getFileIcon(file.name), - status: 0 - }); - } - }) - ) - ); - - // Document, image - const concatFileList = clone( - fileList.concat(loadFiles).sort((a, b) => { - if (a.type === ChatFileTypeEnum.image && b.type === ChatFileTypeEnum.file) { - return 1; - } else if (a.type === ChatFileTypeEnum.file && b.type === ChatFileTypeEnum.image) { - return -1; - } - return 0; - }) - ); - replaceFiles(concatFileList); - }, - [fileList, maxSelectFiles, replaceFiles, toast, t, maxSize] - ); /* on send */ const handleSend = useCallback( @@ -330,91 +180,7 @@ const ChatInput = ({ ), [isSpeaking, isTransCription, t] ); - const RenderFilePreview = useMemo( - () => - fileList.length > 0 ? ( - 0 ? 2 : 0} - > - {fileList.map((item, index) => ( - - removeFiles(index)} - className="close-icon" - display={['', 'none']} - zIndex={10} - /> - {item.type === ChatFileTypeEnum.image && ( - {'img'} - )} - {item.type === ChatFileTypeEnum.file && ( - - - - {item.name} - - - )} - {/* Process */} - {!item.url && ( - - - {/* {item.process ?? 0}% */} - - - )} - - ))} - - ) : null, - [fileList, isPc, removeFiles] - ); + const RenderTextarea = useMemo( () => ( 0 ? 1 : 0} pl={[2, 4]}> @@ -431,10 +197,10 @@ const ChatInput = ({ onOpenSelectFile(); }} > - + - + onSelectFile({ files, fileList })} /> )} @@ -510,7 +276,7 @@ const ChatInput = ({ .filter((file) => { return file && fileTypeFilter(file); }) as File[]; - onSelectFile(files); + onSelectFile({ files, fileList }); if (files.length > 0) { e.stopPropagation(); @@ -636,7 +402,7 @@ const ChatInput = ({ [ File, TextareaDom, - fileList.length, + fileList, handleSend, hasFileUploading, havInput, @@ -650,7 +416,7 @@ const ChatInput = ({ onStop, onWhisperRecord, selectFileIcon, - selectFileTip, + selectFileLabel, setValue, showSelectFile, showSelectImg, @@ -700,7 +466,9 @@ const ChatInput = ({ {RenderTranslateLoading} {/* file preview */} - {RenderFilePreview} + + + {RenderTextarea} diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/Provider.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/Provider.tsx index 064813c1023..89ac94c454e 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/Provider.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/Provider.tsx @@ -20,6 +20,7 @@ import { createContext } from 'use-context-selector'; import { FieldValues, UseFormReturn } from 'react-hook-form'; import { VariableInputEnum } from '@fastgpt/global/core/workflow/constants'; import { getChatResData } from '@/web/core/chat/api'; +import { ChatBoxInputFormType } from './type'; export type ChatProviderProps = OutLinkChatAuthProps & { appAvatar?: string; @@ -29,7 +30,7 @@ export type ChatProviderProps = OutLinkChatAuthProps & { chatHistories: ChatSiteItemType[]; setChatHistories: React.Dispatch>; - variablesForm: UseFormReturn; + variablesForm: UseFormReturn; // not chat test params chatId?: string; diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/hooks/useFileUpload.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/hooks/useFileUpload.tsx new file mode 100644 index 00000000000..33b485f605c --- /dev/null +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/hooks/useFileUpload.tsx @@ -0,0 +1,214 @@ +import { useCallback, useMemo } from 'react'; +import { useToast } from '@fastgpt/web/hooks/useToast'; +import { useTranslation } from 'next-i18next'; +import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; +import { uploadFile2DB } from '@/web/common/file/controller'; +import { ChatFileTypeEnum } from '@fastgpt/global/core/chat/constants'; +import { getNanoid } from '@fastgpt/global/common/string/tools'; +import { getFileIcon } from '@fastgpt/global/common/file/icon'; +import { formatFileSize } from '@fastgpt/global/common/file/tools'; +import { clone } from 'lodash'; +import { getErrText } from '@fastgpt/global/common/error/utils'; +import { Control, useFieldArray } from 'react-hook-form'; +import { ChatBoxInputFormType, UserInputFileItemType } from '../type'; +import { AppFileSelectConfigType } from '@fastgpt/global/core/app/type'; +import { documentFileType } from '@fastgpt/global/common/file/constants'; +import { useSystemStore } from '@/web/common/system/useSystemStore'; + +interface UseFileUploadOptions { + outLinkAuthData: any; + chatId: string; + fileSelectConfig: AppFileSelectConfigType; + control: Control; +} + +export const useFileUpload = (props: UseFileUploadOptions) => { + const { outLinkAuthData, chatId, fileSelectConfig, control } = props; + const { toast } = useToast(); + const { t } = useTranslation(); + const { feConfigs } = useSystemStore(); + + const { + update: updateFiles, + remove: removeFiles, + fields: fileList, + replace: replaceFiles + } = useFieldArray({ + control: control, + name: 'files' + }); + + const showSelectFile = fileSelectConfig?.canSelectFile; + const showSelectImg = fileSelectConfig?.canSelectImg; + const maxSelectFiles = fileSelectConfig?.maxFiles ?? 10; + const maxSize = (feConfigs?.uploadFileMaxSize || 1024) * 1024 * 1024; // nkb + + const { icon: selectFileIcon, label: selectFileLabel } = useMemo(() => { + if (showSelectFile && showSelectImg) { + return { + icon: 'core/chat/fileSelect', + label: t('chat:select_file_img') + }; + } else if (showSelectFile) { + return { + icon: 'core/chat/fileSelect', + label: t('chat:select_file') + }; + } else if (showSelectImg) { + return { + icon: 'core/chat/imgSelect', + label: t('chat:select_img') + }; + } + return {}; + }, [showSelectFile, showSelectImg, t]); + + const { File, onOpen: onOpenSelectFile } = useSelectFile({ + fileType: `${showSelectImg ? 'image/*,' : ''} ${showSelectFile ? documentFileType : ''}`, + multiple: true, + maxCount: maxSelectFiles + }); + + const onSelectFile = useCallback( + async ({ files, fileList }: { files: File[]; fileList: UserInputFileItemType[] }) => { + if (!files || files.length === 0) { + return []; + } + + // Filter max files + if (files.length > maxSelectFiles) { + files = files.slice(0, maxSelectFiles); + toast({ + status: 'warning', + title: t('chat:file_amount_over', { max: maxSelectFiles }) + }); + } + + // Filter files by max size + const filterFilesByMaxSize = files.filter((file) => file.size <= maxSize); + if (filterFilesByMaxSize.length < files.length) { + toast({ + status: 'warning', + title: t('file:some_file_size_exceeds_limit', { maxSize: formatFileSize(maxSize) }) + }); + } + + // Convert files to UserInputFileItemType + const loadFiles = await Promise.all( + filterFilesByMaxSize.map( + (file) => + new Promise((resolve, reject) => { + if (file.type.includes('image')) { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => { + const item: UserInputFileItemType = { + id: getNanoid(6), + rawFile: file, + type: ChatFileTypeEnum.image, + name: file.name, + icon: reader.result as string, + status: 0 + }; + resolve(item); + }; + reader.onerror = () => { + reject(reader.error); + }; + } else { + resolve({ + id: getNanoid(6), + rawFile: file, + type: ChatFileTypeEnum.file, + name: file.name, + icon: getFileIcon(file.name), + status: 0 + }); + } + }) + ) + ); + + // Document, image + const concatFileList = clone( + fileList.concat(loadFiles).sort((a, b) => { + if (a.type === ChatFileTypeEnum.image && b.type === ChatFileTypeEnum.file) { + return 1; + } else if (a.type === ChatFileTypeEnum.file && b.type === ChatFileTypeEnum.image) { + return -1; + } + return 0; + }) + ); + replaceFiles(concatFileList); + + return loadFiles; + }, + [maxSelectFiles, replaceFiles, toast, t, maxSize] + ); + + const uploadFiles = async () => { + const filterFiles = fileList.filter((item) => item.status === 0); + + if (filterFiles.length === 0) return; + + replaceFiles(fileList.map((item) => ({ ...item, status: 1 }))); + let errorFileIndex: number[] = []; + + await Promise.allSettled( + filterFiles.map(async (file) => { + const copyFile = clone(file); + copyFile.status = 1; + if (!copyFile.rawFile) return; + + try { + const fileIndex = fileList.findIndex((item) => item.id === file.id)!; + + // Start upload and update process + const { previewUrl } = await uploadFile2DB({ + file: copyFile.rawFile, + bucketName: 'chat', + outLinkAuthData, + metadata: { + chatId + }, + percentListen(e) { + copyFile.process = e; + if (!copyFile.url) { + updateFiles(fileIndex, copyFile); + } + } + }); + + // Update file url + copyFile.url = `${location.origin}${previewUrl}`; + updateFiles(fileIndex, copyFile); + } catch (error) { + errorFileIndex.push(fileList.findIndex((item) => item.id === file.id)!); + toast({ + status: 'warning', + title: t( + getErrText(error, t('common:error.upload_file_error_filename', { name: file.name })) + ) + }); + } + }) + ); + + removeFiles(errorFileIndex); + }; + + return { + File, + onOpenSelectFile, + fileList, + onSelectFile, + uploadFiles, + selectFileIcon, + selectFileLabel, + showSelectFile, + showSelectImg, + removeFiles, + replaceFiles + }; +}; diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx index 586e529a791..54d55574241 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx @@ -430,7 +430,8 @@ const ChatBox = ( file: { type: file.type, name: file.name, - url: file.url || '' + url: file.url || '', + icon: file.icon || '' } })), ...(text diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/type.d.ts b/projects/app/src/components/core/chat/ChatContainer/ChatBox/type.d.ts index 3f7398c5f32..8c7e947a396 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/type.d.ts +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/type.d.ts @@ -22,6 +22,7 @@ export type ChatBoxInputFormType = { input: string; files: UserInputFileItemType[]; chatStarted: boolean; + [key: string]: any; }; export type ChatBoxInputType = { diff --git a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderInput.tsx b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderInput.tsx index c3b426d1df5..2913f6191cd 100644 --- a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderInput.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderInput.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo } from 'react'; +import React, { useCallback, useEffect, useMemo } from 'react'; import { Controller } from 'react-hook-form'; import RenderPluginInput from './renderPluginInput'; import { Box, Button, Flex } from '@chakra-ui/react'; @@ -6,11 +6,19 @@ import { useTranslation } from 'next-i18next'; import { useContextSelector } from 'use-context-selector'; import { PluginRunContext } from '../context'; import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants'; -import { isEqual } from 'lodash'; -import { AppChatConfigType } from '@fastgpt/global/core/app/type'; import Markdown from '@/components/Markdown'; +import MyIcon from '@fastgpt/web/components/common/Icon'; +import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; +import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; +import { useFileUpload } from '../../ChatBox/hooks/useFileUpload'; +import FilePreview from '../../components/FilePreview'; +import { UserChatItemValueItemType } from '@fastgpt/global/core/chat/type'; +import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; +import { ChatBoxInputFormType, UserInputFileItemType } from '../../ChatBox/type'; const RenderInput = () => { + const { t } = useTranslation(); + const { pluginInputs, variablesForm, @@ -19,10 +27,13 @@ const RenderInput = () => { onNewChat, onSubmit, isChatting, - chatConfig + chatConfig, + chatId, + outLinkAuthData, + restartInputStore, + setRestartInputStore } = useContextSelector(PluginRunContext, (v) => v); - const { t } = useTranslation(); const { control, handleSubmit, @@ -31,46 +42,102 @@ const RenderInput = () => { formState: { errors } } = variablesForm; - const defaultFormValues = useMemo(() => { - return pluginInputs.reduce( + const { + File, + onOpenSelectFile, + fileList, + onSelectFile, + uploadFiles, + selectFileIcon, + showSelectFile, + showSelectImg, + removeFiles, + replaceFiles + } = useFileUpload({ + outLinkAuthData, + chatId: chatId || '', + fileSelectConfig: chatConfig?.fileSelectConfig, + control + }); + const isDisabledInput = histories.length > 0; + + const onClickNewChat = useCallback( + (e: ChatBoxInputFormType, files: UserInputFileItemType[] = []) => { + setRestartInputStore({ + ...e, + files + }); + onNewChat?.(); + }, + [onNewChat, setRestartInputStore] + ); + + useEffect(() => { + // Set last run value + if (!isDisabledInput && restartInputStore) { + reset(restartInputStore); + return; + } + + // Set history to default value + + const defaultFormValues = pluginInputs.reduce( (acc, input) => { acc[input.key] = input.defaultValue; return acc; }, {} as Record ); - }, [pluginInputs]); - const historyFormValues = useMemo(() => { - if (histories.length === 0) return undefined; + const historyFormValues = (() => { + if (!isDisabledInput) return undefined; + const historyValue = histories[0].value; + try { + const inputValueString = historyValue.find((item) => item.type === 'text')?.text?.content; + return ( + inputValueString && + JSON.parse(inputValueString).reduce( + ( + acc: Record, + { + key, + value + }: { + key: string; + value: any; + } + ) => ({ ...acc, [key]: value }), + {} + ) + ); + } catch (error) { + console.error('Failed to parse input value:', error); + return undefined; + } + })(); - try { - const inputValueString = histories[0].value[0].text?.content || '[]'; - return JSON.parse(inputValueString).reduce( - ( - acc: Record, - { - key, - value - }: { - key: string; - value: any; - } - ) => ({ ...acc, [key]: value }), - {} - ); - } catch (error) { - console.error('Failed to parse input value:', error); - return undefined; - } - }, [histories]); + // Parse history file + const historyFileList = (() => { + if (!isDisabledInput) return []; + const historyValue = histories[0].value as UserChatItemValueItemType[]; + return historyValue.filter((item) => item.type === 'file').map((item) => item.file); + })(); - useEffect(() => { - if (isEqual(getValues(), defaultFormValues)) return; - reset(historyFormValues || defaultFormValues); - }, [defaultFormValues, getValues, historyFormValues, reset]); + reset({ + ...(historyFormValues || defaultFormValues), + files: historyFileList + }); + }, [getValues, histories, isDisabledInput, pluginInputs, replaceFiles, reset, restartInputStore]); - const isDisabledInput = histories.length > 0; + const hasFileUploading = useMemo(() => { + return fileList.some((item) => !item.url); + }, [fileList]); + + useRequest2(uploadFiles, { + manual: false, + errorToast: t('common:upload_file_error'), + refreshDeps: [fileList, outLinkAuthData, chatId] + }); return ( <> @@ -88,7 +155,35 @@ const RenderInput = () => { )} - + {/* file select */} + {(showSelectFile || showSelectImg) && ( + + + + {t('chat:file_input')} + + + + {histories.length === 0 && ( + + )} + onSelectFile({ files, fileList })} /> + + + + )} + {/* Filed */} {pluginInputs.map((input) => { return ( { /> ); })} + {/* Run Button */} {onStartChat && onNewChat && ( )} diff --git a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/context.tsx b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/context.tsx index 06c591f49c4..ac753cb8f68 100644 --- a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/context.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/context.tsx @@ -1,8 +1,12 @@ import React, { ReactNode, useCallback, useMemo, useRef, useState } from 'react'; import { createContext } from 'use-context-selector'; import { PluginRunBoxProps } from './type'; -import { AIChatItemValueItemType, ChatSiteItemType } from '@fastgpt/global/core/chat/type'; -import { FieldValues } from 'react-hook-form'; +import { + AIChatItemValueItemType, + ChatSiteItemType, + RuntimeUserPromptType +} from '@fastgpt/global/core/chat/type'; +import { FieldValues, useForm } from 'react-hook-form'; import { PluginRunBoxTabEnum } from './constants'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useToast } from '@fastgpt/web/hooks/useToast'; @@ -10,17 +14,23 @@ import { getNanoid } from '@fastgpt/global/common/string/tools'; import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants'; import { generatingMessageProps } from '../type'; import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants'; -import { getPluginRunContent } from '@fastgpt/global/core/app/plugin/utils'; import { useTranslation } from 'next-i18next'; -type PluginRunContextType = PluginRunBoxProps & { - isChatting: boolean; - onSubmit: (e: FieldValues) => Promise; -}; +import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat'; +import { ChatBoxInputFormType, UserInputFileItemType } from '../ChatBox/type'; +import { chats2GPTMessages } from '@fastgpt/global/core/chat/adapt'; +import { getPluginRunUserQuery } from '@fastgpt/global/core/workflow/utils'; + +type PluginRunContextType = OutLinkChatAuthProps & + PluginRunBoxProps & { + isChatting: boolean; + onSubmit: (e: ChatBoxInputFormType, files?: UserInputFileItemType[]) => Promise; + outLinkAuthData: OutLinkChatAuthProps; + restartInputStore?: ChatBoxInputFormType; + setRestartInputStore: React.Dispatch>; + }; export const PluginRunContext = createContext({ pluginInputs: [], - //@ts-ignore - variablesForm: undefined, histories: [], setHistories: function (value: React.SetStateAction): void { throw new Error('Function not implemented.'); @@ -33,15 +43,24 @@ export const PluginRunContext = createContext({ isChatting: false, onSubmit: function (e: FieldValues): Promise { throw new Error('Function not implemented.'); - } + }, + outLinkAuthData: {}, + //@ts-ignore + variablesForm: undefined }); const PluginRunContextProvider = ({ + shareId, + outLinkUid, + teamId, + teamToken, children, ...props }: PluginRunBoxProps & { children: ReactNode }) => { const { pluginInputs, onStartChat, setHistories, histories, setTab } = props; + const [restartInputStore, setRestartInputStore] = useState(); + const { toast } = useToast(); const chatController = useRef(new AbortController()); const { t } = useTranslation(); @@ -50,6 +69,22 @@ const PluginRunContextProvider = ({ chatController.current?.abort('stop'); }, []); + const outLinkAuthData = useMemo( + () => ({ + shareId, + outLinkUid, + teamId, + teamToken + }), + [shareId, outLinkUid, teamId, teamToken] + ); + + const variablesForm = useForm({ + defaultValues: { + files: [] + } + }); + const generatingMessage = useCallback( ({ event, text = '', status, name, tool }: generatingMessageProps) => { setHistories((state) => @@ -144,90 +179,99 @@ const PluginRunContextProvider = ({ [histories] ); - const { runAsync: onSubmit } = useRequest2(async (e: FieldValues) => { - if (!onStartChat) return; - if (isChatting) { - toast({ - title: t('chat:is_chatting'), - status: 'warning' - }); - return; - } - setTab(PluginRunBoxTabEnum.output); - - // reset controller - abortRequest(); - const abortSignal = new AbortController(); - chatController.current = abortSignal; - - setHistories([ - { - dataId: getNanoid(24), - obj: ChatRoleEnum.Human, - status: 'finish', - value: [ - { - type: ChatItemValueTypeEnum.text, - text: { - content: getPluginRunContent({ - pluginInputs, - variables: e - }) + const { runAsync: onSubmit } = useRequest2( + async (e: ChatBoxInputFormType, files?: UserInputFileItemType[]) => { + if (!onStartChat) return; + if (isChatting) { + toast({ + title: t('chat:is_chatting'), + status: 'warning' + }); + return; + } + + // reset controller + abortRequest(); + const abortSignal = new AbortController(); + chatController.current = abortSignal; + + setHistories([ + { + ...getPluginRunUserQuery({ + pluginInputs, + variables: e, + files: files as RuntimeUserPromptType['files'] + }), + status: 'finish' + }, + { + dataId: getNanoid(24), + obj: ChatRoleEnum.AI, + value: [ + { + type: ChatItemValueTypeEnum.text, + text: { + content: '' + } } - } - ] - }, - { - dataId: getNanoid(24), - obj: ChatRoleEnum.AI, - value: [ + ], + status: 'loading' + } + ]); + setTab(PluginRunBoxTabEnum.output); + + const messages = chats2GPTMessages({ + messages: [ { - type: ChatItemValueTypeEnum.text, - text: { - content: '' - } + dataId: getNanoid(24), + obj: ChatRoleEnum.Human, + value: [] } ], - status: 'loading' - } - ]); - - try { - const { responseData } = await onStartChat({ - messages: [], - controller: chatController.current, - generatingMessage, - variables: e + reserveId: true }); - setHistories((state) => - state.map((item, index) => { - if (index !== state.length - 1) return item; - return { - ...item, - status: 'finish', - responseData - }; - }) - ); - } catch (err: any) { - toast({ title: err.message, status: 'error' }); - setHistories((state) => - state.map((item, index) => { - if (index !== state.length - 1) return item; - return { - ...item, - status: 'finish' - }; - }) - ); + try { + const { responseData } = await onStartChat({ + messages: messages, + controller: chatController.current, + generatingMessage, + variables: e + }); + + setHistories((state) => + state.map((item, index) => { + if (index !== state.length - 1) return item; + return { + ...item, + status: 'finish', + responseData + }; + }) + ); + } catch (err: any) { + toast({ title: err.message, status: 'error' }); + setHistories((state) => + state.map((item, index) => { + if (index !== state.length - 1) return item; + return { + ...item, + status: 'finish' + }; + }) + ); + } } - }); + ); const contextValue: PluginRunContextType = { ...props, isChatting, - onSubmit + onSubmit, + outLinkAuthData, + variablesForm, + restartInputStore, + setRestartInputStore }; return {children}; }; diff --git a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/type.d.ts b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/type.d.ts index 231ceaa5761..4a10455b8bd 100644 --- a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/type.d.ts +++ b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/type.d.ts @@ -5,10 +5,11 @@ import { PluginRunBoxTabEnum } from './constants'; import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat'; import React from 'react'; import { onStartChatType } from '../type'; +import { ChatBoxInputFormType } from '../ChatBox/type'; export type PluginRunBoxProps = OutLinkChatAuthProps & { pluginInputs: FlowNodeInputItemType[]; - variablesForm: UseFormReturn; + variablesForm: UseFormReturn; histories: ChatSiteItemType[]; // chatHistories[1] is the response setHistories: React.Dispatch>; diff --git a/projects/app/src/components/core/chat/ChatContainer/components/FilePreview.tsx b/projects/app/src/components/core/chat/ChatContainer/components/FilePreview.tsx new file mode 100644 index 00000000000..d94acd196f7 --- /dev/null +++ b/projects/app/src/components/core/chat/ChatContainer/components/FilePreview.tsx @@ -0,0 +1,121 @@ +import React, { useMemo } from 'react'; +import { FieldArrayWithId } from 'react-hook-form'; +import { ChatBoxInputFormType } from '../ChatBox/type'; +import { Box, CircularProgress, Flex, HStack, Image } from '@chakra-ui/react'; +import MyBox from '@fastgpt/web/components/common/MyBox'; +import MyIcon from '@fastgpt/web/components/common/Icon'; +import { ChatFileTypeEnum } from '@fastgpt/global/core/chat/constants'; +import { useSystem } from '@fastgpt/web/hooks/useSystem'; + +const RenderFilePreview = ({ + fileList, + removeFiles +}: { + fileList: FieldArrayWithId[]; + removeFiles?: (index?: number | number[]) => void; +}) => { + const { isPc } = useSystem(); + + return fileList.length > 0 ? ( + 0 ? 2 : 0} + pr={0.5} + > + {fileList.map((item, index) => { + const isFile = item.type === ChatFileTypeEnum.file; + const isImage = item.type === ChatFileTypeEnum.image; + return ( + + + {removeFiles && ( + removeFiles(index)} + className="close-icon" + display={['', 'none']} + zIndex={10} + /> + )} + {isImage && ( + {'img'} + )} + {isFile && ( + + + + {item.name} + + + )} + {/* Process */} + {!item.url && ( + + + {/* {item.process ?? 0}% */} + + + )} + + + ); + })} + + ) : null; +}; + +export default React.memo(RenderFilePreview); diff --git a/projects/app/src/components/core/chat/ChatContainer/useChat.ts b/projects/app/src/components/core/chat/ChatContainer/useChat.ts index 16f1590938d..e63640e65f6 100644 --- a/projects/app/src/components/core/chat/ChatContainer/useChat.ts +++ b/projects/app/src/components/core/chat/ChatContainer/useChat.ts @@ -2,14 +2,18 @@ import { ChatSiteItemType } from '@fastgpt/global/core/chat/type'; import { useCallback, useRef, useState } from 'react'; import { useForm } from 'react-hook-form'; import { PluginRunBoxTabEnum } from './PluginRunBox/constants'; -import { ComponentRef as ChatComponentRef, SendPromptFnType } from './ChatBox/type'; +import { + ChatBoxInputFormType, + ComponentRef as ChatComponentRef, + SendPromptFnType +} from './ChatBox/type'; import { eventBus, EventNameEnum } from '@/web/common/utils/eventbus'; export const useChat = () => { const ChatBoxRef = useRef(null); const [chatRecords, setChatRecords] = useState([]); - const variablesForm = useForm(); + const variablesForm = useForm(); // plugin const [pluginRunTab, setPluginRunTab] = useState(PluginRunBoxTabEnum.input); diff --git a/projects/app/src/pages/api/core/chat/chatTest.ts b/projects/app/src/pages/api/core/chat/chatTest.ts index cc34539ab3d..3992f1e64ec 100644 --- a/projects/app/src/pages/api/core/chat/chatTest.ts +++ b/projects/app/src/pages/api/core/chat/chatTest.ts @@ -4,7 +4,7 @@ import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/cons import { responseWrite } from '@fastgpt/service/common/response'; import { pushChatUsage } from '@/service/support/wallet/usage/push'; import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants'; -import type { UserChatItemValueItemType } from '@fastgpt/global/core/chat/type'; +import type { UserChatItemType } from '@fastgpt/global/core/chat/type'; import { authApp } from '@fastgpt/service/support/permission/app/auth'; import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch'; import { authCert } from '@fastgpt/service/support/permission/auth/common'; @@ -13,7 +13,10 @@ import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge'; import { removeEmptyUserInput } from '@fastgpt/global/core/chat/utils'; import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant'; import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; -import { updatePluginInputByVariables } from '@fastgpt/global/core/workflow/utils'; +import { + getPluginRunUserQuery, + updatePluginInputByVariables +} from '@fastgpt/global/core/workflow/utils'; import { NextAPI } from '@/service/middleware/entry'; import { GPTMessages2Chats } from '@fastgpt/global/core/chat/adapt'; import { ChatCompletionMessageParam } from '@fastgpt/global/core/ai/type'; @@ -28,6 +31,7 @@ import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node'; import { getWorkflowResponseWrite } from '@fastgpt/service/core/workflow/dispatch/utils'; import { getNanoid } from '@fastgpt/global/common/string/tools'; import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants'; +import { getPluginInputsFromStoreNodes } from '@fastgpt/global/core/app/plugin/utils'; export type Props = { messages: ChatCompletionMessageParam[]; @@ -65,8 +69,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { throw new Error('Edges is not array'); } const chatMessages = GPTMessages2Chats(messages); - const userInput = chatMessages.pop()?.value as UserChatItemValueItemType[] | undefined; - // console.log(JSON.stringify(chatMessages, null, 2), '====', chatMessages.length); /* user auth */ @@ -82,6 +84,22 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { const isPlugin = app.type === AppTypeEnum.plugin; + const userQuestion: UserChatItemType = (() => { + if (isPlugin) { + return getPluginRunUserQuery({ + pluginInputs: getPluginInputsFromStoreNodes(app.modules), + variables, + files: variables.files + }); + } + + const latestHumanChat = chatMessages.pop() as UserChatItemType | undefined; + if (!latestHumanChat) { + throw new Error('User question is empty'); + } + return latestHumanChat; + })(); + let runtimeNodes = storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes, chatMessages)); // Plugin need to replace inputs @@ -89,7 +107,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { runtimeNodes = updatePluginInputByVariables(runtimeNodes, variables); variables = {}; } else { - if (!userInput) { + if (!userQuestion.value) { throw new Error('Params Error'); } } @@ -117,7 +135,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { runtimeNodes, runtimeEdges: initWorkflowEdgeStatus(edges, chatMessages), variables, - query: removeEmptyUserInput(userInput), + query: removeEmptyUserInput(userQuestion.value), chatConfig, histories: chatMessages, stream: true, diff --git a/projects/app/src/pages/api/v1/chat/completions.ts b/projects/app/src/pages/api/v1/chat/completions.ts index 6688781fa12..b8166c1c098 100644 --- a/projects/app/src/pages/api/v1/chat/completions.ts +++ b/projects/app/src/pages/api/v1/chat/completions.ts @@ -49,13 +49,16 @@ import { NextAPI } from '@/service/middleware/entry'; import { getAppLatestVersion } from '@fastgpt/service/core/app/controller'; import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant'; import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; -import { updatePluginInputByVariables } from '@fastgpt/global/core/workflow/utils'; +import { + getPluginRunUserQuery, + updatePluginInputByVariables +} from '@fastgpt/global/core/workflow/utils'; import { getNanoid } from '@fastgpt/global/common/string/tools'; import { getSystemTime } from '@fastgpt/global/common/time/timezone'; import { rewriteNodeOutputByHistories } from '@fastgpt/global/core/workflow/runtime/utils'; import { getWorkflowResponseWrite } from '@fastgpt/service/core/workflow/dispatch/utils'; -import { getPluginRunUserQuery } from '@fastgpt/service/core/workflow/utils'; import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants'; +import { getPluginInputsFromStoreNodes } from '@fastgpt/global/core/app/plugin/utils'; type FastGptWebChatProps = { chatId?: string; // undefined: get histories from messages, '': new chat, 'xxxxx': get histories from db @@ -185,8 +188,11 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { // Get obj=Human history const userQuestion: UserChatItemType = (() => { if (isPlugin) { - // TODO:get plugin files from variables - return getPluginRunUserQuery({ nodes: app.modules, variables }); + return getPluginRunUserQuery({ + pluginInputs: getPluginInputsFromStoreNodes(app.modules), + variables, + files: variables.files + }); } const latestHumanChat = chatMessages.pop() as UserChatItemType | undefined; diff --git a/projects/app/src/pages/app/detail/components/Logs/DetailLogsModal.tsx b/projects/app/src/pages/app/detail/components/Logs/DetailLogsModal.tsx index 8c3848a8f99..8ea6560cad8 100644 --- a/projects/app/src/pages/app/detail/components/Logs/DetailLogsModal.tsx +++ b/projects/app/src/pages/app/detail/components/Logs/DetailLogsModal.tsx @@ -145,6 +145,7 @@ const DetailLogsModal = ({ {isPlugin ? ( { /* node */ const handleRemoveNode = useMemoizedFn((change: NodeRemoveChange, node: Node) => { if (node.data.forbidDelete) { - return toast({ + toast({ status: 'warning', title: t('common:core.workflow.Can not delete node') }); + return false; } // If the node has child nodes, remove the child nodes @@ -438,6 +439,8 @@ export const useWorkflow = () => { setEdges((state) => state.filter((edge) => edge.source !== change.id && edge.target !== change.id) ); + + return true; }); const handleSelectNode = useMemoizedFn((change: NodeSelectionChange) => { // If the node is not selected and the Ctrl key is pressed, select the node @@ -506,8 +509,9 @@ export const useWorkflow = () => { for (const change of changes) { if (change.type === 'remove') { const node = nodes.find((n) => n.id === change.id); - if (node) { - handleRemoveNode(change, node); + // 如果删除失败,则不继续执行 + if (node && !handleRemoveNode(change, node)) { + return; } } else if (change.type === 'select') { handleSelectNode(change); diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/NodePluginConfig.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/NodePluginConfig.tsx index de815750a18..0d84e163ddd 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/NodePluginConfig.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/NodePluginConfig.tsx @@ -13,6 +13,11 @@ import { getAppChatConfig } from '@fastgpt/global/core/workflow/utils'; import { useCreation } from 'ahooks'; import ChatFunctionTip from '@/components/core/app/Tip'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; +import { WorkflowContext } from '../../../context'; +import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant'; +import FileSelect from '@/components/core/app/FileSelect'; +import { userFilesInput } from '@fastgpt/global/core/workflow/template/system/workflowStart'; +import MyIcon from '@fastgpt/web/components/common/Icon'; type ComponentProps = { chatConfig: AppChatConfigType; @@ -60,6 +65,9 @@ const NodePluginConfig = ({ data, selected }: NodeProps) => { > + + + ); @@ -72,6 +80,7 @@ function Instruction({ chatConfig: { instruction }, setAppDetail }: ComponentPro return ( <> + {t('workflow:plugin.Instructions')} @@ -100,3 +109,48 @@ function Instruction({ chatConfig: { instruction }, setAppDetail }: ComponentPro ); } + +function FileSelectConfig({ chatConfig: { fileSelectConfig }, setAppDetail }: ComponentProps) { + const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode); + const nodes = useContextSelector(WorkflowContext, (v) => v.nodes); + const pluginInputNode = nodes.find((item) => item.type === FlowNodeTypeEnum.pluginInput)!; + + return ( + { + setAppDetail((state) => ({ + ...state, + chatConfig: { + ...state.chatConfig, + fileSelectConfig: e + } + })); + + // Dynamic add or delete userFilesInput + const canUploadFiles = e.canSelectFile || e.canSelectImg; + const repeatKey = pluginInputNode?.data.outputs.find( + (item) => item.key === userFilesInput.key + ); + if (canUploadFiles) { + !repeatKey && + onChangeNode({ + nodeId: pluginInputNode.id, + type: 'addOutput', + value: userFilesInput + }); + } else { + repeatKey && + onChangeNode({ + nodeId: pluginInputNode.id, + type: 'delOutput', + key: userFilesInput.key + }); + } + }} + /> + ); +} diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/PluginInput.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/PluginInput.tsx index af9a312d833..c6de188ba29 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/PluginInput.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/PluginInput.tsx @@ -22,6 +22,7 @@ import { WorkflowContext } from '../../../context'; import IOTitle from '../../components/IOTitle'; import dynamic from 'next/dynamic'; import { defaultInput } from './InputEditModal'; +import RenderOutput from '../render/RenderOutput'; const FieldEditModal = dynamic(() => import('./InputEditModal')); @@ -140,9 +141,15 @@ const NodePluginInput = ({ data, selected }: NodeProps) => { }} /> + {!!outputs.length && ( + + + + + )} ); - }, [data, inputs, nodeId, onChangeNode, selected, t]); + }, [data, inputs, nodeId, onChangeNode, outputs, selected, t]); return ( <> diff --git a/projects/app/src/pages/app/detail/components/useChatTest.tsx b/projects/app/src/pages/app/detail/components/useChatTest.tsx index aa40a38be51..9ed1e1aa013 100644 --- a/projects/app/src/pages/app/detail/components/useChatTest.tsx +++ b/projects/app/src/pages/app/detail/components/useChatTest.tsx @@ -72,7 +72,7 @@ export const useChatTest = ({ const CustomChatContainer = useMemoizedFn(() => appDetail.type === AppTypeEnum.plugin ? ( - +