mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-21 11:17:23 +00:00
4.13.1 features (#5728)
* fix(api): 修复二级路由下的页面判断逻辑 在请求错误处理中,添加基础URL前缀以正确判断当前是否为外部链接页面。 * perf: use global var * remove invalid code * feat: response limit;perf: copy avatar image;perf: markdown parse (#5719) * feat: response limit * remove placeholder * perf: copy avatar image * perf: markdown parse * fix: child app cannot show cite * doc * fix: node template bugs (#5727) * add dataset search count track (#5721) * add dataset search count track * remove pro * change to track * remove unused * fix * perf: track code --------- Co-authored-by: archer <545436317@qq.com> * http response limit * deploy doc * fix: test * doc * remove invalid code * remove invalid code --------- Co-authored-by: 戴盛利 <1639499287@qq.com> Co-authored-by: heheer <heheer@sealos.io>
This commit is contained in:
@@ -197,6 +197,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -172,6 +172,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -154,6 +154,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -137,6 +137,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -197,6 +197,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -172,6 +172,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -154,6 +154,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -137,6 +137,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -136,6 +136,8 @@ ${{vec.db}}
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
@@ -182,6 +184,10 @@ ${{vec.db}}
|
|||||||
<<: *x-share-db-config
|
<<: *x-share-db-config
|
||||||
AUTH_TOKEN: *x-plugin-auth-token
|
AUTH_TOKEN: *x-plugin-auth-token
|
||||||
S3_BUCKET: fastgpt-plugins
|
S3_BUCKET: fastgpt-plugins
|
||||||
|
# 工具网络请求,最大请求和响应体
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
|
# 最大 API 请求体大小
|
||||||
|
MAX_API_SIZE: 10
|
||||||
depends_on:
|
depends_on:
|
||||||
fastgpt-minio:
|
fastgpt-minio:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
@@ -7,9 +7,12 @@ description: 'FastGPT V4.13.1 更新说明'
|
|||||||
|
|
||||||
## 🚀 新增内容
|
## 🚀 新增内容
|
||||||
|
|
||||||
|
1. 增加对 HTTP 请求响应大小限制。
|
||||||
|
|
||||||
## ⚙️ 优化
|
## ⚙️ 优化
|
||||||
|
|
||||||
|
1. 复制应用时,将头像复制一份,避免使用相同的图片链接,导致其中一个应用头像更新后,另一个应用头像丢失。
|
||||||
|
2. Markdown 解析器适配 windows 路径,避免 \ 被认为转义符。
|
||||||
|
|
||||||
## 🐛 修复
|
## 🐛 修复
|
||||||
|
|
||||||
@@ -17,6 +20,11 @@ description: 'FastGPT V4.13.1 更新说明'
|
|||||||
2. 交互节点响应后,未更新对话记录统计数据。
|
2. 交互节点响应后,未更新对话记录统计数据。
|
||||||
3. prompt 编辑器,弹窗中的默认值存在显示异常。
|
3. prompt 编辑器,弹窗中的默认值存在显示异常。
|
||||||
4. 表单输入,变量名包含.符号时,无法正常输入值。
|
4. 表单输入,变量名包含.符号时,无法正常输入值。
|
||||||
|
5. 调用子工作流,自动流知识库引用无法在分享链接中显示。
|
||||||
|
|
||||||
## 🔨 插件更新
|
## 🔨 插件更新
|
||||||
|
|
||||||
|
1. base64 解码工具,可以转化成文本和图片。
|
||||||
|
2. 墨迹天气工具。
|
||||||
|
3. 必优 PPT 生成工具。
|
||||||
|
4. 可配置最大请求体大小,以及内部网络请求最大响应大小,避免响应体过大,导致内存溢出。
|
@@ -28,7 +28,7 @@
|
|||||||
"document/content/docs/introduction/development/modelConfig/ai-proxy.mdx": "2025-08-05T23:20:39+08:00",
|
"document/content/docs/introduction/development/modelConfig/ai-proxy.mdx": "2025-08-05T23:20:39+08:00",
|
||||||
"document/content/docs/introduction/development/modelConfig/intro.mdx": "2025-08-12T22:22:18+08:00",
|
"document/content/docs/introduction/development/modelConfig/intro.mdx": "2025-08-12T22:22:18+08:00",
|
||||||
"document/content/docs/introduction/development/modelConfig/one-api.mdx": "2025-07-23T21:35:03+08:00",
|
"document/content/docs/introduction/development/modelConfig/one-api.mdx": "2025-07-23T21:35:03+08:00",
|
||||||
"document/content/docs/introduction/development/modelConfig/ppio.mdx": "2025-08-05T23:20:39+08:00",
|
"document/content/docs/introduction/development/modelConfig/ppio.mdx": "2025-09-29T11:52:39+08:00",
|
||||||
"document/content/docs/introduction/development/modelConfig/siliconCloud.mdx": "2025-08-05T23:20:39+08:00",
|
"document/content/docs/introduction/development/modelConfig/siliconCloud.mdx": "2025-08-05T23:20:39+08:00",
|
||||||
"document/content/docs/introduction/development/openapi/app.mdx": "2025-09-26T13:18:51+08:00",
|
"document/content/docs/introduction/development/openapi/app.mdx": "2025-09-26T13:18:51+08:00",
|
||||||
"document/content/docs/introduction/development/openapi/chat.mdx": "2025-09-29T11:34:11+08:00",
|
"document/content/docs/introduction/development/openapi/chat.mdx": "2025-09-29T11:34:11+08:00",
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"document/content/docs/introduction/development/proxy/http_proxy.mdx": "2025-07-23T21:35:03+08:00",
|
"document/content/docs/introduction/development/proxy/http_proxy.mdx": "2025-07-23T21:35:03+08:00",
|
||||||
"document/content/docs/introduction/development/proxy/nginx.mdx": "2025-07-23T21:35:03+08:00",
|
"document/content/docs/introduction/development/proxy/nginx.mdx": "2025-07-23T21:35:03+08:00",
|
||||||
"document/content/docs/introduction/development/quick-start.mdx": "2025-09-29T11:34:11+08:00",
|
"document/content/docs/introduction/development/quick-start.mdx": "2025-09-29T11:34:11+08:00",
|
||||||
"document/content/docs/introduction/development/sealos.mdx": "2025-08-05T23:20:39+08:00",
|
"document/content/docs/introduction/development/sealos.mdx": "2025-09-29T11:52:39+08:00",
|
||||||
"document/content/docs/introduction/development/signoz.mdx": "2025-09-17T22:29:56+08:00",
|
"document/content/docs/introduction/development/signoz.mdx": "2025-09-17T22:29:56+08:00",
|
||||||
"document/content/docs/introduction/guide/DialogBoxes/htmlRendering.mdx": "2025-07-23T21:35:03+08:00",
|
"document/content/docs/introduction/guide/DialogBoxes/htmlRendering.mdx": "2025-07-23T21:35:03+08:00",
|
||||||
"document/content/docs/introduction/guide/DialogBoxes/quoteList.mdx": "2025-07-23T21:35:03+08:00",
|
"document/content/docs/introduction/guide/DialogBoxes/quoteList.mdx": "2025-07-23T21:35:03+08:00",
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
"document/content/docs/upgrading/4-12/4123.mdx": "2025-09-07T20:55:14+08:00",
|
"document/content/docs/upgrading/4-12/4123.mdx": "2025-09-07T20:55:14+08:00",
|
||||||
"document/content/docs/upgrading/4-12/4124.mdx": "2025-09-17T22:29:56+08:00",
|
"document/content/docs/upgrading/4-12/4124.mdx": "2025-09-17T22:29:56+08:00",
|
||||||
"document/content/docs/upgrading/4-13/4130.mdx": "2025-09-26T13:32:15+08:00",
|
"document/content/docs/upgrading/4-13/4130.mdx": "2025-09-26T13:32:15+08:00",
|
||||||
"document/content/docs/upgrading/4-13/4131.mdx": "2025-09-27T19:43:37+08:00",
|
"document/content/docs/upgrading/4-13/4131.mdx": "2025-09-30T11:21:41+08:00",
|
||||||
"document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00",
|
"document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00",
|
||||||
"document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00",
|
"document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00",
|
||||||
"document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00",
|
"document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00",
|
||||||
|
@@ -197,6 +197,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -172,6 +172,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -154,6 +154,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -137,6 +137,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -197,6 +197,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -172,6 +172,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -154,6 +154,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -137,6 +137,8 @@ services:
|
|||||||
WORKFLOW_MAX_LOOP_TIMES: 100
|
WORKFLOW_MAX_LOOP_TIMES: 100
|
||||||
# 对话文件过期天数
|
# 对话文件过期天数
|
||||||
CHAT_FILE_EXPIRE_TIME: 7
|
CHAT_FILE_EXPIRE_TIME: 7
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH: 10
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.json:/app/data/config.json
|
- ./config.json:/app/data/config.json
|
||||||
|
|
||||||
|
@@ -4,5 +4,6 @@ export enum TrackEnum {
|
|||||||
useAppTemplate = 'useAppTemplate',
|
useAppTemplate = 'useAppTemplate',
|
||||||
createDataset = 'createDataset',
|
createDataset = 'createDataset',
|
||||||
appNodes = 'appNodes',
|
appNodes = 'appNodes',
|
||||||
runSystemTool = 'runSystemTool'
|
runSystemTool = 'runSystemTool',
|
||||||
|
datasetSearch = 'datasetSearch'
|
||||||
}
|
}
|
||||||
|
@@ -3,13 +3,3 @@ import SwaggerParser from '@apidevtools/swagger-parser';
|
|||||||
export const loadOpenAPISchemaFromUrl = async (url: string) => {
|
export const loadOpenAPISchemaFromUrl = async (url: string) => {
|
||||||
return SwaggerParser.bundle(url);
|
return SwaggerParser.bundle(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const checkOpenAPISchemaValid = async (str: string) => {
|
|
||||||
try {
|
|
||||||
const res = await SwaggerParser.validate(JSON.parse(str));
|
|
||||||
console.log(res);
|
|
||||||
return !!res;
|
|
||||||
} catch (error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
@@ -92,10 +92,13 @@ export const filterPublicNodeResponseData = ({
|
|||||||
responseDetail?: boolean;
|
responseDetail?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const publicNodeMap: Record<string, any> = {
|
const publicNodeMap: Record<string, any> = {
|
||||||
|
[FlowNodeTypeEnum.appModule]: true,
|
||||||
[FlowNodeTypeEnum.pluginModule]: true,
|
[FlowNodeTypeEnum.pluginModule]: true,
|
||||||
[FlowNodeTypeEnum.datasetSearchNode]: true,
|
[FlowNodeTypeEnum.datasetSearchNode]: true,
|
||||||
[FlowNodeTypeEnum.agent]: true,
|
[FlowNodeTypeEnum.agent]: true,
|
||||||
[FlowNodeTypeEnum.pluginOutput]: true
|
[FlowNodeTypeEnum.pluginOutput]: true,
|
||||||
|
|
||||||
|
[FlowNodeTypeEnum.runApp]: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const filedMap: Record<string, boolean> = responseDetail
|
const filedMap: Record<string, boolean> = responseDetail
|
||||||
|
@@ -134,9 +134,6 @@ export enum FlowNodeTypeEnum {
|
|||||||
classifyQuestion = 'classifyQuestion',
|
classifyQuestion = 'classifyQuestion',
|
||||||
contentExtract = 'contentExtract',
|
contentExtract = 'contentExtract',
|
||||||
httpRequest468 = 'httpRequest468',
|
httpRequest468 = 'httpRequest468',
|
||||||
runApp = 'app',
|
|
||||||
appModule = 'appModule',
|
|
||||||
pluginModule = 'pluginModule',
|
|
||||||
pluginInput = 'pluginInput',
|
pluginInput = 'pluginInput',
|
||||||
pluginOutput = 'pluginOutput',
|
pluginOutput = 'pluginOutput',
|
||||||
queryExtension = 'cfr',
|
queryExtension = 'cfr',
|
||||||
@@ -156,7 +153,12 @@ export enum FlowNodeTypeEnum {
|
|||||||
loopEnd = 'loopEnd',
|
loopEnd = 'loopEnd',
|
||||||
formInput = 'formInput',
|
formInput = 'formInput',
|
||||||
tool = 'tool',
|
tool = 'tool',
|
||||||
toolSet = 'toolSet'
|
toolSet = 'toolSet',
|
||||||
|
|
||||||
|
// child:
|
||||||
|
appModule = 'appModule',
|
||||||
|
pluginModule = 'pluginModule',
|
||||||
|
runApp = 'app'
|
||||||
}
|
}
|
||||||
|
|
||||||
// node IO value type
|
// node IO value type
|
||||||
|
@@ -276,7 +276,7 @@ export const appData2FlowNodeIO = ({
|
|||||||
description: '',
|
description: '',
|
||||||
valueType: WorkflowIOValueTypeEnum.any,
|
valueType: WorkflowIOValueTypeEnum.any,
|
||||||
required: item.required,
|
required: item.required,
|
||||||
list: item.enums?.map((enumItem) => ({
|
list: (item.list || item.enums)?.map((enumItem) => ({
|
||||||
label: enumItem.value,
|
label: enumItem.value,
|
||||||
value: enumItem.value
|
value: enumItem.value
|
||||||
}))
|
}))
|
||||||
|
15
packages/service/common/cache/index.ts
vendored
15
packages/service/common/cache/index.ts
vendored
@@ -3,6 +3,7 @@ import { getGlobalRedisConnection } from '../../common/redis';
|
|||||||
import type { SystemCacheKeyEnum } from './type';
|
import type { SystemCacheKeyEnum } from './type';
|
||||||
import { randomUUID } from 'node:crypto';
|
import { randomUUID } from 'node:crypto';
|
||||||
import { initCache } from './init';
|
import { initCache } from './init';
|
||||||
|
import { isProduction } from '@fastgpt/global/common/system/constants';
|
||||||
|
|
||||||
const cachePrefix = `VERSION_KEY:`;
|
const cachePrefix = `VERSION_KEY:`;
|
||||||
|
|
||||||
@@ -48,13 +49,15 @@ export const getCachedData = async <T extends SystemCacheKeyEnum>(key: T, id?: s
|
|||||||
const versionKey = await getVersionKey(key, id);
|
const versionKey = await getVersionKey(key, id);
|
||||||
const isDisableCache = process.env.DISABLE_CACHE === 'true';
|
const isDisableCache = process.env.DISABLE_CACHE === 'true';
|
||||||
|
|
||||||
|
const item = global.systemCache[key];
|
||||||
|
|
||||||
// 命中缓存
|
// 命中缓存
|
||||||
if (global.systemCache[key].versionKey === versionKey && !isDisableCache) {
|
if ((isProduction || !item.devRefresh) && item.versionKey === versionKey && !isDisableCache) {
|
||||||
return global.systemCache[key].data;
|
return item.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshedData = await global.systemCache[key].refreshFunc();
|
const refreshedData = await item.refreshFunc();
|
||||||
global.systemCache[key].data = refreshedData;
|
item.data = refreshedData;
|
||||||
global.systemCache[key].versionKey = versionKey;
|
item.versionKey = versionKey;
|
||||||
return global.systemCache[key].data;
|
return item.data;
|
||||||
};
|
};
|
||||||
|
3
packages/service/common/cache/init.ts
vendored
3
packages/service/common/cache/init.ts
vendored
@@ -6,7 +6,8 @@ export const initCache = () => {
|
|||||||
[SystemCacheKeyEnum.systemTool]: {
|
[SystemCacheKeyEnum.systemTool]: {
|
||||||
versionKey: '',
|
versionKey: '',
|
||||||
data: [],
|
data: [],
|
||||||
refreshFunc: refreshSystemTools
|
refreshFunc: refreshSystemTools,
|
||||||
|
devRefresh: true
|
||||||
},
|
},
|
||||||
[SystemCacheKeyEnum.modelPermission]: {
|
[SystemCacheKeyEnum.modelPermission]: {
|
||||||
versionKey: '',
|
versionKey: '',
|
||||||
|
1
packages/service/common/cache/type.ts
vendored
1
packages/service/common/cache/type.ts
vendored
@@ -15,6 +15,7 @@ type SystemCacheType = {
|
|||||||
versionKey: string;
|
versionKey: string;
|
||||||
data: SystemCacheDataType[K];
|
data: SystemCacheDataType[K];
|
||||||
refreshFunc: () => Promise<SystemCacheDataType[K]>;
|
refreshFunc: () => Promise<SystemCacheDataType[K]>;
|
||||||
|
devRefresh?: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -55,6 +55,46 @@ export async function uploadMongoImg({
|
|||||||
|
|
||||||
return `${process.env.NEXT_PUBLIC_BASE_URL || ''}${imageBaseUrl}${String(_id)}.${extension}`;
|
return `${process.env.NEXT_PUBLIC_BASE_URL || ''}${imageBaseUrl}${String(_id)}.${extension}`;
|
||||||
}
|
}
|
||||||
|
export const copyImage = async ({
|
||||||
|
teamId,
|
||||||
|
imageUrl,
|
||||||
|
session
|
||||||
|
}: {
|
||||||
|
teamId: string;
|
||||||
|
imageUrl: string;
|
||||||
|
session?: ClientSession;
|
||||||
|
}) => {
|
||||||
|
const imageId = getIdFromPath(imageUrl);
|
||||||
|
if (!imageId) return imageUrl;
|
||||||
|
|
||||||
|
const image = await MongoImage.findOne(
|
||||||
|
{
|
||||||
|
_id: imageId,
|
||||||
|
teamId
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
session
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (!image) return imageUrl;
|
||||||
|
|
||||||
|
const [newImage] = await MongoImage.create(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
teamId,
|
||||||
|
binary: image.binary,
|
||||||
|
metadata: image.metadata
|
||||||
|
}
|
||||||
|
],
|
||||||
|
{
|
||||||
|
session,
|
||||||
|
ordered: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return `${process.env.NEXT_PUBLIC_BASE_URL || ''}${imageBaseUrl}${String(newImage._id)}.${image.metadata?.mime?.split('/')[1]}`;
|
||||||
|
};
|
||||||
|
|
||||||
const getIdFromPath = (path?: string) => {
|
const getIdFromPath = (path?: string) => {
|
||||||
if (!path) return;
|
if (!path) return;
|
||||||
|
79
packages/service/common/middle/tracks/processor.ts
Normal file
79
packages/service/common/middle/tracks/processor.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import { delay } from '@fastgpt/global/common/system/utils';
|
||||||
|
import { addLog } from '../../system/log';
|
||||||
|
import { TrackModel } from './schema';
|
||||||
|
import { TrackEnum } from '@fastgpt/global/common/middle/tracks/constants';
|
||||||
|
|
||||||
|
const batchUpdateTime = Number(process.env.TRACK_BATCH_UPDATE_TIME || 10000);
|
||||||
|
|
||||||
|
const getCurrentTenMinuteBoundary = () => {
|
||||||
|
const now = new Date();
|
||||||
|
const minutes = now.getMinutes();
|
||||||
|
const tenMinuteBoundary = Math.floor(minutes / 10) * 10;
|
||||||
|
|
||||||
|
const boundary = new Date(now);
|
||||||
|
boundary.setMinutes(tenMinuteBoundary, 0, 0);
|
||||||
|
return boundary;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const trackTimerProcess = async () => {
|
||||||
|
while (true) {
|
||||||
|
await countTrackTimer();
|
||||||
|
await delay(batchUpdateTime);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const countTrackTimer = async () => {
|
||||||
|
if (!global.countTrackQueue || global.countTrackQueue.size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const queuedItems = Array.from(global.countTrackQueue.values());
|
||||||
|
global.countTrackQueue = new Map();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const currentBoundary = getCurrentTenMinuteBoundary();
|
||||||
|
|
||||||
|
const bulkOps = queuedItems
|
||||||
|
.map(({ event, count, data }) => {
|
||||||
|
if (event === TrackEnum.datasetSearch) {
|
||||||
|
const { teamId, datasetId } = data;
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
updateOne: {
|
||||||
|
filter: {
|
||||||
|
event,
|
||||||
|
teamId,
|
||||||
|
createTime: currentBoundary,
|
||||||
|
'data.datasetId': datasetId
|
||||||
|
},
|
||||||
|
update: [
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
event,
|
||||||
|
teamId,
|
||||||
|
createTime: { $ifNull: ['$createTime', currentBoundary] },
|
||||||
|
data: {
|
||||||
|
datasetId,
|
||||||
|
count: { $add: [{ $ifNull: ['$data.count', 0] }, count] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
upsert: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
})
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
if (bulkOps.length > 0) {
|
||||||
|
await TrackModel.bulkWrite(bulkOps);
|
||||||
|
addLog.info('Track timer processing success');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
addLog.error('Track timer processing error', error);
|
||||||
|
}
|
||||||
|
};
|
@@ -13,6 +13,15 @@ const TrackSchema = new Schema({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
TrackSchema.index({ event: 1 });
|
TrackSchema.index({ event: 1 });
|
||||||
|
|
||||||
|
TrackSchema.index(
|
||||||
|
{ event: 1, teamId: 1, 'data.datasetId': 1, createTime: -1 },
|
||||||
|
{
|
||||||
|
partialFilterExpression: {
|
||||||
|
'data.datasetId': { $exists: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
17
packages/service/common/middle/tracks/type.d.ts
vendored
Normal file
17
packages/service/common/middle/tracks/type.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
export type TracksQueueType = {
|
||||||
|
event: TrackEnum;
|
||||||
|
data: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
var countTrackQueue:
|
||||||
|
| Map<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
event: TrackEnum;
|
||||||
|
count: number;
|
||||||
|
data: Record<string, any>;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
| undefined;
|
||||||
|
}
|
@@ -25,6 +25,42 @@ const createTrack = ({ event, data }: { event: TrackEnum; data: Record<string, a
|
|||||||
data: props
|
data: props
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Run times
|
||||||
|
const pushCountTrack = ({
|
||||||
|
event,
|
||||||
|
key,
|
||||||
|
data
|
||||||
|
}: {
|
||||||
|
event: TrackEnum;
|
||||||
|
key: string;
|
||||||
|
data: Record<string, any>;
|
||||||
|
}) => {
|
||||||
|
if (!global.feConfigs?.isPlus) return;
|
||||||
|
addLog.debug('Push tracks', {
|
||||||
|
event,
|
||||||
|
key
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!global.countTrackQueue) {
|
||||||
|
global.countTrackQueue = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = global.countTrackQueue.get(key);
|
||||||
|
if (value) {
|
||||||
|
global.countTrackQueue.set(key, {
|
||||||
|
...value,
|
||||||
|
count: value.count + 1
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
global.countTrackQueue.set(key, {
|
||||||
|
event,
|
||||||
|
data,
|
||||||
|
count: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const pushTrack = {
|
export const pushTrack = {
|
||||||
login: (data: PushTrackCommonType & { type: `${OAuthEnum}` | 'password' }) => {
|
login: (data: PushTrackCommonType & { type: `${OAuthEnum}` | 'password' }) => {
|
||||||
return createTrack({
|
return createTrack({
|
||||||
@@ -73,5 +109,18 @@ export const pushTrack = {
|
|||||||
event: TrackEnum.runSystemTool,
|
event: TrackEnum.runSystemTool,
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
datasetSearch: (data: { teamId: string; datasetIds: string[] }) => {
|
||||||
|
if (!data.teamId) return;
|
||||||
|
data.datasetIds.forEach((datasetId) => {
|
||||||
|
pushCountTrack({
|
||||||
|
event: TrackEnum.datasetSearch,
|
||||||
|
key: `${TrackEnum.datasetSearch}_${datasetId}`,
|
||||||
|
data: {
|
||||||
|
teamId: data.teamId,
|
||||||
|
datasetId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -6,3 +6,6 @@ export const isFastGPTProService = () => !!global.systemConfig;
|
|||||||
export const isProVersion = () => {
|
export const isProVersion = () => {
|
||||||
return !!global.feConfigs?.isPlus;
|
return !!global.feConfigs?.isPlus;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const serviceRequestMaxContentLength =
|
||||||
|
Number(process.env.SERVICE_REQUEST_MAX_CONTENT_LENGTH || 10) * 1024 * 1024; // 10MB
|
||||||
|
@@ -549,6 +549,7 @@ const dbPluginFormat = (item: SystemPluginConfigSchemaType): SystemPluginTemplat
|
|||||||
/* FastsGPT-Pluign api: */
|
/* FastsGPT-Pluign api: */
|
||||||
export const refreshSystemTools = async (): Promise<SystemPluginTemplateItemType[]> => {
|
export const refreshSystemTools = async (): Promise<SystemPluginTemplateItemType[]> => {
|
||||||
const tools = await APIGetSystemToolList();
|
const tools = await APIGetSystemToolList();
|
||||||
|
|
||||||
// 从数据库里加载插件配置进行替换
|
// 从数据库里加载插件配置进行替换
|
||||||
const systemToolsArray = await MongoSystemPlugin.find({}).lean();
|
const systemToolsArray = await MongoSystemPlugin.find({}).lean();
|
||||||
const systemTools = new Map(systemToolsArray.map((plugin) => [plugin.pluginId, plugin]));
|
const systemTools = new Map(systemToolsArray.map((plugin) => [plugin.pluginId, plugin]));
|
||||||
@@ -596,7 +597,7 @@ export const refreshSystemTools = async (): Promise<SystemPluginTemplateItemType
|
|||||||
.map((item) => dbPluginFormat(item));
|
.map((item) => dbPluginFormat(item));
|
||||||
|
|
||||||
const concatTools = [...formatTools, ...dbPlugins];
|
const concatTools = [...formatTools, ...dbPlugins];
|
||||||
concatTools.sort((a, b) => (a.pluginOrder ?? 0) - (b.pluginOrder ?? 0));
|
concatTools.sort((a, b) => (a.pluginOrder ?? 999) - (b.pluginOrder ?? 999));
|
||||||
|
|
||||||
global.systemToolsTypeCache = {};
|
global.systemToolsTypeCache = {};
|
||||||
concatTools.forEach((item) => {
|
concatTools.forEach((item) => {
|
||||||
|
@@ -32,10 +32,13 @@ import type { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
|||||||
import { datasetSearchQueryExtension } from './utils';
|
import { datasetSearchQueryExtension } from './utils';
|
||||||
import type { RerankModelItemType } from '@fastgpt/global/core/ai/model.d';
|
import type { RerankModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||||
import { formatDatasetDataValue } from '../data/controller';
|
import { formatDatasetDataValue } from '../data/controller';
|
||||||
|
import { pushTrack } from '../../../common/middle/tracks/utils';
|
||||||
|
|
||||||
export type SearchDatasetDataProps = {
|
export type SearchDatasetDataProps = {
|
||||||
histories: ChatItemType[];
|
histories: ChatItemType[];
|
||||||
teamId: string;
|
teamId: string;
|
||||||
|
uid?: string;
|
||||||
|
tmbId?: string;
|
||||||
model: string;
|
model: string;
|
||||||
datasetIds: string[];
|
datasetIds: string[];
|
||||||
reRankQuery: string;
|
reRankQuery: string;
|
||||||
@@ -900,6 +903,8 @@ export async function searchDatasetData(
|
|||||||
// token filter
|
// token filter
|
||||||
const filterMaxTokensResult = await filterDatasetDataByMaxTokens(scoreFilter, maxTokens);
|
const filterMaxTokensResult = await filterDatasetDataByMaxTokens(scoreFilter, maxTokens);
|
||||||
|
|
||||||
|
pushTrack.datasetSearch({ datasetIds, teamId });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
searchRes: filterMaxTokensResult,
|
searchRes: filterMaxTokensResult,
|
||||||
embeddingTokens,
|
embeddingTokens,
|
||||||
|
@@ -52,6 +52,7 @@ export async function dispatchDatasetSearch(
|
|||||||
const {
|
const {
|
||||||
runningAppInfo: { teamId },
|
runningAppInfo: { teamId },
|
||||||
runningUserInfo: { tmbId },
|
runningUserInfo: { tmbId },
|
||||||
|
uid,
|
||||||
histories,
|
histories,
|
||||||
node,
|
node,
|
||||||
params: {
|
params: {
|
||||||
|
@@ -27,6 +27,7 @@ import { addLog } from '../../../../common/system/log';
|
|||||||
import { SERVICE_LOCAL_HOST } from '../../../../common/system/tools';
|
import { SERVICE_LOCAL_HOST } from '../../../../common/system/tools';
|
||||||
import { formatHttpError } from '../utils';
|
import { formatHttpError } from '../utils';
|
||||||
import { isInternalAddress } from '../../../../common/system/utils';
|
import { isInternalAddress } from '../../../../common/system/utils';
|
||||||
|
import { serviceRequestMaxContentLength } from '../../../../common/system/constants';
|
||||||
|
|
||||||
type PropsArrType = {
|
type PropsArrType = {
|
||||||
key: string;
|
key: string;
|
||||||
@@ -505,6 +506,7 @@ async function fetchData({
|
|||||||
|
|
||||||
const { data: response } = await axios({
|
const { data: response } = await axios({
|
||||||
method,
|
method,
|
||||||
|
maxContentLength: serviceRequestMaxContentLength,
|
||||||
baseURL: `http://${SERVICE_LOCAL_HOST}`,
|
baseURL: `http://${SERVICE_LOCAL_HOST}`,
|
||||||
url,
|
url,
|
||||||
headers: {
|
headers: {
|
||||||
|
@@ -10,11 +10,10 @@ export const subRoute = process.env.NEXT_PUBLIC_BASE_URL;
|
|||||||
|
|
||||||
export const getWebReqUrl = (url: string = '') => {
|
export const getWebReqUrl = (url: string = '') => {
|
||||||
if (!url) return '/';
|
if (!url) return '/';
|
||||||
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
|
if (!subRoute) return url;
|
||||||
if (!baseUrl) return url;
|
|
||||||
|
|
||||||
if (!url.startsWith('/') || url.startsWith(baseUrl)) return url;
|
if (!url.startsWith('/') || url.startsWith(subRoute)) return url;
|
||||||
return `${baseUrl}${url}`;
|
return `${subRoute}${url}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isMobile = () => {
|
export const isMobile = () => {
|
||||||
|
@@ -83,6 +83,8 @@ USE_IP_LIMIT=false
|
|||||||
WORKFLOW_MAX_RUN_TIMES=500
|
WORKFLOW_MAX_RUN_TIMES=500
|
||||||
# 循环最大运行次数,避免极端的死循环情况
|
# 循环最大运行次数,避免极端的死循环情况
|
||||||
WORKFLOW_MAX_LOOP_TIMES=50
|
WORKFLOW_MAX_LOOP_TIMES=50
|
||||||
|
# 服务器接收请求,最大大小,单位 MB
|
||||||
|
SERVICE_REQUEST_MAX_CONTENT_LENGTH=10
|
||||||
# 启用内网 IP 检查
|
# 启用内网 IP 检查
|
||||||
CHECK_INTERNAL_IP=false
|
CHECK_INTERNAL_IP=false
|
||||||
# 密码错误锁时长:s
|
# 密码错误锁时长:s
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "app",
|
"name": "app",
|
||||||
"version": "4.13.0",
|
"version": "4.13.1",
|
||||||
"private": false,
|
"private": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
@@ -14,6 +14,11 @@ export enum CodeClassNameEnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const mdTextFormat = (text: string) => {
|
export const mdTextFormat = (text: string) => {
|
||||||
|
// 处理 Windows 文件路径中的反斜杠,防止被 Markdown 转义:C:\path\file 或 c:\path\file
|
||||||
|
text = text.replace(/([A-Za-z]:\\[^\s`\[\]()]*)/g, (match) => {
|
||||||
|
return match.replace(/\\/g, '\\\\');
|
||||||
|
});
|
||||||
|
|
||||||
// NextChat function - Format latex to $$
|
// NextChat function - Format latex to $$
|
||||||
const pattern = /(```[\s\S]*?```|`.*?`)|\\\[([\s\S]*?[^\\])\\\]|\\\((.*?)\\\)/g;
|
const pattern = /(```[\s\S]*?```|`.*?`)|\\\[([\s\S]*?[^\\])\\\]|\\\((.*?)\\\)/g;
|
||||||
text = text.replace(pattern, (match, codeBlock, squareBracket, roundBracket) => {
|
text = text.replace(pattern, (match, codeBlock, squareBracket, roundBracket) => {
|
||||||
|
@@ -94,7 +94,6 @@ export const FormInputComponent = React.memo(function FormInputComponent({
|
|||||||
inputType={inputType}
|
inputType={inputType}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
placeholder={input.label}
|
|
||||||
isDisabled={submitted}
|
isDisabled={submitted}
|
||||||
isInvalid={!!error}
|
isInvalid={!!error}
|
||||||
maxLength={input.maxLength}
|
maxLength={input.maxLength}
|
||||||
|
@@ -20,7 +20,8 @@ export async function register() {
|
|||||||
{ preLoadWorker },
|
{ preLoadWorker },
|
||||||
{ loadSystemModels },
|
{ loadSystemModels },
|
||||||
{ connectSignoz },
|
{ connectSignoz },
|
||||||
{ getSystemTools }
|
{ getSystemTools },
|
||||||
|
{ trackTimerProcess }
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
import('@fastgpt/service/common/mongo/init'),
|
import('@fastgpt/service/common/mongo/init'),
|
||||||
import('@fastgpt/service/common/mongo/index'),
|
import('@fastgpt/service/common/mongo/index'),
|
||||||
@@ -34,7 +35,8 @@ export async function register() {
|
|||||||
import('@fastgpt/service/worker/preload'),
|
import('@fastgpt/service/worker/preload'),
|
||||||
import('@fastgpt/service/core/ai/config/utils'),
|
import('@fastgpt/service/core/ai/config/utils'),
|
||||||
import('@fastgpt/service/common/otel/trace/register'),
|
import('@fastgpt/service/common/otel/trace/register'),
|
||||||
import('@fastgpt/service/core/app/plugin/controller')
|
import('@fastgpt/service/core/app/plugin/controller'),
|
||||||
|
import('@fastgpt/service/common/middle/tracks/processor')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// connect to signoz
|
// connect to signoz
|
||||||
@@ -61,6 +63,7 @@ export async function register() {
|
|||||||
startMongoWatch();
|
startMongoWatch();
|
||||||
startCron();
|
startCron();
|
||||||
startTrainingQueue(true);
|
startTrainingQueue(true);
|
||||||
|
trackTimerProcess();
|
||||||
|
|
||||||
console.log('Init system success');
|
console.log('Init system success');
|
||||||
}
|
}
|
||||||
|
@@ -275,6 +275,13 @@ const NodeTemplateList = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const currentNode = nodeList.find((node) => node.nodeId === handleParams?.nodeId);
|
const currentNode = nodeList.find((node) => node.nodeId === handleParams?.nodeId);
|
||||||
|
if (templateNode.flowNodeType === FlowNodeTypeEnum.loop && !!currentNode?.parentNodeId) {
|
||||||
|
toast({
|
||||||
|
status: 'warning',
|
||||||
|
title: t('workflow:can_not_loop')
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const newNode = nodeTemplate2FlowNode({
|
const newNode = nodeTemplate2FlowNode({
|
||||||
template: {
|
template: {
|
||||||
|
@@ -166,6 +166,7 @@ const InputFormEditModal = ({
|
|||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setValue('type', item.value);
|
setValue('type', item.value);
|
||||||
|
setValue('defaultValue', '');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MyIcon
|
<MyIcon
|
||||||
|
@@ -296,6 +296,7 @@ const FieldEditModal = ({
|
|||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setValue('renderTypeList', item.value);
|
setValue('renderTypeList', item.value);
|
||||||
|
setValue('defaultValue', '');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MyIcon
|
<MyIcon
|
||||||
|
@@ -8,6 +8,8 @@ import { onCreateApp } from './create';
|
|||||||
import { AuditEventEnum } from '@fastgpt/global/support/user/audit/constants';
|
import { AuditEventEnum } from '@fastgpt/global/support/user/audit/constants';
|
||||||
import { addAuditLog } from '@fastgpt/service/support/user/audit/util';
|
import { addAuditLog } from '@fastgpt/service/support/user/audit/util';
|
||||||
import { getI18nAppType } from '@fastgpt/service/support/user/audit/util';
|
import { getI18nAppType } from '@fastgpt/service/support/user/audit/util';
|
||||||
|
import { copyImage } from '@fastgpt/service/common/file/image/controller';
|
||||||
|
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||||
|
|
||||||
export type copyAppQuery = {};
|
export type copyAppQuery = {};
|
||||||
|
|
||||||
@@ -32,19 +34,32 @@ async function handler(
|
|||||||
? await authApp({ req, appId: app.parentId, per: WritePermissionVal, authToken: true })
|
? await authApp({ req, appId: app.parentId, per: WritePermissionVal, authToken: true })
|
||||||
: await authUserPer({ req, authToken: true, per: TeamAppCreatePermissionVal });
|
: await authUserPer({ req, authToken: true, per: TeamAppCreatePermissionVal });
|
||||||
|
|
||||||
|
// Copy avatar
|
||||||
|
const { appId } = await mongoSessionRun(async (session) => {
|
||||||
|
const avatar = await copyImage({
|
||||||
|
teamId,
|
||||||
|
imageUrl: app.avatar,
|
||||||
|
session
|
||||||
|
});
|
||||||
|
|
||||||
const appId = await onCreateApp({
|
const appId = await onCreateApp({
|
||||||
parentId: app.parentId,
|
parentId: app.parentId,
|
||||||
name: app.name + ' Copy',
|
name: app.name + ' Copy',
|
||||||
intro: app.intro,
|
intro: app.intro,
|
||||||
avatar: app.avatar,
|
avatar,
|
||||||
type: app.type,
|
type: app.type,
|
||||||
modules: app.modules,
|
modules: app.modules,
|
||||||
edges: app.edges,
|
edges: app.edges,
|
||||||
chatConfig: app.chatConfig,
|
chatConfig: app.chatConfig,
|
||||||
teamId: app.teamId,
|
teamId: app.teamId,
|
||||||
tmbId,
|
tmbId,
|
||||||
pluginData: app.pluginData
|
pluginData: app.pluginData,
|
||||||
|
session
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return { appId };
|
||||||
|
});
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
addAuditLog({
|
addAuditLog({
|
||||||
tmbId,
|
tmbId,
|
||||||
|
@@ -47,7 +47,7 @@ async function handler(req: ApiRequestProps<SearchTestProps>): Promise<SearchTes
|
|||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
|
|
||||||
// auth dataset role
|
// auth dataset role
|
||||||
const { dataset, teamId, tmbId, apikey } = await authDataset({
|
const { dataset, teamId, tmbId, userId, apikey } = await authDataset({
|
||||||
req,
|
req,
|
||||||
authToken: true,
|
authToken: true,
|
||||||
authApiKey: true,
|
authApiKey: true,
|
||||||
|
@@ -8,7 +8,7 @@ import { clearToken } from '@/web/support/user/auth';
|
|||||||
import { TOKEN_ERROR_CODE } from '@fastgpt/global/common/error/errorCode';
|
import { TOKEN_ERROR_CODE } from '@fastgpt/global/common/error/errorCode';
|
||||||
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
|
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
|
||||||
import { useSystemStore } from '../system/useSystemStore';
|
import { useSystemStore } from '../system/useSystemStore';
|
||||||
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
|
import { getWebReqUrl, subRoute } from '@fastgpt/web/common/system/utils';
|
||||||
import { i18nT } from '@fastgpt/web/i18n/utils';
|
import { i18nT } from '@fastgpt/web/i18n/utils';
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||||
|
|
||||||
@@ -110,9 +110,9 @@ function checkRes(data: ResponseDataType) {
|
|||||||
function responseError(err: any) {
|
function responseError(err: any) {
|
||||||
console.log('error->', '请求错误', err);
|
console.log('error->', '请求错误', err);
|
||||||
const isOutlinkPage = {
|
const isOutlinkPage = {
|
||||||
'/chat/share': true,
|
[`${subRoute}/chat/share`]: true,
|
||||||
'/chat': true,
|
[`${subRoute}/chat`]: true,
|
||||||
'/login': true
|
[`${subRoute}/login`]: true
|
||||||
}[window.location.pathname];
|
}[window.location.pathname];
|
||||||
|
|
||||||
const data = err?.response?.data || err;
|
const data = err?.response?.data || err;
|
||||||
|
@@ -87,7 +87,9 @@ export const storeNode2FlowNode = ({
|
|||||||
moduleTemplatesFlat.find((template) => template.flowNodeType === storeNode.flowNodeType) ||
|
moduleTemplatesFlat.find((template) => template.flowNodeType === storeNode.flowNodeType) ||
|
||||||
EmptyNode;
|
EmptyNode;
|
||||||
|
|
||||||
const templateInputs = template.inputs.filter((input) => !input.canEdit);
|
const templateInputs = template.inputs.filter(
|
||||||
|
(input) => !input.canEdit && input.deprecated !== true
|
||||||
|
);
|
||||||
const templateOutputs = template.outputs.filter(
|
const templateOutputs = template.outputs.filter(
|
||||||
(output) => output.type !== FlowNodeOutputTypeEnum.dynamic
|
(output) => output.type !== FlowNodeOutputTypeEnum.dynamic
|
||||||
);
|
);
|
||||||
|
@@ -75,7 +75,7 @@ describe('storeNode2FlowNode with deprecated inputs/outputs', () => {
|
|||||||
|
|
||||||
const deprecatedInput = result.data.inputs.find((input) => input.key === 'deprecatedInput');
|
const deprecatedInput = result.data.inputs.find((input) => input.key === 'deprecatedInput');
|
||||||
expect(deprecatedInput).toBeDefined();
|
expect(deprecatedInput).toBeDefined();
|
||||||
expect(deprecatedInput?.deprecated).toBe(true);
|
expect(deprecatedInput?.deprecated).toBe(undefined);
|
||||||
|
|
||||||
const deprecatedOutput = result.data.outputs.find(
|
const deprecatedOutput = result.data.outputs.find(
|
||||||
(output) => output.key === 'deprecatedOutput'
|
(output) => output.key === 'deprecatedOutput'
|
||||||
|
@@ -9,8 +9,26 @@ import {
|
|||||||
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
|
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
|
||||||
import { TOKEN_ERROR_CODE } from '@fastgpt/global/common/error/errorCode';
|
import { TOKEN_ERROR_CODE } from '@fastgpt/global/common/error/errorCode';
|
||||||
|
|
||||||
|
// Mock all required dependencies
|
||||||
vi.mock('@fastgpt/web/common/system/utils', () => ({
|
vi.mock('@fastgpt/web/common/system/utils', () => ({
|
||||||
getWebReqUrl: vi.fn().mockReturnValue('http://test.com')
|
getWebReqUrl: vi.fn().mockReturnValue('http://test.com'),
|
||||||
|
subRoute: '/test-route' // Add subRoute mock
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('@/web/support/user/auth', () => ({
|
||||||
|
clearToken: vi.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('../system/useSystemStore', () => ({
|
||||||
|
useSystemStore: {
|
||||||
|
getState: vi.fn().mockReturnValue({
|
||||||
|
setNotSufficientModalType: vi.fn()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('@fastgpt/web/i18n/utils', () => ({
|
||||||
|
i18nT: vi.fn().mockReturnValue('Unauthorized token')
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Mock window.location
|
// Mock window.location
|
||||||
@@ -99,7 +117,7 @@ describe('request utils', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should handle token error for outlink page', async () => {
|
it('should handle token error for outlink page', async () => {
|
||||||
mockLocation.pathname = '/chat/share';
|
mockLocation.pathname = '/test-route/chat/share';
|
||||||
const err = {
|
const err = {
|
||||||
response: {
|
response: {
|
||||||
data: {
|
data: {
|
||||||
|
Reference in New Issue
Block a user