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 66e9bc18ccb..8265f29193d 100644 --- a/packages/global/core/workflow/type/index.d.ts +++ b/packages/global/core/workflow/type/index.d.ts @@ -46,9 +46,21 @@ export type WorkflowTemplateType = { // template market export type TemplateMarketItemType = WorkflowTemplateType & { - tags?: { id: string; label: string }[]; + tags: string[]; + type: AppTypeEnum.simple | AppTypeEnum.workflow | AppTypeEnum.plugin; }; - +// template market list +export type TemplateMarketListItemType = { + id: string; + name: string; + intro: string; + author: string; + tags: 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/type.d.ts b/packages/service/type.d.ts index adfd7b253f5..e982fbc31fd 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 appTemplateMarketTemplates: 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..120e4eeae5a 100644 --- a/packages/web/components/common/MyModal/index.tsx +++ b/packages/web/components/common/MyModal/index.tsx @@ -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/packages/web/i18n/en/app.json b/packages/web/i18n/en/app.json index 9b846b8c7d1..2970ca378da 100644 --- a/packages/web/i18n/en/app.json +++ b/packages/web/i18n/en/app.json @@ -84,6 +84,19 @@ "template": { "simple_robot": "Simple Robot" }, + "templateMarket": { + "Search_template": "Search template", + "Template_market": "Template market", + "no_intro": "No intro~", + "Use": "Use", + "templateTypes": { + "Image_generation": "Image generation", + "Office_services": "Office searvices", + "Roleplay": "Roleplay", + "Web_search": "Web search", + "Writing": "Writing" + } + }, "time_zone": "Time zone", "tool_input_param_tip": "Configure related information before the plugin runs properly", "transition_to_workflow": "Transition to workflow", @@ -91,7 +104,7 @@ "transition_to_workflow_create_new_tip": "After converting to workflow, it will not be able to convert back to simple mode, please confirm!", "type": { "All": "All", - "Create http plugin tip": "Create plug-ins in batches using OpenAPI schema, compatible with GPTs format.", + "Create http plugin tip": "Create plug-ins in batches using OpenAPI schema, compatible with GPTs format", "Create one plugin tip": "The input and output workflows can be customized", "Create plugin bot": "Create plugin bot", "Create simple bot": "Create simple bot", @@ -101,6 +114,7 @@ "Http plugin": "Http plugin", "Plugin": "Plugin", "Simple bot": "Simple bot", + "Template": "Create by template", "Workflow bot": "Workflow" }, "upload_file_max_amount": "Max files", diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index 68d2bb1c581..19d9140254b 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -596,8 +596,7 @@ "success": "Start syncing" } }, - "training": { - } + "training": {} }, "data": { "Auxiliary Data": "Auxiliary data", diff --git a/packages/web/i18n/zh/app.json b/packages/web/i18n/zh/app.json index e43f1d358fe..e6c49fc3e67 100644 --- a/packages/web/i18n/zh/app.json +++ b/packages/web/i18n/zh/app.json @@ -84,6 +84,20 @@ "template": { "simple_robot": "简易机器人" }, + "templateMarket": { + "Use": "使用", + "Search_template": "搜索模板", + "Template_market": "模板市场", + "no_intro": "还没有介绍~", + "templateTypes": { + "Image_generation": "图片生成", + "Office_services": "办公服务", + "Recommendation": "推荐", + "Roleplay": "角色扮演", + "Web_search": "联网搜索", + "Writing": "文本创作" + } + }, "time_zone": "时区", "tool_input_param_tip": "该插件正常运行需要配置相关信息", "transition_to_workflow": "转成工作流", @@ -91,16 +105,18 @@ "transition_to_workflow_create_new_tip": "转化成工作流后,将无法转化回简易模式,请确认!", "type": { "All": "全部", - "Create http plugin tip": "通过 OpenAPI Schema 批量创建插件,兼容 GPTs 格式。", + "Create http plugin tip": "通过 OpenAPI Schema 批量创建插件,兼容 GPTs 格式", "Create one plugin tip": "可以自定义输入和输出的工作流,通常用于封装重复使用的工作流", "Create plugin bot": "创建插件", "Create simple bot": "创建简易应用", "Create simple bot tip": "通过填表单形式,创建简单的 AI 应用,适合新手", + "Create template tip": "在模板市场探索更多玩法,带你理解并上手各种应用", "Create workflow bot": "创建工作流", "Create workflow tip": "通过低代码的方式,构建逻辑复杂的多轮对话 AI 应用,推荐高级玩家使用", "Http plugin": "HTTP 插件", "Plugin": "插件", "Simple bot": "简易应用", + "Template": "通过模板创建", "Workflow bot": "工作流" }, "upload_file_max_amount": "最大文件数量", diff --git a/packages/web/i18n/zh/common.json b/packages/web/i18n/zh/common.json index d84df235418..815f7198880 100644 --- a/packages/web/i18n/zh/common.json +++ b/packages/web/i18n/zh/common.json @@ -361,6 +361,14 @@ }, "no_app": "还没有应用,快去创建一个吧!", "not_published": "未发布", + "more": "查看更多", + "navbar": { + "External": "外部使用", + "Flow mode": "高级编排", + "Publish": "发布", + "Publish app": "发布应用", + "Simple mode": "简易配置" + }, "outLink": { "Can Drag": "图标可拖拽", "Default open": "默认打开", @@ -598,8 +606,7 @@ "success": "开始同步" } }, - "training": { - } + "training": {} }, "data": { "Auxiliary Data": "辅助数据", diff --git a/projects/app/public/appTemplateMarketTemplates/TranslateRobot/avatar.svg b/projects/app/public/appTemplateMarketTemplates/TranslateRobot/avatar.svg new file mode 100644 index 00000000000..8d02841e69d --- /dev/null +++ b/projects/app/public/appTemplateMarketTemplates/TranslateRobot/avatar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/projects/app/public/appTemplateMarketTemplates/TranslateRobot/template.json b/projects/app/public/appTemplateMarketTemplates/TranslateRobot/template.json new file mode 100644 index 00000000000..9533066ec63 --- /dev/null +++ b/projects/app/public/appTemplateMarketTemplates/TranslateRobot/template.json @@ -0,0 +1,581 @@ +{ + "id": "TranslateRobot", + "name": "多轮翻译机器人", + "intro": "通过 4 轮翻译,提高翻译英文的质量", + "author": "Fastgpt Team", + "avatar": "/appTemplateMarketTemplates/TranslateRobot/avatar.svg", + "authorAvatar": "/icon/logo.svg", + "tags": ["recommendation", "office-services"], + "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/appTemplateMarketTemplates/chatGuide/avatar.png b/projects/app/public/appTemplateMarketTemplates/chatGuide/avatar.png new file mode 100644 index 00000000000..598f9ed5eec Binary files /dev/null and b/projects/app/public/appTemplateMarketTemplates/chatGuide/avatar.png differ diff --git a/projects/app/public/appTemplateMarketTemplates/chatGuide/template.json b/projects/app/public/appTemplateMarketTemplates/chatGuide/template.json new file mode 100644 index 00000000000..40a8feabb24 --- /dev/null +++ b/projects/app/public/appTemplateMarketTemplates/chatGuide/template.json @@ -0,0 +1,255 @@ +{ + "id": "chatGuide", + "name": "对话引导 + 变量", + "intro": "可以在对话开始发送一段提示,或者让用户填写一些内容,作为本次对话的变量", + "author": "Fastgpt Team", + "avatar": "/appTemplateMarketTemplates/chatGuide/avatar.png", + "authorAvatar": "/icon/logo.svg", + "tags": ["office-services"], + "type": "simple", + "workflow": { + "nodes": [ + { + "nodeId": "userGuide", + "name": "系统配置", + "intro": "可以配置应用的系统参数", + "avatar": "/imgs/workflow/userGuide.png", + "flowNodeType": "FlowNodeTypeEnum.systemConfig", + "position": { + "x": 496.57560693988853, + "y": -490.7611729549753 + }, + "version": "481", + "inputs": [ + { + "key": "welcomeText", + "renderTypeList": ["FlowNodeInputTypeEnum.hidden"], + "valueType": "WorkflowIOValueTypeEnum.string", + "label": "core.app.Welcome Text", + "value": "你好,我可以为你翻译各种语言,请告诉我你需要翻译成什么语言?" + }, + { + "key": "variables", + "renderTypeList": ["FlowNodeInputTypeEnum.hidden"], + "valueType": "WorkflowIOValueTypeEnum.any", + "label": "core.app.Chat Variable", + "value": [ + { + "id": "myb3xk", + "key": "language", + "label": "目标语言", + "type": "select", + "required": true, + "maxLen": 50, + "enums": [ + { + "value": "中文" + }, + { + "value": "英文" + } + ] + } + ] + }, + { + "key": "questionGuide", + "valueType": "WorkflowIOValueTypeEnum.boolean", + "renderTypeList": ["FlowNodeInputTypeEnum.hidden"], + "label": "core.app.Question Guide", + "value": false + }, + { + "key": "tts", + "renderTypeList": ["FlowNodeInputTypeEnum.hidden"], + "valueType": "WorkflowIOValueTypeEnum.any", + "label": "", + "value": { + "type": "web" + } + }, + { + "key": "whisper", + "renderTypeList": ["FlowNodeInputTypeEnum.hidden"], + "valueType": "WorkflowIOValueTypeEnum.any", + "label": "", + "value": { + "open": false, + "autoSend": false, + "autoTTSResponse": false + } + }, + { + "key": "scheduleTrigger", + "renderTypeList": ["FlowNodeInputTypeEnum.hidden"], + "valueType": "WorkflowIOValueTypeEnum.any", + "label": "", + "value": null + } + ], + "outputs": [] + }, + { + "nodeId": "448745", + "name": "流程开始", + "intro": "", + "avatar": "/imgs/workflow/userChatInput.svg", + "flowNodeType": "FlowNodeTypeEnum.workflowStart", + "position": { + "x": 558.4082376415505, + "y": 123.72387429194112 + }, + "version": "481", + "inputs": [ + { + "key": "userChatInput", + "renderTypeList": ["FlowNodeInputTypeEnum.reference", "FlowNodeInputTypeEnum.textarea"], + "valueType": "WorkflowIOValueTypeEnum.string", + "label": "用户问题", + "required": true, + "toolDescription": "用户问题" + } + ], + "outputs": [ + { + "id": "userChatInput", + "key": "userChatInput", + "label": "core.module.input.label.user question", + "valueType": "WorkflowIOValueTypeEnum.string", + "type": "FlowNodeOutputTypeEnum.static" + } + ] + }, + { + "nodeId": "loOvhld2ZTKa", + "name": "AI 对话", + "intro": "AI 大模型对话", + "avatar": "/imgs/workflow/AI.png", + "flowNodeType": "FlowNodeTypeEnum.chatNode", + "showStatus": true, + "position": { + "x": 1097.7317280958762, + "y": -244.16014496351386 + }, + "version": "481", + "inputs": [ + { + "key": "model", + "renderTypeList": [ + "FlowNodeInputTypeEnum.settingLLMModel", + "FlowNodeInputTypeEnum.reference" + ], + "label": "core.module.input.label.aiModel", + "valueType": "WorkflowIOValueTypeEnum.string", + "value": "gpt-3.5-turbo" + }, + { + "key": "temperature", + "renderTypeList": ["FlowNodeInputTypeEnum.hidden"], + "label": "", + "value": 0, + "valueType": "WorkflowIOValueTypeEnum.number", + "min": 0, + "max": 10, + "step": 1 + }, + { + "key": "maxToken", + "renderTypeList": ["FlowNodeInputTypeEnum.hidden"], + "label": "", + "value": 2000, + "valueType": "WorkflowIOValueTypeEnum.number", + "min": 100, + "max": 4000, + "step": 50 + }, + { + "key": "isResponseAnswerText", + "renderTypeList": ["FlowNodeInputTypeEnum.hidden"], + "label": "", + "value": true, + "valueType": "WorkflowIOValueTypeEnum.boolean" + }, + { + "key": "quoteTemplate", + "renderTypeList": ["FlowNodeInputTypeEnum.hidden"], + "label": "", + "valueType": "WorkflowIOValueTypeEnum.string" + }, + { + "key": "quotePrompt", + "renderTypeList": ["FlowNodeInputTypeEnum.hidden"], + "label": "", + "valueType": "WorkflowIOValueTypeEnum.string" + }, + { + "key": "systemPrompt", + "renderTypeList": ["FlowNodeInputTypeEnum.textarea", "FlowNodeInputTypeEnum.reference"], + "max": 3000, + "valueType": "WorkflowIOValueTypeEnum.string", + "label": "core.ai.Prompt", + "description": "core.app.tip.chatNodeSystemPromptTip", + "placeholder": "core.app.tip.chatNodeSystemPromptTip", + "value": "请直接将我的问题翻译成{{language}},不需要回答问题。" + }, + { + "key": "history", + "renderTypeList": [ + "FlowNodeInputTypeEnum.numberInput", + "FlowNodeInputTypeEnum.reference" + ], + "valueType": "WorkflowIOValueTypeEnum.chatHistory", + "label": "core.module.input.label.chat history", + "required": true, + "min": 0, + "max": 30, + "value": 6 + }, + { + "key": "userChatInput", + "renderTypeList": ["FlowNodeInputTypeEnum.reference", "FlowNodeInputTypeEnum.textarea"], + "valueType": "WorkflowIOValueTypeEnum.string", + "label": "用户问题", + "required": true, + "toolDescription": "用户问题", + "value": ["448745", "userChatInput"] + }, + { + "key": "quoteQA", + "renderTypeList": ["FlowNodeInputTypeEnum.settingDatasetQuotePrompt"], + "label": "", + "debugLabel": "知识库引用", + "description": "", + "valueType": "WorkflowIOValueTypeEnum.datasetQuote" + } + ], + "outputs": [ + { + "id": "history", + "key": "history", + "label": "core.module.output.label.New context", + "description": "core.module.output.description.New context", + "valueType": "WorkflowIOValueTypeEnum.chatHistory", + "type": "FlowNodeOutputTypeEnum.static" + }, + { + "id": "answerText", + "key": "answerText", + "label": "core.module.output.label.Ai response content", + "description": "core.module.output.description.Ai response content", + "valueType": "WorkflowIOValueTypeEnum.string", + "type": "FlowNodeOutputTypeEnum.static" + } + ] + } + ], + "edges": [ + { + "source": "448745", + "target": "loOvhld2ZTKa", + "sourceHandle": "448745-source-right", + "targetHandle": "loOvhld2ZTKa-target-left" + } + ] + } +} diff --git a/projects/app/public/appTemplateMarketTemplates/dalle/avatar.svg b/projects/app/public/appTemplateMarketTemplates/dalle/avatar.svg new file mode 100644 index 00000000000..6eda6b8a848 --- /dev/null +++ b/projects/app/public/appTemplateMarketTemplates/dalle/avatar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/projects/app/public/appTemplateMarketTemplates/dalle/template.json b/projects/app/public/appTemplateMarketTemplates/dalle/template.json new file mode 100644 index 00000000000..6a69551f5d9 --- /dev/null +++ b/projects/app/public/appTemplateMarketTemplates/dalle/template.json @@ -0,0 +1,406 @@ +{ + "id": "dalle", + "name": "Dalle3绘图", + "intro": "通过请求Dalle3接口绘图,需要有 api key", + "author": "Fastgpt Team", + "avatar": "/appTemplateMarketTemplates/dalle/avatar.svg", + "authorAvatar": "/icon/logo.svg", + "type": "advanced", + "tags": ["recommendation", "image"], + "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/appTemplateMarketTemplates/google/avatar.svg b/projects/app/public/appTemplateMarketTemplates/google/avatar.svg new file mode 100644 index 00000000000..f29dfa728c3 --- /dev/null +++ b/projects/app/public/appTemplateMarketTemplates/google/avatar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/projects/app/public/appTemplateMarketTemplates/google/template.json b/projects/app/public/appTemplateMarketTemplates/google/template.json new file mode 100644 index 00000000000..faffa39570b --- /dev/null +++ b/projects/app/public/appTemplateMarketTemplates/google/template.json @@ -0,0 +1,443 @@ +{ + "id": "google", + "name": "谷歌搜索", + "intro": "通过请求谷歌搜索,查询相关内容作为模型的参考。", + "author": "Fastgpt Team", + "avatar": "/appTemplateMarketTemplates/google/avatar.svg", + "authorAvatar": "/icon/logo.svg", + "tags": ["recommendation", "web-search"], + "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/appTemplateMarketTemplates/toolChat/avatar.png b/projects/app/public/appTemplateMarketTemplates/toolChat/avatar.png new file mode 100644 index 00000000000..3fd4b5140d7 Binary files /dev/null and b/projects/app/public/appTemplateMarketTemplates/toolChat/avatar.png differ diff --git a/projects/app/public/appTemplateMarketTemplates/toolChat/template.json b/projects/app/public/appTemplateMarketTemplates/toolChat/template.json new file mode 100644 index 00000000000..174e5d828f5 --- /dev/null +++ b/projects/app/public/appTemplateMarketTemplates/toolChat/template.json @@ -0,0 +1,187 @@ +{ + "id": "toolChat", + "name": "知道时间的机器人", + "intro": "通过挂载时间插件,让模型获取当前最新时间", + "author": "Fastgpt Team", + "avatar": "/appTemplateMarketTemplates/toolChat/avatar.png", + "authorAvatar": "/icon/logo.svg", + "tags": ["recommendation", "roleplay"], + "type": "simple", + "workflow": { + "nodes": [ + { + "nodeId": "userGuide", + "name": "系统配置", + "intro": "可以配置应用的系统参数", + "avatar": "/imgs/workflow/userGuide.png", + "flowNodeType": "FlowNodeTypeEnum.systemConfig", + "position": { + "x": 531.2422736065552, + "y": -486.7611729549753 + }, + "version": "481", + "inputs": [], + "outputs": [] + }, + { + "nodeId": "workflowStartNodeId", + "name": "流程开始", + "intro": "", + "avatar": "/imgs/workflow/userChatInput.svg", + "flowNodeType": "FlowNodeTypeEnum.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", + "valueType": "string", + "type": "static" + } + ] + }, + { + "nodeId": "jrWPV9", + "name": "工具调用", + "intro": "通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。", + "avatar": "/imgs/workflow/tool.svg", + "flowNodeType": "FlowNodeTypeEnum.tools", + "showStatus": true, + "position": { + "x": 1062.1738942532802, + "y": -223.65033022650476 + }, + "version": "481", + "inputs": [ + { + "key": "model", + "renderTypeList": ["settingLLMModel", "reference"], + "label": "core.module.input.label.aiModel", + "valueType": "string", + "llmModelType": "all", + "value": "gpt-3.5-turbo" + }, + { + "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": ["workflowStartNodeId", "userChatInput"] + } + ], + "outputs": [ + { + "id": "answerText", + "key": "answerText", + "label": "core.module.output.label.Ai response content", + "description": "core.module.output.description.Ai response content", + "valueType": "string", + "type": "static" + } + ] + }, + { + "nodeId": "zBxjo5", + "name": "获取当前时间", + "intro": "获取用户当前时区的时间。", + "avatar": "/imgs/workflow/getCurrentTime.svg", + "flowNodeType": "pluginModule", + "showStatus": false, + "position": { + "x": 1000, + "y": 545 + }, + "version": "481", + "inputs": [], + "outputs": [ + { + "id": "time", + "type": "static", + "key": "time", + "valueType": "string", + "label": "time", + "description": "" + } + ], + "pluginId": "community-getTime" + } + ], + "edges": [ + { + "source": "workflowStartNodeId", + "target": "jrWPV9", + "sourceHandle": "workflowStartNodeId-source-right", + "targetHandle": "jrWPV9-target-left" + }, + { + "source": "jrWPV9", + "target": "zBxjo5", + "sourceHandle": "selectedTools", + "targetHandle": "selectedTools" + } + ], + "chatConfig": { + "scheduledTriggerConfig": { + "cronString": "", + "timezone": "Asia/Shanghai", + "defaultPrompt": "" + } + } + } +} diff --git a/projects/app/src/pages/api/core/app/template/getTemplateMarketItemDetail.ts b/projects/app/src/pages/api/core/app/template/getTemplateMarketItemDetail.ts new file mode 100644 index 00000000000..29c80a43414 --- /dev/null +++ b/projects/app/src/pages/api/core/app/template/getTemplateMarketItemDetail.ts @@ -0,0 +1,21 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; +import { authCert } from '@fastgpt/service/support/permission/auth/common'; +import { NextAPI } from '@/service/middleware/entry'; +import { TemplateMarketItemType } from '@fastgpt/global/core/workflow/type'; +import { getTemplateMarketItemDetail } from '@/service/core/app/template'; + +type Props = { + templateId: string; +}; + +async function handler( + req: NextApiRequest, + res: NextApiResponse +): 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..4a112473c2e 100644 --- a/projects/app/src/pages/app/list/components/CreateModal.tsx +++ b/projects/app/src/pages/app/list/components/CreateModal.tsx @@ -7,8 +7,8 @@ import { ModalBody, Input, Grid, - useTheme, - Card + Card, + useDisclosure } from '@chakra-ui/react'; import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; import { useForm } from 'react-hook-form'; @@ -29,6 +29,8 @@ 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'; +import TemplateMarketModal from './TemplateMarketModal'; type FormType = { avatar: string; @@ -45,6 +47,11 @@ const CreateModal = ({ onClose, type }: { type: CreateAppType; onClose: () => vo 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]: { @@ -146,8 +153,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 - + @@ -217,6 +239,7 @@ const CreateModal = ({ onClose, type }: { type: CreateAppType; onClose: () => vo + {isOpenTemplateModal && } ); }; 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..a2c7db4057c --- /dev/null +++ b/projects/app/src/pages/app/list/components/TemplateMarketModal.tsx @@ -0,0 +1,384 @@ +import { + Avatar, + Box, + Button, + Center, + Flex, + Grid, + HStack, + Input, + InputGroup, + InputLeftElement, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalHeader, + ModalOverlay, + 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 { AppTemplateTypeEnum, 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 { useSystem } from '@fastgpt/web/hooks/useSystem'; + +const TemplateMarketModal = ({ onClose }: { onClose: () => void }) => { + const { t } = useTranslation(); + const templateTypes = [ + { + id: AppTemplateTypeEnum.recommendation, + label: t('app:templateMarket.templateTypes.Recommendation') + }, + { + id: AppTemplateTypeEnum.writing, + label: t('app:templateMarket.templateTypes.Writing') + }, + { + id: AppTemplateTypeEnum.imageGeneration, + label: t('app:templateMarket.templateTypes.Image_generation') + }, + { + id: AppTemplateTypeEnum.webSearch, + label: t('app:templateMarket.templateTypes.Web_search') + }, + { + id: AppTemplateTypeEnum.roleplay, + label: t('app:templateMarket.templateTypes.Roleplay') + }, + { + id: AppTemplateTypeEnum.officeServices, + label: t('app:templateMarket.templateTypes.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 { isPc } = useSystem(); + + 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:common.Create Success'), + errorToast: t('common: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 ( + onClose && onClose()} + autoFocus={false} + blockScrollOnMount={false} + closeOnOverlayClick={false} + > + + + + + + + {t('app:templateMarket.Template_market')} + + {isPc && ( + + + + + { + setCurrentSearch(e.target.value); + }, 200)} + bg={'myGray.100'} + /> + + )} + + { + setCurrentAppType(value as AppTypeEnum | 'all'); + }} + bg={'myGray.100'} + list={[ + { 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 } + ]} + /> + + + + + + + + {isPc && + templateTypes.map((item) => { + if ( + templateData + ?.filter((template) => template.tags.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.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 { t } = useTranslation(); + + return ( + {}} + > + + + + {item.name} + + + + + + + {item.intro || t('app:templateMarket.no_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..9b90e5309bb 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( 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..cad29c9d749 --- /dev/null +++ b/projects/app/src/service/core/app/template.ts @@ -0,0 +1,45 @@ +import { isProduction } from '@fastgpt/service/common/system/constants'; +import { promises as fs } from 'fs'; +import path from 'path'; + +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( + templateNames.map(async (name) => { + try { + 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}:`, error); + return null; + } + }) + ); + + return global.appTemplateMarketTemplates; +}; + +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);