From 022c5abd8bfbf1fd297571bd0cd60f951878eaed Mon Sep 17 00:00:00 2001 From: heheer <1239331448@qq.com> Date: Wed, 10 Jul 2024 17:59:54 +0800 Subject: [PATCH 1/5] feat: add app template market --- packages/global/core/workflow/type/index.d.ts | 15 +- packages/service/core/app/template/type.d.ts | 5 + .../web/components/common/Icon/constants.ts | 1 + .../Icon/icons/core/app/type/templateFill.svg | 41 ++ .../web/components/common/MyModal/index.tsx | 13 +- packages/web/i18n/en/app.json | 8 +- packages/web/i18n/en/common.json | 3 +- packages/web/i18n/zh/app.json | 8 +- packages/web/i18n/zh/common.json | 11 +- .../appTemplates/TranslateRobot/avatar.svg | 1 + .../appTemplates/TranslateRobot/template.json | 584 ++++++++++++++++++ .../public/appTemplates/chatGuide/avatar.png | Bin 0 -> 1215 bytes .../appTemplates/chatGuide/template.json | 255 ++++++++ .../app/public/appTemplates/dalle/avatar.svg | 1 + .../public/appTemplates/dalle/template.json | 409 ++++++++++++ .../app/public/appTemplates/google/avatar.svg | 1 + .../public/appTemplates/google/template.json | 446 +++++++++++++ .../public/appTemplates/toolChat/avatar.png | Bin 0 -> 1531 bytes .../appTemplates/toolChat/template.json | 190 ++++++ .../app/plugin/getSystemPluginTemplates.ts | 1 + .../template/getTemplateMarketItemDetail.ts | 21 + .../app/template/getTemplateMarketList.ts | 16 + .../pages/app/list/components/CreateModal.tsx | 53 +- .../list/components/TemplateMarketModal.tsx | 371 +++++++++++ projects/app/src/pages/app/list/index.tsx | 19 +- projects/app/src/service/core/app/template.ts | 44 ++ projects/app/src/web/core/app/api/template.ts | 8 + 27 files changed, 2492 insertions(+), 33 deletions(-) create mode 100644 packages/service/core/app/template/type.d.ts create mode 100644 packages/web/components/common/Icon/icons/core/app/type/templateFill.svg create mode 100644 projects/app/public/appTemplates/TranslateRobot/avatar.svg create mode 100644 projects/app/public/appTemplates/TranslateRobot/template.json create mode 100644 projects/app/public/appTemplates/chatGuide/avatar.png create mode 100644 projects/app/public/appTemplates/chatGuide/template.json create mode 100644 projects/app/public/appTemplates/dalle/avatar.svg create mode 100644 projects/app/public/appTemplates/dalle/template.json create mode 100644 projects/app/public/appTemplates/google/avatar.svg create mode 100644 projects/app/public/appTemplates/google/template.json create mode 100644 projects/app/public/appTemplates/toolChat/avatar.png create mode 100644 projects/app/public/appTemplates/toolChat/template.json create mode 100644 projects/app/src/pages/api/core/app/template/getTemplateMarketItemDetail.ts create mode 100644 projects/app/src/pages/api/core/app/template/getTemplateMarketList.ts create mode 100644 projects/app/src/pages/app/list/components/TemplateMarketModal.tsx create mode 100644 projects/app/src/service/core/app/template.ts create mode 100644 projects/app/src/web/core/app/api/template.ts diff --git a/packages/global/core/workflow/type/index.d.ts b/packages/global/core/workflow/type/index.d.ts index 66e9bc18ccb..e65b7d2065d 100644 --- a/packages/global/core/workflow/type/index.d.ts +++ b/packages/global/core/workflow/type/index.d.ts @@ -47,8 +47,21 @@ export type WorkflowTemplateType = { // template market export type TemplateMarketItemType = WorkflowTemplateType & { tags?: { id: string; label: string }[]; + type: AppTypeEnum.simple | AppTypeEnum.workflow | AppTypeEnum.plugin; + authorAvatar?: string; }; - +// template market list +export type TemplateMarketListItemType = { + id: string; + name: string; + intro?: string; + author?: string; + tags?: { id: string; label: string }[]; + type: AppTypeEnum.simple | AppTypeEnum.workflow | AppTypeEnum.plugin; + avatar: string; + authorAvatar?: string; +}; +export type TemplateMarketListType = Array; // system plugin export type SystemPluginTemplateItemType = WorkflowTemplateType & { templateType: FlowNodeTemplateTypeEnum; diff --git a/packages/service/core/app/template/type.d.ts b/packages/service/core/app/template/type.d.ts new file mode 100644 index 00000000000..91e0a8e850b --- /dev/null +++ b/packages/service/core/app/template/type.d.ts @@ -0,0 +1,5 @@ +import { TemplateMarketItemType, TemplateMarketListType } from '@fastgpt/global/core/workflow/type'; + +declare global { + var appTemplates: TemplateMarketItemType[]; +} diff --git a/packages/web/components/common/Icon/constants.ts b/packages/web/components/common/Icon/constants.ts index 4587b979bfb..e289c780bf0 100644 --- a/packages/web/components/common/Icon/constants.ts +++ b/packages/web/components/common/Icon/constants.ts @@ -93,6 +93,7 @@ export const iconPaths = { 'core/app/type/plugin': () => import('./icons/core/app/type/plugin.svg'), 'core/app/type/pluginFill': () => import('./icons/core/app/type/pluginFill.svg'), 'core/app/type/simple': () => import('./icons/core/app/type/simple.svg'), + 'core/app/type/templateFill': () => import('./icons/core/app/type/templateFill.svg'), 'core/app/type/workflow': () => import('./icons/core/app/type/workflow.svg'), 'core/app/type/workflowFill': () => import('./icons/core/app/type/workflowFill.svg'), 'core/app/variable/external': () => import('./icons/core/app/variable/external.svg'), diff --git a/packages/web/components/common/Icon/icons/core/app/type/templateFill.svg b/packages/web/components/common/Icon/icons/core/app/type/templateFill.svg new file mode 100644 index 00000000000..aa37e97b734 --- /dev/null +++ b/packages/web/components/common/Icon/icons/core/app/type/templateFill.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/web/components/common/MyModal/index.tsx b/packages/web/components/common/MyModal/index.tsx index c01253a66ff..00d212d019f 100644 --- a/packages/web/components/common/MyModal/index.tsx +++ b/packages/web/components/common/MyModal/index.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { ReactElement } from 'react'; import { Modal, ModalOverlay, @@ -22,6 +22,8 @@ export interface MyModalProps extends ModalContentProps { isOpen: boolean; onClose?: () => void; closeOnOverlayClick?: boolean; + customModalHeader?: ReactElement; + headerColor?: string; } const MyModal = ({ @@ -35,6 +37,8 @@ const MyModal = ({ w = 'auto', maxW = ['90vw', '600px'], closeOnOverlayClick = true, + customModalHeader, + headerColor, ...props }: MyModalProps) => { const isPc = useSystem(); @@ -58,12 +62,13 @@ const MyModal = ({ boxShadow={'7'} {...props} > - {!title && onClose && } - {!!title && ( + {!!customModalHeader && customModalHeader} + {!customModalHeader && !title && onClose && } + {!customModalHeader && !!title && ( \ No newline at end of file diff --git a/projects/app/public/appTemplates/TranslateRobot/template.json b/projects/app/public/appTemplates/TranslateRobot/template.json new file mode 100644 index 00000000000..09fcb40ac89 --- /dev/null +++ b/projects/app/public/appTemplates/TranslateRobot/template.json @@ -0,0 +1,584 @@ +{ + "id": "TranslateRobot", + "name": "多轮翻译机器人", + "intro": "通过 4 轮翻译,提高翻译英文的质量", + "author": "Fastgpt Team", + "avatar": "/appTemplates/TranslateRobot/avatar.svg", + "authorAvatar": "/icon/logo.svg", + "tags": [ + { "id": "recommendation", "label": "推荐" }, + { "id": "office-services", "label": "办公服务" } + ], + "type": "advanced", + "workflow": { + "nodes": [ + { + "nodeId": "userGuide", + "name": "系统配置", + "intro": "可以配置应用的系统参数", + "avatar": "/imgs/workflow/userGuide.png", + "flowNodeType": "userGuide", + "position": { + "x": 531.2422736065552, + "y": -486.7611729549753 + }, + "version": "481", + "inputs": [ + { + "key": "welcomeText", + "renderTypeList": ["hidden"], + "valueType": "string", + "label": "core.app.Welcome Text", + "value": "" + }, + { + "key": "variables", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "core.app.Chat Variable", + "value": [] + }, + { + "key": "questionGuide", + "valueType": "boolean", + "renderTypeList": ["hidden"], + "label": "core.app.Question Guide", + "value": false + }, + { + "key": "tts", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "", + "value": { + "type": "web" + } + }, + { + "key": "whisper", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "", + "value": { + "open": false, + "autoSend": false, + "autoTTSResponse": false + } + }, + { + "key": "scheduleTrigger", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "", + "value": null + } + ], + "outputs": [] + }, + { + "nodeId": "448745", + "name": "流程开始", + "intro": "", + "avatar": "/imgs/workflow/userChatInput.svg", + "flowNodeType": "workflowStart", + "position": { + "x": 558.4082376415505, + "y": 123.72387429194112 + }, + "version": "481", + "inputs": [ + { + "key": "userChatInput", + "renderTypeList": ["reference", "textarea"], + "valueType": "string", + "label": "用户问题", + "required": true, + "toolDescription": "用户问题" + } + ], + "outputs": [ + { + "id": "userChatInput", + "key": "userChatInput", + "label": "core.module.input.label.user question", + "type": "static", + "valueType": "string" + } + ] + }, + { + "nodeId": "loOvhld2ZTKa", + "name": "第一轮翻译", + "intro": "AI 大模型对话", + "avatar": "/imgs/workflow/AI.png", + "flowNodeType": "chatNode", + "showStatus": true, + "position": { + "x": 1748.8252410306534, + "y": -245.08260685989214 + }, + "version": "481", + "inputs": [ + { + "key": "model", + "renderTypeList": ["settingLLMModel", "reference"], + "label": "core.module.input.label.aiModel", + "valueType": "string", + "value": "gpt-4o" + }, + { + "key": "temperature", + "renderTypeList": ["hidden"], + "label": "", + "value": 0, + "valueType": "number", + "min": 0, + "max": 10, + "step": 1 + }, + { + "key": "maxToken", + "renderTypeList": ["hidden"], + "label": "", + "value": 2000, + "valueType": "number", + "min": 100, + "max": 4000, + "step": 50 + }, + { + "key": "isResponseAnswerText", + "renderTypeList": ["hidden"], + "label": "", + "value": true, + "valueType": "boolean" + }, + { + "key": "quoteTemplate", + "renderTypeList": ["hidden"], + "label": "", + "valueType": "string" + }, + { + "key": "quotePrompt", + "renderTypeList": ["hidden"], + "label": "", + "valueType": "string" + }, + { + "key": "systemPrompt", + "renderTypeList": ["textarea", "reference"], + "max": 3000, + "valueType": "string", + "label": "core.ai.Prompt", + "description": "core.app.tip.chatNodeSystemPromptTip", + "placeholder": "core.app.tip.chatNodeSystemPromptTip", + "value": "# Role: 资深英汉翻译专家\n\n## Background:\n你是一位经验丰富的英汉翻译专家,精通英汉互译,尤其擅长将英文文章译成流畅易懂的现代汉语。你曾多次带领团队完成大型翻译项目,译文广受好评。\n\n## Attention:\n- 翻译过程中要始终坚持\"信、达、雅\"的原则,但\"达\"尤为重要\n- 译文要符合现代汉语的表达习惯,通俗易懂,连贯流畅 \n- 避免使用过于文绉绉的表达和晦涩难懂的典故引用\n\n## Profile: \n- Author: 米开朗基杨 \n- Version: 0.2\n- Language: 中文\n- Description: 你是一位资深英汉翻译专家,精通英汉互译。你擅长将英文文章译成地道流畅的现代汉语,表达准确易懂,符合当代中文语言习惯。\n\n## Constraints:\n- 必须严格遵循四轮翻译流程:直译、意译、校审、定稿 \n- 译文要忠实原文,准确无误,不能遗漏或曲解原意\n- 译文应以现代白话文为主,避免过多使用文言文和古典诗词\n- 每一轮翻译前后必须添加【思考】和【翻译】标记\n- 最终译文使用Markdown的代码块呈现\n\n## Goals:\n- 通过四轮翻译流程,将英文原文译成高质量的现代汉语译文 \n- 译文要准确传达原文意思,语言表达力求浅显易懂,朗朗上口\n- 适度使用一些熟语俗语、流行网络用语等,增强译文的亲和力\n- 在直译的基础上,提供至少2个不同风格的意译版本供选择\n\n## Skills:\n- 精通英汉双语,具有扎实的语言功底和丰富的翻译经验\n- 擅长将英语表达习惯转换为地道自然的现代汉语\n- 对当代中文语言的发展变化有敏锐洞察,善于把握语言流行趋势\n\n## Workflow:\n1. 第一轮直译:逐字逐句忠实原文,不遗漏任何信息\n2. 第二轮意译:在直译的基础上用通俗流畅的现代汉语意译原文,至少提供2个不同风格的版本\n3. 第三轮校审:仔细审视译文,消除偏差和欠缺,使译文更加地道易懂 \n4. 第四轮定稿:择优选取,反复修改润色,最终定稿出一个简洁畅达、符合大众阅读习惯的译文\n\n## OutputFormat: \n- 每一轮翻译前用【思考】说明该轮要点\n- 每一轮翻译后用【翻译】呈现译文\n- 在\\`\\`\\`代码块中展示最终定稿译文\n\n## Suggestions:\n- 直译时力求忠实原文,但不要过于拘泥逐字逐句\n- 意译时在准确表达原意的基础上,用最朴实无华的现代汉语来表达 \n- 校审环节重点关注译文是否符合当代汉语表达习惯,是否通俗易懂\n- 定稿时适度采用一些熟语谚语、网络流行语等,使译文更接地气\n- 善于利用中文的灵活性,用不同的表述方式展现同一内容,提高译文的可读性\n\n## Initialization\n作为一名资深英汉翻译专家,你必须严格遵循翻译流程的各项要求。首先请向用户问好,介绍你将带领团队完成翻译任务,力求将英文原文译成通俗易懂的现代汉语。然后简要说明四轮翻译流程,请用户提供英文原文,开始进行翻译工作。" + }, + { + "key": "history", + "renderTypeList": ["numberInput", "reference"], + "valueType": "chatHistory", + "label": "core.module.input.label.chat history", + "description": "最多携带多少轮对话记录", + "required": true, + "min": 0, + "max": 50, + "value": 6 + }, + { + "key": "userChatInput", + "renderTypeList": ["reference", "textarea"], + "valueType": "string", + "label": "用户问题", + "required": true, + "toolDescription": "用户问题", + "value": ["gBDvemE4FBhp", "system_text"] + }, + { + "key": "quoteQA", + "renderTypeList": ["settingDatasetQuotePrompt"], + "label": "", + "debugLabel": "知识库引用", + "description": "", + "valueType": "datasetQuote" + } + ], + "outputs": [ + { + "id": "history", + "key": "history", + "required": true, + "label": "core.module.output.label.New context", + "description": "core.module.output.description.New context", + "valueType": "chatHistory", + "type": "static" + }, + { + "id": "answerText", + "key": "answerText", + "required": true, + "label": "core.module.output.label.Ai response content", + "description": "core.module.output.description.Ai response content", + "valueType": "string", + "type": "static" + } + ] + }, + { + "nodeId": "w0oBbQ3YJHye", + "name": "代码运行", + "intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。", + "avatar": "/imgs/workflow/code.svg", + "flowNodeType": "code", + "showStatus": true, + "position": { + "x": 2522.61682940854, + "y": -79.74569750380468 + }, + "version": "482", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": ["addInputParam"], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "这些变量会作为代码的运行的输入参数", + "editField": { + "key": true, + "valueType": true + }, + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + } + }, + { + "key": "codeType", + "renderTypeList": ["hidden"], + "label": "", + "value": "js" + }, + { + "key": "code", + "renderTypeList": ["custom"], + "label": "", + "value": "function main({data1}) {\n const codeBlocks = data1.match(/```[\\s\\S]*?```/g);\n\n if (codeBlocks && codeBlocks.length > 0) {\n const lastCodeBlock = codeBlocks[codeBlocks.length - 1];\n const cleanedCodeBlock = lastCodeBlock.replace(/```[a-zA-Z]*|```/g, '').trim();\n \n return {\n result: cleanedCodeBlock\n };\n }\n\n return {\n result: '未截取到代码块内容'\n };\n}\n" + }, + { + "key": "data1", + "valueType": "string", + "label": "data1", + "renderTypeList": ["reference"], + "description": "", + "canEdit": true, + "editField": { + "key": true, + "valueType": true + }, + "value": ["loOvhld2ZTKa", "answerText"] + } + ], + "outputs": [ + { + "id": "system_addOutputParam", + "key": "system_addOutputParam", + "type": "dynamic", + "valueType": "dynamic", + "label": "", + "description": "将代码中 return 的对象作为输出,传递给后续的节点" + }, + { + "id": "system_rawResponse", + "key": "system_rawResponse", + "label": "完整响应数据", + "valueType": "object", + "type": "static" + }, + { + "id": "error", + "key": "error", + "label": "运行错误", + "description": "代码运行错误信息,成功时返回空", + "valueType": "object", + "type": "static" + }, + { + "id": "qLUQfhG0ILRX", + "type": "dynamic", + "key": "result", + "valueType": "string", + "label": "result" + }, + { + "id": "gR0mkQpJ4Og8", + "type": "dynamic", + "key": "data2", + "valueType": "string", + "label": "data2" + } + ] + }, + { + "nodeId": "foO69L5FOmDQ", + "name": "指定回复", + "intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。", + "avatar": "/imgs/workflow/reply.png", + "flowNodeType": "answerNode", + "position": { + "x": 3798.4479531204515, + "y": 116.03040242110023 + }, + "version": "481", + "inputs": [ + { + "key": "text", + "renderTypeList": ["textarea", "reference"], + "valueType": "any", + "required": true, + "label": "core.module.input.label.Response content", + "description": "core.module.input.description.Response content", + "placeholder": "core.module.input.description.Response content", + "selectedTypeIndex": 1, + "value": ["bcqtxqxE2R6o", "system_text"] + } + ], + "outputs": [] + }, + { + "nodeId": "gBDvemE4FBhp", + "name": "文本拼接", + "intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。", + "avatar": "/imgs/workflow/textEditor.svg", + "flowNodeType": "textEditor", + "position": { + "x": 1031.371061396644, + "y": 38.65839420088383 + }, + "version": "486", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": ["addInputParam"], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "可以引用其他节点的输出,作为文本拼接的变量,通过 {{字段名}} 来引用变量", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": false + } + }, + { + "key": "system_textareaInput", + "renderTypeList": ["textarea"], + "valueType": "string", + "required": true, + "label": "拼接文本", + "placeholder": "可通过 {{字段名}} 来引用变量", + "value": "原文:\n\"\"\"\n{{q}}\n\"\"\"" + }, + { + "renderTypeList": ["reference"], + "valueType": "string", + "canEdit": true, + "key": "q", + "label": "q", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": false + }, + "required": true, + "value": ["448745", "userChatInput"] + } + ], + "outputs": [ + { + "id": "system_text", + "key": "system_text", + "label": "拼接结果", + "type": "static", + "valueType": "string" + } + ] + }, + { + "nodeId": "bcqtxqxE2R6o", + "name": "合并输出结果", + "intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。", + "avatar": "/imgs/workflow/textEditor.svg", + "flowNodeType": "textEditor", + "position": { + "x": 3113.6227559936665, + "y": 12.909197647746709 + }, + "version": "486", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": ["addInputParam"], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "可以引用其他节点的输出,作为文本拼接的变量,通过 {{字段名}} 来引用变量", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": false + } + }, + { + "key": "system_textareaInput", + "renderTypeList": ["textarea"], + "valueType": "string", + "required": true, + "label": "拼接文本", + "placeholder": "可通过 {{字段名}} 来引用变量", + "value": "****** \n\n最终翻译结果如下: \n\n```\n{{result}}\n```" + }, + { + "renderTypeList": ["reference"], + "valueType": "string", + "canEdit": true, + "key": "result", + "label": "result", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": false + }, + "required": true, + "value": ["w0oBbQ3YJHye", "qLUQfhG0ILRX"] + } + ], + "outputs": [ + { + "id": "system_text", + "key": "system_text", + "label": "拼接结果", + "type": "static", + "valueType": "string" + } + ] + } + ], + "edges": [ + { + "source": "loOvhld2ZTKa", + "target": "w0oBbQ3YJHye", + "sourceHandle": "loOvhld2ZTKa-source-right", + "targetHandle": "w0oBbQ3YJHye-target-left" + }, + { + "source": "448745", + "target": "gBDvemE4FBhp", + "sourceHandle": "448745-source-right", + "targetHandle": "gBDvemE4FBhp-target-left" + }, + { + "source": "gBDvemE4FBhp", + "target": "loOvhld2ZTKa", + "sourceHandle": "gBDvemE4FBhp-source-right", + "targetHandle": "loOvhld2ZTKa-target-left" + }, + { + "source": "w0oBbQ3YJHye", + "target": "bcqtxqxE2R6o", + "sourceHandle": "w0oBbQ3YJHye-source-right", + "targetHandle": "bcqtxqxE2R6o-target-left" + }, + { + "source": "bcqtxqxE2R6o", + "target": "foO69L5FOmDQ", + "sourceHandle": "bcqtxqxE2R6o-source-right", + "targetHandle": "foO69L5FOmDQ-target-left" + } + ], + "chatConfig": { + "scheduledTriggerConfig": { + "cronString": "", + "timezone": "Asia/Shanghai", + "defaultPrompt": "" + } + } + } +} diff --git a/projects/app/public/appTemplates/chatGuide/avatar.png b/projects/app/public/appTemplates/chatGuide/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..598f9ed5eec4b751bba24406784a560925351e33 GIT binary patch literal 1215 zcmV;w1VHPx(c}YY;RCr$Pn_W`dFc5%OHka^I!$}|yP;LQv>@=JKat6}rBjFbOJdmEGe)A=2 zt0UPVwzalaE7`2iWvy;MK@Q#3{JuADG;$-CC|58;uD4#3qW@Da|U_-_-O;jEFz8< z93SBfAiH`vheEt_i4XW(3Q;_Fh2R9>fCsrfp+cDa@P(~IQ1eL6$aje$dwF#((8W!bP4{^XTymH+}JKFRCS467vF2!Qf{ zwY_wVFh&E6M2O1j1fQUxw97o(W^DGx#d3BBqDqVJv3nGs3ep;-gjf&r4kY((~T{pfvt1pufSlcEbXbW-IU z07%%1KoI~p<1zyDXKBb$Ho7d?7S;0 z`glvgAp`X8dl(Bq%+qzyJ9#uO@d&ZDegpx4nWwGcuJ7@@WB>~MfpRY)HR z9<4V|c5i14k$ptmA+g3=c{>-7dyIrmkk6Cr%p<)DnblWXck z9Gem_A^>7x;Wlt`<-ZwXCn!|Qp~^YT*-lh#hAQgpqi}YDLIp>aV~k(*y#&Db1MHog zmjfj2F|0&%->VZL^z_B50f23uRL4e@BlOkC-)l!=?8{JQf@ z@c(kOy?TNikT@^N(H=0O3UZOb4T+--g5MBQD}r#BT6_Q;g(dg`s6n{4=K3LK zEVPag05pX1l^IpJ;Z~UydO)uFLIEft9N0@!6c`}^?An`@H4FjZ1H{m8j8bOUCNm^} z28hpmk+KiM7yueeLsf{DFzRoK+vaJg@6p3m)tL3AsSrIXeMR+ptrTZk=e}}e*l1Ff d?{>Xj`xmSFFqv0@P^AC>002ovPDHLkV1g{#E \ No newline at end of file diff --git a/projects/app/public/appTemplates/dalle/template.json b/projects/app/public/appTemplates/dalle/template.json new file mode 100644 index 00000000000..44be36000e2 --- /dev/null +++ b/projects/app/public/appTemplates/dalle/template.json @@ -0,0 +1,409 @@ +{ + "id": "dalle", + "name": "Dalle3绘图", + "intro": "通过请求Dalle3接口绘图,需要有 api key", + "author": "Fastgpt Team", + "avatar": "/appTemplates/dalle/avatar.svg", + "authorAvatar": "/icon/logo.svg", + "type": "advanced", + "tags": [ + { "id": "recommendation", "label": "推荐" }, + { "id": "image", "label": "图片生成" } + ], + "workflow": { + "nodes": [ + { + "nodeId": "userGuide", + "name": "系统配置", + "intro": "可以配置应用的系统参数", + "avatar": "/imgs/workflow/userGuide.png", + "flowNodeType": "userGuide", + "position": { + "x": 531.2422736065552, + "y": -486.7611729549753 + }, + "version": "481", + "inputs": [ + { + "key": "welcomeText", + "renderTypeList": ["hidden"], + "valueType": "string", + "label": "core.app.Welcome Text", + "value": "" + }, + { + "key": "variables", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "core.app.Chat Variable", + "value": [] + }, + { + "key": "questionGuide", + "valueType": "boolean", + "renderTypeList": ["hidden"], + "label": "core.app.Question Guide", + "value": false + }, + { + "key": "tts", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "", + "value": { + "type": "web" + } + }, + { + "key": "whisper", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "", + "value": { + "open": false, + "autoSend": false, + "autoTTSResponse": false + } + }, + { + "key": "scheduleTrigger", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "", + "value": null + } + ], + "outputs": [] + }, + { + "nodeId": "448745", + "name": "流程开始", + "intro": "", + "avatar": "/imgs/workflow/userChatInput.svg", + "flowNodeType": "workflowStart", + "position": { + "x": 532.1275542407774, + "y": 46.03775600322817 + }, + "version": "481", + "inputs": [ + { + "key": "userChatInput", + "renderTypeList": ["reference", "textarea"], + "valueType": "string", + "label": "用户问题", + "required": true, + "toolDescription": "用户问题" + } + ], + "outputs": [ + { + "id": "userChatInput", + "key": "userChatInput", + "label": "core.module.input.label.user question", + "type": "static", + "valueType": "string" + } + ] + }, + { + "nodeId": "tMyUnRL5jIrC", + "name": "HTTP 请求", + "intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)", + "avatar": "/imgs/workflow/http.png", + "flowNodeType": "httpRequest468", + "showStatus": true, + "position": { + "x": 931.6784209157559, + "y": -162.36850541742047 + }, + "version": "486", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": ["addInputParam"], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "core.module.input.description.HTTP Dynamic Input", + "editField": { + "key": true, + "valueType": true + }, + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + } + }, + { + "key": "system_httpMethod", + "renderTypeList": ["custom"], + "valueType": "string", + "label": "", + "value": "POST", + "required": true + }, + { + "key": "system_httpReqUrl", + "renderTypeList": ["hidden"], + "valueType": "string", + "label": "", + "description": "core.module.input.description.Http Request Url", + "placeholder": "https://api.ai.com/getInventory", + "required": false, + "value": "https://api.openai.com/v1/images/generations" + }, + { + "key": "system_httpHeader", + "renderTypeList": ["custom"], + "valueType": "any", + "value": [ + { + "key": "Authorization", + "type": "string", + "value": "Bearer " + } + ], + "label": "", + "description": "core.module.input.description.Http Request Header", + "placeholder": "core.module.input.description.Http Request Header", + "required": false + }, + { + "key": "system_httpParams", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [], + "label": "", + "required": false + }, + { + "key": "system_httpJsonBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": "{\n \"model\": \"dall-e-3\",\n \"prompt\": \"{{prompt}}\",\n \"n\": 1,\n \"size\": \"1024x1024\"\n}", + "label": "", + "required": false + }, + { + "key": "prompt", + "valueType": "string", + "label": "prompt", + "renderTypeList": ["reference"], + "description": "", + "canEdit": true, + "editField": { + "key": true, + "valueType": true + }, + "value": ["448745", "userChatInput"] + } + ], + "outputs": [ + { + "id": "system_addOutputParam", + "key": "system_addOutputParam", + "type": "dynamic", + "valueType": "dynamic", + "label": "", + "customFieldConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + } + }, + { + "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": "DeKGGioBwaMf", + "type": "dynamic", + "key": "data[0].url", + "valueType": "string", + "label": "data[0].url" + } + ] + }, + { + "nodeId": "7mapnCgHfKW6", + "name": "指定回复", + "intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。", + "avatar": "/imgs/workflow/reply.png", + "flowNodeType": "answerNode", + "position": { + "x": 2204.4609372615846, + "y": 163.11883652393863 + }, + "version": "481", + "inputs": [ + { + "key": "text", + "renderTypeList": ["textarea", "reference"], + "valueType": "any", + "label": "core.module.input.label.Response content", + "description": "core.module.input.description.Response content", + "placeholder": "core.module.input.description.Response content", + "selectedTypeIndex": 1, + "value": ["vEXJF8pQ8eOv", "system_text"], + "required": true + } + ], + "outputs": [] + }, + { + "nodeId": "vEXJF8pQ8eOv", + "name": "文本拼接", + "intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。", + "avatar": "/imgs/workflow/textEditor.svg", + "flowNodeType": "textEditor", + "position": { + "x": 1544.8821308368042, + "y": -27.22950739442814 + }, + "version": "486", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": ["addInputParam"], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "可以引用其他节点的输出,作为文本拼接的变量,通过 {{字段名}} 来引用变量", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": false + } + }, + { + "key": "system_textareaInput", + "renderTypeList": ["textarea"], + "valueType": "string", + "required": true, + "label": "拼接文本", + "placeholder": "可通过 {{字段名}} 来引用变量", + "value": "![]({{url}})" + }, + { + "renderTypeList": ["reference"], + "valueType": "string", + "canEdit": true, + "key": "url", + "label": "url", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": false + }, + "required": true, + "value": ["tMyUnRL5jIrC", "DeKGGioBwaMf"] + } + ], + "outputs": [ + { + "id": "system_text", + "key": "system_text", + "label": "拼接结果", + "type": "static", + "valueType": "string" + } + ] + } + ], + "edges": [ + { + "source": "448745", + "target": "tMyUnRL5jIrC", + "sourceHandle": "448745-source-right", + "targetHandle": "tMyUnRL5jIrC-target-left" + }, + { + "source": "tMyUnRL5jIrC", + "target": "vEXJF8pQ8eOv", + "sourceHandle": "tMyUnRL5jIrC-source-right", + "targetHandle": "vEXJF8pQ8eOv-target-left" + }, + { + "source": "vEXJF8pQ8eOv", + "target": "7mapnCgHfKW6", + "sourceHandle": "vEXJF8pQ8eOv-source-right", + "targetHandle": "7mapnCgHfKW6-target-left" + } + ] + } +} diff --git a/projects/app/public/appTemplates/google/avatar.svg b/projects/app/public/appTemplates/google/avatar.svg new file mode 100644 index 00000000000..f29dfa728c3 --- /dev/null +++ b/projects/app/public/appTemplates/google/avatar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/projects/app/public/appTemplates/google/template.json b/projects/app/public/appTemplates/google/template.json new file mode 100644 index 00000000000..9674ae25f91 --- /dev/null +++ b/projects/app/public/appTemplates/google/template.json @@ -0,0 +1,446 @@ +{ + "id": "google", + "name": "谷歌搜索", + "intro": "通过请求谷歌搜索,查询相关内容作为模型的参考。", + "author": "Fastgpt Team", + "avatar": "/appTemplates/google/avatar.svg", + "authorAvatar": "/icon/logo.svg", + "tags": [ + { "id": "recommendation", "label": "推荐" }, + { "id": "web-search", "label": "联网搜索" } + ], + "type": "advanced", + "workflow": { + "nodes": [ + { + "nodeId": "userGuide", + "name": "系统配置", + "intro": "可以配置应用的系统参数", + "avatar": "/imgs/workflow/userGuide.png", + "flowNodeType": "userGuide", + "position": { + "x": 262.2732338817093, + "y": -476.00241136598146 + }, + "version": "481", + "inputs": [ + { + "key": "welcomeText", + "renderTypeList": ["hidden"], + "valueType": "string", + "label": "core.app.Welcome Text", + "value": "" + }, + { + "key": "variables", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "core.app.Chat Variable", + "value": [] + }, + { + "key": "questionGuide", + "valueType": "boolean", + "renderTypeList": ["hidden"], + "label": "core.app.Question Guide", + "value": false + }, + { + "key": "tts", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "", + "value": { + "type": "web" + } + }, + { + "key": "whisper", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "", + "value": { + "open": false, + "autoSend": false, + "autoTTSResponse": false + } + }, + { + "key": "scheduleTrigger", + "renderTypeList": ["hidden"], + "valueType": "any", + "label": "", + "value": null + } + ], + "outputs": [] + }, + { + "nodeId": "448745", + "name": "流程开始", + "intro": "", + "avatar": "/imgs/workflow/userChatInput.svg", + "flowNodeType": "workflowStart", + "position": { + "x": 295.8944548701009, + "y": 110.81336038514848 + }, + "version": "481", + "inputs": [ + { + "key": "userChatInput", + "renderTypeList": ["reference", "textarea"], + "valueType": "string", + "label": "用户问题", + "required": true, + "toolDescription": "用户问题" + } + ], + "outputs": [ + { + "id": "userChatInput", + "key": "userChatInput", + "label": "core.module.input.label.user question", + "valueType": "string", + "type": "static" + } + ] + }, + { + "nodeId": "NOgbnBzUwDgT", + "name": "工具调用", + "intro": "通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。", + "avatar": "/imgs/workflow/tool.svg", + "flowNodeType": "tools", + "showStatus": true, + "position": { + "x": 1028.8358722416106, + "y": -500.8755882990822 + }, + "version": "481", + "inputs": [ + { + "key": "model", + "renderTypeList": ["settingLLMModel", "reference"], + "label": "core.module.input.label.aiModel", + "valueType": "string", + "llmModelType": "all", + "value": "FastAI-plus" + }, + { + "key": "temperature", + "renderTypeList": ["hidden"], + "label": "", + "value": 0, + "valueType": "number", + "min": 0, + "max": 10, + "step": 1 + }, + { + "key": "maxToken", + "renderTypeList": ["hidden"], + "label": "", + "value": 2000, + "valueType": "number", + "min": 100, + "max": 4000, + "step": 50 + }, + { + "key": "systemPrompt", + "renderTypeList": ["textarea", "reference"], + "max": 3000, + "valueType": "string", + "label": "core.ai.Prompt", + "description": "core.app.tip.chatNodeSystemPromptTip", + "placeholder": "core.app.tip.chatNodeSystemPromptTip", + "value": "" + }, + { + "key": "history", + "renderTypeList": ["numberInput", "reference"], + "valueType": "chatHistory", + "label": "core.module.input.label.chat history", + "description": "最多携带多少轮对话记录", + "required": true, + "min": 0, + "max": 30, + "value": 6 + }, + { + "key": "userChatInput", + "renderTypeList": ["reference", "textarea"], + "valueType": "string", + "label": "用户问题", + "required": true, + "value": ["448745", "userChatInput"] + } + ], + "outputs": [ + { + "id": "NodeOutputKeyEnum.answerText", + "key": "NodeOutputKeyEnum.answerText", + "label": "core.module.output.label.Ai response content", + "description": "core.module.output.description.Ai response content", + "valueType": "WorkflowIOValueTypeEnum.string", + "type": "FlowNodeOutputTypeEnum.static" + } + ] + }, + { + "nodeId": "GMELVPxHfpg5", + "name": "HTTP 请求", + "intro": "调用谷歌搜索,查询相关内容", + "avatar": "/imgs/workflow/http.png", + "flowNodeType": "httpRequest468", + "showStatus": true, + "position": { + "x": 1005.4777753640342, + "y": 319.4905539380939 + }, + "version": "481", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": ["addInputParam"], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "core.module.input.description.HTTP Dynamic Input" + }, + { + "valueType": "string", + "renderTypeList": ["reference"], + "key": "query", + "label": "query", + "toolDescription": "谷歌搜索检索词", + "required": true, + "canEdit": true, + "editField": { + "key": true, + "description": true + } + }, + { + "key": "system_httpMethod", + "renderTypeList": ["custom"], + "valueType": "string", + "label": "", + "value": "GET", + "required": true + }, + { + "key": "system_httpReqUrl", + "renderTypeList": ["hidden"], + "valueType": "string", + "label": "", + "description": "core.module.input.description.Http Request Url", + "placeholder": "https://api.ai.com/getInventory", + "required": false, + "value": "https://www.googleapis.com/customsearch/v1" + }, + { + "key": "system_httpHeader", + "renderTypeList": ["custom"], + "valueType": "any", + "value": [], + "label": "", + "description": "core.module.input.description.Http Request Header", + "placeholder": "core.module.input.description.Http Request Header", + "required": false + }, + { + "key": "system_httpParams", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": [ + { + "key": "q", + "type": "string", + "value": "{{query}}" + }, + { + "key": "cx", + "type": "string", + "value": "谷歌搜索cxID" + }, + { + "key": "key", + "type": "string", + "value": "谷歌搜索key" + }, + { + "key": "c2coff", + "type": "string", + "value": "1" + }, + { + "key": "start", + "type": "string", + "value": "1" + }, + { + "key": "end", + "type": "string", + "value": "20" + }, + { + "key": "dateRestrict", + "type": "string", + "value": "m[1]" + } + ], + "label": "", + "required": false + }, + { + "key": "system_httpJsonBody", + "renderTypeList": ["hidden"], + "valueType": "any", + "value": "", + "label": "", + "required": false + } + ], + "outputs": [ + { + "id": "system_addOutputParam", + "key": "system_addOutputParam", + "type": "dynamic", + "valueType": "dynamic", + "label": "", + "editField": { + "key": true, + "valueType": true + } + }, + { + "id": "httpRawResponse", + "key": "httpRawResponse", + "label": "原始响应", + "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。", + "valueType": "any", + "type": "static", + "required": true + }, + { + "id": "M5YmxaYe8em1", + "type": "dynamic", + "key": "prompt", + "valueType": "string", + "label": "prompt" + } + ] + }, + { + "nodeId": "poIbrrA8aiR0", + "name": "代码运行", + "intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。", + "avatar": "/imgs/workflow/code.svg", + "flowNodeType": "code", + "showStatus": true, + "position": { + "x": 1711.805344753384, + "y": 650.1023414708576 + }, + "version": "482", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": ["addInputParam"], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "这些变量会作为代码的运行的输入参数", + "editField": { + "key": true, + "valueType": true + } + }, + { + "key": "data", + "valueType": "object", + "label": "data", + "renderTypeList": ["reference"], + "description": "", + "canEdit": true, + "editField": { + "key": true, + "valueType": true + }, + "value": ["GMELVPxHfpg5", "httpRawResponse"] + }, + { + "key": "codeType", + "renderTypeList": ["hidden"], + "label": "", + "value": "js" + }, + { + "key": "code", + "renderTypeList": ["custom"], + "label": "", + "value": "function main({data}){\n const result = data.items.map((item) => ({\n title: item.title,\n link: item.link,\n snippet: item.snippet\n }))\n return { prompt: JSON.stringify(result) }\n}" + } + ], + "outputs": [ + { + "id": "system_addOutputParam", + "key": "system_addOutputParam", + "type": "dynamic", + "valueType": "dynamic", + "label": "", + "editField": { + "key": true, + "valueType": true + }, + "description": "将代码中 return 的对象作为输出,传递给后续的节点" + }, + { + "id": "system_rawResponse", + "key": "system_rawResponse", + "label": "完整响应数据", + "valueType": "object", + "type": "static" + }, + { + "id": "error", + "key": "error", + "label": "运行错误", + "description": "代码运行错误信息,成功时返回空", + "valueType": "object", + "type": "static" + }, + { + "id": "qLUQfhG0ILRX", + "type": "dynamic", + "key": "prompt", + "valueType": "string", + "label": "prompt" + } + ] + } + ], + "edges": [ + { + "source": "448745", + "target": "NOgbnBzUwDgT", + "sourceHandle": "448745-source-right", + "targetHandle": "NOgbnBzUwDgT-target-left" + }, + { + "source": "NOgbnBzUwDgT", + "target": "GMELVPxHfpg5", + "sourceHandle": "selectedTools", + "targetHandle": "selectedTools" + }, + { + "source": "GMELVPxHfpg5", + "target": "poIbrrA8aiR0", + "sourceHandle": "GMELVPxHfpg5-source-right", + "targetHandle": "poIbrrA8aiR0-target-left" + } + ] + } +} diff --git a/projects/app/public/appTemplates/toolChat/avatar.png b/projects/app/public/appTemplates/toolChat/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd4b5140d79bc930b07b1cc542cb64acd52ad04 GIT binary patch literal 1531 zcmVPx)wMj%lRCr$Pnoo-yMHIka)yyI&sCNTSAP0|vWHz!B(mR{Gf!s~@;!W@yB=Z?O zhzHrt7f|meJsr{un+fp)2q7bacTtkV&h(S&nVzk!zptySdr7i$oUX2}_pA4>UOfiy z_>aBg^1}sy3k_(Iz;=>c!V~@zF!+Qs`1<%s`a9)wUwoN-*5mv~V1NMZn_2$o56XKX zV_G$V;m+Q#!0@Z}!d}es^a^E>+oQcH0w(LR(^;O5Der}hX&1m~{1*URsuuQszu3yM zY~fqza5Vl806tic`*)V7ANt-2eSQHTlw9@RwImrVmptk9itISc=JI^Q>wAZQcxV0J zqgkHbqgny3=aQT{l`~3OCe`Mgrg1?mJnauL^ zK4o6hm|y_gJL3ana95rb8SFoMk{*UGhVtIE(aofQVycXt@P2WqY9M94AOKfKyHf_N z^3tpCAk1e+>1EePh1w$Ejb0!3)x`=^Di*v1>f6!b&iExT7@UC*n3?AFL8t|wwD$!& zFbU5Y-*?%g5FP;TRj`1;gGx|!SACjP!aCv87!Ya!Fzq}7X3z5Ju8;H?0M%fGIWnB9 zKpDc})1!3XHKz@N&_upf>{88v48SA+Rd^xDTE%7OWtEQu-=%tYlP>}QvSTCxFgYH| zE~ye)9N3v*b%d{8G-?+Sf){{k=j!ad2I17%t^C31FW8fdDNGR5upATyHM=Kxd!Ik3 zOrjjO=ntss?wePQ4q~Hxk-@0}MyfUJ)3@N*&uuw^E3EnepuETsyN@lTZ@#*wU75cgWpqhb6lQjTpm8Z_ZqK+wa0YH_71i+9;L=Ask`2g`9 z6@W>bH4RYJCggNR(S$BEKr6HuY8Sc*DCI87iHahyI;IN%>r>(;+L-bU4ZxX&t?F}8 z6QC|lz!V8od2|3u=y>A+$O)HWL%jgrWD}s|G;g&JPyvv903~?{ae7WCC>|orUj#6b7}UWJ|X_rpt{|=!hUFNu4(nY%3ME*7d8cj{t&_)cFrXqF|w1dd5&sF-LW? z%nG=t-tug|(Ex-R(n*IQ<0-1;LTDQxC=o!&N-Bu7Wd^Dy#RNf7e=7iLF(H;I1cC6} z{AjfRixykcT!WWxxB39-#CF=$aL!ub(~>HzD*Z#^Z|A0YkGh&KsM&x(S$M25 zAs4w`0Gk^esV7H-MYdH;s9hMb1a!?~>RzE#v%CPx#K_dP7!mH6&hlbW4A^7Q(GC5@ zJS1cap?Lu}5FoME3yAG-Hn5EVl-XC+>7n%Qsvi`&L&4#35BXdG5zl2PRhqkG#eg96 zO68$9Y1(1d7(gYcOGTTgzV@zYujMd_)s-F%Kt~{=AI72ss6ecXDhXJ81XU}_w43n< zO;x=$A3zag14Go{5I!v!4j8gkzrXMu>#lK*Y>o{6L +): Promise { + await authCert({ req, authToken: true }); + const { templateId } = req.query as Props; + + return getTemplateMarketItemDetail(templateId); +} + +export default NextAPI(handler); diff --git a/projects/app/src/pages/api/core/app/template/getTemplateMarketList.ts b/projects/app/src/pages/api/core/app/template/getTemplateMarketList.ts new file mode 100644 index 00000000000..a4eb864cbd7 --- /dev/null +++ b/projects/app/src/pages/api/core/app/template/getTemplateMarketList.ts @@ -0,0 +1,16 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; +import { authCert } from '@fastgpt/service/support/permission/auth/common'; +import { NextAPI } from '@/service/middleware/entry'; +import { TemplateMarketListType } from '@fastgpt/global/core/workflow/type'; +import { getTemplateMarketItemList } from '@/service/core/app/template'; + +async function handler( + req: NextApiRequest, + res: NextApiResponse +): Promise { + await authCert({ req, authToken: true }); + + return getTemplateMarketItemList(); +} + +export default NextAPI(handler); diff --git a/projects/app/src/pages/app/list/components/CreateModal.tsx b/projects/app/src/pages/app/list/components/CreateModal.tsx index e647b784b33..bd1e70e2766 100644 --- a/projects/app/src/pages/app/list/components/CreateModal.tsx +++ b/projects/app/src/pages/app/list/components/CreateModal.tsx @@ -1,15 +1,5 @@ import React, { useCallback, useRef } from 'react'; -import { - Box, - Flex, - Button, - ModalFooter, - ModalBody, - Input, - Grid, - useTheme, - Card -} from '@chakra-ui/react'; +import { Box, Flex, Button, ModalFooter, ModalBody, Input, Grid, Card } from '@chakra-ui/react'; import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; import { useForm } from 'react-hook-form'; import { compressImgFileAndUpload } from '@/web/common/file/controller'; @@ -29,6 +19,7 @@ import { AppListContext } from './context'; import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; import { useI18n } from '@/web/context/I18n'; import { useSystem } from '@fastgpt/web/hooks/useSystem'; +import { ChevronRightIcon } from '@chakra-ui/icons'; type FormType = { avatar: string; @@ -38,7 +29,15 @@ type FormType = { export type CreateAppType = AppTypeEnum.simple | AppTypeEnum.workflow | AppTypeEnum.plugin; -const CreateModal = ({ onClose, type }: { type: CreateAppType; onClose: () => void }) => { +const CreateModal = ({ + onClose, + type, + onOpenTemplateModal +}: { + type: CreateAppType; + onClose: () => void; + onOpenTemplateModal: () => void; +}) => { const { t } = useTranslation(); const { appT } = useI18n(); const { toast } = useToast(); @@ -136,6 +135,7 @@ const CreateModal = ({ onClose, type }: { type: CreateAppType; onClose: () => vo isOpen onClose={onClose} isCentered={!isPc} + headerColor="white" > @@ -146,8 +146,8 @@ const CreateModal = ({ onClose, type }: { type: CreateAppType; onClose: () => vo vo vo })} /> - - {t('common:core.app.Select app from template')} - + + + {t('common:core.app.Select app from template')} + + + + {t('core.app.more')} + + + vo - + diff --git a/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx b/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx new file mode 100644 index 00000000000..a64aca6f75c --- /dev/null +++ b/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx @@ -0,0 +1,371 @@ +import { + Avatar, + Box, + Button, + Center, + Flex, + Grid, + HStack, + Input, + InputGroup, + InputLeftElement, + ModalBody, + ModalCloseButton, + ModalHeader, + Spinner +} from '@chakra-ui/react'; +import MyModal from '@fastgpt/web/components/common/MyModal'; +import MyIcon from '@fastgpt/web/components/common/Icon'; +import { useState } from 'react'; +import MyBox from '@fastgpt/web/components/common/MyBox'; +import AppTypeTag from './TypeTag'; +import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; +import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest'; +import { + getTemplateMarketItemDetail, + getTemplateMarketItemList +} from '@/web/core/app/api/template'; +import { TemplateMarketListItemType } from '@fastgpt/global/core/workflow/type'; +import { postCreateApp } from '@/web/core/app/api'; +import { useContextSelector } from 'use-context-selector'; +import { AppListContext } from './context'; +import { useRouter } from 'next/router'; +import { SearchIcon } from '@chakra-ui/icons'; +import MySelect from '@fastgpt/web/components/common/MySelect'; +import { debounce, throttle } from 'lodash'; +import { useTranslation } from 'react-i18next'; +import { useI18n } from '@/web/context/I18n'; +import { useSystemStore } from '@/web/common/system/useSystemStore'; + +const templateTypes = [ + { + id: 'recommendation', + label: '推荐' + }, + { + id: 'writing', + label: '文本创作' + }, + { + id: 'image-generation', + label: '图片生成' + }, + { + id: 'web-search', + label: '联网搜索' + }, + { + id: 'roleplay', + label: '角色扮演' + }, + { + id: 'office-services', + label: '办公服务' + } +]; + +const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { + const [currentType, setCurrentType] = useState(templateTypes[0].id); + const [currentAppType, setCurrentAppType] = useState('all'); + const [currentSearch, setCurrentSearch] = useState(''); + const { parentId, loadMyApps } = useContextSelector(AppListContext, (v) => v); + const router = useRouter(); + const { t } = useTranslation(); + const { appT } = useI18n(); + const { isPc } = useSystemStore(); + + const { data: templateData, loading: isLoadingTemplates } = useRequest2( + async () => { + return getTemplateMarketItemList(); + }, + { + manual: false + } + ); + + const { mutate: onUseTemplate, isLoading: creating } = useRequest({ + mutationFn: async (data) => { + const templateDetail = await getTemplateMarketItemDetail({ templateId: data.id }); + return postCreateApp({ + parentId, + avatar: templateDetail.avatar, + name: templateDetail.name, + type: templateDetail.type, + modules: templateDetail.workflow.nodes || [], + edges: templateDetail.workflow.edges || [] + }); + }, + onSuccess(id: string) { + router.push(`/app/detail?appId=${id}`); + loadMyApps(); + }, + successToast: t('common.Create Success'), + errorToast: t('common.Create Failed') + }); + + const handleScroll = throttle(() => { + let firstVisibleTitle: any = null; + + templateTypes + .map((type) => type.id) + .forEach((type: string) => { + const element = document.getElementById(type); + if (!element) return; + + const elementRect = element.getBoundingClientRect(); + if (elementRect.top <= window.innerHeight && elementRect.bottom >= 0) { + if ( + !firstVisibleTitle || + elementRect.top < firstVisibleTitle.getBoundingClientRect().top + ) { + firstVisibleTitle = element; + } + } + }); + + if (firstVisibleTitle) { + setCurrentType(firstVisibleTitle.id); + } + }, 100); + + return ( + + + + + {appT('template.templateMarket')} + + {isPc && ( + + + + + { + setCurrentSearch(e.target.value); + }, 200)} + bg={'myGray.100'} + /> + + )} + + { + setCurrentAppType(value as AppTypeEnum | 'all'); + }} + bg={'myGray.100'} + list={[ + { label: appT('type.All'), value: 'all' }, + { label: appT('type.Simple bot'), value: AppTypeEnum.simple }, + { label: appT('type.Workflow bot'), value: AppTypeEnum.workflow }, + { label: appT('type.Plugin'), value: AppTypeEnum.plugin } + ]} + /> + + + + + } + w={['90vw', '75vw']} + maxW={['90vw', '75vw']} + h={['90vh', '80vh']} + position={'relative'} + > + + + + {isPc && + templateTypes.map((item) => { + if ( + templateData + ?.filter((template) => template.tags?.map((tag) => tag.id).includes(item.id)) + .filter((templateData) => { + if (currentAppType === 'all') return true; + return templateData.type === currentAppType; + }) + .filter((template) => template.name.includes(currentSearch)).length === 0 + ) + return null; + return ( + { + setCurrentType(item.id); + const anchor = document.getElementById(item.id); + if (anchor) { + anchor.scrollIntoView({ behavior: 'auto', block: 'start' }); + } + }} + > + {item.label} + + ); + })} + + + {isLoadingTemplates || creating ? ( +
+ +
+ ) : ( + + {templateTypes.map((item) => { + const currentTemplates = templateData + ?.filter((template) => template.tags?.map((tag) => tag.id).includes(item.id)) + .filter((template) => { + if (currentAppType === 'all') return true; + return template.type === currentAppType; + }) + .filter((template) => template.name.includes(currentSearch)); + if (!currentTemplates || currentTemplates.length === 0) return null; + return ( + <> + + {item.label} + + + {currentTemplates.map((item) => ( + + ))} + + + ); + })} + + )} +
+
+
+ + ); +}; + +export const TemplateCard = ({ + item, + onUseTemplate +}: { + item: TemplateMarketListItemType; + onUseTemplate: (data: any) => void; +}) => { + const { appT } = useI18n(); + + return ( + {}} + > + + + + {item.name} + + + + + + + {item.intro || '还没写介绍~'} + + + + + + {item.author} + + + + + + + + ); +}; + +export default TemplateMarketModal; diff --git a/projects/app/src/pages/app/list/index.tsx b/projects/app/src/pages/app/list/index.tsx index 920abea1e57..abcbde914f9 100644 --- a/projects/app/src/pages/app/list/index.tsx +++ b/projects/app/src/pages/app/list/index.tsx @@ -42,6 +42,7 @@ import MyBox from '@fastgpt/web/components/common/MyBox'; import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs'; import { useSystem } from '@fastgpt/web/hooks/useSystem'; import MyIcon from '@fastgpt/web/components/common/Icon'; +import TemplateMarketModal from './components/TemplateMarketModal'; const CreateModal = dynamic(() => import('./components/CreateModal')); const EditFolderModal = dynamic( @@ -76,6 +77,11 @@ const MyApps = () => { onOpen: onOpenCreateHttpPlugin, onClose: onCloseCreateHttpPlugin } = useDisclosure(); + const { + isOpen: isOpenTemplateModal, + onOpen: onOpenTemplateModal, + onClose: onCloseTemplateModal + } = useDisclosure(); const [editFolder, setEditFolder] = useState(); const { runAsync: onCreateFolder } = useRequest2(postCreateAppFolder, { @@ -216,6 +222,12 @@ const MyApps = () => { label: appT('type.Http plugin'), description: appT('type.Create http plugin tip'), onClick: onOpenCreateHttpPlugin + }, + { + icon: 'core/app/type/templateFill', + label: appT('type.Template'), + description: appT('type.Create template tip'), + onClick: onOpenTemplateModal } ] }, @@ -306,9 +318,14 @@ const MyApps = () => { /> )} {!!createAppType && ( - setCreateAppType(undefined)} /> + setCreateAppType(undefined)} + onOpenTemplateModal={onOpenTemplateModal} + /> )} {isOpenCreateHttpPlugin && } + {isOpenTemplateModal && } ); }; diff --git a/projects/app/src/service/core/app/template.ts b/projects/app/src/service/core/app/template.ts new file mode 100644 index 00000000000..65039c6afd9 --- /dev/null +++ b/projects/app/src/service/core/app/template.ts @@ -0,0 +1,44 @@ +import { isProduction } from '@fastgpt/service/common/system/constants'; +import { promises as fs } from 'fs'; +import path from 'path'; + +let appTemplateIdList = ['TranslateRobot', 'dalle', 'chatGuide', 'toolChat', 'google']; + +export const getTemplateMarketItems = async () => { + if (isProduction && global.appTemplates) return global.appTemplates; + + global.appTemplates = await Promise.all( + appTemplateIdList.map(async (name) => { + try { + const filePath = path.join(process.cwd(), 'public', 'appTemplates', name, 'template.json'); + const fileContent = await fs.readFile(filePath, 'utf-8'); + const data = JSON.parse(fileContent); + return data; + } catch (error) { + console.error(`Error fetching template ${name}:`); + return null; + } + }) + ); + + return global.appTemplates; +}; + +export const getTemplateMarketItemDetail = async (id: string) => { + const templateMarketItems = await getTemplateMarketItems(); + return templateMarketItems.find((item) => item.id === id); +}; + +export const getTemplateMarketItemList = async () => { + const templateMarketItems = await getTemplateMarketItems(); + return templateMarketItems.map((item) => ({ + id: item.id, + name: item.name, + avatar: item.avatar, + intro: item.intro, + author: item.author, + authorAvatar: item.authorAvatar, + tags: item.tags, + type: item.type + })); +}; diff --git a/projects/app/src/web/core/app/api/template.ts b/projects/app/src/web/core/app/api/template.ts new file mode 100644 index 00000000000..99f3628e589 --- /dev/null +++ b/projects/app/src/web/core/app/api/template.ts @@ -0,0 +1,8 @@ +import { GET } from '@/web/common/api/request'; +import { TemplateMarketItemType, TemplateMarketListType } from '@fastgpt/global/core/workflow/type'; + +export const getTemplateMarketItemList = () => + GET('/core/app/template/getTemplateMarketList'); + +export const getTemplateMarketItemDetail = (data: { templateId: string }) => + GET(`/core/app/template/getTemplateMarketItemDetail`, data); From 0352ce40c9e1dce683f7f9deee20eab48287a8f0 Mon Sep 17 00:00:00 2001 From: heheer <1239331448@qq.com> Date: Thu, 8 Aug 2024 17:53:17 +0800 Subject: [PATCH 2/5] fix --- packages/global/core/workflow/type/index.d.ts | 6 +- packages/service/core/app/template/type.d.ts | 5 - packages/service/type.d.ts | 1 + .../web/components/common/MyModal/index.tsx | 11 +- packages/web/i18n/en/app.json | 13 +- packages/web/i18n/zh/app.json | 11 +- .../pages/app/list/components/CreateModal.tsx | 3 +- .../list/components/TemplateMarketModal.tsx | 279 ++++---- .../pages/app/list/components/constants.tsx | 12 + .../src/pages/app/list/components/test.txt | 608 ++++++++++++++++++ 10 files changed, 795 insertions(+), 154 deletions(-) delete mode 100644 packages/service/core/app/template/type.d.ts create mode 100644 projects/app/src/pages/app/list/components/constants.tsx create mode 100644 projects/app/src/pages/app/list/components/test.txt diff --git a/packages/global/core/workflow/type/index.d.ts b/packages/global/core/workflow/type/index.d.ts index e65b7d2065d..7f967c30f98 100644 --- a/packages/global/core/workflow/type/index.d.ts +++ b/packages/global/core/workflow/type/index.d.ts @@ -54,9 +54,9 @@ export type TemplateMarketItemType = WorkflowTemplateType & { export type TemplateMarketListItemType = { id: string; name: string; - intro?: string; - author?: string; - tags?: { id: string; label: string }[]; + intro: string; + author: string; + tags: { id: string; label: string }[]; type: AppTypeEnum.simple | AppTypeEnum.workflow | AppTypeEnum.plugin; avatar: string; authorAvatar?: string; diff --git a/packages/service/core/app/template/type.d.ts b/packages/service/core/app/template/type.d.ts deleted file mode 100644 index 91e0a8e850b..00000000000 --- a/packages/service/core/app/template/type.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { TemplateMarketItemType, TemplateMarketListType } from '@fastgpt/global/core/workflow/type'; - -declare global { - var appTemplates: TemplateMarketItemType[]; -} diff --git a/packages/service/type.d.ts b/packages/service/type.d.ts index adfd7b253f5..dda2ee40545 100644 --- a/packages/service/type.d.ts +++ b/packages/service/type.d.ts @@ -25,4 +25,5 @@ declare global { var systemLoadedGlobalConfig: boolean; var workerPoll: Record; + var appTemplates: TemplateMarketItemType[]; } diff --git a/packages/web/components/common/MyModal/index.tsx b/packages/web/components/common/MyModal/index.tsx index 00d212d019f..776c595d552 100644 --- a/packages/web/components/common/MyModal/index.tsx +++ b/packages/web/components/common/MyModal/index.tsx @@ -22,8 +22,6 @@ export interface MyModalProps extends ModalContentProps { isOpen: boolean; onClose?: () => void; closeOnOverlayClick?: boolean; - customModalHeader?: ReactElement; - headerColor?: string; } const MyModal = ({ @@ -37,8 +35,6 @@ const MyModal = ({ w = 'auto', maxW = ['90vw', '600px'], closeOnOverlayClick = true, - customModalHeader, - headerColor, ...props }: MyModalProps) => { const isPc = useSystem(); @@ -62,13 +58,12 @@ const MyModal = ({ boxShadow={'7'} {...props} > - {!!customModalHeader && customModalHeader} - {!customModalHeader && !title && onClose && } - {!customModalHeader && !!title && ( + {!title && onClose && } + {!!title && ( @@ -222,7 +221,7 @@ const CreateModal = ({ - + diff --git a/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx b/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx index a64aca6f75c..db36e578e85 100644 --- a/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx +++ b/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx @@ -9,9 +9,12 @@ import { Input, InputGroup, InputLeftElement, + Modal, ModalBody, ModalCloseButton, + ModalContent, ModalHeader, + ModalOverlay, Spinner } from '@chakra-ui/react'; import MyModal from '@fastgpt/web/components/common/MyModal'; @@ -35,44 +38,44 @@ import MySelect from '@fastgpt/web/components/common/MySelect'; import { debounce, throttle } from 'lodash'; import { useTranslation } from 'react-i18next'; import { useI18n } from '@/web/context/I18n'; -import { useSystemStore } from '@/web/common/system/useSystemStore'; - -const templateTypes = [ - { - id: 'recommendation', - label: '推荐' - }, - { - id: 'writing', - label: '文本创作' - }, - { - id: 'image-generation', - label: '图片生成' - }, - { - id: 'web-search', - label: '联网搜索' - }, - { - id: 'roleplay', - label: '角色扮演' - }, - { - id: 'office-services', - label: '办公服务' - } -]; +import { useSystem } from '@fastgpt/web/hooks/useSystem'; +import { AppTemplateTypeEnum } from './constants'; const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { + const { t } = useTranslation(); + const templateTypes = [ + { + id: AppTemplateTypeEnum.recommendation, + label: t('app:template.type.Recommendation') + }, + { + id: AppTemplateTypeEnum.writing, + label: t('app:template.type.Writing') + }, + { + id: AppTemplateTypeEnum.imageGeneration, + label: t('app:template.type.Image_generation') + }, + { + id: AppTemplateTypeEnum.webSearch, + label: t('app:template.type.Web_search') + }, + { + id: AppTemplateTypeEnum.roleplay, + label: t('app:template.type.Roleplay') + }, + { + id: AppTemplateTypeEnum.officeServices, + label: t('app:template.type.Office_services') + } + ]; const [currentType, setCurrentType] = useState(templateTypes[0].id); const [currentAppType, setCurrentAppType] = useState('all'); const [currentSearch, setCurrentSearch] = useState(''); const { parentId, loadMyApps } = useContextSelector(AppListContext, (v) => v); const router = useRouter(); - const { t } = useTranslation(); const { appT } = useI18n(); - const { isPc } = useSystemStore(); + const { isPc } = useSystem(); const { data: templateData, loading: isLoadingTemplates } = useRequest2( async () => { @@ -129,10 +132,21 @@ const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { }, 100); return ( - onClose && onClose()} + autoFocus={false} + blockScrollOnMount={false} + closeOnOverlayClick={false} + > + + void }) => { - } - w={['90vw', '75vw']} - maxW={['90vw', '75vw']} - h={['90vh', '80vh']} - position={'relative'} - > - - - - {isPc && - templateTypes.map((item) => { - if ( - templateData - ?.filter((template) => template.tags?.map((tag) => tag.id).includes(item.id)) - .filter((templateData) => { - if (currentAppType === 'all') return true; - return templateData.type === currentAppType; - }) - .filter((template) => template.name.includes(currentSearch)).length === 0 - ) - return null; - return ( - { - setCurrentType(item.id); - const anchor = document.getElementById(item.id); - if (anchor) { - anchor.scrollIntoView({ behavior: 'auto', block: 'start' }); - } - }} - > - {item.label} - - ); - })} - - - {isLoadingTemplates || creating ? ( -
- -
- ) : ( - - {templateTypes.map((item) => { - const currentTemplates = templateData - ?.filter((template) => template.tags?.map((tag) => tag.id).includes(item.id)) - .filter((template) => { - if (currentAppType === 'all') return true; - return template.type === currentAppType; - }) - .filter((template) => template.name.includes(currentSearch)); - if (!currentTemplates || currentTemplates.length === 0) return null; + + + + {isPc && + templateTypes.map((item) => { + if ( + templateData + ?.filter((template) => template.tags?.map((tag) => tag.id).includes(item.id)) + .filter((templateData) => { + if (currentAppType === 'all') return true; + return templateData.type === currentAppType; + }) + .filter((template) => template.name.includes(currentSearch)).length === 0 + ) + return null; return ( - <> - - {item.label} - - - {currentTemplates.map((item) => ( - - ))} - - + { + setCurrentType(item.id); + const anchor = document.getElementById(item.id); + if (anchor) { + anchor.scrollIntoView({ behavior: 'auto', block: 'start' }); + } + }} + > + {item.label} + ); })} - - )} - -
-
-
+ + + {isLoadingTemplates || creating ? ( +
+ +
+ ) : ( + + {templateTypes.map((item) => { + const currentTemplates = templateData + ?.filter((template) => template.tags?.map((tag) => tag.id).includes(item.id)) + .filter((template) => { + if (currentAppType === 'all') return true; + return template.type === currentAppType; + }) + .filter((template) => template.name.includes(currentSearch)); + if (!currentTemplates || currentTemplates.length === 0) return null; + return ( + <> + + {item.label} + + + {currentTemplates.map((item) => ( + + ))} + + + ); + })} + + )} +
+ + + + ); }; @@ -290,7 +305,7 @@ export const TemplateCard = ({ item: TemplateMarketListItemType; onUseTemplate: (data: any) => void; }) => { - const { appT } = useI18n(); + const { t } = useTranslation(); return ( diff --git a/projects/app/src/pages/app/list/components/constants.tsx b/projects/app/src/pages/app/list/components/constants.tsx new file mode 100644 index 00000000000..b3de29120b1 --- /dev/null +++ b/projects/app/src/pages/app/list/components/constants.tsx @@ -0,0 +1,12 @@ +export enum AppTemplateTypeEnum { + recommendation = 'recommendation', + writing = 'writing', + imageGeneration = 'image-generation', + webSearch = 'web-search', + roleplay = 'roleplay', + officeServices = 'office-services' +} + +export default function Dom() { + return <>; +} diff --git a/projects/app/src/pages/app/list/components/test.txt b/projects/app/src/pages/app/list/components/test.txt new file mode 100644 index 00000000000..aa8928532b1 --- /dev/null +++ b/projects/app/src/pages/app/list/components/test.txt @@ -0,0 +1,608 @@ +{ + "nodes": [ + { + "nodeId": "pluginInput", + "name": "自定义插件输入", + "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", + "avatar": "core/workflow/template/workflowStart", + "flowNodeType": "pluginInput", + "showStatus": false, + "position": { + "x": -219.6824105687828, + "y": -101.77531175072627 + }, + "version": "481", + "inputs": [ + { + "renderTypeList": [ + "textarea" + ], + "selectedTypeIndex": 0, + "valueType": "string", + "canEdit": true, + "key": "task", + "label": "task", + "description": "需要执行的任务", + "required": true, + "defaultValue": "翻译外文文本" + }, + { + "renderTypeList": [ + "textarea" + ], + "selectedTypeIndex": 0, + "valueType": "string", + "canEdit": true, + "key": "prompt_example", + "label": "prompt_example", + "description": "提示词示例", + "required": true, + "defaultValue": "Sealos is a cloud operating system distribution based on the Kubernetes kernel. It adopts a cloud-native approach, discarding traditional cloud computing architecture, and shifting towards a new architecture with Kubernetes as the cloud kernel. This allows enterprises to use the cloud as effortlessly as they would use a personal computer.\n\nUsers will be able to install any high-availability distributed application on Kubernetes with the click of a button, similar to using a personal computer. It practically requires no professional delivery or operational costs. Simultaneously, utilizing unique cluster imaging capabilities, users can package any distributed application into an OCI image, freely combine a variety of distributed applications, and easily customize their desired cloud. The powerful and flexible app store function can meet the diverse needs of various users." + }, + { + "renderTypeList": [ + "textarea" + ], + "selectedTypeIndex": 0, + "valueType": "string", + "canEdit": true, + "key": "response_example", + "label": "response_example", + "description": "AI 回复示例", + "required": true, + "defaultValue": "Sealos 是一款以 Kubernetes 为内核的云操作系统发行版。它以云原生的方式,抛弃了传统的云计算架构,转向以 Kubernetes 为云内核的新架构,使企业能够像使用个人电脑一样简单地使用云。\n\n用户将可以像使用个人电脑一样在 Kubernetes 上一键安装任意高可用分布式应用,几乎不需要任何专业的交付和运维成本。同时,利用独特的集群镜像能力,用户可将任意分布式应用打包成 OCI 镜像,自由组合各种分布式应用,轻松订制所需的云。通过强大且灵活的应用商店功能,可满足各类用户的多样化需求。" + } + ], + "outputs": [ + { + "id": "task", + "valueType": "string", + "key": "task", + "label": "task", + "type": "hidden" + }, + { + "id": "prompt_example", + "valueType": "string", + "key": "prompt_example", + "label": "prompt_example", + "type": "hidden" + }, + { + "id": "response_example", + "valueType": "string", + "key": "response_example", + "label": "response_example", + "type": "hidden" + } + ] + }, + { + "nodeId": "pluginOutput", + "name": "自定义插件输出", + "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", + "avatar": "core/workflow/template/pluginOutput", + "flowNodeType": "pluginOutput", + "showStatus": false, + "position": { + "x": 2588.698874413269, + "y": -37.73399941782753 + }, + "version": "481", + "inputs": [ + { + "renderTypeList": [ + "reference" + ], + "valueType": "chatHistory", + "canEdit": true, + "key": "问答示例", + "label": "问答示例", + "description": "高性能 AI 的问答示例", + "value": [ + "kGZBVzwZJvRr", + "sFzDC79CgJjR" + ] + } + ], + "outputs": [] + }, + { + "nodeId": "vvDMOt1OJVpO", + "name": "生成提示词和回答例子", + "intro": "AI 大模型对话", + "avatar": "core/workflow/template/aiChat", + "flowNodeType": "chatNode", + "showStatus": true, + "position": { + "x": 389.6070084022975, + "y": -390.1563503559081 + }, + "version": "481", + "inputs": [ + { + "key": "model", + "renderTypeList": [ + "settingLLMModel", + "reference" + ], + "label": "core.module.input.label.aiModel", + "valueType": "string", + "selectedTypeIndex": 0, + "value": "claude-3-5-sonnet-20240620" + }, + { + "key": "temperature", + "renderTypeList": [ + "hidden" + ], + "label": "", + "value": 0, + "valueType": "number", + "min": 0, + "max": 10, + "step": 1 + }, + { + "key": "maxToken", + "renderTypeList": [ + "hidden" + ], + "label": "", + "value": 2000, + "valueType": "number", + "min": 100, + "max": 4000, + "step": 50 + }, + { + "key": "isResponseAnswerText", + "renderTypeList": [ + "hidden" + ], + "label": "", + "value": false, + "valueType": "boolean" + }, + { + "key": "quoteTemplate", + "renderTypeList": [ + "hidden" + ], + "label": "", + "valueType": "string" + }, + { + "key": "quotePrompt", + "renderTypeList": [ + "hidden" + ], + "label": "", + "valueType": "string" + }, + { + "key": "systemPrompt", + "renderTypeList": [ + "textarea", + "reference" + ], + "max": 3000, + "valueType": "string", + "label": "core.ai.Prompt", + "description": "core.app.tip.chatNodeSystemPromptTip", + "placeholder": "core.app.tip.chatNodeSystemPromptTip", + "value": "## Task:\nGiven an example training sample, create 7 additional samples for the same task that are even better. Each example should contain a and a .\n\n## Rules:\n1. Ensure the new examples are diverse and unique from one another.\n2. They should all be perfect. If you make a mistake, this system won't work.\n\n## OutputFormat:\n\n\nPUT_PROMPT_HERE\n\n\nPUT_RESPONSE_HERE\n\n\n\n\n\nPUT_PROMPT_HERE\n\n\nPUT_RESPONSE_HERE\n\n\n" + }, + { + "key": "history", + "renderTypeList": [ + "numberInput", + "reference" + ], + "valueType": "chatHistory", + "label": "core.module.input.label.chat history", + "description": "最多携带多少轮对话记录", + "required": true, + "min": 0, + "max": 50, + "value": 6 + }, + { + "key": "userChatInput", + "renderTypeList": [ + "reference", + "textarea" + ], + "valueType": "string", + "label": "用户问题", + "required": true, + "toolDescription": "用户问题", + "selectedTypeIndex": 1, + "value": "\n{{$pluginInput.task$}}\n\n\n\n{{$pluginInput.prompt_example$}}\n\n\n\n{{$pluginInput.response_example$}}\n" + }, + { + "key": "quoteQA", + "renderTypeList": [ + "settingDatasetQuotePrompt" + ], + "label": "", + "debugLabel": "知识库引用", + "description": "", + "valueType": "datasetQuote" + } + ], + "outputs": [ + { + "id": "history", + "key": "history", + "required": true, + "label": "core.module.output.label.New context", + "description": "core.module.output.description.New context", + "valueType": "chatHistory", + "type": "static" + }, + { + "id": "answerText", + "key": "answerText", + "required": true, + "label": "core.module.output.label.Ai response content", + "description": "core.module.output.description.Ai response content", + "valueType": "string", + "type": "static" + } + ] + }, + { + "nodeId": "kGZBVzwZJvRr", + "name": "生成聊天记录", + "intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。", + "avatar": "core/workflow/template/codeRun", + "flowNodeType": "code", + "showStatus": true, + "position": { + "x": 1917.9673096589154, + "y": -368.753298042259 + }, + "version": "482", + "inputs": [ + { + "key": "system_addInputParam", + "renderTypeList": [ + "addInputParam" + ], + "valueType": "dynamic", + "label": "", + "required": false, + "description": "这些变量会作为代码的运行的输入参数", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + } + }, + { + "key": "codeType", + "renderTypeList": [ + "hidden" + ], + "label": "", + "value": "js" + }, + { + "key": "code", + "renderTypeList": [ + "custom" + ], + "label": "", + "value": "function main({promptAndResponseExamples, systemPrompt}){\n const promptsAndResponses = [];\n const examplePattern = /(.*?)<\\/example_\\w+>/gs;\n const promptPattern = /(.*?)<\\/prompt>/s;\n const responsePattern = /(.*?)<\\/response>/s;\n\n let exampleMatch;\n while ((exampleMatch = examplePattern.exec(promptAndResponseExamples)) !== null) {\n const exampleContent = exampleMatch[1];\n const promptMatch = promptPattern.exec(exampleContent);\n const responseMatch = responsePattern.exec(exampleContent);\n\n if (promptMatch && responseMatch) {\n const prompt = promptMatch[1].trim();\n const response = responseMatch[1].trim();\n promptsAndResponses.push({ prompt, response });\n }\n }\n \n const chatHistory = [\n {\n \"obj\": \"System\",\n \"value\": [\n {\n \"type\": \"text\",\n \"text\": {\n \"content\": systemPrompt.replace(/^\\n|\\n<\\/system_prompt>$/g, '')\n }\n }\n ]\n },\n ...promptsAndResponses.map(({prompt, response}) => [\n {\n \"obj\": \"Human\",\n \"value\": [\n {\n \"type\": \"text\",\n \"text\": {\n \"content\": prompt\n }\n }\n ]\n },\n {\n \"obj\": \"AI\",\n \"value\": [\n {\n \"type\": \"text\",\n \"text\": {\n \"content\": response\n }\n }\n ]\n }\n ]).flat()\n ];\n\n return {\n chatHistory\n };\n}\n" + }, + { + "renderTypeList": [ + "reference" + ], + "valueType": "string", + "canEdit": true, + "key": "promptAndResponseExamples", + "label": "promptAndResponseExamples", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + }, + "required": true, + "value": [ + "vvDMOt1OJVpO", + "answerText" + ] + }, + { + "renderTypeList": [ + "reference" + ], + "valueType": "string", + "canEdit": true, + "key": "systemPrompt", + "label": "systemPrompt", + "customInputConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": true + }, + "required": true, + "value": [ + "agJb9pvuJCKl", + "answerText" + ] + } + ], + "outputs": [ + { + "id": "system_rawResponse", + "key": "system_rawResponse", + "label": "完整响应数据", + "valueType": "object", + "type": "static" + }, + { + "id": "error", + "key": "error", + "label": "运行错误", + "description": "代码运行错误信息,成功时返回空", + "valueType": "object", + "type": "static" + }, + { + "id": "system_addOutputParam", + "key": "system_addOutputParam", + "type": "dynamic", + "valueType": "dynamic", + "label": "", + "customFieldConfig": { + "selectValueTypeList": [ + "string", + "number", + "boolean", + "object", + "arrayString", + "arrayNumber", + "arrayBoolean", + "arrayObject", + "any", + "chatHistory", + "datasetQuote", + "dynamic", + "selectApp", + "selectDataset" + ], + "showDescription": false, + "showDefaultValue": false + }, + "description": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key" + }, + { + "id": "sFzDC79CgJjR", + "valueType": "chatHistory", + "type": "dynamic", + "key": "chatHistory", + "label": "chatHistory" + } + ] + }, + { + "nodeId": "agJb9pvuJCKl", + "name": "生成系统提示词", + "intro": "AI 大模型对话", + "avatar": "core/workflow/template/aiChat", + "flowNodeType": "chatNode", + "showStatus": true, + "position": { + "x": 1166.5280665265466, + "y": -391.87506915222184 + }, + "version": "481", + "inputs": [ + { + "key": "model", + "renderTypeList": [ + "settingLLMModel", + "reference" + ], + "label": "core.module.input.label.aiModel", + "valueType": "string", + "selectedTypeIndex": 0, + "value": "claude-3-5-sonnet-20240620" + }, + { + "key": "temperature", + "renderTypeList": [ + "hidden" + ], + "label": "", + "value": 0, + "valueType": "number", + "min": 0, + "max": 10, + "step": 1 + }, + { + "key": "maxToken", + "renderTypeList": [ + "hidden" + ], + "label": "", + "value": 2000, + "valueType": "number", + "min": 100, + "max": 4000, + "step": 50 + }, + { + "key": "isResponseAnswerText", + "renderTypeList": [ + "hidden" + ], + "label": "", + "value": false, + "valueType": "boolean" + }, + { + "key": "quoteTemplate", + "renderTypeList": [ + "hidden" + ], + "label": "", + "valueType": "string" + }, + { + "key": "quotePrompt", + "renderTypeList": [ + "hidden" + ], + "label": "", + "valueType": "string" + }, + { + "key": "systemPrompt", + "renderTypeList": [ + "textarea", + "reference" + ], + "max": 3000, + "valueType": "string", + "label": "core.ai.Prompt", + "description": "core.app.tip.chatNodeSystemPromptTip", + "placeholder": "core.app.tip.chatNodeSystemPromptTip", + "value": "## Role:\nGiven a user-description of their a set of prompt / response pairs (it'll be in JSON for easy reading) for the types of outputs we want to generate given inputs, write a fantastic system prompt that describes the task to be done perfectly.\n\n## Rules:\n1. Do this perfectly.\n2. Respond only with the system prompt, and nothing else. No other text will be allowed.\n\n## OutputFormat:\n\nWRITE_SYSTEM_PROMPT_HERE\n" + }, + { + "key": "history", + "renderTypeList": [ + "numberInput", + "reference" + ], + "valueType": "chatHistory", + "label": "core.module.input.label.chat history", + "description": "最多携带多少轮对话记录", + "required": true, + "min": 0, + "max": 50, + "value": 6 + }, + { + "key": "userChatInput", + "renderTypeList": [ + "reference", + "textarea" + ], + "valueType": "string", + "label": "用户问题", + "required": true, + "toolDescription": "用户问题", + "selectedTypeIndex": 1, + "value": "\n{{$pluginInput.task$}}\n\n\n\n{{$vvDMOt1OJVpO.answerText$}}\n" + }, + { + "key": "quoteQA", + "renderTypeList": [ + "settingDatasetQuotePrompt" + ], + "label": "", + "debugLabel": "知识库引用", + "description": "", + "valueType": "datasetQuote" + } + ], + "outputs": [ + { + "id": "history", + "key": "history", + "required": true, + "label": "core.module.output.label.New context", + "description": "core.module.output.description.New context", + "valueType": "chatHistory", + "type": "static" + }, + { + "id": "answerText", + "key": "answerText", + "required": true, + "label": "core.module.output.label.Ai response content", + "description": "core.module.output.description.Ai response content", + "valueType": "string", + "type": "static" + } + ] + } + ], + "edges": [ + { + "source": "pluginInput", + "target": "vvDMOt1OJVpO", + "sourceHandle": "pluginInput-source-right", + "targetHandle": "vvDMOt1OJVpO-target-left" + }, + { + "source": "vvDMOt1OJVpO", + "target": "agJb9pvuJCKl", + "sourceHandle": "vvDMOt1OJVpO-source-right", + "targetHandle": "agJb9pvuJCKl-target-left" + }, + { + "source": "agJb9pvuJCKl", + "target": "kGZBVzwZJvRr", + "sourceHandle": "agJb9pvuJCKl-source-right", + "targetHandle": "kGZBVzwZJvRr-target-left" + }, + { + "source": "kGZBVzwZJvRr", + "target": "pluginOutput", + "sourceHandle": "kGZBVzwZJvRr-source-right", + "targetHandle": "pluginOutput-target-left" + } + ] +} \ No newline at end of file From eb979f0664f0be520b7c03884b68145eb788bfdf Mon Sep 17 00:00:00 2001 From: heheer <1239331448@qq.com> Date: Fri, 9 Aug 2024 10:29:06 +0800 Subject: [PATCH 3/5] fix --- packages/global/core/app/constants.ts | 9 + packages/global/core/workflow/type/index.d.ts | 5 +- packages/service/type.d.ts | 2 +- .../web/components/common/MyModal/index.tsx | 3 +- .../TranslateRobot/avatar.svg | 0 .../TranslateRobot/template.json | 7 +- .../chatGuide/avatar.png | Bin .../chatGuide/template.json | 4 +- .../dalle/avatar.svg | 0 .../dalle/template.json | 7 +- .../google/avatar.svg | 0 .../google/template.json | 7 +- .../toolChat/avatar.png | Bin .../toolChat/template.json | 7 +- .../app/plugin/getSystemPluginTemplates.ts | 1 - .../list/components/TemplateMarketModal.tsx | 7 +- .../pages/app/list/components/constants.tsx | 12 - .../src/pages/app/list/components/test.txt | 608 ------------------ projects/app/src/pages/app/list/index.tsx | 6 - projects/app/src/service/core/app/template.ts | 14 +- 20 files changed, 36 insertions(+), 663 deletions(-) rename projects/app/public/{appTemplates => appTemplateMarketTemplates}/TranslateRobot/avatar.svg (100%) rename projects/app/public/{appTemplates => appTemplateMarketTemplates}/TranslateRobot/template.json (99%) rename projects/app/public/{appTemplates => appTemplateMarketTemplates}/chatGuide/avatar.png (100%) rename projects/app/public/{appTemplates => appTemplateMarketTemplates}/chatGuide/template.json (98%) rename projects/app/public/{appTemplates => appTemplateMarketTemplates}/dalle/avatar.svg (100%) rename projects/app/public/{appTemplates => appTemplateMarketTemplates}/dalle/template.json (98%) rename projects/app/public/{appTemplates => appTemplateMarketTemplates}/google/avatar.svg (100%) rename projects/app/public/{appTemplates => appTemplateMarketTemplates}/google/template.json (98%) rename projects/app/public/{appTemplates => appTemplateMarketTemplates}/toolChat/avatar.png (100%) rename projects/app/public/{appTemplates => appTemplateMarketTemplates}/toolChat/template.json (96%) delete mode 100644 projects/app/src/pages/app/list/components/constants.tsx delete mode 100644 projects/app/src/pages/app/list/components/test.txt diff --git a/packages/global/core/app/constants.ts b/packages/global/core/app/constants.ts index 232206a6c66..e6600f23c97 100644 --- a/packages/global/core/app/constants.ts +++ b/packages/global/core/app/constants.ts @@ -29,3 +29,12 @@ export const defaultAppSelectFileConfig: AppFileSelectConfigType = { canSelectImg: false, maxFiles: 10 }; + +export enum AppTemplateTypeEnum { + recommendation = 'recommendation', + writing = 'writing', + imageGeneration = 'image-generation', + webSearch = 'web-search', + roleplay = 'roleplay', + officeServices = 'office-services' +} diff --git a/packages/global/core/workflow/type/index.d.ts b/packages/global/core/workflow/type/index.d.ts index 7f967c30f98..8265f29193d 100644 --- a/packages/global/core/workflow/type/index.d.ts +++ b/packages/global/core/workflow/type/index.d.ts @@ -46,9 +46,8 @@ export type WorkflowTemplateType = { // template market export type TemplateMarketItemType = WorkflowTemplateType & { - tags?: { id: string; label: string }[]; + tags: string[]; type: AppTypeEnum.simple | AppTypeEnum.workflow | AppTypeEnum.plugin; - authorAvatar?: string; }; // template market list export type TemplateMarketListItemType = { @@ -56,7 +55,7 @@ export type TemplateMarketListItemType = { name: string; intro: string; author: string; - tags: { id: string; label: string }[]; + tags: string[]; type: AppTypeEnum.simple | AppTypeEnum.workflow | AppTypeEnum.plugin; avatar: string; authorAvatar?: string; diff --git a/packages/service/type.d.ts b/packages/service/type.d.ts index dda2ee40545..e982fbc31fd 100644 --- a/packages/service/type.d.ts +++ b/packages/service/type.d.ts @@ -25,5 +25,5 @@ declare global { var systemLoadedGlobalConfig: boolean; var workerPoll: Record; - var appTemplates: TemplateMarketItemType[]; + var appTemplateMarketTemplates: TemplateMarketItemType[]; } diff --git a/packages/web/components/common/MyModal/index.tsx b/packages/web/components/common/MyModal/index.tsx index 776c595d552..120e4eeae5a 100644 --- a/packages/web/components/common/MyModal/index.tsx +++ b/packages/web/components/common/MyModal/index.tsx @@ -1,4 +1,4 @@ -import React, { ReactElement } from 'react'; +import React from 'react'; import { Modal, ModalOverlay, @@ -9,7 +9,6 @@ import { Box, Image } from '@chakra-ui/react'; -import MyIcon from '../Icon'; import MyBox from '../MyBox'; import { useSystem } from '../../../hooks/useSystem'; import Avatar from '../Avatar'; diff --git a/projects/app/public/appTemplates/TranslateRobot/avatar.svg b/projects/app/public/appTemplateMarketTemplates/TranslateRobot/avatar.svg similarity index 100% rename from projects/app/public/appTemplates/TranslateRobot/avatar.svg rename to projects/app/public/appTemplateMarketTemplates/TranslateRobot/avatar.svg diff --git a/projects/app/public/appTemplates/TranslateRobot/template.json b/projects/app/public/appTemplateMarketTemplates/TranslateRobot/template.json similarity index 99% rename from projects/app/public/appTemplates/TranslateRobot/template.json rename to projects/app/public/appTemplateMarketTemplates/TranslateRobot/template.json index 09fcb40ac89..9533066ec63 100644 --- a/projects/app/public/appTemplates/TranslateRobot/template.json +++ b/projects/app/public/appTemplateMarketTemplates/TranslateRobot/template.json @@ -3,12 +3,9 @@ "name": "多轮翻译机器人", "intro": "通过 4 轮翻译,提高翻译英文的质量", "author": "Fastgpt Team", - "avatar": "/appTemplates/TranslateRobot/avatar.svg", + "avatar": "/appTemplateMarketTemplates/TranslateRobot/avatar.svg", "authorAvatar": "/icon/logo.svg", - "tags": [ - { "id": "recommendation", "label": "推荐" }, - { "id": "office-services", "label": "办公服务" } - ], + "tags": ["recommendation", "office-services"], "type": "advanced", "workflow": { "nodes": [ diff --git a/projects/app/public/appTemplates/chatGuide/avatar.png b/projects/app/public/appTemplateMarketTemplates/chatGuide/avatar.png similarity index 100% rename from projects/app/public/appTemplates/chatGuide/avatar.png rename to projects/app/public/appTemplateMarketTemplates/chatGuide/avatar.png diff --git a/projects/app/public/appTemplates/chatGuide/template.json b/projects/app/public/appTemplateMarketTemplates/chatGuide/template.json similarity index 98% rename from projects/app/public/appTemplates/chatGuide/template.json rename to projects/app/public/appTemplateMarketTemplates/chatGuide/template.json index 191b7f9cd26..40a8feabb24 100644 --- a/projects/app/public/appTemplates/chatGuide/template.json +++ b/projects/app/public/appTemplateMarketTemplates/chatGuide/template.json @@ -3,9 +3,9 @@ "name": "对话引导 + 变量", "intro": "可以在对话开始发送一段提示,或者让用户填写一些内容,作为本次对话的变量", "author": "Fastgpt Team", - "avatar": "/appTemplates/chatGuide/avatar.png", + "avatar": "/appTemplateMarketTemplates/chatGuide/avatar.png", "authorAvatar": "/icon/logo.svg", - "tags": [{ "id": "office-services", "label": "办公服务" }], + "tags": ["office-services"], "type": "simple", "workflow": { "nodes": [ diff --git a/projects/app/public/appTemplates/dalle/avatar.svg b/projects/app/public/appTemplateMarketTemplates/dalle/avatar.svg similarity index 100% rename from projects/app/public/appTemplates/dalle/avatar.svg rename to projects/app/public/appTemplateMarketTemplates/dalle/avatar.svg diff --git a/projects/app/public/appTemplates/dalle/template.json b/projects/app/public/appTemplateMarketTemplates/dalle/template.json similarity index 98% rename from projects/app/public/appTemplates/dalle/template.json rename to projects/app/public/appTemplateMarketTemplates/dalle/template.json index 44be36000e2..6a69551f5d9 100644 --- a/projects/app/public/appTemplates/dalle/template.json +++ b/projects/app/public/appTemplateMarketTemplates/dalle/template.json @@ -3,13 +3,10 @@ "name": "Dalle3绘图", "intro": "通过请求Dalle3接口绘图,需要有 api key", "author": "Fastgpt Team", - "avatar": "/appTemplates/dalle/avatar.svg", + "avatar": "/appTemplateMarketTemplates/dalle/avatar.svg", "authorAvatar": "/icon/logo.svg", "type": "advanced", - "tags": [ - { "id": "recommendation", "label": "推荐" }, - { "id": "image", "label": "图片生成" } - ], + "tags": ["recommendation", "image"], "workflow": { "nodes": [ { diff --git a/projects/app/public/appTemplates/google/avatar.svg b/projects/app/public/appTemplateMarketTemplates/google/avatar.svg similarity index 100% rename from projects/app/public/appTemplates/google/avatar.svg rename to projects/app/public/appTemplateMarketTemplates/google/avatar.svg diff --git a/projects/app/public/appTemplates/google/template.json b/projects/app/public/appTemplateMarketTemplates/google/template.json similarity index 98% rename from projects/app/public/appTemplates/google/template.json rename to projects/app/public/appTemplateMarketTemplates/google/template.json index 9674ae25f91..faffa39570b 100644 --- a/projects/app/public/appTemplates/google/template.json +++ b/projects/app/public/appTemplateMarketTemplates/google/template.json @@ -3,12 +3,9 @@ "name": "谷歌搜索", "intro": "通过请求谷歌搜索,查询相关内容作为模型的参考。", "author": "Fastgpt Team", - "avatar": "/appTemplates/google/avatar.svg", + "avatar": "/appTemplateMarketTemplates/google/avatar.svg", "authorAvatar": "/icon/logo.svg", - "tags": [ - { "id": "recommendation", "label": "推荐" }, - { "id": "web-search", "label": "联网搜索" } - ], + "tags": ["recommendation", "web-search"], "type": "advanced", "workflow": { "nodes": [ diff --git a/projects/app/public/appTemplates/toolChat/avatar.png b/projects/app/public/appTemplateMarketTemplates/toolChat/avatar.png similarity index 100% rename from projects/app/public/appTemplates/toolChat/avatar.png rename to projects/app/public/appTemplateMarketTemplates/toolChat/avatar.png diff --git a/projects/app/public/appTemplates/toolChat/template.json b/projects/app/public/appTemplateMarketTemplates/toolChat/template.json similarity index 96% rename from projects/app/public/appTemplates/toolChat/template.json rename to projects/app/public/appTemplateMarketTemplates/toolChat/template.json index c06fc79d965..174e5d828f5 100644 --- a/projects/app/public/appTemplates/toolChat/template.json +++ b/projects/app/public/appTemplateMarketTemplates/toolChat/template.json @@ -3,12 +3,9 @@ "name": "知道时间的机器人", "intro": "通过挂载时间插件,让模型获取当前最新时间", "author": "Fastgpt Team", - "avatar": "/appTemplates/toolChat/avatar.png", + "avatar": "/appTemplateMarketTemplates/toolChat/avatar.png", "authorAvatar": "/icon/logo.svg", - "tags": [ - { "id": "recommendation", "label": "推荐" }, - { "id": "roleplay", "label": "角色扮演" } - ], + "tags": ["recommendation", "roleplay"], "type": "simple", "workflow": { "nodes": [ diff --git a/projects/app/src/pages/api/core/app/plugin/getSystemPluginTemplates.ts b/projects/app/src/pages/api/core/app/plugin/getSystemPluginTemplates.ts index 17283924f6d..13fad850fb3 100644 --- a/projects/app/src/pages/api/core/app/plugin/getSystemPluginTemplates.ts +++ b/projects/app/src/pages/api/core/app/plugin/getSystemPluginTemplates.ts @@ -50,7 +50,6 @@ async function handler( return item.parentId === formatParentId; }) ); - // return getCommunityPluginsTemplateList(); } export default NextAPI(handler); diff --git a/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx b/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx index db36e578e85..446d883eb90 100644 --- a/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx +++ b/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx @@ -22,7 +22,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon'; import { useState } from 'react'; import MyBox from '@fastgpt/web/components/common/MyBox'; import AppTypeTag from './TypeTag'; -import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; +import { AppTemplateTypeEnum, AppTypeEnum } from '@fastgpt/global/core/app/constants'; import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { getTemplateMarketItemDetail, @@ -39,7 +39,6 @@ import { debounce, throttle } from 'lodash'; import { useTranslation } from 'react-i18next'; import { useI18n } from '@/web/context/I18n'; import { useSystem } from '@fastgpt/web/hooks/useSystem'; -import { AppTemplateTypeEnum } from './constants'; const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { const { t } = useTranslation(); @@ -208,7 +207,7 @@ const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { templateTypes.map((item) => { if ( templateData - ?.filter((template) => template.tags?.map((tag) => tag.id).includes(item.id)) + ?.filter((template) => template.tags.includes(item.id)) .filter((templateData) => { if (currentAppType === 'all') return true; return templateData.type === currentAppType; @@ -251,7 +250,7 @@ const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { {templateTypes.map((item) => { const currentTemplates = templateData - ?.filter((template) => template.tags?.map((tag) => tag.id).includes(item.id)) + ?.filter((template) => template.tags.includes(item.id)) .filter((template) => { if (currentAppType === 'all') return true; return template.type === currentAppType; diff --git a/projects/app/src/pages/app/list/components/constants.tsx b/projects/app/src/pages/app/list/components/constants.tsx deleted file mode 100644 index b3de29120b1..00000000000 --- a/projects/app/src/pages/app/list/components/constants.tsx +++ /dev/null @@ -1,12 +0,0 @@ -export enum AppTemplateTypeEnum { - recommendation = 'recommendation', - writing = 'writing', - imageGeneration = 'image-generation', - webSearch = 'web-search', - roleplay = 'roleplay', - officeServices = 'office-services' -} - -export default function Dom() { - return <>; -} diff --git a/projects/app/src/pages/app/list/components/test.txt b/projects/app/src/pages/app/list/components/test.txt deleted file mode 100644 index aa8928532b1..00000000000 --- a/projects/app/src/pages/app/list/components/test.txt +++ /dev/null @@ -1,608 +0,0 @@ -{ - "nodes": [ - { - "nodeId": "pluginInput", - "name": "自定义插件输入", - "intro": "可以配置插件需要哪些输入,利用这些输入来运行插件", - "avatar": "core/workflow/template/workflowStart", - "flowNodeType": "pluginInput", - "showStatus": false, - "position": { - "x": -219.6824105687828, - "y": -101.77531175072627 - }, - "version": "481", - "inputs": [ - { - "renderTypeList": [ - "textarea" - ], - "selectedTypeIndex": 0, - "valueType": "string", - "canEdit": true, - "key": "task", - "label": "task", - "description": "需要执行的任务", - "required": true, - "defaultValue": "翻译外文文本" - }, - { - "renderTypeList": [ - "textarea" - ], - "selectedTypeIndex": 0, - "valueType": "string", - "canEdit": true, - "key": "prompt_example", - "label": "prompt_example", - "description": "提示词示例", - "required": true, - "defaultValue": "Sealos is a cloud operating system distribution based on the Kubernetes kernel. It adopts a cloud-native approach, discarding traditional cloud computing architecture, and shifting towards a new architecture with Kubernetes as the cloud kernel. This allows enterprises to use the cloud as effortlessly as they would use a personal computer.\n\nUsers will be able to install any high-availability distributed application on Kubernetes with the click of a button, similar to using a personal computer. It practically requires no professional delivery or operational costs. Simultaneously, utilizing unique cluster imaging capabilities, users can package any distributed application into an OCI image, freely combine a variety of distributed applications, and easily customize their desired cloud. The powerful and flexible app store function can meet the diverse needs of various users." - }, - { - "renderTypeList": [ - "textarea" - ], - "selectedTypeIndex": 0, - "valueType": "string", - "canEdit": true, - "key": "response_example", - "label": "response_example", - "description": "AI 回复示例", - "required": true, - "defaultValue": "Sealos 是一款以 Kubernetes 为内核的云操作系统发行版。它以云原生的方式,抛弃了传统的云计算架构,转向以 Kubernetes 为云内核的新架构,使企业能够像使用个人电脑一样简单地使用云。\n\n用户将可以像使用个人电脑一样在 Kubernetes 上一键安装任意高可用分布式应用,几乎不需要任何专业的交付和运维成本。同时,利用独特的集群镜像能力,用户可将任意分布式应用打包成 OCI 镜像,自由组合各种分布式应用,轻松订制所需的云。通过强大且灵活的应用商店功能,可满足各类用户的多样化需求。" - } - ], - "outputs": [ - { - "id": "task", - "valueType": "string", - "key": "task", - "label": "task", - "type": "hidden" - }, - { - "id": "prompt_example", - "valueType": "string", - "key": "prompt_example", - "label": "prompt_example", - "type": "hidden" - }, - { - "id": "response_example", - "valueType": "string", - "key": "response_example", - "label": "response_example", - "type": "hidden" - } - ] - }, - { - "nodeId": "pluginOutput", - "name": "自定义插件输出", - "intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出", - "avatar": "core/workflow/template/pluginOutput", - "flowNodeType": "pluginOutput", - "showStatus": false, - "position": { - "x": 2588.698874413269, - "y": -37.73399941782753 - }, - "version": "481", - "inputs": [ - { - "renderTypeList": [ - "reference" - ], - "valueType": "chatHistory", - "canEdit": true, - "key": "问答示例", - "label": "问答示例", - "description": "高性能 AI 的问答示例", - "value": [ - "kGZBVzwZJvRr", - "sFzDC79CgJjR" - ] - } - ], - "outputs": [] - }, - { - "nodeId": "vvDMOt1OJVpO", - "name": "生成提示词和回答例子", - "intro": "AI 大模型对话", - "avatar": "core/workflow/template/aiChat", - "flowNodeType": "chatNode", - "showStatus": true, - "position": { - "x": 389.6070084022975, - "y": -390.1563503559081 - }, - "version": "481", - "inputs": [ - { - "key": "model", - "renderTypeList": [ - "settingLLMModel", - "reference" - ], - "label": "core.module.input.label.aiModel", - "valueType": "string", - "selectedTypeIndex": 0, - "value": "claude-3-5-sonnet-20240620" - }, - { - "key": "temperature", - "renderTypeList": [ - "hidden" - ], - "label": "", - "value": 0, - "valueType": "number", - "min": 0, - "max": 10, - "step": 1 - }, - { - "key": "maxToken", - "renderTypeList": [ - "hidden" - ], - "label": "", - "value": 2000, - "valueType": "number", - "min": 100, - "max": 4000, - "step": 50 - }, - { - "key": "isResponseAnswerText", - "renderTypeList": [ - "hidden" - ], - "label": "", - "value": false, - "valueType": "boolean" - }, - { - "key": "quoteTemplate", - "renderTypeList": [ - "hidden" - ], - "label": "", - "valueType": "string" - }, - { - "key": "quotePrompt", - "renderTypeList": [ - "hidden" - ], - "label": "", - "valueType": "string" - }, - { - "key": "systemPrompt", - "renderTypeList": [ - "textarea", - "reference" - ], - "max": 3000, - "valueType": "string", - "label": "core.ai.Prompt", - "description": "core.app.tip.chatNodeSystemPromptTip", - "placeholder": "core.app.tip.chatNodeSystemPromptTip", - "value": "## Task:\nGiven an example training sample, create 7 additional samples for the same task that are even better. Each example should contain a and a .\n\n## Rules:\n1. Ensure the new examples are diverse and unique from one another.\n2. They should all be perfect. If you make a mistake, this system won't work.\n\n## OutputFormat:\n\n\nPUT_PROMPT_HERE\n\n\nPUT_RESPONSE_HERE\n\n\n\n\n\nPUT_PROMPT_HERE\n\n\nPUT_RESPONSE_HERE\n\n\n" - }, - { - "key": "history", - "renderTypeList": [ - "numberInput", - "reference" - ], - "valueType": "chatHistory", - "label": "core.module.input.label.chat history", - "description": "最多携带多少轮对话记录", - "required": true, - "min": 0, - "max": 50, - "value": 6 - }, - { - "key": "userChatInput", - "renderTypeList": [ - "reference", - "textarea" - ], - "valueType": "string", - "label": "用户问题", - "required": true, - "toolDescription": "用户问题", - "selectedTypeIndex": 1, - "value": "\n{{$pluginInput.task$}}\n\n\n\n{{$pluginInput.prompt_example$}}\n\n\n\n{{$pluginInput.response_example$}}\n" - }, - { - "key": "quoteQA", - "renderTypeList": [ - "settingDatasetQuotePrompt" - ], - "label": "", - "debugLabel": "知识库引用", - "description": "", - "valueType": "datasetQuote" - } - ], - "outputs": [ - { - "id": "history", - "key": "history", - "required": true, - "label": "core.module.output.label.New context", - "description": "core.module.output.description.New context", - "valueType": "chatHistory", - "type": "static" - }, - { - "id": "answerText", - "key": "answerText", - "required": true, - "label": "core.module.output.label.Ai response content", - "description": "core.module.output.description.Ai response content", - "valueType": "string", - "type": "static" - } - ] - }, - { - "nodeId": "kGZBVzwZJvRr", - "name": "生成聊天记录", - "intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。", - "avatar": "core/workflow/template/codeRun", - "flowNodeType": "code", - "showStatus": true, - "position": { - "x": 1917.9673096589154, - "y": -368.753298042259 - }, - "version": "482", - "inputs": [ - { - "key": "system_addInputParam", - "renderTypeList": [ - "addInputParam" - ], - "valueType": "dynamic", - "label": "", - "required": false, - "description": "这些变量会作为代码的运行的输入参数", - "customInputConfig": { - "selectValueTypeList": [ - "string", - "number", - "boolean", - "object", - "arrayString", - "arrayNumber", - "arrayBoolean", - "arrayObject", - "any", - "chatHistory", - "datasetQuote", - "dynamic", - "selectApp", - "selectDataset" - ], - "showDescription": false, - "showDefaultValue": true - } - }, - { - "key": "codeType", - "renderTypeList": [ - "hidden" - ], - "label": "", - "value": "js" - }, - { - "key": "code", - "renderTypeList": [ - "custom" - ], - "label": "", - "value": "function main({promptAndResponseExamples, systemPrompt}){\n const promptsAndResponses = [];\n const examplePattern = /(.*?)<\\/example_\\w+>/gs;\n const promptPattern = /(.*?)<\\/prompt>/s;\n const responsePattern = /(.*?)<\\/response>/s;\n\n let exampleMatch;\n while ((exampleMatch = examplePattern.exec(promptAndResponseExamples)) !== null) {\n const exampleContent = exampleMatch[1];\n const promptMatch = promptPattern.exec(exampleContent);\n const responseMatch = responsePattern.exec(exampleContent);\n\n if (promptMatch && responseMatch) {\n const prompt = promptMatch[1].trim();\n const response = responseMatch[1].trim();\n promptsAndResponses.push({ prompt, response });\n }\n }\n \n const chatHistory = [\n {\n \"obj\": \"System\",\n \"value\": [\n {\n \"type\": \"text\",\n \"text\": {\n \"content\": systemPrompt.replace(/^\\n|\\n<\\/system_prompt>$/g, '')\n }\n }\n ]\n },\n ...promptsAndResponses.map(({prompt, response}) => [\n {\n \"obj\": \"Human\",\n \"value\": [\n {\n \"type\": \"text\",\n \"text\": {\n \"content\": prompt\n }\n }\n ]\n },\n {\n \"obj\": \"AI\",\n \"value\": [\n {\n \"type\": \"text\",\n \"text\": {\n \"content\": response\n }\n }\n ]\n }\n ]).flat()\n ];\n\n return {\n chatHistory\n };\n}\n" - }, - { - "renderTypeList": [ - "reference" - ], - "valueType": "string", - "canEdit": true, - "key": "promptAndResponseExamples", - "label": "promptAndResponseExamples", - "customInputConfig": { - "selectValueTypeList": [ - "string", - "number", - "boolean", - "object", - "arrayString", - "arrayNumber", - "arrayBoolean", - "arrayObject", - "any", - "chatHistory", - "datasetQuote", - "dynamic", - "selectApp", - "selectDataset" - ], - "showDescription": false, - "showDefaultValue": true - }, - "required": true, - "value": [ - "vvDMOt1OJVpO", - "answerText" - ] - }, - { - "renderTypeList": [ - "reference" - ], - "valueType": "string", - "canEdit": true, - "key": "systemPrompt", - "label": "systemPrompt", - "customInputConfig": { - "selectValueTypeList": [ - "string", - "number", - "boolean", - "object", - "arrayString", - "arrayNumber", - "arrayBoolean", - "arrayObject", - "any", - "chatHistory", - "datasetQuote", - "dynamic", - "selectApp", - "selectDataset" - ], - "showDescription": false, - "showDefaultValue": true - }, - "required": true, - "value": [ - "agJb9pvuJCKl", - "answerText" - ] - } - ], - "outputs": [ - { - "id": "system_rawResponse", - "key": "system_rawResponse", - "label": "完整响应数据", - "valueType": "object", - "type": "static" - }, - { - "id": "error", - "key": "error", - "label": "运行错误", - "description": "代码运行错误信息,成功时返回空", - "valueType": "object", - "type": "static" - }, - { - "id": "system_addOutputParam", - "key": "system_addOutputParam", - "type": "dynamic", - "valueType": "dynamic", - "label": "", - "customFieldConfig": { - "selectValueTypeList": [ - "string", - "number", - "boolean", - "object", - "arrayString", - "arrayNumber", - "arrayBoolean", - "arrayObject", - "any", - "chatHistory", - "datasetQuote", - "dynamic", - "selectApp", - "selectDataset" - ], - "showDescription": false, - "showDefaultValue": false - }, - "description": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key" - }, - { - "id": "sFzDC79CgJjR", - "valueType": "chatHistory", - "type": "dynamic", - "key": "chatHistory", - "label": "chatHistory" - } - ] - }, - { - "nodeId": "agJb9pvuJCKl", - "name": "生成系统提示词", - "intro": "AI 大模型对话", - "avatar": "core/workflow/template/aiChat", - "flowNodeType": "chatNode", - "showStatus": true, - "position": { - "x": 1166.5280665265466, - "y": -391.87506915222184 - }, - "version": "481", - "inputs": [ - { - "key": "model", - "renderTypeList": [ - "settingLLMModel", - "reference" - ], - "label": "core.module.input.label.aiModel", - "valueType": "string", - "selectedTypeIndex": 0, - "value": "claude-3-5-sonnet-20240620" - }, - { - "key": "temperature", - "renderTypeList": [ - "hidden" - ], - "label": "", - "value": 0, - "valueType": "number", - "min": 0, - "max": 10, - "step": 1 - }, - { - "key": "maxToken", - "renderTypeList": [ - "hidden" - ], - "label": "", - "value": 2000, - "valueType": "number", - "min": 100, - "max": 4000, - "step": 50 - }, - { - "key": "isResponseAnswerText", - "renderTypeList": [ - "hidden" - ], - "label": "", - "value": false, - "valueType": "boolean" - }, - { - "key": "quoteTemplate", - "renderTypeList": [ - "hidden" - ], - "label": "", - "valueType": "string" - }, - { - "key": "quotePrompt", - "renderTypeList": [ - "hidden" - ], - "label": "", - "valueType": "string" - }, - { - "key": "systemPrompt", - "renderTypeList": [ - "textarea", - "reference" - ], - "max": 3000, - "valueType": "string", - "label": "core.ai.Prompt", - "description": "core.app.tip.chatNodeSystemPromptTip", - "placeholder": "core.app.tip.chatNodeSystemPromptTip", - "value": "## Role:\nGiven a user-description of their a set of prompt / response pairs (it'll be in JSON for easy reading) for the types of outputs we want to generate given inputs, write a fantastic system prompt that describes the task to be done perfectly.\n\n## Rules:\n1. Do this perfectly.\n2. Respond only with the system prompt, and nothing else. No other text will be allowed.\n\n## OutputFormat:\n\nWRITE_SYSTEM_PROMPT_HERE\n" - }, - { - "key": "history", - "renderTypeList": [ - "numberInput", - "reference" - ], - "valueType": "chatHistory", - "label": "core.module.input.label.chat history", - "description": "最多携带多少轮对话记录", - "required": true, - "min": 0, - "max": 50, - "value": 6 - }, - { - "key": "userChatInput", - "renderTypeList": [ - "reference", - "textarea" - ], - "valueType": "string", - "label": "用户问题", - "required": true, - "toolDescription": "用户问题", - "selectedTypeIndex": 1, - "value": "\n{{$pluginInput.task$}}\n\n\n\n{{$vvDMOt1OJVpO.answerText$}}\n" - }, - { - "key": "quoteQA", - "renderTypeList": [ - "settingDatasetQuotePrompt" - ], - "label": "", - "debugLabel": "知识库引用", - "description": "", - "valueType": "datasetQuote" - } - ], - "outputs": [ - { - "id": "history", - "key": "history", - "required": true, - "label": "core.module.output.label.New context", - "description": "core.module.output.description.New context", - "valueType": "chatHistory", - "type": "static" - }, - { - "id": "answerText", - "key": "answerText", - "required": true, - "label": "core.module.output.label.Ai response content", - "description": "core.module.output.description.Ai response content", - "valueType": "string", - "type": "static" - } - ] - } - ], - "edges": [ - { - "source": "pluginInput", - "target": "vvDMOt1OJVpO", - "sourceHandle": "pluginInput-source-right", - "targetHandle": "vvDMOt1OJVpO-target-left" - }, - { - "source": "vvDMOt1OJVpO", - "target": "agJb9pvuJCKl", - "sourceHandle": "vvDMOt1OJVpO-source-right", - "targetHandle": "agJb9pvuJCKl-target-left" - }, - { - "source": "agJb9pvuJCKl", - "target": "kGZBVzwZJvRr", - "sourceHandle": "agJb9pvuJCKl-source-right", - "targetHandle": "kGZBVzwZJvRr-target-left" - }, - { - "source": "kGZBVzwZJvRr", - "target": "pluginOutput", - "sourceHandle": "kGZBVzwZJvRr-source-right", - "targetHandle": "pluginOutput-target-left" - } - ] -} \ No newline at end of file diff --git a/projects/app/src/pages/app/list/index.tsx b/projects/app/src/pages/app/list/index.tsx index abcbde914f9..763695e11da 100644 --- a/projects/app/src/pages/app/list/index.tsx +++ b/projects/app/src/pages/app/list/index.tsx @@ -222,12 +222,6 @@ const MyApps = () => { label: appT('type.Http plugin'), description: appT('type.Create http plugin tip'), onClick: onOpenCreateHttpPlugin - }, - { - icon: 'core/app/type/templateFill', - label: appT('type.Template'), - description: appT('type.Create template tip'), - onClick: onOpenTemplateModal } ] }, diff --git a/projects/app/src/service/core/app/template.ts b/projects/app/src/service/core/app/template.ts index 65039c6afd9..0468f815f4a 100644 --- a/projects/app/src/service/core/app/template.ts +++ b/projects/app/src/service/core/app/template.ts @@ -5,12 +5,18 @@ import path from 'path'; let appTemplateIdList = ['TranslateRobot', 'dalle', 'chatGuide', 'toolChat', 'google']; export const getTemplateMarketItems = async () => { - if (isProduction && global.appTemplates) return global.appTemplates; + if (isProduction && global.appTemplateMarketTemplates) return global.appTemplateMarketTemplates; - global.appTemplates = await Promise.all( + global.appTemplateMarketTemplates = await Promise.all( appTemplateIdList.map(async (name) => { try { - const filePath = path.join(process.cwd(), 'public', 'appTemplates', name, 'template.json'); + const filePath = path.join( + process.cwd(), + 'public', + 'appTemplateMarketTemplates', + name, + 'template.json' + ); const fileContent = await fs.readFile(filePath, 'utf-8'); const data = JSON.parse(fileContent); return data; @@ -21,7 +27,7 @@ export const getTemplateMarketItems = async () => { }) ); - return global.appTemplates; + return global.appTemplateMarketTemplates; }; export const getTemplateMarketItemDetail = async (id: string) => { From 2a830f8982a1767a4ba795c21605808521c8ad44 Mon Sep 17 00:00:00 2001 From: heheer <1239331448@qq.com> Date: Fri, 9 Aug 2024 10:44:52 +0800 Subject: [PATCH 4/5] i18n --- packages/web/i18n/en/app.json | 11 ++++--- packages/web/i18n/zh/app.json | 11 ++++--- .../list/components/TemplateMarketModal.tsx | 33 +++++++++---------- projects/app/src/service/core/app/template.ts | 10 ++++-- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/packages/web/i18n/en/app.json b/packages/web/i18n/en/app.json index 4e38d61c6d4..2970ca378da 100644 --- a/packages/web/i18n/en/app.json +++ b/packages/web/i18n/en/app.json @@ -82,11 +82,14 @@ "setting_app": "Settings", "setting_plugin": "Setting plugin", "template": { - "Search template": "Search template", + "simple_robot": "Simple Robot" + }, + "templateMarket": { + "Search_template": "Search template", + "Template_market": "Template market", + "no_intro": "No intro~", "Use": "Use", - "simple_robot": "Simple Robot", - "templateMarket": "Template market", - "type": { + "templateTypes": { "Image_generation": "Image generation", "Office_services": "Office searvices", "Roleplay": "Roleplay", diff --git a/packages/web/i18n/zh/app.json b/packages/web/i18n/zh/app.json index 134883bec4f..e6c49fc3e67 100644 --- a/packages/web/i18n/zh/app.json +++ b/packages/web/i18n/zh/app.json @@ -82,11 +82,14 @@ "setting_app": "应用配置", "setting_plugin": "插件配置", "template": { - "Search template": "搜索模板", + "simple_robot": "简易机器人" + }, + "templateMarket": { "Use": "使用", - "simple_robot": "简易机器人", - "templateMarket": "模板市场", - "type": { + "Search_template": "搜索模板", + "Template_market": "模板市场", + "no_intro": "还没有介绍~", + "templateTypes": { "Image_generation": "图片生成", "Office_services": "办公服务", "Recommendation": "推荐", diff --git a/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx b/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx index 446d883eb90..a2c7db4057c 100644 --- a/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx +++ b/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx @@ -45,27 +45,27 @@ const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { const templateTypes = [ { id: AppTemplateTypeEnum.recommendation, - label: t('app:template.type.Recommendation') + label: t('app:templateMarket.templateTypes.Recommendation') }, { id: AppTemplateTypeEnum.writing, - label: t('app:template.type.Writing') + label: t('app:templateMarket.templateTypes.Writing') }, { id: AppTemplateTypeEnum.imageGeneration, - label: t('app:template.type.Image_generation') + label: t('app:templateMarket.templateTypes.Image_generation') }, { id: AppTemplateTypeEnum.webSearch, - label: t('app:template.type.Web_search') + label: t('app:templateMarket.templateTypes.Web_search') }, { id: AppTemplateTypeEnum.roleplay, - label: t('app:template.type.Roleplay') + label: t('app:templateMarket.templateTypes.Roleplay') }, { id: AppTemplateTypeEnum.officeServices, - label: t('app:template.type.Office_services') + label: t('app:templateMarket.templateTypes.Office_services') } ]; const [currentType, setCurrentType] = useState(templateTypes[0].id); @@ -73,7 +73,6 @@ const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { const [currentSearch, setCurrentSearch] = useState(''); const { parentId, loadMyApps } = useContextSelector(AppListContext, (v) => v); const router = useRouter(); - const { appT } = useI18n(); const { isPc } = useSystem(); const { data: templateData, loading: isLoadingTemplates } = useRequest2( @@ -101,8 +100,8 @@ const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { router.push(`/app/detail?appId=${id}`); loadMyApps(); }, - successToast: t('common.Create Success'), - errorToast: t('common.Create Failed') + successToast: t('common:common.Create Success'), + errorToast: t('common:common.Create Failed') }); const handleScroll = throttle(() => { @@ -157,7 +156,7 @@ const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { - {appT('template.templateMarket')} + {t('app:templateMarket.Template_market')} {isPc && ( @@ -167,7 +166,7 @@ const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { { setCurrentSearch(e.target.value); }, 200)} @@ -184,10 +183,10 @@ const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { }} bg={'myGray.100'} list={[ - { label: appT('type.All'), value: 'all' }, - { label: appT('type.Simple bot'), value: AppTypeEnum.simple }, - { label: appT('type.Workflow bot'), value: AppTypeEnum.workflow }, - { label: appT('type.Plugin'), value: AppTypeEnum.plugin } + { label: t('app:type.All'), value: 'all' }, + { label: t('app:type.Simple bot'), value: AppTypeEnum.simple }, + { label: t('app:type.Workflow bot'), value: AppTypeEnum.workflow }, + { label: t('app:type.Plugin'), value: AppTypeEnum.plugin } ]} /> @@ -351,7 +350,7 @@ export const TemplateCard = ({ fontSize={'xs'} color={'myGray.500'} > - {item.intro || '还没写介绍~'} + {item.intro || t('app:templateMarket.no_intro')} diff --git a/projects/app/src/service/core/app/template.ts b/projects/app/src/service/core/app/template.ts index 0468f815f4a..30dbc7d9f69 100644 --- a/projects/app/src/service/core/app/template.ts +++ b/projects/app/src/service/core/app/template.ts @@ -2,13 +2,19 @@ import { isProduction } from '@fastgpt/service/common/system/constants'; import { promises as fs } from 'fs'; import path from 'path'; -let appTemplateIdList = ['TranslateRobot', 'dalle', 'chatGuide', 'toolChat', 'google']; +let appTemplateMarketTemplatesIdList = [ + 'TranslateRobot', + 'dalle', + 'chatGuide', + 'toolChat', + 'google' +]; export const getTemplateMarketItems = async () => { if (isProduction && global.appTemplateMarketTemplates) return global.appTemplateMarketTemplates; global.appTemplateMarketTemplates = await Promise.all( - appTemplateIdList.map(async (name) => { + appTemplateMarketTemplatesIdList.map(async (name) => { try { const filePath = path.join( process.cwd(), From 774f6020e3985837cc794250d566bb6d2e0992e4 Mon Sep 17 00:00:00 2001 From: heheer <1239331448@qq.com> Date: Fri, 9 Aug 2024 11:29:42 +0800 Subject: [PATCH 5/5] fix --- .../pages/app/list/components/CreateModal.tsx | 29 ++++++++++++------- projects/app/src/pages/app/list/index.tsx | 12 +------- projects/app/src/service/core/app/template.ts | 23 ++++----------- 3 files changed, 26 insertions(+), 38 deletions(-) diff --git a/projects/app/src/pages/app/list/components/CreateModal.tsx b/projects/app/src/pages/app/list/components/CreateModal.tsx index 5dc79e8a938..4a112473c2e 100644 --- a/projects/app/src/pages/app/list/components/CreateModal.tsx +++ b/projects/app/src/pages/app/list/components/CreateModal.tsx @@ -1,5 +1,15 @@ import React, { useCallback, useRef } from 'react'; -import { Box, Flex, Button, ModalFooter, ModalBody, Input, Grid, Card } from '@chakra-ui/react'; +import { + Box, + Flex, + Button, + ModalFooter, + ModalBody, + Input, + Grid, + Card, + useDisclosure +} from '@chakra-ui/react'; import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; import { useForm } from 'react-hook-form'; import { compressImgFileAndUpload } from '@/web/common/file/controller'; @@ -20,6 +30,7 @@ import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; import { useI18n } from '@/web/context/I18n'; import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { ChevronRightIcon } from '@chakra-ui/icons'; +import TemplateMarketModal from './TemplateMarketModal'; type FormType = { avatar: string; @@ -29,21 +40,18 @@ type FormType = { export type CreateAppType = AppTypeEnum.simple | AppTypeEnum.workflow | AppTypeEnum.plugin; -const CreateModal = ({ - onClose, - type, - onOpenTemplateModal -}: { - type: CreateAppType; - onClose: () => void; - onOpenTemplateModal: () => void; -}) => { +const CreateModal = ({ onClose, type }: { type: CreateAppType; onClose: () => void }) => { const { t } = useTranslation(); const { appT } = useI18n(); const { toast } = useToast(); const router = useRouter(); const { parentId, loadMyApps } = useContextSelector(AppListContext, (v) => v); const { isPc } = useSystem(); + const { + isOpen: isOpenTemplateModal, + onOpen: onOpenTemplateModal, + onClose: onCloseTemplateModal + } = useDisclosure(); const typeMap = useRef({ [AppTypeEnum.simple]: { @@ -231,6 +239,7 @@ const CreateModal = ({
+ {isOpenTemplateModal && } ); }; diff --git a/projects/app/src/pages/app/list/index.tsx b/projects/app/src/pages/app/list/index.tsx index 763695e11da..9b90e5309bb 100644 --- a/projects/app/src/pages/app/list/index.tsx +++ b/projects/app/src/pages/app/list/index.tsx @@ -77,11 +77,6 @@ const MyApps = () => { onOpen: onOpenCreateHttpPlugin, onClose: onCloseCreateHttpPlugin } = useDisclosure(); - const { - isOpen: isOpenTemplateModal, - onOpen: onOpenTemplateModal, - onClose: onCloseTemplateModal - } = useDisclosure(); const [editFolder, setEditFolder] = useState(); const { runAsync: onCreateFolder } = useRequest2(postCreateAppFolder, { @@ -312,14 +307,9 @@ const MyApps = () => { /> )} {!!createAppType && ( - setCreateAppType(undefined)} - onOpenTemplateModal={onOpenTemplateModal} - /> + setCreateAppType(undefined)} /> )} {isOpenCreateHttpPlugin && } - {isOpenTemplateModal && } ); }; diff --git a/projects/app/src/service/core/app/template.ts b/projects/app/src/service/core/app/template.ts index 30dbc7d9f69..cad29c9d749 100644 --- a/projects/app/src/service/core/app/template.ts +++ b/projects/app/src/service/core/app/template.ts @@ -2,32 +2,21 @@ import { isProduction } from '@fastgpt/service/common/system/constants'; import { promises as fs } from 'fs'; import path from 'path'; -let appTemplateMarketTemplatesIdList = [ - 'TranslateRobot', - 'dalle', - 'chatGuide', - 'toolChat', - 'google' -]; - export const getTemplateMarketItems = async () => { if (isProduction && global.appTemplateMarketTemplates) return global.appTemplateMarketTemplates; + const templatesDir = path.join(process.cwd(), 'public', 'appTemplateMarketTemplates'); + const templateNames = await fs.readdir(templatesDir); + global.appTemplateMarketTemplates = await Promise.all( - appTemplateMarketTemplatesIdList.map(async (name) => { + templateNames.map(async (name) => { try { - const filePath = path.join( - process.cwd(), - 'public', - 'appTemplateMarketTemplates', - name, - 'template.json' - ); + const filePath = path.join(templatesDir, name, 'template.json'); const fileContent = await fs.readFile(filePath, 'utf-8'); const data = JSON.parse(fileContent); return data; } catch (error) { - console.error(`Error fetching template ${name}:`); + console.error(`Error fetching template ${name}:`, error); return null; } })