diff --git a/.vscode/settings.json b/.vscode/settings.json index 71f333fe0e2..2508d1ce820 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,5 +24,10 @@ "i18n-ally.translate.engines": ["google"], "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" - } + }, + "markdown.copyFiles.destination": { + "/docSite/content/**/*": "${documentWorkspaceFolder}/docSite/assets/imgs/" + }, + "markdown.copyFiles.overwriteBehavior": "nameIncrementally", + "markdown.copyFiles.transformPath": "const filename = uri.path.split('/').pop(); return `/imgs/${filename}`;" } \ No newline at end of file diff --git a/docSite/assets/imgs/image-1.png b/docSite/assets/imgs/image-1.png new file mode 100644 index 00000000000..6a479fe2c59 Binary files /dev/null and b/docSite/assets/imgs/image-1.png differ diff --git a/docSite/assets/imgs/image-2.png b/docSite/assets/imgs/image-2.png new file mode 100644 index 00000000000..4e8901e3276 Binary files /dev/null and b/docSite/assets/imgs/image-2.png differ diff --git a/docSite/assets/imgs/image-3.png b/docSite/assets/imgs/image-3.png new file mode 100644 index 00000000000..36069d7ee89 Binary files /dev/null and b/docSite/assets/imgs/image-3.png differ diff --git a/docSite/assets/imgs/image-4.png b/docSite/assets/imgs/image-4.png new file mode 100644 index 00000000000..f74f7ed6b69 Binary files /dev/null and b/docSite/assets/imgs/image-4.png differ diff --git a/docSite/assets/imgs/image.png b/docSite/assets/imgs/image.png new file mode 100644 index 00000000000..f226c3830ac Binary files /dev/null and b/docSite/assets/imgs/image.png differ diff --git a/docSite/content/zh-cn/docs/course/openapi.md b/docSite/content/zh-cn/docs/course/openapi.md index 5f473789303..898e20138bf 100644 --- a/docSite/content/zh-cn/docs/course/openapi.md +++ b/docSite/content/zh-cn/docs/course/openapi.md @@ -27,7 +27,7 @@ Tips: 安全起见,你可以设置一个额度或者过期时间,放置 key ## 替换三方应用的变量 ```bash -OPENAI_API_BASE_URL: https://api.tryfastgpt.ai/api (改成自己部署的域名) +OPENAI_API_BASE_URL: https://api.fastgpt.in/api (改成自己部署的域名) OPENAI_API_KEY = 上一步获取到的密钥 ``` diff --git a/docSite/content/zh-cn/docs/development/openapi/auth.md b/docSite/content/zh-cn/docs/development/openapi/auth.md index 13d2203b067..cea42082521 100644 --- a/docSite/content/zh-cn/docs/development/openapi/auth.md +++ b/docSite/content/zh-cn/docs/development/openapi/auth.md @@ -32,7 +32,7 @@ FastGPT 的 API Key **有 2 类**,一类是全局通用的 key (无法直接 OpenAPI 中,所有的接口都通过 Header.Authorization 进行鉴权。 ``` -baseUrl: "https://api.tryfastgpt.ai/api" +baseUrl: "https://api.fastgpt.in/api" headers: { Authorization: "Bearer {{apikey}}" } @@ -41,7 +41,7 @@ headers: { **发起应用对话示例** ```sh -curl --location --request POST 'https://api.tryfastgpt.ai/api/v1/chat/completions' \ +curl --location --request POST 'https://api.fastgpt.in/api/v1/chat/completions' \ --header 'Authorization: Bearer fastgpt-xxxxxx' \ --header 'Content-Type: application/json' \ --data-raw '{ diff --git a/docSite/content/zh-cn/docs/development/openapi/chat.md b/docSite/content/zh-cn/docs/development/openapi/chat.md index 4a336bb37b8..85fbb31ee60 100644 --- a/docSite/content/zh-cn/docs/development/openapi/chat.md +++ b/docSite/content/zh-cn/docs/development/openapi/chat.md @@ -29,7 +29,7 @@ weight: 852 {{< markdownify >}} ```bash -curl --location --request POST 'https://api.tryfastgpt.ai/api/v1/chat/completions' \ +curl --location --request POST 'https://api.fastgpt.in/api/v1/chat/completions' \ --header 'Authorization: Bearer fastgpt-xxxxxx' \ --header 'Content-Type: application/json' \ --data-raw '{ diff --git a/docSite/content/zh-cn/docs/development/openapi/dataset.md b/docSite/content/zh-cn/docs/development/openapi/dataset.md index 0f16a6011bc..d7d14303421 100644 --- a/docSite/content/zh-cn/docs/development/openapi/dataset.md +++ b/docSite/content/zh-cn/docs/development/openapi/dataset.md @@ -22,7 +22,7 @@ weight: 853 **新例子** ```bash -curl --location --request POST 'https://api.tryfastgpt.ai/api/support/wallet/usage/createTrainingUsage' \ +curl --location --request POST 'https://api.fastgpt.in/api/support/wallet/usage/createTrainingUsage' \ --header 'Authorization: Bearer {{apikey}}' \ --header 'Content-Type: application/json' \ --data-raw '{ @@ -34,7 +34,7 @@ curl --location --request POST 'https://api.tryfastgpt.ai/api/support/wallet/usa **x例子** ```bash -curl --location --request POST 'https://api.tryfastgpt.ai/api/support/wallet/bill/createTrainingBill' \ +curl --location --request POST 'https://api.fastgpt.in/api/support/wallet/bill/createTrainingBill' \ --header 'Authorization: Bearer {{apikey}}' \ --header 'Content-Type: application/json' \ --data-raw '{ @@ -991,7 +991,7 @@ curl --location --request DELETE 'http://localhost:3000/api/core/dataset/collect {{< markdownify >}} ```bash -curl --location --request POST 'https://api.tryfastgpt.ai/api/core/dataset/data/pushData' \ +curl --location --request POST 'https://api.fastgpt.in/api/core/dataset/data/pushData' \ --header 'Authorization: Bearer apikey' \ --header 'Content-Type: application/json' \ --data-raw '{ @@ -1328,7 +1328,7 @@ curl --location --request DELETE 'http://localhost:3000/api/core/dataset/data/de {{< markdownify >}} ```bash -curl --location --request POST 'https://api.tryfastgpt.ai/api/core/dataset/searchTest' \ +curl --location --request POST 'https://api.fastgpt.in/api/core/dataset/searchTest' \ --header 'Authorization: Bearer fastgpt-xxxxx' \ --header 'Content-Type: application/json' \ --data-raw '{ diff --git a/docSite/content/zh-cn/docs/development/upgrading/4811.md b/docSite/content/zh-cn/docs/development/upgrading/4811.md index a30802178ed..4a66b957131 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/4811.md +++ b/docSite/content/zh-cn/docs/development/upgrading/4811.md @@ -88,26 +88,27 @@ weight: 813 1. 新增 - 表单输入节点,允许用户在工作流中让用户输入一些信息。 2. 新增 - 循环运行节点,可传入数组进行批量调用,目前最多支持 50 长度的数组串行执行。 -3. 新增 - 节点支持折叠。 -4. 新增 - 聊天记录滚动加载,不再只加载 30 条。 -5. 新增 - 工作流增加触摸板优先模式,可以通过工作流右下角按键进行切换。 -6. 新增 - 沙盒增加字符串转 base64 全局方法(全局变量 strToBase64)。 -7. 新增 - 支持 Openai o1 模型,需增加模型的 `defaultConfig` 配置,覆盖 `temperature`、`max_tokens` 和 `stream`配置,o1 不支持 stream 模式, 详细可重新拉取 `config.json` 配置文件查看。 -8. 新增 - AI 对话节点知识库引用,支持配置 role=system 和 role=user,已配置的过自定义提示词的节点将会保持 user 模式,其余用户将转成 system 模式。 -9. 新增 - 插件支持上传系统文件。 -10. 新增 - 子应用嵌套调用时,版本锁定。主应用未主动更新版本时,不会取最新版进行执行,保证主应用服务稳定。 -11. 新增 - 插件输出,支持指定字段作为工具响应。 -12. 新增 - 支持工作流嵌套子应用时,可以设置`非流模式`,同时简易模式也可以选择工作流作为插件了,简易模式调用子应用时,都将强制使用非流模式。 -13. 新增 - 调试模式下,子应用调用,支持返回详细运行数据。 -14. 新增 - 保留所有模式下子应用嵌套调用的日志。 -15. 优化 - 工作流嵌套层级限制 20 层,避免因编排不合理导致的无限死循环。 -16. 优化 - 工作流 handler 性能优化。 -17. 优化 - 工作流快捷键,避免调试测试时也会触发复制和回退。 -18. 修复 - 工作流工具调用中修改全局变量后,无法传递到后续流程。 -19. 优化 - 流输出,切换浏览器 Tab 后仍可以继续输出。 -20. 优化 - 完善外部文件知识库相关 API -21. 修复 - 知识库选择权限问题。 -22. 修复 - 空 chatId 发起对话,首轮携带用户选择时会异常。 -23. 修复 - createDataset 接口,intro 为赋值。 -24. 修复 - 对话框渲染性能问题。 -25. 修复 - 工具调用历史记录存储不正确。 +3. 新增 - 自定义工具变量节点,可以为工具调用子流程完全自定义变量。在构建复杂 Agent 时有帮助。 +4. 新增 - 节点支持折叠。 +5. 新增 - 聊天记录滚动加载,不再只加载 30 条。 +6. 新增 - 工作流增加触摸板优先模式,可以通过工作流右下角按键进行切换。 +7. 新增 - 沙盒增加字符串转 base64 全局方法(全局变量 strToBase64)。 +8. 新增 - 支持 Openai o1 模型,需增加模型的 `defaultConfig` 配置,覆盖 `temperature`、`max_tokens` 和 `stream`配置,o1 不支持 stream 模式, 详细可重新拉取 `config.json` 配置文件查看。 +9. 新增 - AI 对话节点知识库引用,支持配置 role=system 和 role=user,已配置的过自定义提示词的节点将会保持 user 模式,其余用户将转成 system 模式。 +10. 新增 - 插件支持上传系统文件。 +11. 新增 - 子应用嵌套调用时,版本锁定。主应用未主动更新版本时,不会取最新版进行执行,保证主应用服务稳定。 +12. 新增 - 插件输出,支持指定字段作为工具响应。 +13. 新增 - 支持工作流嵌套子应用时,可以设置`非流模式`,同时简易模式也可以选择工作流作为插件了,简易模式调用子应用时,都将强制使用非流模式。 +14. 新增 - 调试模式下,子应用调用,支持返回详细运行数据。 +15. 新增 - 保留所有模式下子应用嵌套调用的日志。 +16. 优化 - 工作流嵌套层级限制 20 层,避免因编排不合理导致的无限死循环。 +17. 优化 - 工作流 handler 性能优化。 +18. 优化 - 工作流快捷键,避免调试测试时也会触发复制和回退。 +19. 修复 - 工作流工具调用中修改全局变量后,无法传递到后续流程。 +20. 优化 - 流输出,切换浏览器 Tab 后仍可以继续输出。 +21. 优化 - 完善外部文件知识库相关 API +22. 修复 - 知识库选择权限问题。 +23. 修复 - 空 chatId 发起对话,首轮携带用户选择时会异常。 +24. 修复 - createDataset 接口,intro 为赋值。 +25. 修复 - 对话框渲染性能问题。 +26. 修复 - 工具调用历史记录存储不正确。 diff --git a/docSite/content/zh-cn/docs/use-cases/onwechat.md b/docSite/content/zh-cn/docs/use-cases/onwechat.md index 51549b1ce03..bc8959bdd4b 100644 --- a/docSite/content/zh-cn/docs/use-cases/onwechat.md +++ b/docSite/content/zh-cn/docs/use-cases/onwechat.md @@ -26,7 +26,7 @@ weight: 504 ## 3. 创建 docker-compose.yml 文件 -只需要修改 `OPEN_AI_API_KEY` 和 `OPEN_AI_API_BASE` 两个环境变量即可。其中 `OPEN_AI_API_KEY` 为第一步获取的密钥,`OPEN_AI_API_BASE` 为 FastGPT 的 OpenAPI 地址,例如:`https://api.tryfastgpt.ai/api/v1`。 +只需要修改 `OPEN_AI_API_KEY` 和 `OPEN_AI_API_BASE` 两个环境变量即可。其中 `OPEN_AI_API_KEY` 为第一步获取的密钥,`OPEN_AI_API_BASE` 为 FastGPT 的 OpenAPI 地址,例如:`https://api.fastgpt.in/api/v1`。 随便找一个目录,创建一个 docker-compose.yml 文件,将下面的代码复制进去。 @@ -40,7 +40,7 @@ services: - seccomp:unconfined environment: OPEN_AI_API_KEY: 'fastgpt-z51pkjqm9nrk03a1rx2funoy' - OPEN_AI_API_BASE: 'https://api.tryfastgpt.ai/api/v1' + OPEN_AI_API_BASE: 'https://api.fastgpt.in/api/v1' MODEL: 'gpt-3.5-turbo' CHANNEL_TYPE: 'wx' PROXY: '' diff --git a/docSite/content/zh-cn/docs/workflow/modules/sandbox.md b/docSite/content/zh-cn/docs/workflow/modules/sandbox.md new file mode 100644 index 00000000000..5c968412f1d --- /dev/null +++ b/docSite/content/zh-cn/docs/workflow/modules/sandbox.md @@ -0,0 +1,87 @@ +--- +title: "代码运行" +description: "FastGPT 代码运行节点介绍" +icon: "input" +draft: false +toc: true +weight: 364 +--- + +![alt text](/imgs/image.png) + +## 功能 + +可用于执行一段简单的 js 代码,用于进行一些复杂的数据处理。代码运行在沙盒中,无法进行网络请求、dom和异步操作。如需复杂操作,需外挂 HTTP 实现。 + +**注意事项** + +- 私有化用户需要部署`fastgpt-sandbox` 镜像,并配置`SANDBOX_URL`环境变量。 +- 沙盒最大运行 10s, 32M 内存限制。 + + +## 变量输入 + +可在自定义输入中添加代码运行需要的变量,在代码的 main 函数中,可解构出相同名字的变量。 + +如上图,自定义输入中有 data1 和 data2 两个变量,main 函数中可以解构出相同名字的变量。 + +## 结果输出 + +务必返回一个 object 对象 + +自定义输出中,可以添加变量名来获取 object 对应 key 下的值。例如上图中,返回了一个对象: + +```json +{ + result: data1, + data2 +} +``` + +他有 2 个 key:result和 data2(js 缩写,key=data2,value=data2)。这时候自定义输出中就可以添加 2 个变量来获取对应 key 下的 value。 + +## 内置 JS 全局变量 + +### delay 延迟 + +延迟 1 秒后返回 + +```js +async function main({data1, data2}){ + await delay(1000) + return { + result: "111" + } +} +``` + +### countToken 统计 token + +```js +function main({input}){ + return { + result: countToken(input) + } +} +``` + +![alt text](/imgs/image-1.png) + +### strToBase64 字符串转 base64(4.8.11 版本新增) + +可用于将 SVG 图片转换为 base64 格式展示。 + +```js +function main({input}){ + + return { + /* + param1: input 需要转换的字符串 + param2: base64 prefix 前缀 + */ + result: strToBase64(input,'data:image/svg+xml;base64,') + } +} +``` + +![alt text](/imgs/image-2.png) \ No newline at end of file diff --git a/docSite/content/zh-cn/docs/workflow/modules/tool.md b/docSite/content/zh-cn/docs/workflow/modules/tool.md index 715182657ba..ea3b1e82a87 100644 --- a/docSite/content/zh-cn/docs/workflow/modules/tool.md +++ b/docSite/content/zh-cn/docs/workflow/modules/tool.md @@ -35,8 +35,6 @@ weight: 356 1. 无必须的参数:尽管上下文中,没有适合的参数,也可以调用该工具。但有时候,LLM会自己伪造一个参数。 2. 有必须的参数:如果没有适合的参数,LLM可能不会调用该工具。可以通过提示词,引导用户提供参数。 -### 工具调用逻辑 - 在支持`函数调用`的模型中,可以一次性调用多个工具,调用逻辑如下: ![](/imgs/flow-tool2.png) @@ -49,10 +47,24 @@ weight: 356 高级编排中,托动工具调用的连接点,可用的工具头部会出现一个菱形,可以将它与工具调用模块底部的菱形相连接。 -被连接的工具,会自动分离工具输入与普通的输入,并且可以编辑`介绍`,可以通过调整介绍,使得该工具调用时机更加精确。 +被连接的工具,会自动分离工具输入与普通的输入,并且可以编辑`描述`,可以通过调整介绍,使得该工具调用时机更加精确。对于一些内置的节点,务必修改`描述`才能让模型正常调用。 关于工具调用,如何调试仍然是一个玄学,所以建议,不要一次性增加太多工具,选择少量工具调优后再进一步尝试。 +## 组合节点 + +### 工具调用终止 + +工具调用默认会把子流程运行的结果作为`工具结果`,返回给模型进行回答。有时候,你可能不希望模型做回答,你可以给对应子流程的末尾增加上一个`工具调用终止`节点,这样,子流程的结果就不会被返回给模型。 + +![alt text](/imgs/image-3.png) + +### 自定义工具变量 + +工具调用的子流程运行,有时候会依赖`AI`生成的一些变量,为了简化交互流程,我们给系统内置的节点都指定了`工具变量`。然而,有些时候,你需要的变量不仅是目标流程的`首个节点`的变量,而是需要更复杂的变量,此时你可以使用`自定义工具变量`。它允许你完全自定义该`工具流程`的变量。 + +![alt text](/imgs/image-4.png) + ## 相关示例 - [谷歌搜索](/docs/workflow/examples/google_search/) diff --git a/packages/global/core/workflow/constants.ts b/packages/global/core/workflow/constants.ts index f4d1b02b2b0..3cde9035d07 100644 --- a/packages/global/core/workflow/constants.ts +++ b/packages/global/core/workflow/constants.ts @@ -37,6 +37,60 @@ export enum WorkflowIOValueTypeEnum { selectDataset = 'selectDataset' } +export const toolValueTypeList = [ + { + label: WorkflowIOValueTypeEnum.string, + value: WorkflowIOValueTypeEnum.string, + jsonSchema: { + type: 'string' + } + }, + { + label: WorkflowIOValueTypeEnum.number, + value: WorkflowIOValueTypeEnum.number, + jsonSchema: { + type: 'number' + } + }, + { + label: WorkflowIOValueTypeEnum.boolean, + value: WorkflowIOValueTypeEnum.boolean, + jsonSchema: { + type: 'boolean' + } + }, + { + label: 'array', + value: WorkflowIOValueTypeEnum.arrayString, + jsonSchema: { + type: 'array', + items: { + type: 'string' + } + } + }, + { + label: 'array', + value: WorkflowIOValueTypeEnum.arrayNumber, + jsonSchema: { + type: 'array', + items: { + type: 'number' + } + } + }, + { + label: 'array', + value: WorkflowIOValueTypeEnum.arrayBoolean, + jsonSchema: { + type: 'array', + items: { + type: 'boolean' + } + } + } +]; + /* reg: modulename key */ export enum NodeInputKeyEnum { // old diff --git a/packages/global/core/workflow/template/system/toolParams.ts b/packages/global/core/workflow/template/system/toolParams.ts index edfc0aa3680..a13c479c478 100644 --- a/packages/global/core/workflow/template/system/toolParams.ts +++ b/packages/global/core/workflow/template/system/toolParams.ts @@ -11,7 +11,7 @@ export const ToolParamsNode: FlowNodeTemplateType = { sourceHandle: getHandleConfig(true, true, true, true), targetHandle: getHandleConfig(true, true, true, true), avatar: 'core/workflow/template/toolParams', - name: i18nT('workflow:tool_params_config'), + name: i18nT('workflow:tool_custom_field'), intro: i18nT('workflow:intro_tool_params_config'), version: '4811', isTool: true, diff --git a/packages/service/common/mongo/index.ts b/packages/service/common/mongo/index.ts index 90cfb452191..fb1835d3df7 100644 --- a/packages/service/common/mongo/index.ts +++ b/packages/service/common/mongo/index.ts @@ -63,7 +63,7 @@ export const getMongoModel = (name: string, schema: mongoose.Schema) => { const model = connectionMongo.model(name, schema); - if (process.env.SYNC_INDEX !== '0') { + if (process.env.SYNC_INDEX !== '0' && process.env.NODE_ENV !== 'test') { try { model.syncIndexes({ background: true }); } catch (error) { diff --git a/packages/service/core/workflow/dispatch/agent/runTool/functionCall.ts b/packages/service/core/workflow/dispatch/agent/runTool/functionCall.ts index 46f8a789f39..483974e3060 100644 --- a/packages/service/core/workflow/dispatch/agent/runTool/functionCall.ts +++ b/packages/service/core/workflow/dispatch/agent/runTool/functionCall.ts @@ -25,6 +25,7 @@ import { AIChatItemType } from '@fastgpt/global/core/chat/type'; import { GPTMessages2Chats } from '@fastgpt/global/core/chat/adapt'; import { updateToolInputValue } from './utils'; import { computedMaxToken, llmCompletionsBodyFormat } from '../../../../ai/utils'; +import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants'; type FunctionRunResponseType = { toolRunResponse: DispatchFlowResponse; @@ -64,10 +65,12 @@ export const runToolWithFunctionCall = async ( } > = {}; item.toolParams.forEach((item) => { - const isArray = item.valueType?.startsWith('array'); + const jsonSchema = ( + toolValueTypeList.find((type) => type.value === item.valueType) || toolValueTypeList[0] + ).jsonSchema; + properties[item.key] = { - type: isArray ? 'array' : item.valueType || 'string', - ...(isArray && { items: { type: item.valueType?.slice(5).toLowerCase() || 'string' } }), + ...jsonSchema, description: item.toolDescription || '', enum: item.enum?.split('\n').filter(Boolean) || [] }; diff --git a/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts b/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts index c84a79098c2..ae9ead2eb23 100644 --- a/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts +++ b/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts @@ -27,6 +27,7 @@ import { GPTMessages2Chats } from '@fastgpt/global/core/chat/adapt'; import { updateToolInputValue } from './utils'; import { computedMaxToken, llmCompletionsBodyFormat } from '../../../../ai/utils'; import { WorkflowResponseType } from '../../type'; +import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants'; type FunctionCallCompletion = { id: string; @@ -72,10 +73,12 @@ export const runToolWithPromptCall = async ( } > = {}; item.toolParams.forEach((item) => { - const isArray = item.valueType?.startsWith('array'); + const jsonSchema = ( + toolValueTypeList.find((type) => type.value === item.valueType) || toolValueTypeList[0] + ).jsonSchema; + properties[item.key] = { - type: isArray ? 'array' : item.valueType || 'string', - ...(isArray && { items: { type: item.valueType?.slice(5).toLowerCase() || 'string' } }), + ...jsonSchema, description: item.toolDescription || '', enum: item.enum?.split('\n').filter(Boolean) || [] }; diff --git a/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts b/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts index 20e5db2823f..1e5c47515af 100644 --- a/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts +++ b/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts @@ -26,6 +26,7 @@ import { updateToolInputValue } from './utils'; import { computedMaxToken, llmCompletionsBodyFormat } from '../../../../ai/utils'; import { getNanoid, sliceStrStartEnd } from '@fastgpt/global/common/string/tools'; import { addLog } from '../../../../../common/system/log'; +import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants'; type ToolRunResponseType = { toolRunResponse: DispatchFlowResponse; @@ -78,10 +79,11 @@ export const runToolWithToolChoice = async ( } > = {}; item.toolParams.forEach((item) => { - const isArray = item.valueType?.startsWith('array'); + const jsonSchema = ( + toolValueTypeList.find((type) => type.value === item.valueType) || toolValueTypeList[0] + )?.jsonSchema; properties[item.key] = { - type: isArray ? 'array' : item.valueType || 'string', - ...(isArray && { items: { type: item.valueType?.slice(5).toLowerCase() || 'string' } }), + ...jsonSchema, description: item.toolDescription || '', enum: item.enum?.split('\n').filter(Boolean) || [] }; diff --git a/packages/web/hooks/usePagination.tsx b/packages/web/hooks/usePagination.tsx index e65491cbe69..477c3267237 100644 --- a/packages/web/hooks/usePagination.tsx +++ b/packages/web/hooks/usePagination.tsx @@ -50,12 +50,12 @@ export function usePagination({ const [isLoading, { setTrue, setFalse }] = useBoolean(false); + const [pageNum, setPageNum] = useState(1); const [total, setTotal] = useState(0); const [data, setData] = useState([]); const totalDataLength = useMemo(() => Math.max(total, data.length), [total, data.length]); const isEmpty = total === 0 && !isLoading; - const pageNum = useMemo(() => Math.ceil(data.length / pageSize), [data.length, pageSize]); const noMore = data.length >= totalDataLength; const fetchData = useLockFn( @@ -71,6 +71,7 @@ export function usePagination({ }); // Check total and set + setPageNum(num); res.total !== undefined && setTotal(res.total); if (type === 'scroll') { diff --git a/packages/web/i18n/en/workflow.json b/packages/web/i18n/en/workflow.json index cdceb63208a..fb0c1dddcda 100644 --- a/packages/web/i18n/en/workflow.json +++ b/packages/web/i18n/en/workflow.json @@ -28,7 +28,6 @@ "create_link_error": "Error creating link", "custom_feedback": "Custom Feedback", "custom_input": "Custom Input", - "custom_tool_input": "Custom tool input", "dataset_quote_role": "Role", "dataset_quote_role_system_option_desc": "Historical records should be consistent first (recommended)", "dataset_quote_role_tip": "When set to System, the knowledge base reference content will be placed in the system message, which can ensure the continuity of the history record, but the constraint effect may not be good.\n\nWhen set to User, the knowledge base reference content will be placed in the user message, and the {{question}} variable location needs to be specified. \nIt will have a certain impact on the consistency of historical records, but usually the constraint effect is better.", @@ -81,7 +80,7 @@ "intro_text_concatenation": "Can process and output fixed or incoming text. Non-string type data will be converted to string type.", "intro_text_content_extraction": "Can extract specified data from text, such as SQL statements, search keywords, code, etc.", "intro_tool_call_termination": "This module needs to be configured for tool calls. When this module is executed, the current tool call will be forcibly terminated, and AI will no longer answer questions based on the tool call results.", - "intro_tool_params_config": " This module works with tool calls. It creates required tool parameters. Tool calls automatically generate parameter content and pass it to corresponding function blocks.", + "intro_tool_params_config": "This module needs to be used with tool calls. \nYou can customize tool call parameters and pass them to downstream nodes for use.", "is_empty": "Is Empty", "is_equal_to": "Is Equal To", "is_not_empty": "Is Not Empty", @@ -160,6 +159,7 @@ "text_to_extract": "Text to Extract", "these_variables_will_be_input_parameters_for_code_execution": "These variables will be input parameters for code execution", "tool_call_termination": "Tool Call Termination", + "tool_custom_field": "Custom tool parameters", "tool_field": " Tool Field Parameter Configuration", "tool_input": "Tool Input", "tool_params.enum_placeholder": "apple \npeach \nwatermelon", @@ -169,7 +169,6 @@ "tool_params.params_description_placeholder": "Name/Age/SQL statement..", "tool_params.params_name": "Name", "tool_params.params_name_placeholder": "name/age/sql", - "tool_params.tool_params_result": "Tool params result", "tool_params_config": "Tool params config", "trigger_after_application_completion": "Will be triggered after the application is fully completed", "update_link_error": "Error updating link", diff --git a/packages/web/i18n/zh/workflow.json b/packages/web/i18n/zh/workflow.json index c193a5bab36..c18173018f8 100644 --- a/packages/web/i18n/zh/workflow.json +++ b/packages/web/i18n/zh/workflow.json @@ -29,7 +29,6 @@ "create_link_error": "创建链接异常", "custom_feedback": "自定义反馈", "custom_input": "自定义输入", - "custom_tool_input": "自定义工具参数", "dataset_quote_role": "角色", "dataset_quote_role_system_option_desc": "历史记录连贯优先(推荐)", "dataset_quote_role_tip": "设置为 System 时,将会把知识库引用内容放置到 system 消息中,可以确保历史记录的连贯性,但约束效果可能不佳,需要多调试。\n设置为 User 时,将会把知识库引用内容放置到 user 消息中,并且需要指定 {{question}} 变量位置。会对历史记录连贯性有一定影响,但通常约束效果更优。", @@ -82,7 +81,7 @@ "intro_text_concatenation": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。", "intro_text_content_extraction": "可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等", "intro_tool_call_termination": "该模块需配置工具调用使用。当该模块被执行时,本次工具调用将会强制结束,并且不再调用AI针对工具调用结果回答问题。", - "intro_tool_params_config": "该模块需要配合工具调用使用。可以创建所需的工具参数,工具调用将自动生成参数内容并传给对应的功能块。", + "intro_tool_params_config": "该模块需要配合工具调用使用。可以自定义工具调用参数,并传递到下游节点使用", "is_empty": "为空", "is_equal_to": "等于", "is_not_empty": "不为空", @@ -161,6 +160,7 @@ "text_to_extract": "需要提取的文本", "these_variables_will_be_input_parameters_for_code_execution": "这些变量会作为代码的运行的输入参数", "tool_call_termination": "工具调用终止", + "tool_custom_field": "自定义工具变量", "tool_field": "工具参数配置", "tool_input": "工具参数", "tool_params.enum_placeholder": "apple \npeach \nwatermelon", @@ -171,7 +171,6 @@ "tool_params.params_name": "参数名", "tool_params.params_name_placeholder": "name/age/sql", "tool_params.tool_params_result": "参数配置结果", - "tool_params_config": "工具参数配置", "trigger_after_application_completion": "将在应用完全结束后触发", "update_link_error": "更新链接异常", "update_specified_node_output_or_global_variable": "可以更新指定节点的输出值或更新全局变量", diff --git a/projects/app/src/pages/api/__mocks__/base.ts b/projects/app/src/pages/api/__mocks__/base.ts index ea99c35c6a1..261704acd7c 100644 --- a/projects/app/src/pages/api/__mocks__/base.ts +++ b/projects/app/src/pages/api/__mocks__/base.ts @@ -57,11 +57,25 @@ jest.mock('@/service/middleware/entry', () => { }); beforeAll(async () => { + // 新建一个内存数据库,然后让 mongoose 连接这个数据库 if (!global.mongod || !global.mongodb) { const mongod = await MongoMemoryServer.create(); global.mongod = mongod; global.mongodb = mongoose; - await global.mongodb.connect(mongod.getUri()); + + await global.mongodb.connect(mongod.getUri(), { + bufferCommands: true, + maxConnecting: 50, + maxPoolSize: 50, + minPoolSize: 20, + connectTimeoutMS: 60000, + waitQueueTimeoutMS: 60000, + socketTimeoutMS: 60000, + maxIdleTimeMS: 300000, + retryWrites: true, + retryReads: true + }); + await initMockData(); } }); diff --git a/projects/app/src/pages/api/__mocks__/db/init.ts b/projects/app/src/pages/api/__mocks__/db/init.ts index f53f14675da..804323cefd5 100644 --- a/projects/app/src/pages/api/__mocks__/db/init.ts +++ b/projects/app/src/pages/api/__mocks__/db/init.ts @@ -13,34 +13,37 @@ export const root = { }; export const initMockData = async () => { - // init root user - const rootUser = await MongoUser.create({ - username: 'root', - password: '123456' - }); + const initRootUser = async () => { + // init root user + const rootUser = await MongoUser.create({ + username: 'root', + password: '123456' + }); - const rootTeam = await MongoTeam.create({ - name: 'root-default-team', - ownerId: rootUser._id - }); + const rootTeam = await MongoTeam.create({ + name: 'root-default-team', + ownerId: rootUser._id + }); - const rootTeamMember = await MongoTeamMember.create({ - teamId: rootTeam._id, - userId: rootUser._id, - name: 'root-default-team-member', - status: 'active', - role: TeamMemberRoleEnum.owner - }); + const rootTeamMember = await MongoTeamMember.create({ + teamId: rootTeam._id, + userId: rootUser._id, + name: 'root-default-team-member', + status: 'active', + role: TeamMemberRoleEnum.owner + }); + const rootApp = await MongoApp.create({ + name: 'root-default-app', + teamId: rootTeam._id, + tmbId: rootTeam._id, + type: 'advanced' + }); - const rootApp = await MongoApp.create({ - name: 'root-default-app', - teamId: rootTeam._id, - tmbId: rootTeam._id, - type: 'advanced' - }); + root.uid = rootUser._id; + root.tmbId = rootTeamMember._id; + root.teamId = rootTeam._id; + root.appId = rootApp._id; + }; - root.uid = rootUser._id; - root.tmbId = rootTeamMember._id; - root.teamId = rootTeam._id; - root.appId = rootApp._id; + await initRootUser(); }; diff --git a/projects/app/src/pages/api/core/app/version/latest.test.ts b/projects/app/src/pages/api/core/app/version/latest.test.ts new file mode 100644 index 00000000000..7e4f8f83cf4 --- /dev/null +++ b/projects/app/src/pages/api/core/app/version/latest.test.ts @@ -0,0 +1,55 @@ +import '@/pages/api/__mocks__/base'; +import { root } from '@/pages/api/__mocks__/db/init'; +import { getTestRequest } from '@/test/utils'; +import handler, { getLatestVersionQuery, getLatestVersionResponse } from './latest'; +import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema'; + +beforeAll(async () => { + // 创建3个测试数据,其中2个是已发布的 + await MongoAppVersion.create([ + { + appId: root.appId, + nodes: [1], + edges: [], + chatConfig: {}, + isPublish: false, + versionName: 'v1', + tmbId: root.tmbId, + time: new Date('2023-01-01') + }, + { + appId: root.appId, + nodes: [2], + edges: [], + chatConfig: {}, + isPublish: true, + versionName: 'v2', + tmbId: root.tmbId, + time: new Date('2023-01-02') + }, + { + appId: root.appId, + nodes: [3], + edges: [], + chatConfig: {}, + isPublish: false, + versionName: 'v3', + tmbId: root.tmbId, + time: new Date('2023-01-03') + } + ]); +}); + +test('获取最新版本并检查', async () => { + const _res = (await handler( + ...getTestRequest<{}, getLatestVersionQuery>({ + query: { + appId: root.appId + }, + user: root + }) + )) as any; + const res = _res.data as getLatestVersionResponse; + + expect(res.nodes[0]).toEqual(2); +}); diff --git a/projects/app/src/pages/api/core/app/version/publish.test.ts b/projects/app/src/pages/api/core/app/version/publish.test.ts new file mode 100644 index 00000000000..a929fdde125 --- /dev/null +++ b/projects/app/src/pages/api/core/app/version/publish.test.ts @@ -0,0 +1,37 @@ +import '@/pages/api/__mocks__/base'; +import { root } from '@/pages/api/__mocks__/db/init'; +import { getTestRequest } from '@/test/utils'; +import handler from './publish'; +import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema'; +import { PostPublishAppProps } from '@/global/core/app/api'; +import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; + +describe('发布应用版本测试', () => { + test('发布一个未发布的版本', async () => { + const publishData: PostPublishAppProps = { + nodes: [], + edges: [], + chatConfig: {}, + type: AppTypeEnum.simple, + isPublish: false, + versionName: '1' + }; + + await handler( + ...getTestRequest<{ appId: string }, PostPublishAppProps>({ + body: publishData, + query: { appId: root.appId }, + user: root + }) + ); + + // 检查数据库是否插入成功 + const insertedVersion = await MongoAppVersion.countDocuments(); + + console.log(insertedVersion, '==-'); + + // expect(insertedVersion).toBeTruthy(); + // expect(insertedVersion?.isPublish).toBe(false); + // expect(insertedVersion?.versionName).toBe('1'); + }); +}); diff --git a/projects/app/src/pages/api/core/app/version/publish.ts b/projects/app/src/pages/api/core/app/version/publish.ts index 44273342032..cc6c7c89f89 100644 --- a/projects/app/src/pages/api/core/app/version/publish.ts +++ b/projects/app/src/pages/api/core/app/version/publish.ts @@ -8,7 +8,6 @@ import { beforeUpdateAppFormat } from '@fastgpt/service/core/app/controller'; import { getNextTimeByCronStringAndTimezone } from '@fastgpt/global/common/string/time'; import { PostPublishAppProps } from '@/global/core/app/api'; import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; -import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; async function handler(req: NextApiRequest, res: NextApiResponse): Promise<{}> { const { appId } = req.query as { appId: string }; diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeComment.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeComment.tsx index 594bf31034f..fd623c2c08e 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeComment.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeComment.tsx @@ -9,7 +9,7 @@ import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { useTranslation } from 'react-i18next'; -const NodeComment = ({ data, selected }: NodeProps) => { +const NodeComment = ({ data }: NodeProps) => { const { nodeId, inputs } = data; const { commentText, commentSize } = useMemo( () => ({ @@ -39,8 +39,8 @@ const NodeComment = ({ data, selected }: NodeProps) => { const deltaY = e.clientY - initialY.current; const deltaX = e.clientX - initialX.current; setSize((prevSize) => ({ - width: prevSize.width + deltaX < 240 ? 240 : prevSize.width + deltaX, - height: prevSize.height + deltaY < 140 ? 140 : prevSize.height + deltaY + width: prevSize.width + deltaX < 120 ? 120 : prevSize.width + deltaX, + height: prevSize.height + deltaY < 60 ? 60 : prevSize.height + deltaY })); initialY.current = e.clientY; initialX.current = e.clientX; @@ -70,59 +70,63 @@ const NodeComment = ({ data, selected }: NodeProps) => { [commentSize, nodeId, onChangeNode, size.height, size.width] ); - return ( - - - - + const Render = useMemo(() => { + return ( + + + + + +