Compare commits
6 Commits
v4.9.10-de
...
v4.9.10-fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02b214b3ec | ||
|
|
a171c7b11c | ||
|
|
802de11363 | ||
|
|
b4ecfb0b79 | ||
|
|
331b851a78 | ||
|
|
50d235c42a |
@@ -132,15 +132,15 @@ services:
|
|||||||
# fastgpt
|
# fastgpt
|
||||||
sandbox:
|
sandbox:
|
||||||
container_name: sandbox
|
container_name: sandbox
|
||||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
|
||||||
networks:
|
networks:
|
||||||
- fastgpt
|
- fastgpt
|
||||||
restart: always
|
restart: always
|
||||||
fastgpt-mcp-server:
|
fastgpt-mcp-server:
|
||||||
container_name: fastgpt-mcp-server
|
container_name: fastgpt-mcp-server
|
||||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3005:3000
|
- 3005:3000
|
||||||
networks:
|
networks:
|
||||||
@@ -150,8 +150,8 @@ services:
|
|||||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||||
fastgpt:
|
fastgpt:
|
||||||
container_name: fastgpt
|
container_name: fastgpt
|
||||||
image: ghcr.io/labring/fastgpt:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -109,15 +109,15 @@ services:
|
|||||||
# fastgpt
|
# fastgpt
|
||||||
sandbox:
|
sandbox:
|
||||||
container_name: sandbox
|
container_name: sandbox
|
||||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
|
||||||
networks:
|
networks:
|
||||||
- fastgpt
|
- fastgpt
|
||||||
restart: always
|
restart: always
|
||||||
fastgpt-mcp-server:
|
fastgpt-mcp-server:
|
||||||
container_name: fastgpt-mcp-server
|
container_name: fastgpt-mcp-server
|
||||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3005:3000
|
- 3005:3000
|
||||||
networks:
|
networks:
|
||||||
@@ -127,8 +127,8 @@ services:
|
|||||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||||
fastgpt:
|
fastgpt:
|
||||||
container_name: fastgpt
|
container_name: fastgpt
|
||||||
image: ghcr.io/labring/fastgpt:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -96,15 +96,15 @@ services:
|
|||||||
# fastgpt
|
# fastgpt
|
||||||
sandbox:
|
sandbox:
|
||||||
container_name: sandbox
|
container_name: sandbox
|
||||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
|
||||||
networks:
|
networks:
|
||||||
- fastgpt
|
- fastgpt
|
||||||
restart: always
|
restart: always
|
||||||
fastgpt-mcp-server:
|
fastgpt-mcp-server:
|
||||||
container_name: fastgpt-mcp-server
|
container_name: fastgpt-mcp-server
|
||||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3005:3000
|
- 3005:3000
|
||||||
networks:
|
networks:
|
||||||
@@ -114,8 +114,8 @@ services:
|
|||||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||||
fastgpt:
|
fastgpt:
|
||||||
container_name: fastgpt
|
container_name: fastgpt
|
||||||
image: ghcr.io/labring/fastgpt:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -72,15 +72,15 @@ services:
|
|||||||
|
|
||||||
sandbox:
|
sandbox:
|
||||||
container_name: sandbox
|
container_name: sandbox
|
||||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
|
||||||
networks:
|
networks:
|
||||||
- fastgpt
|
- fastgpt
|
||||||
restart: always
|
restart: always
|
||||||
fastgpt-mcp-server:
|
fastgpt-mcp-server:
|
||||||
container_name: fastgpt-mcp-server
|
container_name: fastgpt-mcp-server
|
||||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3005:3000
|
- 3005:3000
|
||||||
networks:
|
networks:
|
||||||
@@ -90,8 +90,8 @@ services:
|
|||||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||||
fastgpt:
|
fastgpt:
|
||||||
container_name: fastgpt
|
container_name: fastgpt
|
||||||
image: ghcr.io/labring/fastgpt:v4.9.10 # git
|
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 'V4.9.10(进行中)'
|
title: 'V4.9.10'
|
||||||
description: 'FastGPT V4.9.10 更新说明'
|
description: 'FastGPT V4.9.10 更新说明'
|
||||||
icon: 'upgrade'
|
icon: 'upgrade'
|
||||||
draft: false
|
draft: false
|
||||||
@@ -15,8 +15,8 @@ weight: 790
|
|||||||
|
|
||||||
### 2. 更新镜像 tag
|
### 2. 更新镜像 tag
|
||||||
|
|
||||||
- 更新 FastGPT 镜像 tag: v4.9.10
|
- 更新 FastGPT 镜像 tag: v4.9.10-fix2
|
||||||
- 更新 FastGPT 商业版镜像 tag: v4.9.10
|
- 更新 FastGPT 商业版镜像 tag: v4.9.10-fix2
|
||||||
- mcp_server 无需更新
|
- mcp_server 无需更新
|
||||||
- Sandbox 无需更新
|
- Sandbox 无需更新
|
||||||
- AIProxy 无需更新
|
- AIProxy 无需更新
|
||||||
|
|||||||
24
docSite/content/zh-cn/docs/development/upgrading/4911.md
Normal file
24
docSite/content/zh-cn/docs/development/upgrading/4911.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
title: 'V4.9.11(进行中)'
|
||||||
|
description: 'FastGPT V4.9.11 更新说明'
|
||||||
|
icon: 'upgrade'
|
||||||
|
draft: false
|
||||||
|
toc: true
|
||||||
|
weight: 789
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## 🚀 新增内容
|
||||||
|
|
||||||
|
1. 工作流中,子流程版本控制,可选择“保持最新版本”,无需手动更新。
|
||||||
|
|
||||||
|
## ⚙️ 优化
|
||||||
|
|
||||||
|
1. 原文缓存改用 gridfs 存储,提高上限。
|
||||||
|
|
||||||
|
## 🐛 修复
|
||||||
|
|
||||||
|
1. 工作流中,管理员声明的全局系统工具,无法进行版本管理。
|
||||||
|
2. 工具调用节点前,有交互节点时,上下文异常。
|
||||||
|
3. 修复备份导入,小于 1000 字时,无法分块问题。
|
||||||
|
4. 自定义 PDF 解析,无法保存 base64 图片。
|
||||||
@@ -10,6 +10,8 @@ import { AppTypeEnum } from './constants';
|
|||||||
import { AppErrEnum } from '../../common/error/code/app';
|
import { AppErrEnum } from '../../common/error/code/app';
|
||||||
import { PluginErrEnum } from '../../common/error/code/plugin';
|
import { PluginErrEnum } from '../../common/error/code/plugin';
|
||||||
import { i18nT } from '../../../web/i18n/utils';
|
import { i18nT } from '../../../web/i18n/utils';
|
||||||
|
import appErrList from '../../common/error/code/app';
|
||||||
|
import pluginErrList from '../../common/error/code/plugin';
|
||||||
|
|
||||||
export const getDefaultAppForm = (): AppSimpleEditFormType => {
|
export const getDefaultAppForm = (): AppSimpleEditFormType => {
|
||||||
return {
|
return {
|
||||||
@@ -190,17 +192,10 @@ export const getAppType = (config?: WorkflowTemplateBasicType | AppSimpleEditFor
|
|||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
export const formatToolError = (error?: string) => {
|
export const formatToolError = (error?: any) => {
|
||||||
const unExistError: Array<string> = [
|
if (!error || typeof error !== 'string') return;
|
||||||
AppErrEnum.unAuthApp,
|
|
||||||
AppErrEnum.unExist,
|
|
||||||
PluginErrEnum.unAuth,
|
|
||||||
PluginErrEnum.unExist
|
|
||||||
];
|
|
||||||
|
|
||||||
if (error && unExistError.includes(error)) {
|
const errorText = appErrList[error]?.message || pluginErrList[error]?.message;
|
||||||
return i18nT('app:un_auth');
|
|
||||||
} else {
|
return errorText || error;
|
||||||
return error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
1
packages/global/core/workflow/type/node.d.ts
vendored
1
packages/global/core/workflow/type/node.d.ts
vendored
@@ -59,7 +59,6 @@ export type FlowNodeCommonType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type PluginDataType = {
|
export type PluginDataType = {
|
||||||
version?: string;
|
|
||||||
diagram?: string;
|
diagram?: string;
|
||||||
userGuide?: string;
|
userGuide?: string;
|
||||||
courseUrl?: string;
|
courseUrl?: string;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "4816",
|
|
||||||
"name": "钉钉 webhook",
|
"name": "钉钉 webhook",
|
||||||
"avatar": "plugins/dingding",
|
"avatar": "plugins/dingding",
|
||||||
"intro": "向钉钉机器人发起 webhook 请求。",
|
"intro": "向钉钉机器人发起 webhook 请求。",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "Menghuan1918",
|
"author": "Menghuan1918",
|
||||||
"version": "488",
|
|
||||||
"name": "PDF识别",
|
"name": "PDF识别",
|
||||||
"avatar": "plugins/doc2x",
|
"avatar": "plugins/doc2x",
|
||||||
"intro": "将PDF文件发送至Doc2X进行解析,返回结构化的LaTeX公式的文本(markdown),支持传入String类型的URL或者流程输出中的文件链接变量",
|
"intro": "将PDF文件发送至Doc2X进行解析,返回结构化的LaTeX公式的文本(markdown),支持传入String类型的URL或者流程输出中的文件链接变量",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "Menghuan1918",
|
"author": "Menghuan1918",
|
||||||
"version": "488",
|
|
||||||
"name": "Doc2X服务",
|
"name": "Doc2X服务",
|
||||||
"avatar": "plugins/doc2x",
|
"avatar": "plugins/doc2x",
|
||||||
"intro": "将传入的图片或PDF文件发送至Doc2X进行解析,返回带LaTeX公式的markdown格式的文本。",
|
"intro": "将传入的图片或PDF文件发送至Doc2X进行解析,返回带LaTeX公式的markdown格式的文本。",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "4816",
|
|
||||||
"name": "企业微信 webhook",
|
"name": "企业微信 webhook",
|
||||||
"avatar": "plugins/qiwei",
|
"avatar": "plugins/qiwei",
|
||||||
"intro": "向企业微信机器人发起 webhook 请求。只能内部群使用。",
|
"intro": "向企业微信机器人发起 webhook 请求。只能内部群使用。",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "4811",
|
|
||||||
"name": "Bing搜索",
|
"name": "Bing搜索",
|
||||||
"avatar": "core/workflow/template/bing",
|
"avatar": "core/workflow/template/bing",
|
||||||
"intro": "在Bing中搜索。",
|
"intro": "在Bing中搜索。",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "silencezhang",
|
"author": "silencezhang",
|
||||||
"version": "4811",
|
|
||||||
"name": "数据库连接",
|
"name": "数据库连接",
|
||||||
"avatar": "core/workflow/template/datasource",
|
"avatar": "core/workflow/template/datasource",
|
||||||
"intro": "可连接常用数据库,并执行sql",
|
"intro": "可连接常用数据库,并执行sql",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "collin",
|
"author": "collin",
|
||||||
"version": "4817",
|
|
||||||
"name": "流程等待",
|
"name": "流程等待",
|
||||||
"avatar": "core/workflow/template/sleep",
|
"avatar": "core/workflow/template/sleep",
|
||||||
"intro": "让工作流等待指定时间后运行",
|
"intro": "让工作流等待指定时间后运行",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "silencezhang",
|
"author": "silencezhang",
|
||||||
"version": "4817",
|
|
||||||
"name": "基础图表",
|
"name": "基础图表",
|
||||||
"avatar": "core/workflow/template/baseChart",
|
"avatar": "core/workflow/template/baseChart",
|
||||||
"intro": "根据数据生成图表,可根据chartType生成柱状图,折线图,饼图",
|
"intro": "根据数据生成图表,可根据chartType生成柱状图,折线图,饼图",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "silencezhang",
|
"author": "silencezhang",
|
||||||
"version": "486",
|
|
||||||
"name": "BI图表功能",
|
"name": "BI图表功能",
|
||||||
"avatar": "core/workflow/template/BI",
|
"avatar": "core/workflow/template/BI",
|
||||||
"intro": "BI图表功能,可以生成一些常用的图表,如饼图,柱状图,折线图等",
|
"intro": "BI图表功能,可以生成一些常用的图表,如饼图,柱状图,折线图等",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "486",
|
|
||||||
"name": "DuckDuckGo 网络搜索",
|
"name": "DuckDuckGo 网络搜索",
|
||||||
"avatar": "core/workflow/template/duckduckgo",
|
"avatar": "core/workflow/template/duckduckgo",
|
||||||
"intro": "使用 DuckDuckGo 进行网络搜索",
|
"intro": "使用 DuckDuckGo 进行网络搜索",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "486",
|
|
||||||
"name": "DuckDuckGo 图片搜索",
|
"name": "DuckDuckGo 图片搜索",
|
||||||
"avatar": "core/workflow/template/duckduckgo",
|
"avatar": "core/workflow/template/duckduckgo",
|
||||||
"intro": "使用 DuckDuckGo 进行图片搜索",
|
"intro": "使用 DuckDuckGo 进行图片搜索",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "486",
|
|
||||||
"name": "DuckDuckGo 新闻检索",
|
"name": "DuckDuckGo 新闻检索",
|
||||||
"avatar": "core/workflow/template/duckduckgo",
|
"avatar": "core/workflow/template/duckduckgo",
|
||||||
"intro": "使用 DuckDuckGo 进行新闻检索",
|
"intro": "使用 DuckDuckGo 进行新闻检索",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "486",
|
|
||||||
"name": "DuckDuckGo 视频搜索",
|
"name": "DuckDuckGo 视频搜索",
|
||||||
"avatar": "core/workflow/template/duckduckgo",
|
"avatar": "core/workflow/template/duckduckgo",
|
||||||
"intro": "使用 DuckDuckGo 进行视频搜索",
|
"intro": "使用 DuckDuckGo 进行视频搜索",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "486",
|
|
||||||
"name": "DuckDuckGo服务",
|
"name": "DuckDuckGo服务",
|
||||||
"avatar": "core/workflow/template/duckduckgo",
|
"avatar": "core/workflow/template/duckduckgo",
|
||||||
"intro": "DuckDuckGo 服务,包含网络搜索、图片搜索、新闻搜索等。",
|
"intro": "DuckDuckGo 服务,包含网络搜索、图片搜索、新闻搜索等。",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "488",
|
|
||||||
"name": "飞书 webhook",
|
"name": "飞书 webhook",
|
||||||
"avatar": "core/app/templates/plugin-feishu",
|
"avatar": "core/app/templates/plugin-feishu",
|
||||||
"intro": "向飞书机器人发起 webhook 请求。",
|
"intro": "向飞书机器人发起 webhook 请求。",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "486",
|
|
||||||
"name": "网页内容抓取",
|
"name": "网页内容抓取",
|
||||||
"avatar": "core/workflow/template/fetchUrl",
|
"avatar": "core/workflow/template/fetchUrl",
|
||||||
"intro": "可获取一个网页链接内容,并以 Markdown 格式输出,仅支持获取静态网站。",
|
"intro": "可获取一个网页链接内容,并以 Markdown 格式输出,仅支持获取静态网站。",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "481",
|
|
||||||
"templateType": "tools",
|
"templateType": "tools",
|
||||||
"name": "获取当前时间",
|
"name": "获取当前时间",
|
||||||
"avatar": "core/workflow/template/getTime",
|
"avatar": "core/workflow/template/getTime",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "4811",
|
|
||||||
"name": "Google搜索",
|
"name": "Google搜索",
|
||||||
"avatar": "core/workflow/template/google",
|
"avatar": "core/workflow/template/google",
|
||||||
"intro": "在google中搜索。",
|
"intro": "在google中搜索。",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "486",
|
|
||||||
"name": "数学公式执行",
|
"name": "数学公式执行",
|
||||||
"avatar": "core/workflow/template/mathCall",
|
"avatar": "core/workflow/template/mathCall",
|
||||||
"intro": "用于执行数学表达式的工具,通过 js 的 expr-eval 库运行表达式并返回结果。",
|
"intro": "用于执行数学表达式的工具,通过 js 的 expr-eval 库运行表达式并返回结果。",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "4816",
|
|
||||||
"name": "Search XNG 搜索",
|
"name": "Search XNG 搜索",
|
||||||
"avatar": "core/workflow/template/searxng",
|
"avatar": "core/workflow/template/searxng",
|
||||||
"intro": "使用 Search XNG 服务进行搜索。",
|
"intro": "使用 Search XNG 服务进行搜索。",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "cloudpense",
|
"author": "cloudpense",
|
||||||
"version": "1.0.0",
|
|
||||||
"name": "Email 邮件发送",
|
"name": "Email 邮件发送",
|
||||||
"avatar": "plugins/email",
|
"avatar": "plugins/email",
|
||||||
"intro": "通过SMTP协议发送电子邮件(nodemailer)",
|
"intro": "通过SMTP协议发送电子邮件(nodemailer)",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "489",
|
|
||||||
"name": "文本加工",
|
"name": "文本加工",
|
||||||
"avatar": "/imgs/workflow/textEditor.svg",
|
"avatar": "/imgs/workflow/textEditor.svg",
|
||||||
"intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。",
|
"intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"author": "",
|
"author": "",
|
||||||
"version": "4811",
|
|
||||||
"name": "Wiki搜索",
|
"name": "Wiki搜索",
|
||||||
"avatar": "core/workflow/template/wiki",
|
"avatar": "core/workflow/template/wiki",
|
||||||
"intro": "在Wiki中查询释义。",
|
"intro": "在Wiki中查询释义。",
|
||||||
|
|||||||
179
packages/service/common/buffer/rawText/controller.ts
Normal file
179
packages/service/common/buffer/rawText/controller.ts
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
import { retryFn } from '@fastgpt/global/common/system/utils';
|
||||||
|
import { connectionMongo } from '../../mongo';
|
||||||
|
import { MongoRawTextBufferSchema, bucketName } from './schema';
|
||||||
|
import { addLog } from '../../system/log';
|
||||||
|
import { setCron } from '../../system/cron';
|
||||||
|
import { checkTimerLock } from '../../system/timerLock/utils';
|
||||||
|
import { TimerIdEnum } from '../../system/timerLock/constants';
|
||||||
|
|
||||||
|
const getGridBucket = () => {
|
||||||
|
return new connectionMongo.mongo.GridFSBucket(connectionMongo.connection.db!, {
|
||||||
|
bucketName: bucketName
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addRawTextBuffer = async ({
|
||||||
|
sourceId,
|
||||||
|
sourceName,
|
||||||
|
text,
|
||||||
|
expiredTime
|
||||||
|
}: {
|
||||||
|
sourceId: string;
|
||||||
|
sourceName: string;
|
||||||
|
text: string;
|
||||||
|
expiredTime: Date;
|
||||||
|
}) => {
|
||||||
|
const gridBucket = getGridBucket();
|
||||||
|
const metadata = {
|
||||||
|
sourceId,
|
||||||
|
sourceName,
|
||||||
|
expiredTime
|
||||||
|
};
|
||||||
|
|
||||||
|
const buffer = Buffer.from(text);
|
||||||
|
|
||||||
|
const fileSize = buffer.length;
|
||||||
|
// 单块大小:尽可能大,但不超过 14MB,不小于128KB
|
||||||
|
const chunkSizeBytes = (() => {
|
||||||
|
// 计算理想块大小:文件大小 ÷ 目标块数(10)。 并且每个块需要小于 14MB
|
||||||
|
const idealChunkSize = Math.min(Math.ceil(fileSize / 10), 14 * 1024 * 1024);
|
||||||
|
|
||||||
|
// 确保块大小至少为128KB
|
||||||
|
const minChunkSize = 128 * 1024; // 128KB
|
||||||
|
|
||||||
|
// 取理想块大小和最小块大小中的较大值
|
||||||
|
let chunkSize = Math.max(idealChunkSize, minChunkSize);
|
||||||
|
|
||||||
|
// 将块大小向上取整到最接近的64KB的倍数,使其更整齐
|
||||||
|
chunkSize = Math.ceil(chunkSize / (64 * 1024)) * (64 * 1024);
|
||||||
|
|
||||||
|
return chunkSize;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const uploadStream = gridBucket.openUploadStream(sourceId, {
|
||||||
|
metadata,
|
||||||
|
chunkSizeBytes
|
||||||
|
});
|
||||||
|
|
||||||
|
return retryFn(async () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uploadStream.end(buffer);
|
||||||
|
uploadStream.on('finish', () => {
|
||||||
|
resolve(uploadStream.id);
|
||||||
|
});
|
||||||
|
uploadStream.on('error', (error) => {
|
||||||
|
addLog.error('addRawTextBuffer error', error);
|
||||||
|
resolve('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRawTextBuffer = async (sourceId: string) => {
|
||||||
|
const gridBucket = getGridBucket();
|
||||||
|
|
||||||
|
return retryFn(async () => {
|
||||||
|
const bufferData = await MongoRawTextBufferSchema.findOne(
|
||||||
|
{
|
||||||
|
'metadata.sourceId': sourceId
|
||||||
|
},
|
||||||
|
'_id metadata'
|
||||||
|
).lean();
|
||||||
|
if (!bufferData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file content
|
||||||
|
const downloadStream = gridBucket.openDownloadStream(bufferData._id);
|
||||||
|
const chunks: Buffer[] = [];
|
||||||
|
|
||||||
|
return new Promise<{
|
||||||
|
text: string;
|
||||||
|
sourceName: string;
|
||||||
|
} | null>((resolve, reject) => {
|
||||||
|
downloadStream.on('data', (chunk) => {
|
||||||
|
chunks.push(chunk);
|
||||||
|
});
|
||||||
|
|
||||||
|
downloadStream.on('end', () => {
|
||||||
|
const buffer = Buffer.concat(chunks);
|
||||||
|
const text = buffer.toString('utf8');
|
||||||
|
resolve({
|
||||||
|
text,
|
||||||
|
sourceName: bufferData.metadata?.sourceName || ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
downloadStream.on('error', (error) => {
|
||||||
|
addLog.error('getRawTextBuffer error', error);
|
||||||
|
resolve(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteRawTextBuffer = async (sourceId: string): Promise<boolean> => {
|
||||||
|
const gridBucket = getGridBucket();
|
||||||
|
|
||||||
|
return retryFn(async () => {
|
||||||
|
const buffer = await MongoRawTextBufferSchema.findOne({ 'metadata.sourceId': sourceId });
|
||||||
|
if (!buffer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await gridBucket.delete(buffer._id);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateRawTextBufferExpiredTime = async ({
|
||||||
|
sourceId,
|
||||||
|
expiredTime
|
||||||
|
}: {
|
||||||
|
sourceId: string;
|
||||||
|
expiredTime: Date;
|
||||||
|
}) => {
|
||||||
|
return retryFn(async () => {
|
||||||
|
return MongoRawTextBufferSchema.updateOne(
|
||||||
|
{ 'metadata.sourceId': sourceId },
|
||||||
|
{ $set: { 'metadata.expiredTime': expiredTime } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const clearExpiredRawTextBufferCron = async () => {
|
||||||
|
const clearExpiredRawTextBuffer = async () => {
|
||||||
|
addLog.debug('Clear expired raw text buffer start');
|
||||||
|
const gridBucket = getGridBucket();
|
||||||
|
|
||||||
|
return retryFn(async () => {
|
||||||
|
const data = await MongoRawTextBufferSchema.find(
|
||||||
|
{
|
||||||
|
'metadata.expiredTime': { $lt: new Date() }
|
||||||
|
},
|
||||||
|
'_id'
|
||||||
|
).lean();
|
||||||
|
|
||||||
|
for (const item of data) {
|
||||||
|
await gridBucket.delete(item._id);
|
||||||
|
}
|
||||||
|
addLog.debug('Clear expired raw text buffer end');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
setCron('*/10 * * * *', async () => {
|
||||||
|
if (
|
||||||
|
await checkTimerLock({
|
||||||
|
timerId: TimerIdEnum.clearExpiredRawTextBuffer,
|
||||||
|
lockMinuted: 9
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
await clearExpiredRawTextBuffer();
|
||||||
|
} catch (error) {
|
||||||
|
addLog.error('clearExpiredRawTextBufferCron error', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
clearExpiredRawTextBuffer();
|
||||||
|
};
|
||||||
@@ -1,33 +1,22 @@
|
|||||||
import { getMongoModel, Schema } from '../../mongo';
|
import { getMongoModel, type Types, Schema } from '../../mongo';
|
||||||
import { type RawTextBufferSchemaType } from './type';
|
|
||||||
|
|
||||||
export const collectionName = 'buffer_rawtexts';
|
export const bucketName = 'buffer_rawtext';
|
||||||
|
|
||||||
const RawTextBufferSchema = new Schema({
|
const RawTextBufferSchema = new Schema({
|
||||||
sourceId: {
|
metadata: {
|
||||||
type: String,
|
sourceId: { type: String, required: true },
|
||||||
required: true
|
sourceName: { type: String, required: true },
|
||||||
},
|
expiredTime: { type: Date, required: true }
|
||||||
rawText: {
|
}
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
createTime: {
|
|
||||||
type: Date,
|
|
||||||
default: () => new Date()
|
|
||||||
},
|
|
||||||
metadata: Object
|
|
||||||
});
|
});
|
||||||
|
RawTextBufferSchema.index({ 'metadata.sourceId': 'hashed' });
|
||||||
|
RawTextBufferSchema.index({ 'metadata.expiredTime': -1 });
|
||||||
|
|
||||||
try {
|
export const MongoRawTextBufferSchema = getMongoModel<{
|
||||||
RawTextBufferSchema.index({ sourceId: 1 });
|
_id: Types.ObjectId;
|
||||||
// 20 minutes
|
metadata: {
|
||||||
RawTextBufferSchema.index({ createTime: 1 }, { expireAfterSeconds: 20 * 60 });
|
sourceId: string;
|
||||||
} catch (error) {
|
sourceName: string;
|
||||||
console.log(error);
|
expiredTime: Date;
|
||||||
}
|
};
|
||||||
|
}>(`${bucketName}.files`, RawTextBufferSchema);
|
||||||
export const MongoRawTextBuffer = getMongoModel<RawTextBufferSchemaType>(
|
|
||||||
collectionName,
|
|
||||||
RawTextBufferSchema
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
export type RawTextBufferSchemaType = {
|
|
||||||
sourceId: string;
|
|
||||||
rawText: string;
|
|
||||||
createTime: Date;
|
|
||||||
metadata?: {
|
|
||||||
filename: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -6,13 +6,13 @@ import { type DatasetFileSchema } from '@fastgpt/global/core/dataset/type';
|
|||||||
import { MongoChatFileSchema, MongoDatasetFileSchema } from './schema';
|
import { MongoChatFileSchema, MongoDatasetFileSchema } from './schema';
|
||||||
import { detectFileEncoding, detectFileEncodingByPath } from '@fastgpt/global/common/file/tools';
|
import { detectFileEncoding, detectFileEncodingByPath } from '@fastgpt/global/common/file/tools';
|
||||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||||
import { MongoRawTextBuffer } from '../../buffer/rawText/schema';
|
|
||||||
import { readRawContentByFileBuffer } from '../read/utils';
|
import { readRawContentByFileBuffer } from '../read/utils';
|
||||||
import { gridFsStream2Buffer, stream2Encoding } from './utils';
|
import { gridFsStream2Buffer, stream2Encoding } from './utils';
|
||||||
import { addLog } from '../../system/log';
|
import { addLog } from '../../system/log';
|
||||||
import { readFromSecondary } from '../../mongo/utils';
|
|
||||||
import { parseFileExtensionFromUrl } from '@fastgpt/global/common/string/tools';
|
import { parseFileExtensionFromUrl } from '@fastgpt/global/common/string/tools';
|
||||||
import { Readable } from 'stream';
|
import { Readable } from 'stream';
|
||||||
|
import { addRawTextBuffer, getRawTextBuffer } from '../../buffer/rawText/controller';
|
||||||
|
import { addMinutes } from 'date-fns';
|
||||||
|
|
||||||
export function getGFSCollection(bucket: `${BucketNameEnum}`) {
|
export function getGFSCollection(bucket: `${BucketNameEnum}`) {
|
||||||
MongoDatasetFileSchema;
|
MongoDatasetFileSchema;
|
||||||
@@ -225,13 +225,11 @@ export const readFileContentFromMongo = async ({
|
|||||||
}> => {
|
}> => {
|
||||||
const bufferId = `${fileId}-${customPdfParse}`;
|
const bufferId = `${fileId}-${customPdfParse}`;
|
||||||
// read buffer
|
// read buffer
|
||||||
const fileBuffer = await MongoRawTextBuffer.findOne({ sourceId: bufferId }, undefined, {
|
const fileBuffer = await getRawTextBuffer(bufferId);
|
||||||
...readFromSecondary
|
|
||||||
}).lean();
|
|
||||||
if (fileBuffer) {
|
if (fileBuffer) {
|
||||||
return {
|
return {
|
||||||
rawText: fileBuffer.rawText,
|
rawText: fileBuffer.text,
|
||||||
filename: fileBuffer.metadata?.filename || ''
|
filename: fileBuffer?.sourceName
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,16 +263,13 @@ export const readFileContentFromMongo = async ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// < 14M
|
// Add buffer
|
||||||
if (fileBuffers.length < 14 * 1024 * 1024 && rawText.trim()) {
|
addRawTextBuffer({
|
||||||
MongoRawTextBuffer.create({
|
|
||||||
sourceId: bufferId,
|
sourceId: bufferId,
|
||||||
rawText,
|
sourceName: file.filename,
|
||||||
metadata: {
|
text: rawText,
|
||||||
filename: file.filename
|
expiredTime: addMinutes(new Date(), 20)
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
rawText,
|
rawText,
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import { Schema, getMongoModel } from '../../mongo';
|
import { Schema, getMongoModel } from '../../mongo';
|
||||||
|
|
||||||
const DatasetFileSchema = new Schema({});
|
const DatasetFileSchema = new Schema({
|
||||||
const ChatFileSchema = new Schema({});
|
metadata: Object
|
||||||
|
});
|
||||||
|
const ChatFileSchema = new Schema({
|
||||||
|
metadata: Object
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
DatasetFileSchema.index({ uploadDate: -1 });
|
||||||
DatasetFileSchema.index({ uploadDate: -1 });
|
|
||||||
|
|
||||||
ChatFileSchema.index({ uploadDate: -1 });
|
ChatFileSchema.index({ uploadDate: -1 });
|
||||||
ChatFileSchema.index({ 'metadata.chatId': 1 });
|
ChatFileSchema.index({ 'metadata.chatId': 1 });
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const MongoDatasetFileSchema = getMongoModel('dataset.files', DatasetFileSchema);
|
export const MongoDatasetFileSchema = getMongoModel('dataset.files', DatasetFileSchema);
|
||||||
export const MongoChatFileSchema = getMongoModel('chat.files', ChatFileSchema);
|
export const MongoChatFileSchema = getMongoModel('chat.files', ChatFileSchema);
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ export const readRawContentByFileBuffer = async ({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
rawText: text,
|
rawText: text,
|
||||||
formatText: rawText,
|
formatText: text,
|
||||||
imageList
|
imageList
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ export enum TimerIdEnum {
|
|||||||
clearExpiredSubPlan = 'clearExpiredSubPlan',
|
clearExpiredSubPlan = 'clearExpiredSubPlan',
|
||||||
updateStandardPlan = 'updateStandardPlan',
|
updateStandardPlan = 'updateStandardPlan',
|
||||||
scheduleTriggerApp = 'scheduleTriggerApp',
|
scheduleTriggerApp = 'scheduleTriggerApp',
|
||||||
notification = 'notification'
|
notification = 'notification',
|
||||||
|
clearExpiredRawTextBuffer = 'clearExpiredRawTextBuffer'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum LockNotificationEnum {
|
export enum LockNotificationEnum {
|
||||||
|
|||||||
@@ -30,8 +30,7 @@ import { Types } from 'mongoose';
|
|||||||
community: community-id
|
community: community-id
|
||||||
commercial: commercial-id
|
commercial: commercial-id
|
||||||
*/
|
*/
|
||||||
|
export function splitCombineToolId(id: string) {
|
||||||
export async function splitCombinePluginId(id: string) {
|
|
||||||
const splitRes = id.split('-');
|
const splitRes = id.split('-');
|
||||||
if (splitRes.length === 1) {
|
if (splitRes.length === 1) {
|
||||||
// app id
|
// app id
|
||||||
@@ -42,7 +41,7 @@ export async function splitCombinePluginId(id: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [source, pluginId] = id.split('-') as [PluginSourceEnum, string];
|
const [source, pluginId] = id.split('-') as [PluginSourceEnum, string];
|
||||||
if (!source || !pluginId) return Promise.reject('pluginId not found');
|
if (!source || !pluginId) throw new Error('pluginId not found');
|
||||||
|
|
||||||
return { source, pluginId: id };
|
return { source, pluginId: id };
|
||||||
}
|
}
|
||||||
@@ -54,7 +53,7 @@ const getSystemPluginTemplateById = async (
|
|||||||
versionId?: string
|
versionId?: string
|
||||||
): Promise<ChildAppType> => {
|
): Promise<ChildAppType> => {
|
||||||
const item = getSystemPluginTemplates().find((plugin) => plugin.id === pluginId);
|
const item = getSystemPluginTemplates().find((plugin) => plugin.id === pluginId);
|
||||||
if (!item) return Promise.reject(PluginErrEnum.unAuth);
|
if (!item) return Promise.reject(PluginErrEnum.unExist);
|
||||||
|
|
||||||
const plugin = cloneDeep(item);
|
const plugin = cloneDeep(item);
|
||||||
|
|
||||||
@@ -64,10 +63,10 @@ const getSystemPluginTemplateById = async (
|
|||||||
{ pluginId: plugin.id, 'customConfig.associatedPluginId': plugin.associatedPluginId },
|
{ pluginId: plugin.id, 'customConfig.associatedPluginId': plugin.associatedPluginId },
|
||||||
'associatedPluginId'
|
'associatedPluginId'
|
||||||
).lean();
|
).lean();
|
||||||
if (!systemPlugin) return Promise.reject(PluginErrEnum.unAuth);
|
if (!systemPlugin) return Promise.reject(PluginErrEnum.unExist);
|
||||||
|
|
||||||
const app = await MongoApp.findById(plugin.associatedPluginId).lean();
|
const app = await MongoApp.findById(plugin.associatedPluginId).lean();
|
||||||
if (!app) return Promise.reject(PluginErrEnum.unAuth);
|
if (!app) return Promise.reject(PluginErrEnum.unExist);
|
||||||
|
|
||||||
const version = versionId
|
const version = versionId
|
||||||
? await getAppVersionById({
|
? await getAppVersionById({
|
||||||
@@ -77,6 +76,12 @@ const getSystemPluginTemplateById = async (
|
|||||||
})
|
})
|
||||||
: await getAppLatestVersion(plugin.associatedPluginId, app);
|
: await getAppLatestVersion(plugin.associatedPluginId, app);
|
||||||
if (!version.versionId) return Promise.reject('App version not found');
|
if (!version.versionId) return Promise.reject('App version not found');
|
||||||
|
const isLatest = version.versionId
|
||||||
|
? await checkIsLatestVersion({
|
||||||
|
appId: plugin.associatedPluginId,
|
||||||
|
versionId: version.versionId
|
||||||
|
})
|
||||||
|
: true;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...plugin,
|
...plugin,
|
||||||
@@ -85,12 +90,19 @@ const getSystemPluginTemplateById = async (
|
|||||||
edges: version.edges,
|
edges: version.edges,
|
||||||
chatConfig: version.chatConfig
|
chatConfig: version.chatConfig
|
||||||
},
|
},
|
||||||
version: versionId || String(version.versionId),
|
version: versionId ? version?.versionId : '',
|
||||||
|
versionLabel: version?.versionName,
|
||||||
|
isLatestVersion: isLatest,
|
||||||
teamId: String(app.teamId),
|
teamId: String(app.teamId),
|
||||||
tmbId: String(app.tmbId)
|
tmbId: String(app.tmbId)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return plugin;
|
|
||||||
|
return {
|
||||||
|
...plugin,
|
||||||
|
version: undefined,
|
||||||
|
isLatestVersion: true
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Format plugin to workflow preview node data */
|
/* Format plugin to workflow preview node data */
|
||||||
@@ -102,11 +114,11 @@ export async function getChildAppPreviewNode({
|
|||||||
versionId?: string;
|
versionId?: string;
|
||||||
}): Promise<FlowNodeTemplateType> {
|
}): Promise<FlowNodeTemplateType> {
|
||||||
const app: ChildAppType = await (async () => {
|
const app: ChildAppType = await (async () => {
|
||||||
const { source, pluginId } = await splitCombinePluginId(appId);
|
const { source, pluginId } = splitCombineToolId(appId);
|
||||||
|
|
||||||
if (source === PluginSourceEnum.personal) {
|
if (source === PluginSourceEnum.personal) {
|
||||||
const item = await MongoApp.findById(appId).lean();
|
const item = await MongoApp.findById(appId).lean();
|
||||||
if (!item) return Promise.reject('plugin not found');
|
if (!item) return Promise.reject(PluginErrEnum.unExist);
|
||||||
|
|
||||||
const version = await getAppVersionById({ appId, versionId, app: item });
|
const version = await getAppVersionById({ appId, versionId, app: item });
|
||||||
|
|
||||||
@@ -132,8 +144,8 @@ export async function getChildAppPreviewNode({
|
|||||||
},
|
},
|
||||||
templateType: FlowNodeTemplateTypeEnum.teamApp,
|
templateType: FlowNodeTemplateTypeEnum.teamApp,
|
||||||
|
|
||||||
version: version.versionId,
|
version: versionId ? version?.versionId : '',
|
||||||
versionLabel: version?.versionName || '',
|
versionLabel: version?.versionName,
|
||||||
isLatestVersion: isLatest,
|
isLatestVersion: isLatest,
|
||||||
|
|
||||||
originCost: 0,
|
originCost: 0,
|
||||||
@@ -142,7 +154,7 @@ export async function getChildAppPreviewNode({
|
|||||||
pluginOrder: 0
|
pluginOrder: 0
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return getSystemPluginTemplateById(pluginId);
|
return getSystemPluginTemplateById(pluginId, versionId);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@@ -216,12 +228,12 @@ export async function getChildAppRuntimeById(
|
|||||||
id: string,
|
id: string,
|
||||||
versionId?: string
|
versionId?: string
|
||||||
): Promise<PluginRuntimeType> {
|
): Promise<PluginRuntimeType> {
|
||||||
const app: ChildAppType = await (async () => {
|
const app = await (async () => {
|
||||||
const { source, pluginId } = await splitCombinePluginId(id);
|
const { source, pluginId } = splitCombineToolId(id);
|
||||||
|
|
||||||
if (source === PluginSourceEnum.personal) {
|
if (source === PluginSourceEnum.personal) {
|
||||||
const item = await MongoApp.findById(id).lean();
|
const item = await MongoApp.findById(id).lean();
|
||||||
if (!item) return Promise.reject('plugin not found');
|
if (!item) return Promise.reject(PluginErrEnum.unExist);
|
||||||
|
|
||||||
const version = await getAppVersionById({
|
const version = await getAppVersionById({
|
||||||
appId: id,
|
appId: id,
|
||||||
@@ -244,8 +256,6 @@ export async function getChildAppRuntimeById(
|
|||||||
},
|
},
|
||||||
templateType: FlowNodeTemplateTypeEnum.teamApp,
|
templateType: FlowNodeTemplateTypeEnum.teamApp,
|
||||||
|
|
||||||
// 用不到
|
|
||||||
version: item?.pluginData?.nodeVersion,
|
|
||||||
originCost: 0,
|
originCost: 0,
|
||||||
currentCost: 0,
|
currentCost: 0,
|
||||||
hasTokenFee: false,
|
hasTokenFee: false,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { type ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
import { type ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||||
import { type PluginRuntimeType } from '@fastgpt/global/core/plugin/type';
|
import { type PluginRuntimeType } from '@fastgpt/global/core/plugin/type';
|
||||||
import { splitCombinePluginId } from './controller';
|
import { splitCombineToolId } from './controller';
|
||||||
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -20,7 +20,7 @@ export const computedPluginUsage = async ({
|
|||||||
childrenUsage: ChatNodeUsageType[];
|
childrenUsage: ChatNodeUsageType[];
|
||||||
error?: boolean;
|
error?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const { source } = await splitCombinePluginId(plugin.id);
|
const { source } = splitCombineToolId(plugin.id);
|
||||||
const childrenUsages = childrenUsage.reduce((sum, item) => sum + (item.totalPoints || 0), 0);
|
const childrenUsages = childrenUsage.reduce((sum, item) => sum + (item.totalPoints || 0), 0);
|
||||||
|
|
||||||
if (source !== PluginSourceEnum.personal) {
|
if (source !== PluginSourceEnum.personal) {
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { MongoDataset } from '../dataset/schema';
|
import { MongoDataset } from '../dataset/schema';
|
||||||
import { getEmbeddingModel } from '../ai/model';
|
import { getEmbeddingModel } from '../ai/model';
|
||||||
import {
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
AppNodeFlowNodeTypeMap,
|
|
||||||
FlowNodeTypeEnum
|
|
||||||
} from '@fastgpt/global/core/workflow/node/constant';
|
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||||
import { MongoAppVersion } from './version/schema';
|
import { getChildAppPreviewNode, splitCombineToolId } from './plugin/controller';
|
||||||
import { checkIsLatestVersion } from './version/controller';
|
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
import { Types } from '../../common/mongo';
|
import { authAppByTmbId } from '../../support/permission/app/auth';
|
||||||
|
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
|
|
||||||
export async function listAppDatasetDataByTeamIdAndDatasetIds({
|
export async function listAppDatasetDataByTeamIdAndDatasetIds({
|
||||||
teamId,
|
teamId,
|
||||||
@@ -33,53 +32,58 @@ export async function listAppDatasetDataByTeamIdAndDatasetIds({
|
|||||||
export async function rewriteAppWorkflowToDetail({
|
export async function rewriteAppWorkflowToDetail({
|
||||||
nodes,
|
nodes,
|
||||||
teamId,
|
teamId,
|
||||||
isRoot
|
isRoot,
|
||||||
|
ownerTmbId
|
||||||
}: {
|
}: {
|
||||||
nodes: StoreNodeItemType[];
|
nodes: StoreNodeItemType[];
|
||||||
teamId: string;
|
teamId: string;
|
||||||
isRoot: boolean;
|
isRoot: boolean;
|
||||||
|
ownerTmbId: string;
|
||||||
}) {
|
}) {
|
||||||
const datasetIdSet = new Set<string>();
|
const datasetIdSet = new Set<string>();
|
||||||
|
|
||||||
// Add node(App Type) versionlabel and latest sign
|
/* Add node(App Type) versionlabel and latest sign ==== */
|
||||||
const appNodes = nodes.filter((node) => AppNodeFlowNodeTypeMap[node.flowNodeType]);
|
await Promise.all(
|
||||||
const versionIds = appNodes
|
nodes.map(async (node) => {
|
||||||
.filter((node) => node.version && Types.ObjectId.isValid(node.version))
|
if (!node.pluginId) return;
|
||||||
.map((node) => node.version);
|
const { source } = splitCombineToolId(node.pluginId);
|
||||||
|
|
||||||
if (versionIds.length > 0) {
|
try {
|
||||||
const versionDataList = await MongoAppVersion.find(
|
const [preview] = await Promise.all([
|
||||||
{
|
getChildAppPreviewNode({
|
||||||
_id: { $in: versionIds }
|
appId: node.pluginId,
|
||||||
},
|
versionId: node.version
|
||||||
'_id versionName appId time'
|
}),
|
||||||
).lean();
|
...(source === PluginSourceEnum.personal
|
||||||
|
? [
|
||||||
|
authAppByTmbId({
|
||||||
|
tmbId: ownerTmbId,
|
||||||
|
appId: node.pluginId,
|
||||||
|
per: ReadPermissionVal
|
||||||
|
})
|
||||||
|
]
|
||||||
|
: [])
|
||||||
|
]);
|
||||||
|
|
||||||
const versionMap: Record<string, any> = {};
|
node.pluginData = {
|
||||||
|
diagram: preview.diagram,
|
||||||
const isLatestChecks = await Promise.all(
|
userGuide: preview.userGuide,
|
||||||
versionDataList.map(async (version) => {
|
courseUrl: preview.courseUrl,
|
||||||
const isLatest = await checkIsLatestVersion({
|
name: preview.name,
|
||||||
appId: version.appId,
|
avatar: preview.avatar
|
||||||
versionId: version._id
|
};
|
||||||
});
|
node.versionLabel = preview.versionLabel;
|
||||||
|
node.isLatestVersion = preview.isLatestVersion;
|
||||||
return { versionId: String(version._id), isLatest };
|
node.version = preview.version;
|
||||||
|
} catch (error) {
|
||||||
|
node.pluginData = {
|
||||||
|
error: getErrText(error)
|
||||||
|
};
|
||||||
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const isLatestMap = new Map(isLatestChecks.map((item) => [item.versionId, item.isLatest]));
|
|
||||||
versionDataList.forEach((version) => {
|
/* Add node(App Type) versionlabel and latest sign ==== */
|
||||||
versionMap[String(version._id)] = version;
|
|
||||||
});
|
|
||||||
appNodes.forEach((node) => {
|
|
||||||
if (!node.version) return;
|
|
||||||
const versionData = versionMap[String(node.version)];
|
|
||||||
if (versionData) {
|
|
||||||
node.versionLabel = versionData.versionName;
|
|
||||||
node.isLatestVersion = isLatestMap.get(String(node.version)) || false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get all dataset ids from nodes
|
// Get all dataset ids from nodes
|
||||||
nodes.forEach((node) => {
|
nodes.forEach((node) => {
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ export const checkIsLatestVersion = async ({
|
|||||||
appId: string;
|
appId: string;
|
||||||
versionId: string;
|
versionId: string;
|
||||||
}) => {
|
}) => {
|
||||||
|
if (!Types.ObjectId.isValid(versionId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const version = await MongoAppVersion.findOne(
|
const version = await MongoAppVersion.findOne(
|
||||||
{
|
{
|
||||||
appId,
|
appId,
|
||||||
|
|||||||
@@ -77,7 +77,10 @@ export const createCollectionAndInsertData = async ({
|
|||||||
const chunkSplitter = computeChunkSplitter(createCollectionParams);
|
const chunkSplitter = computeChunkSplitter(createCollectionParams);
|
||||||
const paragraphChunkDeep = computeParagraphChunkDeep(createCollectionParams);
|
const paragraphChunkDeep = computeParagraphChunkDeep(createCollectionParams);
|
||||||
|
|
||||||
if (trainingType === DatasetCollectionDataProcessModeEnum.qa) {
|
if (
|
||||||
|
trainingType === DatasetCollectionDataProcessModeEnum.qa ||
|
||||||
|
trainingType === DatasetCollectionDataProcessModeEnum.backup
|
||||||
|
) {
|
||||||
delete createCollectionParams.chunkTriggerType;
|
delete createCollectionParams.chunkTriggerType;
|
||||||
delete createCollectionParams.chunkTriggerMinSize;
|
delete createCollectionParams.chunkTriggerMinSize;
|
||||||
delete createCollectionParams.dataEnhanceCollectionName;
|
delete createCollectionParams.dataEnhanceCollectionName;
|
||||||
|
|||||||
@@ -218,6 +218,10 @@ export const rawText2Chunks = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (backupParse) {
|
||||||
|
return parseDatasetBackup2Chunks(rawText).chunks;
|
||||||
|
}
|
||||||
|
|
||||||
// Chunk condition
|
// Chunk condition
|
||||||
// 1. 选择最大值条件,只有超过了最大值(默认为模型的最大值*0.7),才会触发分块
|
// 1. 选择最大值条件,只有超过了最大值(默认为模型的最大值*0.7),才会触发分块
|
||||||
if (chunkTriggerType === ChunkTriggerConfigTypeEnum.maxSize) {
|
if (chunkTriggerType === ChunkTriggerConfigTypeEnum.maxSize) {
|
||||||
@@ -240,10 +244,6 @@ export const rawText2Chunks = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backupParse) {
|
|
||||||
return parseDatasetBackup2Chunks(rawText).chunks;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { chunks } = splitText2Chunks({
|
const { chunks } = splitText2Chunks({
|
||||||
text: rawText,
|
text: rawText,
|
||||||
chunkSize,
|
chunkSize,
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Check interactive entry
|
// Check interactive entry
|
||||||
const interactiveResponse = lastInteractive;
|
|
||||||
props.node.isEntry = false;
|
props.node.isEntry = false;
|
||||||
const hasReadFilesTool = toolNodes.some(
|
const hasReadFilesTool = toolNodes.some(
|
||||||
(item) => item.flowNodeType === FlowNodeTypeEnum.readFiles
|
(item) => item.flowNodeType === FlowNodeTypeEnum.readFiles
|
||||||
@@ -143,7 +142,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
if (interactiveResponse) {
|
if (lastInteractive && isEntry) {
|
||||||
return value.slice(0, -2);
|
return value.slice(0, -2);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
@@ -183,7 +182,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
toolModel,
|
toolModel,
|
||||||
maxRunToolTimes: 30,
|
maxRunToolTimes: 30,
|
||||||
messages: adaptMessages,
|
messages: adaptMessages,
|
||||||
interactiveEntryToolParams: interactiveResponse?.toolParams
|
interactiveEntryToolParams: lastInteractive?.toolParams
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (toolModel.functionCall) {
|
if (toolModel.functionCall) {
|
||||||
@@ -194,7 +193,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
toolNodes,
|
toolNodes,
|
||||||
toolModel,
|
toolModel,
|
||||||
messages: adaptMessages,
|
messages: adaptMessages,
|
||||||
interactiveEntryToolParams: interactiveResponse?.toolParams
|
interactiveEntryToolParams: lastInteractive?.toolParams
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +223,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
toolNodes,
|
toolNodes,
|
||||||
toolModel,
|
toolModel,
|
||||||
messages: adaptMessages,
|
messages: adaptMessages,
|
||||||
interactiveEntryToolParams: interactiveResponse?.toolParams
|
interactiveEntryToolParams: lastInteractive?.toolParams
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
|||||||
import { type DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
import { type DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { serverRequestBaseUrl } from '../../../../common/api/serverRequest';
|
import { serverRequestBaseUrl } from '../../../../common/api/serverRequest';
|
||||||
import { MongoRawTextBuffer } from '../../../../common/buffer/rawText/schema';
|
|
||||||
import { readFromSecondary } from '../../../../common/mongo/utils';
|
|
||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
import { detectFileEncoding, parseUrlToFileType } from '@fastgpt/global/common/file/tools';
|
import { detectFileEncoding, parseUrlToFileType } from '@fastgpt/global/common/file/tools';
|
||||||
import { readRawContentByFileBuffer } from '../../../../common/file/read/utils';
|
import { readRawContentByFileBuffer } from '../../../../common/file/read/utils';
|
||||||
@@ -14,6 +12,8 @@ import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
|||||||
import { type ChatItemType, type UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
import { type ChatItemType, type UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||||
import { parseFileExtensionFromUrl } from '@fastgpt/global/common/string/tools';
|
import { parseFileExtensionFromUrl } from '@fastgpt/global/common/string/tools';
|
||||||
import { addLog } from '../../../../common/system/log';
|
import { addLog } from '../../../../common/system/log';
|
||||||
|
import { addRawTextBuffer, getRawTextBuffer } from '../../../../common/buffer/rawText/controller';
|
||||||
|
import { addMinutes } from 'date-fns';
|
||||||
|
|
||||||
type Props = ModuleDispatchProps<{
|
type Props = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.fileUrlList]: string[];
|
[NodeInputKeyEnum.fileUrlList]: string[];
|
||||||
@@ -158,14 +158,12 @@ export const getFileContentFromLinks = async ({
|
|||||||
parseUrlList
|
parseUrlList
|
||||||
.map(async (url) => {
|
.map(async (url) => {
|
||||||
// Get from buffer
|
// Get from buffer
|
||||||
const fileBuffer = await MongoRawTextBuffer.findOne({ sourceId: url }, undefined, {
|
const fileBuffer = await getRawTextBuffer(url);
|
||||||
...readFromSecondary
|
|
||||||
}).lean();
|
|
||||||
if (fileBuffer) {
|
if (fileBuffer) {
|
||||||
return formatResponseObject({
|
return formatResponseObject({
|
||||||
filename: fileBuffer.metadata?.filename || url,
|
filename: fileBuffer.sourceName || url,
|
||||||
url,
|
url,
|
||||||
content: fileBuffer.rawText
|
content: fileBuffer.text
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,17 +218,12 @@ export const getFileContentFromLinks = async ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add to buffer
|
// Add to buffer
|
||||||
try {
|
addRawTextBuffer({
|
||||||
if (buffer.length < 14 * 1024 * 1024 && rawText.trim()) {
|
|
||||||
MongoRawTextBuffer.create({
|
|
||||||
sourceId: url,
|
sourceId: url,
|
||||||
rawText,
|
sourceName: filename,
|
||||||
metadata: {
|
text: rawText,
|
||||||
filename: filename
|
expiredTime: addMinutes(new Date(), 20)
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} catch (error) {}
|
|
||||||
|
|
||||||
return formatResponseObject({ filename, url, content: rawText });
|
return formatResponseObject({ filename, url, content: rawText });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { AppPermission } from '@fastgpt/global/support/permission/app/controller
|
|||||||
import { type PermissionValueType } from '@fastgpt/global/support/permission/type';
|
import { type PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||||
import { AppFolderTypeList } from '@fastgpt/global/core/app/constants';
|
import { AppFolderTypeList } from '@fastgpt/global/core/app/constants';
|
||||||
import { type ParentIdType } from '@fastgpt/global/common/parentFolder/type';
|
import { type ParentIdType } from '@fastgpt/global/common/parentFolder/type';
|
||||||
import { splitCombinePluginId } from '../../../core/app/plugin/controller';
|
import { splitCombineToolId } from '../../../core/app/plugin/controller';
|
||||||
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
import { type AuthModeType, type AuthResponseType } from '../type';
|
import { type AuthModeType, type AuthResponseType } from '../type';
|
||||||
import { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/constant';
|
import { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/constant';
|
||||||
@@ -24,7 +24,7 @@ export const authPluginByTmbId = async ({
|
|||||||
appId: string;
|
appId: string;
|
||||||
per: PermissionValueType;
|
per: PermissionValueType;
|
||||||
}) => {
|
}) => {
|
||||||
const { source } = await splitCombinePluginId(appId);
|
const { source } = splitCombineToolId(appId);
|
||||||
if (source === PluginSourceEnum.personal) {
|
if (source === PluginSourceEnum.personal) {
|
||||||
const { app } = await authAppByTmbId({
|
const { app } = await authAppByTmbId({
|
||||||
appId,
|
appId,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default function Variable({ variableLabel }: { variableLabel: string }) {
|
|||||||
: { bg: 'red.50', color: 'red.600' })}
|
: { bg: 'red.50', color: 'red.600' })}
|
||||||
>
|
>
|
||||||
{variableLabel ? (
|
{variableLabel ? (
|
||||||
<Flex alignItems={'center'}>{variableLabel}</Flex>
|
<Flex alignItems={'center'}>{t(variableLabel as any)}</Flex>
|
||||||
) : (
|
) : (
|
||||||
<Box>{t('common:invalid_variable')}</Box>
|
<Box>{t('common:invalid_variable')}</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ export function useScrollPagination<
|
|||||||
scrollLoadType = 'bottom',
|
scrollLoadType = 'bottom',
|
||||||
|
|
||||||
pageSize = 10,
|
pageSize = 10,
|
||||||
params = {},
|
params,
|
||||||
EmptyTip,
|
EmptyTip,
|
||||||
showErrorToast = true,
|
showErrorToast = true,
|
||||||
disalbed = false,
|
disalbed = false,
|
||||||
@@ -196,7 +196,7 @@ export function useScrollPagination<
|
|||||||
scrollLoadType?: 'top' | 'bottom';
|
scrollLoadType?: 'top' | 'bottom';
|
||||||
|
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
params?: Record<string, any>;
|
params?: Omit<TParams, 'offset' | 'pageSize'>;
|
||||||
EmptyTip?: React.JSX.Element;
|
EmptyTip?: React.JSX.Element;
|
||||||
showErrorToast?: boolean;
|
showErrorToast?: boolean;
|
||||||
disalbed?: boolean;
|
disalbed?: boolean;
|
||||||
|
|||||||
@@ -85,6 +85,7 @@
|
|||||||
"interval.per_hour": "Every Hour",
|
"interval.per_hour": "Every Hour",
|
||||||
"intro": "A comprehensive model application orchestration system that offers out-of-the-box data processing and model invocation capabilities. It allows for rapid Dataset construction and workflow orchestration through Flow visualization, enabling complex Dataset scenarios!",
|
"intro": "A comprehensive model application orchestration system that offers out-of-the-box data processing and model invocation capabilities. It allows for rapid Dataset construction and workflow orchestration through Flow visualization, enabling complex Dataset scenarios!",
|
||||||
"invalid_json_format": "JSON format error",
|
"invalid_json_format": "JSON format error",
|
||||||
|
"keep_the_latest": "Keep the latest",
|
||||||
"llm_not_support_vision": "This model does not support image recognition",
|
"llm_not_support_vision": "This model does not support image recognition",
|
||||||
"llm_use_vision": "Vision",
|
"llm_use_vision": "Vision",
|
||||||
"llm_use_vision_tip": "After clicking on the model selection, you can see whether the model supports image recognition and the ability to control whether to start image recognition. \nAfter starting image recognition, the model will read the image content in the file link, and if the user question is less than 500 words, it will automatically parse the image in the user question.",
|
"llm_use_vision_tip": "After clicking on the model selection, you can see whether the model supports image recognition and the ability to control whether to start image recognition. \nAfter starting image recognition, the model will read the image content in the file link, and if the user question is less than 500 words, it will automatically parse the image in the user question.",
|
||||||
|
|||||||
@@ -145,8 +145,8 @@
|
|||||||
"code_error.outlink_error.invalid_link": "Invalid Share Link",
|
"code_error.outlink_error.invalid_link": "Invalid Share Link",
|
||||||
"code_error.outlink_error.link_not_exist": "Share Link Does Not Exist",
|
"code_error.outlink_error.link_not_exist": "Share Link Does Not Exist",
|
||||||
"code_error.outlink_error.un_auth_user": "Identity Verification Failed",
|
"code_error.outlink_error.un_auth_user": "Identity Verification Failed",
|
||||||
"code_error.plugin_error.not_exist": "Plugin Does Not Exist",
|
"code_error.plugin_error.not_exist": "The tool does not exist",
|
||||||
"code_error.plugin_error.un_auth": "Unauthorized to Operate This Plugin",
|
"code_error.plugin_error.un_auth": "No permission to operate the tool",
|
||||||
"code_error.system_error.community_version_num_limit": "Exceeded Open Source Version Limit, Please Upgrade to Commercial Version: https://tryfastgpt.ai",
|
"code_error.system_error.community_version_num_limit": "Exceeded Open Source Version Limit, Please Upgrade to Commercial Version: https://tryfastgpt.ai",
|
||||||
"code_error.system_error.license_app_amount_limit": "Exceed the maximum number of applications in the system",
|
"code_error.system_error.license_app_amount_limit": "Exceed the maximum number of applications in the system",
|
||||||
"code_error.system_error.license_dataset_amount_limit": "Exceed the maximum number of knowledge bases in the system",
|
"code_error.system_error.license_dataset_amount_limit": "Exceed the maximum number of knowledge bases in the system",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"chunk_size": "Block size",
|
"chunk_size": "Block size",
|
||||||
"chunk_trigger": "Blocking conditions",
|
"chunk_trigger": "Blocking conditions",
|
||||||
"chunk_trigger_force_chunk": "Forced chunking",
|
"chunk_trigger_force_chunk": "Forced chunking",
|
||||||
"chunk_trigger_max_size": "The original text length is less than the maximum context 70% of the file processing model",
|
"chunk_trigger_max_size": "The original text length is greater than the maximum context of the file processing model 70%",
|
||||||
"chunk_trigger_min_size": "The original text is greater than",
|
"chunk_trigger_min_size": "The original text is greater than",
|
||||||
"chunk_trigger_tips": "Block storage is triggered when certain conditions are met, otherwise the original text will be stored in full directly",
|
"chunk_trigger_tips": "Block storage is triggered when certain conditions are met, otherwise the original text will be stored in full directly",
|
||||||
"close_auto_sync": "Are you sure you want to turn off automatic sync?",
|
"close_auto_sync": "Are you sure you want to turn off automatic sync?",
|
||||||
|
|||||||
@@ -85,6 +85,7 @@
|
|||||||
"interval.per_hour": "每小时",
|
"interval.per_hour": "每小时",
|
||||||
"intro": "是一个大模型应用编排系统,提供开箱即用的数据处理、模型调用等能力,可以快速的构建知识库并通过 Flow 可视化进行工作流编排,实现复杂的知识库场景!",
|
"intro": "是一个大模型应用编排系统,提供开箱即用的数据处理、模型调用等能力,可以快速的构建知识库并通过 Flow 可视化进行工作流编排,实现复杂的知识库场景!",
|
||||||
"invalid_json_format": "JSON 格式错误",
|
"invalid_json_format": "JSON 格式错误",
|
||||||
|
"keep_the_latest": "保持最新版本",
|
||||||
"llm_not_support_vision": "该模型不支持图片识别",
|
"llm_not_support_vision": "该模型不支持图片识别",
|
||||||
"llm_use_vision": "图片识别",
|
"llm_use_vision": "图片识别",
|
||||||
"llm_use_vision_tip": "点击模型选择后,可以看到模型是否支持图片识别以及控制是否启动图片识别的能力。启动图片识别后,模型会读取文件链接里图片内容,并且如果用户问题少于 500 字,会自动解析用户问题中的图片。",
|
"llm_use_vision_tip": "点击模型选择后,可以看到模型是否支持图片识别以及控制是否启动图片识别的能力。启动图片识别后,模型会读取文件链接里图片内容,并且如果用户问题少于 500 字,会自动解析用户问题中的图片。",
|
||||||
|
|||||||
@@ -145,8 +145,8 @@
|
|||||||
"code_error.outlink_error.invalid_link": "分享链接无效",
|
"code_error.outlink_error.invalid_link": "分享链接无效",
|
||||||
"code_error.outlink_error.link_not_exist": "分享链接不存在",
|
"code_error.outlink_error.link_not_exist": "分享链接不存在",
|
||||||
"code_error.outlink_error.un_auth_user": "身份校验失败",
|
"code_error.outlink_error.un_auth_user": "身份校验失败",
|
||||||
"code_error.plugin_error.not_exist": "插件不存在",
|
"code_error.plugin_error.not_exist": "工具不存在",
|
||||||
"code_error.plugin_error.un_auth": "无权操作该插件",
|
"code_error.plugin_error.un_auth": "无权操作该工具",
|
||||||
"code_error.system_error.community_version_num_limit": "超出开源版数量限制,请升级商业版: https://fastgpt.in",
|
"code_error.system_error.community_version_num_limit": "超出开源版数量限制,请升级商业版: https://fastgpt.in",
|
||||||
"code_error.system_error.license_app_amount_limit": "超出系统最大应用数量",
|
"code_error.system_error.license_app_amount_limit": "超出系统最大应用数量",
|
||||||
"code_error.system_error.license_dataset_amount_limit": "超出系统最大知识库数量",
|
"code_error.system_error.license_dataset_amount_limit": "超出系统最大知识库数量",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"chunk_size": "分块大小",
|
"chunk_size": "分块大小",
|
||||||
"chunk_trigger": "分块条件",
|
"chunk_trigger": "分块条件",
|
||||||
"chunk_trigger_force_chunk": "强制分块",
|
"chunk_trigger_force_chunk": "强制分块",
|
||||||
"chunk_trigger_max_size": "原文长度小于文件处理模型最大上下文70%",
|
"chunk_trigger_max_size": "原文长度大于文件处理模型最大上下文70%",
|
||||||
"chunk_trigger_min_size": "原文长度大于",
|
"chunk_trigger_min_size": "原文长度大于",
|
||||||
"chunk_trigger_tips": "当满足一定条件时才触发分块存储,否则会直接完整存储原文",
|
"chunk_trigger_tips": "当满足一定条件时才触发分块存储,否则会直接完整存储原文",
|
||||||
"close_auto_sync": "确认关闭自动同步功能?",
|
"close_auto_sync": "确认关闭自动同步功能?",
|
||||||
|
|||||||
@@ -85,6 +85,7 @@
|
|||||||
"interval.per_hour": "每小時",
|
"interval.per_hour": "每小時",
|
||||||
"intro": "FastGPT 是一個基於大型語言模型的知識庫平臺,提供開箱即用的資料處理、向量檢索和視覺化 AI 工作流程編排等功能,讓您可以輕鬆開發和部署複雜的問答系統,而無需繁瑣的設定或設定。",
|
"intro": "FastGPT 是一個基於大型語言模型的知識庫平臺,提供開箱即用的資料處理、向量檢索和視覺化 AI 工作流程編排等功能,讓您可以輕鬆開發和部署複雜的問答系統,而無需繁瑣的設定或設定。",
|
||||||
"invalid_json_format": "JSON 格式錯誤",
|
"invalid_json_format": "JSON 格式錯誤",
|
||||||
|
"keep_the_latest": "保持最新版本",
|
||||||
"llm_not_support_vision": "這個模型不支援圖片辨識",
|
"llm_not_support_vision": "這個模型不支援圖片辨識",
|
||||||
"llm_use_vision": "圖片辨識",
|
"llm_use_vision": "圖片辨識",
|
||||||
"llm_use_vision_tip": "點選模型選擇後,可以看到模型是否支援圖片辨識以及控制是否啟用圖片辨識的功能。啟用圖片辨識後,模型會讀取檔案連結中的圖片內容,並且如果使用者問題少於 500 字,會自動解析使用者問題中的圖片。",
|
"llm_use_vision_tip": "點選模型選擇後,可以看到模型是否支援圖片辨識以及控制是否啟用圖片辨識的功能。啟用圖片辨識後,模型會讀取檔案連結中的圖片內容,並且如果使用者問題少於 500 字,會自動解析使用者問題中的圖片。",
|
||||||
|
|||||||
@@ -145,8 +145,8 @@
|
|||||||
"code_error.outlink_error.invalid_link": "分享連結無效",
|
"code_error.outlink_error.invalid_link": "分享連結無效",
|
||||||
"code_error.outlink_error.link_not_exist": "分享連結不存在",
|
"code_error.outlink_error.link_not_exist": "分享連結不存在",
|
||||||
"code_error.outlink_error.un_auth_user": "身份驗證失敗",
|
"code_error.outlink_error.un_auth_user": "身份驗證失敗",
|
||||||
"code_error.plugin_error.not_exist": "外掛程式不存在",
|
"code_error.plugin_error.not_exist": "工具不存在",
|
||||||
"code_error.plugin_error.un_auth": "無權操作此外掛程式",
|
"code_error.plugin_error.un_auth": "無權操作該工具",
|
||||||
"code_error.system_error.community_version_num_limit": "超出開源版數量限制,請升級商業版:https://tryfastgpt.ai",
|
"code_error.system_error.community_version_num_limit": "超出開源版數量限制,請升級商業版:https://tryfastgpt.ai",
|
||||||
"code_error.system_error.license_app_amount_limit": "超出系統最大應用數量",
|
"code_error.system_error.license_app_amount_limit": "超出系統最大應用數量",
|
||||||
"code_error.system_error.license_dataset_amount_limit": "超出系統最大知識庫數量",
|
"code_error.system_error.license_dataset_amount_limit": "超出系統最大知識庫數量",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"chunk_size": "分塊大小",
|
"chunk_size": "分塊大小",
|
||||||
"chunk_trigger": "分塊條件",
|
"chunk_trigger": "分塊條件",
|
||||||
"chunk_trigger_force_chunk": "強制分塊",
|
"chunk_trigger_force_chunk": "強制分塊",
|
||||||
"chunk_trigger_max_size": "原文長度小於文件處理模型最大上下文 70%",
|
"chunk_trigger_max_size": "原文長度大於文件處理模型最大上下文70%",
|
||||||
"chunk_trigger_min_size": "原文長度大於",
|
"chunk_trigger_min_size": "原文長度大於",
|
||||||
"close_auto_sync": "確認關閉自動同步功能?",
|
"close_auto_sync": "確認關閉自動同步功能?",
|
||||||
"collection.Create update time": "建立/更新時間",
|
"collection.Create update time": "建立/更新時間",
|
||||||
|
|||||||
2
projects/app/src/global/core/chat/api.d.ts
vendored
2
projects/app/src/global/core/chat/api.d.ts
vendored
@@ -24,7 +24,7 @@ export type GetChatRecordsProps = OutLinkChatAuthProps & {
|
|||||||
appId: string;
|
appId: string;
|
||||||
chatId?: string;
|
chatId?: string;
|
||||||
loadCustomFeedbacks?: boolean;
|
loadCustomFeedbacks?: boolean;
|
||||||
type: `${GetChatTypeEnum}`;
|
type?: `${GetChatTypeEnum}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type InitOutLinkChatProps = {
|
export type InitOutLinkChatProps = {
|
||||||
|
|||||||
@@ -39,6 +39,12 @@ export async function register() {
|
|||||||
systemStartCb();
|
systemStartCb();
|
||||||
initGlobalVariables();
|
initGlobalVariables();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await preLoadWorker();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Preload worker error', error);
|
||||||
|
}
|
||||||
|
|
||||||
// Connect to MongoDB
|
// Connect to MongoDB
|
||||||
await connectMongo(connectionMongo, MONGO_URL);
|
await connectMongo(connectionMongo, MONGO_URL);
|
||||||
connectMongo(connectionLogMongo, MONGO_LOG_URL);
|
connectMongo(connectionLogMongo, MONGO_LOG_URL);
|
||||||
@@ -54,12 +60,6 @@ export async function register() {
|
|||||||
startCron();
|
startCron();
|
||||||
startTrainingQueue(true);
|
startTrainingQueue(true);
|
||||||
|
|
||||||
try {
|
|
||||||
await preLoadWorker();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Preload worker error', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Init system success');
|
console.log('Init system success');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export const useNodeTemplates = () => {
|
|||||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
const hasToolNode = useMemo(
|
const hasToolNode = useMemo(
|
||||||
() => nodeList.some((node) => node.flowNodeType === FlowNodeTypeEnum.toolSet),
|
() => nodeList.some((node) => node.flowNodeType === FlowNodeTypeEnum.tools),
|
||||||
[nodeList]
|
[nodeList]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback, useMemo, useRef } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import { Box, Button, Flex, HStack, useDisclosure, type FlexProps } from '@chakra-ui/react';
|
import { Box, Button, Flex, useDisclosure, type FlexProps } from '@chakra-ui/react';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||||
import type { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node.d';
|
import type { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node.d';
|
||||||
@@ -15,7 +15,7 @@ import { ToolSourceHandle, ToolTargetHandle } from './Handle/ToolHandle';
|
|||||||
import { useEditTextarea } from '@fastgpt/web/hooks/useEditTextarea';
|
import { useEditTextarea } from '@fastgpt/web/hooks/useEditTextarea';
|
||||||
import { ConnectionSourceHandle, ConnectionTargetHandle } from './Handle/ConnectionHandle';
|
import { ConnectionSourceHandle, ConnectionTargetHandle } from './Handle/ConnectionHandle';
|
||||||
import { useDebug } from '../../hooks/useDebug';
|
import { useDebug } from '../../hooks/useDebug';
|
||||||
import { getPreviewPluginNode } from '@/web/core/app/api/plugin';
|
import { getPreviewPluginNode, getToolVersionList } from '@/web/core/app/api/plugin';
|
||||||
import { storeNode2FlowNode } from '@/web/core/workflow/utils';
|
import { storeNode2FlowNode } from '@/web/core/workflow/utils';
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
@@ -104,12 +104,9 @@ const NodeCard = (props: Props) => {
|
|||||||
}, [nodeList, nodeId]);
|
}, [nodeList, nodeId]);
|
||||||
const isAppNode = node && AppNodeFlowNodeTypeMap[node?.flowNodeType];
|
const isAppNode = node && AppNodeFlowNodeTypeMap[node?.flowNodeType];
|
||||||
const showVersion = useMemo(() => {
|
const showVersion = useMemo(() => {
|
||||||
if (!isAppNode || !node?.pluginId) return false;
|
if (!isAppNode || !node?.pluginId || node?.pluginData?.error) return false;
|
||||||
if ([FlowNodeTypeEnum.tool, FlowNodeTypeEnum.toolSet].includes(node.flowNodeType)) return false;
|
if ([FlowNodeTypeEnum.tool, FlowNodeTypeEnum.toolSet].includes(node.flowNodeType)) return false;
|
||||||
if (node.pluginId.split('-').length > 1) {
|
return typeof node.version === 'string';
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}, [isAppNode, node]);
|
}, [isAppNode, node]);
|
||||||
|
|
||||||
const { data: nodeTemplate } = useRequest2(
|
const { data: nodeTemplate } = useRequest2(
|
||||||
@@ -617,11 +614,10 @@ const NodeVersion = React.memo(function NodeVersion({ node }: { node: FlowNodeIt
|
|||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
|
||||||
// Load version list
|
// Load version list
|
||||||
const { ScrollData, data: versionList } = useScrollPagination(getAppVersionList, {
|
const { ScrollData, data: versionList } = useScrollPagination(getToolVersionList, {
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
params: {
|
params: {
|
||||||
appId: node.pluginId,
|
toolId: node.pluginId
|
||||||
isPublish: true
|
|
||||||
},
|
},
|
||||||
refreshDeps: [node.pluginId, isOpen],
|
refreshDeps: [node.pluginId, isOpen],
|
||||||
disalbed: !isOpen,
|
disalbed: !isOpen,
|
||||||
@@ -653,18 +649,23 @@ const NodeVersion = React.memo(function NodeVersion({ node }: { node: FlowNodeIt
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderList = useCreation(
|
const renderVersionList = useCreation(
|
||||||
() =>
|
() => [
|
||||||
versionList.map((item) => ({
|
{
|
||||||
|
label: t('app:keep_the_latest'),
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
...versionList.map((item) => ({
|
||||||
label: item.versionName,
|
label: item.versionName,
|
||||||
value: item._id
|
value: item._id
|
||||||
})),
|
}))
|
||||||
|
],
|
||||||
[node.isLatestVersion, node.version, t, versionList]
|
[node.isLatestVersion, node.version, t, versionList]
|
||||||
);
|
);
|
||||||
const valueLabel = useMemo(() => {
|
const valueLabel = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<Flex alignItems={'center'} gap={0.5}>
|
<Flex alignItems={'center'} gap={0.5}>
|
||||||
{node?.versionLabel}
|
{node?.version === '' ? t('app:keep_the_latest') : node?.versionLabel}
|
||||||
{!node.isLatestVersion && (
|
{!node.isLatestVersion && (
|
||||||
<MyTag type="fill" colorSchema={'adora'} fontSize={'mini'} borderRadius={'lg'}>
|
<MyTag type="fill" colorSchema={'adora'} fontSize={'mini'} borderRadius={'lg'}>
|
||||||
{t('app:not_the_newest')}
|
{t('app:not_the_newest')}
|
||||||
@@ -672,7 +673,7 @@ const NodeVersion = React.memo(function NodeVersion({ node }: { node: FlowNodeIt
|
|||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}, [node.isLatestVersion, node?.versionLabel, t]);
|
}, [node.isLatestVersion, node?.version, node?.versionLabel, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MySelect
|
<MySelect
|
||||||
@@ -685,7 +686,7 @@ const NodeVersion = React.memo(function NodeVersion({ node }: { node: FlowNodeIt
|
|||||||
placeholder={node?.versionLabel}
|
placeholder={node?.versionLabel}
|
||||||
variant={'whitePrimaryOutline'}
|
variant={'whitePrimaryOutline'}
|
||||||
size={'sm'}
|
size={'sm'}
|
||||||
list={renderList}
|
list={renderVersionList}
|
||||||
ScrollData={(props) => (
|
ScrollData={(props) => (
|
||||||
<ScrollData minH={'100px'} maxH={'40vh'}>
|
<ScrollData minH={'100px'} maxH={'40vh'}>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ type WorkflowContextType = {
|
|||||||
|
|
||||||
// nodes
|
// nodes
|
||||||
nodeList: FlowNodeItemType[];
|
nodeList: FlowNodeItemType[];
|
||||||
hasToolNode: boolean;
|
|
||||||
|
|
||||||
onUpdateNodeError: (node: string, isError: Boolean) => void;
|
onUpdateNodeError: (node: string, isError: Boolean) => void;
|
||||||
onResetNode: (e: { id: string; node: FlowNodeTemplateType }) => void;
|
onResetNode: (e: { id: string; node: FlowNodeTemplateType }) => void;
|
||||||
@@ -226,7 +225,6 @@ export const WorkflowContext = createContext<WorkflowContextType>({
|
|||||||
},
|
},
|
||||||
basicNodeTemplates: [],
|
basicNodeTemplates: [],
|
||||||
nodeList: [],
|
nodeList: [],
|
||||||
hasToolNode: false,
|
|
||||||
onUpdateNodeError: function (node: string, isError: Boolean): void {
|
onUpdateNodeError: function (node: string, isError: Boolean): void {
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
@@ -399,10 +397,6 @@ const WorkflowContextProvider = ({
|
|||||||
[nodeListString]
|
[nodeListString]
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasToolNode = useMemo(() => {
|
|
||||||
return !!nodeList.find((node) => node.flowNodeType === FlowNodeTypeEnum.tools);
|
|
||||||
}, [nodeList]);
|
|
||||||
|
|
||||||
const onUpdateNodeError = useMemoizedFn((nodeId: string, isError: Boolean) => {
|
const onUpdateNodeError = useMemoizedFn((nodeId: string, isError: Boolean) => {
|
||||||
setNodes((state) => {
|
setNodes((state) => {
|
||||||
return state.map((item) => {
|
return state.map((item) => {
|
||||||
@@ -1011,7 +1005,6 @@ const WorkflowContextProvider = ({
|
|||||||
|
|
||||||
// node
|
// node
|
||||||
nodeList,
|
nodeList,
|
||||||
hasToolNode,
|
|
||||||
onUpdateNodeError,
|
onUpdateNodeError,
|
||||||
onResetNode,
|
onResetNode,
|
||||||
onChangeNode,
|
onChangeNode,
|
||||||
@@ -1057,7 +1050,6 @@ const WorkflowContextProvider = ({
|
|||||||
flowData2StoreDataAndCheck,
|
flowData2StoreDataAndCheck,
|
||||||
future,
|
future,
|
||||||
getNodeDynamicInputs,
|
getNodeDynamicInputs,
|
||||||
hasToolNode,
|
|
||||||
initData,
|
initData,
|
||||||
nodeList,
|
nodeList,
|
||||||
onChangeNode,
|
onChangeNode,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
|||||||
import { NextAPI } from '@/service/middleware/entry';
|
import { NextAPI } from '@/service/middleware/entry';
|
||||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||||
import { checkNode } from '@/service/core/app/utils';
|
|
||||||
import { rewriteAppWorkflowToDetail } from '@fastgpt/service/core/app/utils';
|
import { rewriteAppWorkflowToDetail } from '@fastgpt/service/core/app/utils';
|
||||||
/* 获取应用详情 */
|
/* 获取应用详情 */
|
||||||
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
@@ -23,6 +22,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
|||||||
await rewriteAppWorkflowToDetail({
|
await rewriteAppWorkflowToDetail({
|
||||||
nodes: app.modules,
|
nodes: app.modules,
|
||||||
teamId,
|
teamId,
|
||||||
|
ownerTmbId: app.tmbId,
|
||||||
isRoot
|
isRoot
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -34,12 +34,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return app;
|
||||||
...app,
|
|
||||||
modules: await Promise.all(
|
|
||||||
app.modules.map((node) => checkNode({ node, ownerTmbId: app.tmbId }))
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NextAPI(handler);
|
export default NextAPI(handler);
|
||||||
|
|||||||
@@ -138,18 +138,20 @@ async function handler(req: ApiRequestProps<ListAppBody>): Promise<AppListItemTy
|
|||||||
})();
|
})();
|
||||||
const limit = (() => {
|
const limit = (() => {
|
||||||
if (getRecentlyChat) return 15;
|
if (getRecentlyChat) return 15;
|
||||||
if (searchKey) return 20;
|
if (searchKey) return 50;
|
||||||
return 1000;
|
return;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const myApps = await MongoApp.find(
|
const myApps = await MongoApp.find(
|
||||||
findAppsQuery,
|
findAppsQuery,
|
||||||
'_id parentId avatar type name intro tmbId updateTime pluginData inheritPermission'
|
'_id parentId avatar type name intro tmbId updateTime pluginData inheritPermission',
|
||||||
|
{
|
||||||
|
limit: limit
|
||||||
|
}
|
||||||
)
|
)
|
||||||
.sort({
|
.sort({
|
||||||
updateTime: -1
|
updateTime: -1
|
||||||
})
|
})
|
||||||
.limit(limit)
|
|
||||||
.lean();
|
.lean();
|
||||||
|
|
||||||
// Add app permission and filter apps by read permission
|
// Add app permission and filter apps by read permission
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import type { NextApiResponse } from 'next';
|
import type { NextApiResponse } from 'next';
|
||||||
import {
|
import {
|
||||||
getChildAppPreviewNode,
|
getChildAppPreviewNode,
|
||||||
splitCombinePluginId
|
splitCombineToolId
|
||||||
} from '@fastgpt/service/core/app/plugin/controller';
|
} from '@fastgpt/service/core/app/plugin/controller';
|
||||||
import { type FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node.d';
|
import { type FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node.d';
|
||||||
import { NextAPI } from '@/service/middleware/entry';
|
import { NextAPI } from '@/service/middleware/entry';
|
||||||
@@ -21,7 +21,7 @@ async function handler(
|
|||||||
): Promise<FlowNodeTemplateType> {
|
): Promise<FlowNodeTemplateType> {
|
||||||
const { appId, versionId } = req.query;
|
const { appId, versionId } = req.query;
|
||||||
|
|
||||||
const { source } = await splitCombinePluginId(appId);
|
const { source } = splitCombineToolId(appId);
|
||||||
|
|
||||||
if (source === PluginSourceEnum.personal) {
|
if (source === PluginSourceEnum.personal) {
|
||||||
await authApp({ req, authToken: true, appId, per: ReadPermissionVal });
|
await authApp({ req, authToken: true, appId, per: ReadPermissionVal });
|
||||||
|
|||||||
86
projects/app/src/pages/api/core/app/plugin/getVersionList.ts
Normal file
86
projects/app/src/pages/api/core/app/plugin/getVersionList.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import type { NextApiResponse } from 'next';
|
||||||
|
import { NextAPI } from '@/service/middleware/entry';
|
||||||
|
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
|
||||||
|
import { type PaginationProps, type PaginationResponse } from '@fastgpt/web/common/fetch/type';
|
||||||
|
import { type ApiRequestProps } from '@fastgpt/service/type/next';
|
||||||
|
import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
||||||
|
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
|
import { parsePaginationRequest } from '@fastgpt/service/common/api/pagination';
|
||||||
|
import { splitCombineToolId } from '@fastgpt/service/core/app/plugin/controller';
|
||||||
|
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
|
import { getSystemPluginTemplates } from '@fastgpt/plugins/register';
|
||||||
|
import { PluginErrEnum } from '@fastgpt/global/common/error/code/plugin';
|
||||||
|
import { Types } from '@fastgpt/service/common/mongo';
|
||||||
|
|
||||||
|
export type getToolVersionListProps = PaginationProps<{
|
||||||
|
toolId?: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type getToolVersionResponse = PaginationResponse<{
|
||||||
|
_id: string;
|
||||||
|
versionName: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
async function handler(
|
||||||
|
req: ApiRequestProps<getToolVersionListProps>,
|
||||||
|
_res: NextApiResponse<any>
|
||||||
|
): Promise<getToolVersionResponse> {
|
||||||
|
const { toolId } = req.body;
|
||||||
|
const { offset, pageSize } = parsePaginationRequest(req);
|
||||||
|
|
||||||
|
if (!toolId) {
|
||||||
|
return {
|
||||||
|
total: 0,
|
||||||
|
list: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { source, pluginId: formatToolId } = splitCombineToolId(toolId);
|
||||||
|
|
||||||
|
// Auth
|
||||||
|
const appId = await (async () => {
|
||||||
|
if (source === PluginSourceEnum.personal) {
|
||||||
|
const { app } = await authApp({
|
||||||
|
appId: formatToolId,
|
||||||
|
req,
|
||||||
|
per: ReadPermissionVal,
|
||||||
|
authToken: true
|
||||||
|
});
|
||||||
|
return app._id;
|
||||||
|
} else {
|
||||||
|
const item = getSystemPluginTemplates().find((plugin) => plugin.id === formatToolId);
|
||||||
|
if (!item) return Promise.reject(PluginErrEnum.unAuth);
|
||||||
|
return item.associatedPluginId;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (!appId || !Types.ObjectId.isValid(appId)) {
|
||||||
|
return {
|
||||||
|
total: 0,
|
||||||
|
list: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = {
|
||||||
|
appId,
|
||||||
|
isPublish: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const [result, total] = await Promise.all([
|
||||||
|
await MongoAppVersion.find(match, 'versionName')
|
||||||
|
.sort({
|
||||||
|
time: -1
|
||||||
|
})
|
||||||
|
.skip(offset)
|
||||||
|
.limit(pageSize)
|
||||||
|
.lean(),
|
||||||
|
MongoAppVersion.countDocuments(match)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
total,
|
||||||
|
list: result
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NextAPI(handler);
|
||||||
@@ -5,7 +5,6 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
|||||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
import { type AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
import { type AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
||||||
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
|
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
|
||||||
import { checkNode } from '@/service/core/app/utils';
|
|
||||||
import { rewriteAppWorkflowToDetail } from '@fastgpt/service/core/app/utils';
|
import { rewriteAppWorkflowToDetail } from '@fastgpt/service/core/app/utils';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -34,14 +33,12 @@ async function handler(
|
|||||||
await rewriteAppWorkflowToDetail({
|
await rewriteAppWorkflowToDetail({
|
||||||
nodes: result.nodes,
|
nodes: result.nodes,
|
||||||
teamId,
|
teamId,
|
||||||
|
ownerTmbId: app.tmbId,
|
||||||
isRoot
|
isRoot
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
nodes: await Promise.all(
|
|
||||||
result.nodes.map((n) => checkNode({ node: n, ownerTmbId: app.tmbId }))
|
|
||||||
),
|
|
||||||
versionName: result?.versionName || formatTime2YMDHM(result?.time)
|
versionName: result?.versionName || formatTime2YMDHM(result?.time)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,13 +31,16 @@ async function handler(
|
|||||||
per: WritePermissionVal
|
per: WritePermissionVal
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const version = await getAppLatestVersion(req.query.appId, app);
|
||||||
|
|
||||||
await rewriteAppWorkflowToDetail({
|
await rewriteAppWorkflowToDetail({
|
||||||
nodes: app.modules,
|
nodes: version.nodes,
|
||||||
teamId,
|
teamId,
|
||||||
isRoot
|
isRoot,
|
||||||
|
ownerTmbId: app.tmbId
|
||||||
});
|
});
|
||||||
|
|
||||||
return getAppLatestVersion(req.query.appId, app);
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NextAPI(handler);
|
export default NextAPI(handler);
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import { type FileIdCreateDatasetCollectionParams } from '@fastgpt/global/core/d
|
|||||||
import { createCollectionAndInsertData } from '@fastgpt/service/core/dataset/collection/controller';
|
import { createCollectionAndInsertData } from '@fastgpt/service/core/dataset/collection/controller';
|
||||||
import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||||
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
|
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
|
||||||
import { MongoRawTextBuffer } from '@fastgpt/service/common/buffer/rawText/schema';
|
|
||||||
import { NextAPI } from '@/service/middleware/entry';
|
import { NextAPI } from '@/service/middleware/entry';
|
||||||
import { type ApiRequestProps } from '@fastgpt/service/type/next';
|
import { type ApiRequestProps } from '@fastgpt/service/type/next';
|
||||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
import { type CreateCollectionResponse } from '@/global/core/dataset/api';
|
import { type CreateCollectionResponse } from '@/global/core/dataset/api';
|
||||||
|
import { deleteRawTextBuffer } from '@fastgpt/service/common/buffer/rawText/controller';
|
||||||
|
|
||||||
async function handler(
|
async function handler(
|
||||||
req: ApiRequestProps<FileIdCreateDatasetCollectionParams>
|
req: ApiRequestProps<FileIdCreateDatasetCollectionParams>
|
||||||
@@ -52,7 +52,7 @@ async function handler(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// remove buffer
|
// remove buffer
|
||||||
await MongoRawTextBuffer.deleteOne({ sourceId: fileId });
|
await deleteRawTextBuffer(fileId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
collectionId,
|
collectionId,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { checkTimerLock } from '@fastgpt/service/common/system/timerLock/utils';
|
|||||||
import { TimerIdEnum } from '@fastgpt/service/common/system/timerLock/constants';
|
import { TimerIdEnum } from '@fastgpt/service/common/system/timerLock/constants';
|
||||||
import { addHours } from 'date-fns';
|
import { addHours } from 'date-fns';
|
||||||
import { getScheduleTriggerApp } from '@/service/core/app/utils';
|
import { getScheduleTriggerApp } from '@/service/core/app/utils';
|
||||||
|
import { clearExpiredRawTextBufferCron } from '@fastgpt/service/common/buffer/rawText/controller';
|
||||||
|
|
||||||
// Try to run train every minute
|
// Try to run train every minute
|
||||||
const setTrainingQueueCron = () => {
|
const setTrainingQueueCron = () => {
|
||||||
@@ -83,4 +84,5 @@ export const startCron = () => {
|
|||||||
setClearTmpUploadFilesCron();
|
setClearTmpUploadFilesCron();
|
||||||
clearInvalidDataCron();
|
clearInvalidDataCron();
|
||||||
scheduleTriggerAppCron();
|
scheduleTriggerAppCron();
|
||||||
|
clearExpiredRawTextBufferCron();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { saveChat } from '@fastgpt/service/core/chat/saveChat';
|
|||||||
import { getAppLatestVersion } from '@fastgpt/service/core/app/version/controller';
|
import { getAppLatestVersion } from '@fastgpt/service/core/app/version/controller';
|
||||||
import {
|
import {
|
||||||
getChildAppPreviewNode,
|
getChildAppPreviewNode,
|
||||||
splitCombinePluginId
|
splitCombineToolId
|
||||||
} from '@fastgpt/service/core/app/plugin/controller';
|
} from '@fastgpt/service/core/app/plugin/controller';
|
||||||
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
import { authAppByTmbId } from '@fastgpt/service/support/permission/app/auth';
|
import { authAppByTmbId } from '@fastgpt/service/support/permission/app/auth';
|
||||||
@@ -137,46 +137,3 @@ export const getScheduleTriggerApp = async () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const checkNode = async ({
|
|
||||||
node,
|
|
||||||
ownerTmbId
|
|
||||||
}: {
|
|
||||||
node: StoreNodeItemType;
|
|
||||||
ownerTmbId: string;
|
|
||||||
}): Promise<StoreNodeItemType> => {
|
|
||||||
const pluginId = node.pluginId;
|
|
||||||
if (!pluginId) return node;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { source } = await splitCombinePluginId(pluginId);
|
|
||||||
|
|
||||||
if (source === PluginSourceEnum.personal) {
|
|
||||||
await authAppByTmbId({
|
|
||||||
tmbId: ownerTmbId,
|
|
||||||
appId: pluginId,
|
|
||||||
per: ReadPermissionVal
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const preview = await getChildAppPreviewNode({ appId: pluginId });
|
|
||||||
return {
|
|
||||||
...node,
|
|
||||||
pluginData: {
|
|
||||||
version: preview.version,
|
|
||||||
diagram: preview.diagram,
|
|
||||||
userGuide: preview.userGuide,
|
|
||||||
courseUrl: preview.courseUrl,
|
|
||||||
name: preview.name,
|
|
||||||
avatar: preview.avatar
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (error: any) {
|
|
||||||
return {
|
|
||||||
...node,
|
|
||||||
pluginData: {
|
|
||||||
error: getErrText(error)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ import { type McpToolConfigType } from '@fastgpt/global/core/app/type';
|
|||||||
import type { updateMCPToolsBody } from '@/pages/api/core/app/mcpTools/update';
|
import type { updateMCPToolsBody } from '@/pages/api/core/app/mcpTools/update';
|
||||||
import type { RunMCPToolBody } from '@/pages/api/support/mcp/client/runTool';
|
import type { RunMCPToolBody } from '@/pages/api/support/mcp/client/runTool';
|
||||||
import type { getMCPToolsBody } from '@/pages/api/support/mcp/client/getTools';
|
import type { getMCPToolsBody } from '@/pages/api/support/mcp/client/getTools';
|
||||||
|
import type {
|
||||||
|
getToolVersionListProps,
|
||||||
|
getToolVersionResponse
|
||||||
|
} from '@/pages/api/core/app/plugin/getVersionList';
|
||||||
|
|
||||||
/* ============ team plugin ============== */
|
/* ============ team plugin ============== */
|
||||||
export const getTeamPlugTemplates = (data?: ListAppBody) =>
|
export const getTeamPlugTemplates = (data?: ListAppBody) =>
|
||||||
@@ -71,6 +75,9 @@ export const getSystemPluginPaths = (data: GetPathProps) => {
|
|||||||
export const getPreviewPluginNode = (data: GetPreviewNodeQuery) =>
|
export const getPreviewPluginNode = (data: GetPreviewNodeQuery) =>
|
||||||
GET<FlowNodeTemplateType>('/core/app/plugin/getPreviewNode', data);
|
GET<FlowNodeTemplateType>('/core/app/plugin/getPreviewNode', data);
|
||||||
|
|
||||||
|
export const getToolVersionList = (data: getToolVersionListProps) =>
|
||||||
|
POST<getToolVersionResponse>('/core/app/plugin/getVersionList', data);
|
||||||
|
|
||||||
/* ============ mcp tools ============== */
|
/* ============ mcp tools ============== */
|
||||||
export const postCreateMCPTools = (data: createMCPToolsBody) =>
|
export const postCreateMCPTools = (data: createMCPToolsBody) =>
|
||||||
POST('/core/app/mcpTools/create', data);
|
POST('/core/app/mcpTools/create', data);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const ChatRecordContextProvider = ({
|
|||||||
params
|
params
|
||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
params: Record<string, any>;
|
params: Omit<getPaginationRecordsBody, 'offset' | 'pageSize'>;
|
||||||
}) => {
|
}) => {
|
||||||
const ChatBoxRef = useContextSelector(ChatItemContext, (v) => v.ChatBoxRef);
|
const ChatBoxRef = useContextSelector(ChatItemContext, (v) => v.ChatBoxRef);
|
||||||
const [isChatRecordsLoaded, setIsChatRecordsLoaded] = useState(false);
|
const [isChatRecordsLoaded, setIsChatRecordsLoaded] = useState(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user