Compare commits
26 Commits
test-tool
...
v4.9.9-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
554b2ca8dc | ||
|
|
4e83840c14 | ||
|
|
a6c80684d1 | ||
|
|
a4db03a3b7 | ||
|
|
cba8f773fe | ||
|
|
bd93f28d6f | ||
|
|
2063cb6314 | ||
|
|
12acaf491c | ||
|
|
3688842cc7 | ||
|
|
398d131bac | ||
|
|
d5f188a1a4 | ||
|
|
1edca309c4 | ||
|
|
1470c37ef1 | ||
|
|
bdb1221d94 | ||
|
|
cac4b1d435 | ||
|
|
0ef3d40296 | ||
|
|
3cc6b8a17a | ||
|
|
681ec30c38 | ||
|
|
24cd1c98dc | ||
|
|
eaceabcc43 | ||
|
|
a7f9411dca | ||
|
|
657fa32217 | ||
|
|
12d6948ba7 | ||
|
|
83d54d046d | ||
|
|
c75f154728 | ||
|
|
96e7dd581e |
@@ -132,15 +132,15 @@ services:
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.8 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.8 # 阿里云
|
||||
ports:
|
||||
- 3005:3000
|
||||
networks:
|
||||
@@ -150,8 +150,8 @@ services:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.8 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -109,15 +109,15 @@ services:
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.8 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.8 # 阿里云
|
||||
ports:
|
||||
- 3005:3000
|
||||
networks:
|
||||
@@ -127,8 +127,8 @@ services:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.8 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -96,15 +96,15 @@ services:
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.8 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.8 # 阿里云
|
||||
ports:
|
||||
- 3005:3000
|
||||
networks:
|
||||
@@ -114,8 +114,8 @@ services:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.8 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -72,15 +72,15 @@ services:
|
||||
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.8 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.8 # 阿里云
|
||||
ports:
|
||||
- 3005:3000
|
||||
networks:
|
||||
@@ -90,8 +90,8 @@ services:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.7-fix2 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.9.8 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.8 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: 'V4.9.8(进行中)'
|
||||
title: 'V4.9.8'
|
||||
description: 'FastGPT V4.9.8 更新说明'
|
||||
icon: 'upgrade'
|
||||
draft: false
|
||||
@@ -7,6 +7,17 @@ toc: true
|
||||
weight: 792
|
||||
---
|
||||
|
||||
## 升级指南
|
||||
|
||||
### 1. 做好数据备份
|
||||
|
||||
### 2. 更新镜像 tag
|
||||
|
||||
- 更新 FastGPT 镜像 tag: v4.9.8
|
||||
- 更新 FastGPT 商业版镜像 tag: v4.9.8
|
||||
- mcp_server 无需更新
|
||||
- Sandbox 无需更新
|
||||
- AIProxy 无需更新
|
||||
|
||||
## 🚀 新增内容
|
||||
|
||||
@@ -14,14 +25,25 @@ weight: 792
|
||||
2. 将所有内置任务,从非 stream 模式调整成 stream 模式,避免部分模型不支持非 stream 模式。如需覆盖,则可以在模型`额外 Body`参数中,强制指定`stream=false`。
|
||||
3. qwen3 模型预设
|
||||
4. 语雀知识库支持设置根目录。
|
||||
5. 可配置密码过期时间,过期后下次登录会强制要求修改密码。
|
||||
6. 密码登录增加 preLogin 临时密钥校验。
|
||||
7. 支持 Admin 后台配置发布渠道和第三方知识库的显示隐藏。
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
1. Chat log list 优化,避免大数据时超出内存限制。
|
||||
2. 预加载 token 计算 worker,避免主任务中并发创建导致线程阻塞。
|
||||
3. 工作流节点版本控制交互优化。
|
||||
4. 网络获取以及 html2md 优化,支持视频和音频标签的转换。
|
||||
|
||||
## 🐛 修复
|
||||
|
||||
1. 应用列表/知识库列表,删除行权限展示问题。
|
||||
2. 打开知识库搜索参数后,重排选项自动被打开。
|
||||
3. LLM json_schema 模式 API 请求格式错误。
|
||||
4. 重新训练时,图片过期索引未成功清除,导致图片会丢失。
|
||||
5. 重新训练权限问题。
|
||||
6. 文档链接地址。
|
||||
7. Claude 工具调用,由于 index 为空,导致工具调用失败。
|
||||
8. 嵌套工作流,工具调用下包含交互节点时,流程异常。
|
||||
|
||||
|
||||
25
docSite/content/zh-cn/docs/development/upgrading/499.md
Normal file
25
docSite/content/zh-cn/docs/development/upgrading/499.md
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
title: 'V4.9.9(进行中)'
|
||||
description: 'FastGPT V4.9.9 更新说明'
|
||||
icon: 'upgrade'
|
||||
draft: false
|
||||
toc: true
|
||||
weight: 791
|
||||
---
|
||||
|
||||
|
||||
## 🚀 新增内容
|
||||
|
||||
1. 切换 SessionId 来替代 JWT 实现登录鉴权,可控制最大登录客户端数量。
|
||||
2. 新的商业版 License 管理模式。
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
1. 优化工具调用,新工具的判断逻辑。
|
||||
2. 调整 Cite 引用提示词。
|
||||
|
||||
## 🐛 修复
|
||||
|
||||
1. 无法正常获取应用历史保存/发布记录。
|
||||
2. 成员创建 MCP 工具权限问题。
|
||||
3. 来源引用展示,存在 ID 传递错误,导致提示无权操作该文件。
|
||||
@@ -43,7 +43,7 @@ type ResponseType = {
|
||||
// 文件列表中,单项的文件类型
|
||||
type FileListItem = {
|
||||
id: string;
|
||||
parentId: string | null;
|
||||
parentId: string //也可能为 null 或者 undefined 类型;
|
||||
name: string;
|
||||
type: 'file' | 'folder';
|
||||
updateTime: Date;
|
||||
@@ -59,7 +59,7 @@ type FileListItem = {
|
||||
{{< markdownify >}}
|
||||
|
||||
{{% alert icon=" " context="success" %}}
|
||||
- parentId - 父级 id,可选,或者 null。
|
||||
- parentId - 父级 id,可选,或者 null | undefined。
|
||||
- searchKey - 检索词,可选
|
||||
{{% /alert %}}
|
||||
|
||||
@@ -68,7 +68,7 @@ curl --location --request POST '{{baseURL}}/v1/file/list' \
|
||||
--header 'Authorization: Bearer {{authorization}}' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"parentId": null,
|
||||
"parentId": "",
|
||||
"searchKey": ""
|
||||
}'
|
||||
```
|
||||
|
||||
@@ -95,6 +95,10 @@ weight: 506
|
||||
121.196.228.45
|
||||
121.43.126.202
|
||||
120.26.144.37
|
||||
47.98.196.113
|
||||
47.97.204.90
|
||||
118.31.41.236
|
||||
118.178.185.61
|
||||
```
|
||||
|
||||
## 4. 获取AES Key,选择加密方式
|
||||
@@ -125,6 +129,11 @@ weight: 506
|
||||
|
||||
## FAQ
|
||||
|
||||
### 公众号没响应
|
||||
|
||||
检查应用对话日志,如果有对话日志,但是微信公众号无响应,则是白名单 IP未成功。
|
||||
添加白名单IP 后,通常需要等待几分钟微信更新。
|
||||
|
||||
### 如何新开一个聊天记录
|
||||
|
||||
如果你想重置你的聊天记录,可以给机器人发送 `Reset` 消息(注意大小写),机器人会新开一个聊天记录。
|
||||
如果你想重置你的聊天记录,可以给机器人发送 `Reset` 消息(注意大小写),机器人会新开一个聊天记录。
|
||||
|
||||
3
env.d.ts
vendored
3
env.d.ts
vendored
@@ -4,7 +4,6 @@ declare global {
|
||||
LOG_DEPTH: string;
|
||||
DEFAULT_ROOT_PSW: string;
|
||||
DB_MAX_LINK: string;
|
||||
TOKEN_KEY: string;
|
||||
FILE_TOKEN_KEY: string;
|
||||
ROOT_KEY: string;
|
||||
OPENAI_BASE_URL: string;
|
||||
@@ -36,6 +35,8 @@ declare global {
|
||||
SHOW_COUPON?: string;
|
||||
CONFIG_JSON_PATH?: string;
|
||||
PASSWORD_LOGIN_LOCK_SECONDS?: string;
|
||||
PASSWORD_EXPIRED_MONTH?: string;
|
||||
MAX_LOGIN_SESSION?: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,28 @@ import { type ErrType } from '../errorCode';
|
||||
import { i18nT } from '../../../../web/i18n/utils';
|
||||
/* dataset: 509000 */
|
||||
export enum SystemErrEnum {
|
||||
communityVersionNumLimit = 'communityVersionNumLimit'
|
||||
communityVersionNumLimit = 'communityVersionNumLimit',
|
||||
licenseAppAmountLimit = 'licenseAppAmountLimit',
|
||||
licenseDatasetAmountLimit = 'licenseDatasetAmountLimit',
|
||||
licenseUserAmountLimit = 'licenseUserAmountLimit'
|
||||
}
|
||||
|
||||
const systemErr = [
|
||||
{
|
||||
statusText: SystemErrEnum.communityVersionNumLimit,
|
||||
message: i18nT('common:code_error.system_error.community_version_num_limit')
|
||||
},
|
||||
{
|
||||
statusText: SystemErrEnum.licenseAppAmountLimit,
|
||||
message: i18nT('common:code_error.system_error.license_app_amount_limit')
|
||||
},
|
||||
{
|
||||
statusText: SystemErrEnum.licenseDatasetAmountLimit,
|
||||
message: i18nT('common:code_error.system_error.license_dataset_amount_limit')
|
||||
},
|
||||
{
|
||||
statusText: SystemErrEnum.licenseUserAmountLimit,
|
||||
message: i18nT('common:code_error.system_error.license_user_amount_limit')
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ export const checkPasswordRule = (password: string) => {
|
||||
/[A-Z]/, // Contains uppercase letters
|
||||
/[!@#$%^&*()_+=-]/ // Contains special characters
|
||||
];
|
||||
const validChars = /^[\dA-Za-z!@#$%^&*()_+=-]{6,100}$/;
|
||||
const validChars = /^[\dA-Za-z!@#$%^&*()_+=-]{8,100}$/;
|
||||
|
||||
// Check length and valid characters
|
||||
if (!validChars.test(password)) return false;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
export enum SystemConfigsTypeEnum {
|
||||
fastgpt = 'fastgpt',
|
||||
fastgptPro = 'fastgptPro',
|
||||
systemMsgModal = 'systemMsgModal'
|
||||
systemMsgModal = 'systemMsgModal',
|
||||
license = 'license'
|
||||
}
|
||||
|
||||
export const SystemConfigsTypeMap = {
|
||||
@@ -13,5 +14,8 @@ export const SystemConfigsTypeMap = {
|
||||
},
|
||||
[SystemConfigsTypeEnum.systemMsgModal]: {
|
||||
label: 'systemMsgModal'
|
||||
},
|
||||
[SystemConfigsTypeEnum.license]: {
|
||||
label: 'license'
|
||||
}
|
||||
};
|
||||
|
||||
27
packages/global/common/system/types/index.d.ts
vendored
27
packages/global/common/system/types/index.d.ts
vendored
@@ -64,6 +64,15 @@ export type FastGPTFeConfigsType = {
|
||||
show_coupon?: boolean;
|
||||
concatMd?: string;
|
||||
|
||||
show_dataset_feishu?: boolean;
|
||||
show_dataset_yuque?: boolean;
|
||||
show_publish_feishu?: boolean;
|
||||
show_publish_dingtalk?: boolean;
|
||||
show_publish_offiaccount?: boolean;
|
||||
|
||||
show_dataset_enhance?: boolean;
|
||||
show_batch_eval?: boolean;
|
||||
|
||||
concatMd?: string;
|
||||
docUrl?: string;
|
||||
openAPIDocUrl?: string;
|
||||
@@ -136,3 +145,21 @@ export type customPdfParseType = {
|
||||
doc2xKey?: string;
|
||||
price?: number;
|
||||
};
|
||||
|
||||
export type LicenseDataType = {
|
||||
startTime: string;
|
||||
expiredTime: string;
|
||||
company: string;
|
||||
description?: string; // 描述
|
||||
hosts?: string[]; // 管理端有效域名
|
||||
maxUsers?: number; // 最大用户数,不填默认不上限
|
||||
maxApps?: number; // 最大应用数,不填默认不上限
|
||||
maxDatasets?: number; // 最大数据集数,不填默认不上限
|
||||
functions: {
|
||||
sso: boolean;
|
||||
pay: boolean;
|
||||
customTemplates: boolean;
|
||||
datasetEnhance: boolean;
|
||||
batchEval: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,6 +2,248 @@ import { type PromptTemplateItem } from '../type.d';
|
||||
import { i18nT } from '../../../../web/i18n/utils';
|
||||
import { getPromptByVersion } from './utils';
|
||||
|
||||
export const Prompt_userQuotePromptList: PromptTemplateItem[] = [
|
||||
{
|
||||
title: i18nT('app:template.standard_template'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.7']: `## 任务描述
|
||||
你是一个知识库回答助手,可以使用 <Cites></Cites> 中的内容作为你本次回答的参考。
|
||||
同时,为了使回答结果更加可信并且可追溯,你需要在每段话结尾添加引用标记,标识参考了哪些内容。
|
||||
|
||||
## 追溯展示规则
|
||||
|
||||
- 使用 [id](CITE) 的格式来引用 <Cites></Cites> 中的知识,其中 CITE 是固定常量, id 为引文中的 id。
|
||||
- 在 **每段话结尾** 自然地整合引用。例如: "Nginx是一款轻量级的Web服务器、反向代理服务器[67e517e74767063e882d6861](CITE)。"。
|
||||
- 每段话**至少包含一个引用**,多个引用时按顺序排列,例如:"Nginx是一款轻量级的Web服务器、反向代理服务器[67e517e74767063e882d6861](CITE)[67e517e74767063e882d6862](CITE)。\n 它的特点是非常轻量[67e517e74767063e882d6863](CITE)。"
|
||||
- 不要把示例作为知识点。
|
||||
- 不要伪造 id,返回的 id 必须都存在 <Cites></Cites> 中!
|
||||
|
||||
## 通用规则
|
||||
|
||||
- 如果你不清楚答案,你需要澄清。
|
||||
- 避免提及你是从 <Cites></Cites> 获取的知识。
|
||||
- 保持答案与 <Cites></Cites> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。尤其是图片、表格、序列号等内容,需严格完整输出。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
<Cites>
|
||||
{{quote}}
|
||||
</Cites>
|
||||
|
||||
## 用户问题
|
||||
|
||||
{{question}}
|
||||
|
||||
## 回答
|
||||
`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.qa_template'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.7']: `## 任务描述
|
||||
作为一个问答助手,你会使用 <QA></QA> 标记中的提供的数据对进行内容回答。
|
||||
|
||||
## 回答要求
|
||||
- 选择其中一个或多个问答对进行回答。
|
||||
- 回答的内容应尽可能与 <Answer></Answer> 中的内容一致。
|
||||
- 如果没有相关的问答对,你需要澄清。
|
||||
- 避免提及你是从 <QA></QA> 获取的知识,只需要回复答案。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
<QA>
|
||||
{{quote}}
|
||||
</QA>
|
||||
|
||||
## 用户问题
|
||||
|
||||
{{question}}
|
||||
|
||||
## 回答
|
||||
`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.standard_strict'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.7']: `## 任务描述
|
||||
你是一个知识库回答助手,可以使用 <Cites></Cites> 中的内容作为你本次回答的参考。
|
||||
同时,为了使回答结果更加可信并且可追溯,你需要在每段话结尾添加引用标记,标识参考了哪些内容。
|
||||
|
||||
## 追溯展示规则
|
||||
|
||||
- 使用 [id](CITE) 的格式来引用 <Cites></Cites> 中的知识,其中 CITE 是固定常量, id 为引文中的 id。
|
||||
- 在 **每段话结尾** 自然地整合引用。例如: "Nginx是一款轻量级的Web服务器、反向代理服务器[67e517e74767063e882d6861](CITE)。"。
|
||||
- 每段话**至少包含一个引用**,多个引用时按顺序排列,例如:"Nginx是一款轻量级的Web服务器、反向代理服务器[67e517e74767063e882d6861](CITE)[67e517e74767063e882d6862](CITE)。\n 它的特点是非常轻量[67e517e74767063e882d6863](CITE)。"
|
||||
- 不要把示例作为知识点。
|
||||
- 不要伪造 id,返回的 id 必须都存在 <Cites></Cites> 中!
|
||||
|
||||
## 通用规则
|
||||
|
||||
- 如果你不清楚答案,你需要澄清。
|
||||
- 避免提及你是从 <Cites></Cites> 获取的知识。
|
||||
- 保持答案与 <Cites></Cites> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。尤其是图片、表格、序列号等内容,需严格完整输出。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
## 严格要求
|
||||
|
||||
你只能使用 <Cites></Cites> 标记中的内容作为参考,不能使用自身的知识,并且回答的内容需严格与 <Cites></Cites> 中的内容一致。
|
||||
|
||||
<Cites>
|
||||
{{quote}}
|
||||
</Cites>
|
||||
|
||||
## 用户问题
|
||||
|
||||
{{question}}
|
||||
|
||||
## 回答
|
||||
`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.hard_strict'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.7']: `## 任务描述
|
||||
作为一个问答助手,你会使用 <QA></QA> 标记中的提供的数据对进行内容回答。
|
||||
|
||||
## 回答要求
|
||||
- 选择其中一个或多个问答对进行回答。
|
||||
- 回答的内容应尽可能与 <Answer></Answer> 中的内容一致。
|
||||
- 如果没有相关的问答对,你需要澄清。
|
||||
- 避免提及你是从 <QA></QA> 获取的知识,只需要回复答案。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
## 严格要求
|
||||
|
||||
你只能使用 <QA></QA> 标记中的内容作为参考,不能使用自身的知识,并且回答的内容需严格与 <QA></QA> 中的内容一致。
|
||||
|
||||
<QA>
|
||||
{{quote}}
|
||||
</QA>
|
||||
|
||||
## 用户问题
|
||||
|
||||
{{question}}
|
||||
|
||||
## 回答
|
||||
`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export const Prompt_systemQuotePromptList: PromptTemplateItem[] = [
|
||||
{
|
||||
title: i18nT('app:template.standard_template'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.7']: `## 任务描述
|
||||
你是一个知识库回答助手,可以使用 <Cites></Cites> 中的内容作为你本次回答的参考。
|
||||
同时,为了使回答结果更加可信并且可追溯,你需要在每段话结尾添加引用标记,标识参考了哪些内容。
|
||||
|
||||
## 追溯展示规则
|
||||
|
||||
- 使用 [id](CITE) 的格式来引用 <Cites></Cites> 中的知识,其中 CITE 是固定常量, id 为引文中的 id。
|
||||
- 在 **每段话结尾** 自然地整合引用。例如: "Nginx是一款轻量级的Web服务器、反向代理服务器[67e517e74767063e882d6861](CITE)。"。
|
||||
- 每段话**至少包含一个引用**,多个引用时按顺序排列,例如:"Nginx是一款轻量级的Web服务器、反向代理服务器[67e517e74767063e882d6861](CITE)[67e517e74767063e882d6862](CITE)。\n 它的特点是非常轻量[67e517e74767063e882d6863](CITE)。"
|
||||
- 不要把示例作为知识点。
|
||||
- 不要伪造 id,返回的 id 必须都存在 <Cites></Cites> 中!
|
||||
|
||||
## 通用规则
|
||||
|
||||
- 如果你不清楚答案,你需要澄清。
|
||||
- 避免提及你是从 <Cites></Cites> 获取的知识。
|
||||
- 保持答案与 <Cites></Cites> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。尤其是图片、表格、序列号等内容,需严格完整输出。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
<Cites>
|
||||
{{quote}}
|
||||
</Cites>`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.qa_template'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.8']: `## 任务描述
|
||||
作为一个问答助手,你会使用 <QA></QA> 标记中的提供的数据对进行内容回答。
|
||||
|
||||
## 回答要求
|
||||
- 选择其中一个或多个问答对进行回答。
|
||||
- 回答的内容应尽可能与 <Answer></Answer> 中的内容一致。
|
||||
- 如果没有相关的问答对,你需要澄清。
|
||||
- 避免提及你是从 <QA></QA> 获取的知识,只需要回复答案。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
<QA>
|
||||
{{quote}}
|
||||
</QA>`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.standard_strict'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.7']: `## 任务描述
|
||||
你是一个知识库回答助手,可以使用 <Cites></Cites> 中的内容作为你本次回答的参考。
|
||||
同时,为了使回答结果更加可信并且可追溯,你需要在每段话结尾添加引用标记,标识参考了哪些内容。
|
||||
|
||||
## 追溯展示规则
|
||||
|
||||
- 使用 [id](CITE) 的格式来引用 <Cites></Cites> 中的知识,其中 CITE 是固定常量, id 为引文中的 id。
|
||||
- 在 **每段话结尾** 自然地整合引用。例如: "Nginx是一款轻量级的Web服务器、反向代理服务器[67e517e74767063e882d6861](CITE)。"。
|
||||
- 每段话**至少包含一个引用**,多个引用时按顺序排列,例如:"Nginx是一款轻量级的Web服务器、反向代理服务器[67e517e74767063e882d6861](CITE)[67e517e74767063e882d6862](CITE)。\n 它的特点是非常轻量[67e517e74767063e882d6863](CITE)。"
|
||||
- 不要把示例作为知识点。
|
||||
- 不要伪造 id,返回的 id 必须都存在 <Cites></Cites> 中!
|
||||
|
||||
## 通用规则
|
||||
|
||||
- 如果你不清楚答案,你需要澄清。
|
||||
- 避免提及你是从 <Cites></Cites> 获取的知识。
|
||||
- 保持答案与 <Cites></Cites> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。尤其是图片、表格、序列号等内容,需严格完整输出。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
## 严格要求
|
||||
|
||||
你只能使用 <Cites></Cites> 标记中的内容作为参考,不能使用自身的知识,并且回答的内容需严格与 <Cites></Cites> 中的内容一致。
|
||||
|
||||
<Cites>
|
||||
{{quote}}
|
||||
</Cites>`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.hard_strict'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.7']: `## 任务描述
|
||||
作为一个问答助手,你会使用 <QA></QA> 标记中的提供的数据对进行内容回答。
|
||||
|
||||
## 回答要求
|
||||
- 选择其中一个或多个问答对进行回答。
|
||||
- 回答的内容应尽可能与 <Answer></Answer> 中的内容一致。
|
||||
- 如果没有相关的问答对,你需要澄清。
|
||||
- 避免提及你是从 <QA></QA> 获取的知识,只需要回复答案。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
## 严格要求
|
||||
|
||||
你只能使用 <QA></QA> 标记中的内容作为参考,不能使用自身的知识,并且回答的内容需严格与 <QA></QA> 中的内容一致。
|
||||
|
||||
<QA>
|
||||
{{quote}}
|
||||
</QA>`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export const Prompt_QuoteTemplateList: PromptTemplateItem[] = [
|
||||
{
|
||||
title: i18nT('app:template.standard_template'),
|
||||
@@ -10,11 +252,6 @@ export const Prompt_QuoteTemplateList: PromptTemplateItem[] = [
|
||||
['4.9.7']: `{
|
||||
"id": "{{id}}",
|
||||
"sourceName": "{{source}}",
|
||||
"content": "{{q}}\n{{a}}"
|
||||
}
|
||||
`,
|
||||
['4.9.2']: `{
|
||||
"sourceName": "{{source}}",
|
||||
"updateTime": "{{updateTime}}",
|
||||
"content": "{{q}}\n{{a}}"
|
||||
}
|
||||
@@ -25,7 +262,7 @@ export const Prompt_QuoteTemplateList: PromptTemplateItem[] = [
|
||||
title: i18nT('app:template.qa_template'),
|
||||
desc: i18nT('app:template.qa_template_des'),
|
||||
value: {
|
||||
['4.9.2']: `<Question>
|
||||
['4.9.7']: `<Question>
|
||||
{{q}}
|
||||
</Question>
|
||||
<Answer>
|
||||
@@ -40,11 +277,6 @@ export const Prompt_QuoteTemplateList: PromptTemplateItem[] = [
|
||||
['4.9.7']: `{
|
||||
"id": "{{id}}",
|
||||
"sourceName": "{{source}}",
|
||||
"content": "{{q}}\n{{a}}"
|
||||
}
|
||||
`,
|
||||
['4.9.2']: `{
|
||||
"sourceName": "{{source}}",
|
||||
"updateTime": "{{updateTime}}",
|
||||
"content": "{{q}}\n{{a}}"
|
||||
}
|
||||
@@ -55,7 +287,7 @@ export const Prompt_QuoteTemplateList: PromptTemplateItem[] = [
|
||||
title: i18nT('app:template.hard_strict'),
|
||||
desc: i18nT('app:template.hard_strict_des'),
|
||||
value: {
|
||||
['4.9.2']: `<Question>
|
||||
['4.9.7']: `<Question>
|
||||
{{q}}
|
||||
</Question>
|
||||
<Answer>
|
||||
@@ -64,263 +296,12 @@ export const Prompt_QuoteTemplateList: PromptTemplateItem[] = [
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export const getQuoteTemplate = (version?: string) => {
|
||||
const defaultTemplate = Prompt_QuoteTemplateList[0].value;
|
||||
|
||||
return getPromptByVersion(version, defaultTemplate);
|
||||
};
|
||||
|
||||
export const Prompt_userQuotePromptList: PromptTemplateItem[] = [
|
||||
{
|
||||
title: i18nT('app:template.standard_template'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.7']: `使用 <Reference></Reference> 标记中的内容作为本次对话的参考:
|
||||
|
||||
<Reference>
|
||||
{{quote}}
|
||||
</Reference>
|
||||
|
||||
回答要求:
|
||||
- 如果你不清楚答案,你需要澄清。
|
||||
- 避免提及你是从 <Reference></Reference> 获取的知识。
|
||||
- 保持答案与 <Reference></Reference> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。
|
||||
- 使用 [id](CITE) 格式来引用<Reference></Reference>中的知识,其中 CITE 是固定常量, id 为引文中的 id。
|
||||
- 在每段结尾自然地整合引用。例如: "FastGPT 是一个基于大语言模型(LLM)的知识库问答系统[67e517e74767063e882d6861](CITE)。"
|
||||
- 每段至少包含一个引用,也可根据内容需要加入多个引用,按顺序排列。`,
|
||||
['4.9.2']: `使用 <Reference></Reference> 标记中的内容作为本次对话的参考:
|
||||
|
||||
<Reference>
|
||||
{{quote}}
|
||||
</Reference>
|
||||
|
||||
回答要求:
|
||||
- 如果你不清楚答案,你需要澄清。
|
||||
- 避免提及你是从 <Reference></Reference> 获取的知识。
|
||||
- 保持答案与 <Reference></Reference> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
问题:"""{{question}}"""`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.qa_template'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.2']: `使用 <QA></QA> 标记中的问答对进行回答。
|
||||
|
||||
<QA>
|
||||
{{quote}}
|
||||
</QA>
|
||||
|
||||
回答要求:
|
||||
- 选择其中一个或多个问答对进行回答。
|
||||
- 回答的内容应尽可能与 <答案></答案> 中的内容一致。
|
||||
- 如果没有相关的问答对,你需要澄清。
|
||||
- 避免提及你是从 QA 获取的知识,只需要回复答案。
|
||||
|
||||
问题:"""{{question}}"""`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.standard_strict'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.7']: `忘记你已有的知识,仅使用 <Reference></Reference> 标记中的内容作为本次对话的参考:
|
||||
|
||||
<Reference>
|
||||
{{quote}}
|
||||
</Reference>
|
||||
|
||||
思考流程:
|
||||
1. 判断问题是否与 <Reference></Reference> 标记中的内容有关。
|
||||
2. 如果有关,你按下面的要求回答。
|
||||
3. 如果无关,你直接拒绝回答本次问题。
|
||||
|
||||
回答要求:
|
||||
- 避免提及你是从 <Reference></Reference> 获取的知识。
|
||||
- 保持答案与 <Reference></Reference> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。
|
||||
- 使用 [id](CITE) 格式来引用<Reference></Reference>中的知识,其中 CITE 是固定常量, id 为引文中的 id。
|
||||
- 在每段结尾自然地整合引用。例如: "FastGPT 是一个基于大语言模型(LLM)的知识库问答系统[67e517e74767063e882d6861](CITE)。"
|
||||
- 每段至少包含一个引用,也可根据内容需要加入多个引用,按顺序排列。
|
||||
|
||||
问题:"""{{question}}"""`,
|
||||
['4.9.2']: `忘记你已有的知识,仅使用 <Reference></Reference> 标记中的内容作为本次对话的参考:
|
||||
|
||||
<Reference>
|
||||
{{quote}}
|
||||
</Reference>
|
||||
|
||||
思考流程:
|
||||
1. 判断问题是否与 <Reference></Reference> 标记中的内容有关。
|
||||
2. 如果有关,你按下面的要求回答。
|
||||
3. 如果无关,你直接拒绝回答本次问题。
|
||||
|
||||
回答要求:
|
||||
- 避免提及你是从 <Reference></Reference> 获取的知识。
|
||||
- 保持答案与 <Reference></Reference> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
问题:"""{{question}}"""`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.hard_strict'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.2']: `忘记你已有的知识,仅使用 <QA></QA> 标记中的问答对进行回答。
|
||||
|
||||
<QA>
|
||||
{{quote}}
|
||||
</QA>
|
||||
|
||||
思考流程:
|
||||
1. 判断问题是否与 <QA></QA> 标记中的内容有关。
|
||||
2. 如果无关,你直接拒绝回答本次问题。
|
||||
3. 判断是否有相近或相同的问题。
|
||||
4. 如果有相同的问题,直接输出对应答案。
|
||||
5. 如果只有相近的问题,请把相近的问题和答案一起输出。
|
||||
|
||||
回答要求:
|
||||
- 如果没有相关的问答对,你需要澄清。
|
||||
- 回答的内容应尽可能与 <QA></QA> 标记中的内容一致。
|
||||
- 避免提及你是从 QA 获取的知识,只需要回复答案。
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。
|
||||
|
||||
问题:"""{{question}}"""`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export const Prompt_systemQuotePromptList: PromptTemplateItem[] = [
|
||||
{
|
||||
title: i18nT('app:template.standard_template'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.7']: `使用 <Reference></Reference> 标记中的内容作为本次对话的参考:
|
||||
|
||||
<Reference>
|
||||
{{quote}}
|
||||
</Reference>
|
||||
|
||||
回答要求:
|
||||
- 如果你不清楚答案,你需要澄清。
|
||||
- 避免提及你是从 <Reference></Reference> 获取的知识。
|
||||
- 保持答案与 <Reference></Reference> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。
|
||||
- 使用 [id](CITE) 格式来引用<Reference></Reference>中的知识,其中 CITE 是固定常量, id 为引文中的 id。
|
||||
- 在每段结尾自然地整合引用。例如: "FastGPT 是一个基于大语言模型(LLM)的知识库问答系统[67e517e74767063e882d6861](CITE)。"
|
||||
- 每段至少包含一个引用,也可根据内容需要加入多个引用,按顺序排列。`,
|
||||
['4.9.2']: `使用 <Reference></Reference> 标记中的内容作为本次对话的参考:
|
||||
|
||||
<Reference>
|
||||
{{quote}}
|
||||
</Reference>
|
||||
|
||||
回答要求:
|
||||
- 如果你不清楚答案,你需要澄清。
|
||||
- 避免提及你是从 <Reference></Reference> 获取的知识。
|
||||
- 保持答案与 <Reference></Reference> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.qa_template'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.2']: `使用 <QA></QA> 标记中的问答对进行回答。
|
||||
|
||||
<QA>
|
||||
{{quote}}
|
||||
</QA>
|
||||
|
||||
回答要求:
|
||||
- 选择其中一个或多个问答对进行回答。
|
||||
- 回答的内容应尽可能与 <答案></答案> 中的内容一致。
|
||||
- 如果没有相关的问答对,你需要澄清。
|
||||
- 避免提及你是从 QA 获取的知识,只需要回复答案。`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.standard_strict'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.7']: `忘记你已有的知识,仅使用 <Reference></Reference> 标记中的内容作为本次对话的参考:
|
||||
|
||||
<Reference>
|
||||
{{quote}}
|
||||
</Reference>
|
||||
|
||||
思考流程:
|
||||
1. 判断问题是否与 <Reference></Reference> 标记中的内容有关。
|
||||
2. 如果有关,你按下面的要求回答。
|
||||
3. 如果无关,你直接拒绝回答本次问题。
|
||||
|
||||
回答要求:
|
||||
- 避免提及你是从 <Reference></Reference> 获取的知识。
|
||||
- 保持答案与 <Reference></Reference> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。
|
||||
- 使用 [id](CITE) 格式来引用<Reference></Reference>中的知识,其中 CITE 是固定常量, id 为引文中的 id。
|
||||
- 在每段结尾自然地整合引用。例如: "FastGPT 是一个基于大语言模型(LLM)的知识库问答系统[67e517e74767063e882d6861](CITE)。"
|
||||
- 每段至少包含一个引用,也可根据内容需要加入多个引用,按顺序排列。
|
||||
|
||||
问题:"""{{question}}"""`,
|
||||
['4.9.2']: `忘记你已有的知识,仅使用 <Reference></Reference> 标记中的内容作为本次对话的参考:
|
||||
|
||||
<Reference>
|
||||
{{quote}}
|
||||
</Reference>
|
||||
|
||||
思考流程:
|
||||
1. 判断问题是否与 <Reference></Reference> 标记中的内容有关。
|
||||
2. 如果有关,你按下面的要求回答。
|
||||
3. 如果无关,你直接拒绝回答本次问题。
|
||||
|
||||
回答要求:
|
||||
- 避免提及你是从 <Reference></Reference> 获取的知识。
|
||||
- 保持答案与 <Reference></Reference> 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18nT('app:template.hard_strict'),
|
||||
desc: '',
|
||||
value: {
|
||||
['4.9.2']: `忘记你已有的知识,仅使用 <QA></QA> 标记中的问答对进行回答。
|
||||
|
||||
<QA>
|
||||
{{quote}}
|
||||
</QA>
|
||||
|
||||
思考流程:
|
||||
1. 判断问题是否与 <QA></QA> 标记中的内容有关。
|
||||
2. 如果无关,你直接拒绝回答本次问题。
|
||||
3. 判断是否有相近或相同的问题。
|
||||
4. 如果有相同的问题,直接输出对应答案。
|
||||
5. 如果只有相近的问题,请把相近的问题和答案一起输出。
|
||||
|
||||
回答要求:
|
||||
- 如果没有相关的问答对,你需要澄清。
|
||||
- 回答的内容应尽可能与 <QA></QA> 标记中的内容一致。
|
||||
- 避免提及你是从 QA 获取的知识,只需要回复答案。
|
||||
- 使用 Markdown 语法优化回答格式。
|
||||
- 使用与问题相同的语言回答。`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export const getQuotePrompt = (version?: string, role: 'user' | 'system' = 'user') => {
|
||||
const quotePromptTemplates =
|
||||
role === 'user' ? Prompt_userQuotePromptList : Prompt_systemQuotePromptList;
|
||||
@@ -331,9 +312,9 @@ export const getQuotePrompt = (version?: string, role: 'user' | 'system' = 'user
|
||||
};
|
||||
|
||||
// Document quote prompt
|
||||
export const getDocumentQuotePrompt = (version: string) => {
|
||||
export const getDocumentQuotePrompt = (version?: string) => {
|
||||
const promptMap = {
|
||||
['4.9.2']: `将 <FilesContent></FilesContent> 中的内容作为本次对话的参考:
|
||||
['4.9.7']: `将 <FilesContent></FilesContent> 中的内容作为本次对话的参考:
|
||||
<FilesContent>
|
||||
{{quote}}
|
||||
</FilesContent>
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
export const getDatasetSearchToolResponsePrompt = () => {
|
||||
return `## Role
|
||||
你是一个知识库回答助手,可以 "quotes" 中的内容作为本次对话的参考。为了使回答结果更加可信并且可追溯,你需要在每段话结尾添加引用标记。
|
||||
你是一个知识库回答助手,可以 "cites" 中的内容作为本次对话的参考。为了使回答结果更加可信并且可追溯,你需要在每段话结尾添加引用标记,标识参考了哪些内容。
|
||||
|
||||
## Rules
|
||||
## 追溯展示规则
|
||||
|
||||
- 使用 **[id](CITE)** 格式来引用 "cites" 中的知识,其中 CITE 是固定常量, id 为引文中的 id。
|
||||
- 在 **每段话结尾** 自然地整合引用。例如: "Nginx是一款轻量级的Web服务器、反向代理服务器[67e517e74767063e882d6861](CITE)。"。
|
||||
- 每段话**至少包含一个引用**,多个引用时按顺序排列,例如:"Nginx是一款轻量级的Web服务器、反向代理服务器[67e517e74767063e882d6861](CITE)[67e517e74767063e882d6862](CITE)。\n 它的特点是非常轻量[67e517e74767063e882d6863](CITE)。"
|
||||
- 不要把示例作为知识点。
|
||||
- 不要伪造 id,返回的 id 必须都存在 cites 中!
|
||||
|
||||
## 通用规则
|
||||
- 如果你不清楚答案,你需要澄清。
|
||||
- 避免提及你是从 "quotes" 获取的知识。
|
||||
- 保持答案与 "quotes" 中描述的一致。
|
||||
- 避免提及你是从 "cites" 获取的知识。
|
||||
- 保持答案与 "cites" 中描述的一致。
|
||||
- 使用 Markdown 语法优化回答格式。尤其是图片、表格、序列号等内容,需严格完整输出。
|
||||
- 使用与问题相同的语言回答。
|
||||
- 使用 [id](CITE) 格式来引用 "quotes" 中的知识,其中 CITE 是固定常量, id 为引文中的 id。
|
||||
- 在每段话结尾自然地整合引用。例如: "FastGPT 是一个基于大语言模型(LLM)的知识库问答系统[67e517e74767063e882d6861](CITE)。"
|
||||
- 每段话至少包含一个引用,也可根据内容需要加入多个引用,按顺序排列。`;
|
||||
- 使用与问题相同的语言回答。`;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const getPromptByVersion = (version?: string, promptMap: Record<string, string> = {}) => {
|
||||
// 版本号大的在前面
|
||||
const versions = Object.keys(promptMap).sort((a, b) => {
|
||||
const [majorA, minorA, patchA] = a.split('.').map(Number);
|
||||
const [majorB, minorB, patchB] = b.split('.').map(Number);
|
||||
@@ -15,5 +16,5 @@ export const getPromptByVersion = (version?: string, promptMap: Record<string, s
|
||||
if (version in promptMap) {
|
||||
return promptMap[version];
|
||||
}
|
||||
return promptMap[versions[versions.length - 1]];
|
||||
return promptMap[versions[0]];
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
FlowNodeTypeEnum
|
||||
} from '../../workflow/node/constant';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { type ToolType } from '../type';
|
||||
import { type McpToolConfigType } from '../type';
|
||||
import { i18nT } from '../../../../web/i18n/utils';
|
||||
import { type RuntimeNodeItemType } from '../../workflow/runtime/type';
|
||||
|
||||
@@ -16,7 +16,7 @@ export const getMCPToolSetRuntimeNode = ({
|
||||
avatar
|
||||
}: {
|
||||
url: string;
|
||||
toolList: ToolType[];
|
||||
toolList: McpToolConfigType[];
|
||||
name?: string;
|
||||
avatar?: string;
|
||||
}): RuntimeNodeItemType => {
|
||||
@@ -45,7 +45,7 @@ export const getMCPToolRuntimeNode = ({
|
||||
url,
|
||||
avatar = 'core/app/type/mcpToolsFill'
|
||||
}: {
|
||||
tool: ToolType;
|
||||
tool: McpToolConfigType;
|
||||
url: string;
|
||||
avatar?: string;
|
||||
}): RuntimeNodeItemType => {
|
||||
@@ -65,7 +65,7 @@ export const getMCPToolRuntimeNode = ({
|
||||
...Object.entries(tool.inputSchema?.properties || {}).map(([key, value]) => ({
|
||||
key,
|
||||
label: key,
|
||||
valueType: value.type as WorkflowIOValueTypeEnum,
|
||||
valueType: value.type as WorkflowIOValueTypeEnum, // TODO: 这里需要做一个映射
|
||||
description: value.description,
|
||||
toolDescription: value.description || key,
|
||||
required: tool.inputSchema?.required?.includes(key) || false,
|
||||
|
||||
20
packages/global/core/app/type.d.ts
vendored
20
packages/global/core/app/type.d.ts
vendored
@@ -16,16 +16,6 @@ import { FlowNodeInputTypeEnum } from '../../core/workflow/node/constant';
|
||||
import type { WorkflowTemplateBasicType } from '@fastgpt/global/core/workflow/type';
|
||||
import type { SourceMemberType } from '../../support/user/type';
|
||||
|
||||
export type ToolType = {
|
||||
name: string;
|
||||
description: string;
|
||||
inputSchema: {
|
||||
type: string;
|
||||
properties?: Record<string, { type: string; description?: string }>;
|
||||
required?: string[];
|
||||
};
|
||||
};
|
||||
|
||||
export type AppSchema = {
|
||||
_id: string;
|
||||
parentId?: ParentIdType;
|
||||
@@ -117,6 +107,16 @@ export type AppSimpleEditFormType = {
|
||||
chatConfig: AppChatConfigType;
|
||||
};
|
||||
|
||||
export type McpToolConfigType = {
|
||||
name: string;
|
||||
description: string;
|
||||
inputSchema: {
|
||||
type: string;
|
||||
properties?: Record<string, { type: string; description?: string }>;
|
||||
required?: string[];
|
||||
};
|
||||
};
|
||||
|
||||
/* app chat config type */
|
||||
export type AppChatConfigType = {
|
||||
welcomeText?: string;
|
||||
|
||||
@@ -9,6 +9,7 @@ import { type WorkflowTemplateBasicType } from '../workflow/type';
|
||||
import { AppTypeEnum } from './constants';
|
||||
import { AppErrEnum } from '../../common/error/code/app';
|
||||
import { PluginErrEnum } from '../../common/error/code/plugin';
|
||||
import { i18nT } from '../../../web/i18n/utils';
|
||||
|
||||
export const getDefaultAppForm = (): AppSimpleEditFormType => {
|
||||
return {
|
||||
@@ -189,7 +190,7 @@ export const getAppType = (config?: WorkflowTemplateBasicType | AppSimpleEditFor
|
||||
return '';
|
||||
};
|
||||
|
||||
export const checkAppUnExistError = (error?: string) => {
|
||||
export const formatToolError = (error?: string) => {
|
||||
const unExistError: Array<string> = [
|
||||
AppErrEnum.unAuthApp,
|
||||
AppErrEnum.unExist,
|
||||
@@ -197,9 +198,9 @@ export const checkAppUnExistError = (error?: string) => {
|
||||
PluginErrEnum.unExist
|
||||
];
|
||||
|
||||
if (!!error && unExistError.includes(error)) {
|
||||
return error;
|
||||
if (error && unExistError.includes(error)) {
|
||||
return i18nT('app:un_auth');
|
||||
} else {
|
||||
return undefined;
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -218,7 +218,6 @@ export const FlowValueTypeMap: Record<
|
||||
};
|
||||
|
||||
export const EDGE_TYPE = 'default';
|
||||
export const defaultNodeVersion = '481';
|
||||
|
||||
export const chatHistoryValueDesc = `{
|
||||
obj: System | Human | AI;
|
||||
@@ -236,3 +235,10 @@ export const datasetQuoteValueDesc = `{
|
||||
export const datasetSelectValueDesc = `{
|
||||
datasetId: string;
|
||||
}[]`;
|
||||
|
||||
export const AppNodeFlowNodeTypeMap: Record<any, boolean> = {
|
||||
[FlowNodeTypeEnum.pluginModule]: true,
|
||||
[FlowNodeTypeEnum.appModule]: true,
|
||||
[FlowNodeTypeEnum.tool]: true,
|
||||
[FlowNodeTypeEnum.toolSet]: true
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ import type {
|
||||
} from '../../chat/type';
|
||||
import { NodeOutputItemType } from '../../chat/type';
|
||||
import type { FlowNodeInputItemType, FlowNodeOutputItemType } from '../type/io.d';
|
||||
import type { StoreNodeItemType } from '../type/node';
|
||||
import type { NodeToolConfigType, StoreNodeItemType } from '../type/node';
|
||||
import type { DispatchNodeResponseKeyEnum } from './constants';
|
||||
import type { StoreEdgeItemType } from '../type/edge';
|
||||
import type { NodeInputKeyEnum } from '../constants';
|
||||
@@ -101,7 +101,10 @@ export type RuntimeNodeItemType = {
|
||||
outputs: FlowNodeOutputItemType[];
|
||||
|
||||
pluginId?: string; // workflow id / plugin id
|
||||
version: string;
|
||||
version?: string;
|
||||
|
||||
// tool
|
||||
toolConfig?: NodeToolConfigType;
|
||||
};
|
||||
|
||||
export type RuntimeEdgeItemType = StoreEdgeItemType & {
|
||||
@@ -114,7 +117,7 @@ export type DispatchNodeResponseType = {
|
||||
runningTime?: number;
|
||||
query?: string;
|
||||
textOutput?: string;
|
||||
error?: Record<string, any>;
|
||||
error?: Record<string, any> | string;
|
||||
customInputs?: Record<string, any>;
|
||||
customOutputs?: Record<string, any>;
|
||||
nodeInputs?: Record<string, any>;
|
||||
|
||||
@@ -25,7 +25,6 @@ export const RunAppModule: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:application_call'),
|
||||
intro: i18nT('workflow:select_another_application_to_call'),
|
||||
showStatus: true,
|
||||
version: '481',
|
||||
isTool: true,
|
||||
inputs: [
|
||||
{
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
Input_Template_UserChatInput,
|
||||
Input_Template_File_Link
|
||||
} from '../../input';
|
||||
import { chatNodeSystemPromptTip, systemPromptTip } from '../../tip';
|
||||
import { getHandleConfig } from '../../utils';
|
||||
import { i18nT } from '../../../../../../web/i18n/utils';
|
||||
|
||||
@@ -54,7 +53,7 @@ export const AiChatModule: FlowNodeTemplateType = {
|
||||
intro: i18nT('workflow:template.ai_chat_intro'),
|
||||
showStatus: true,
|
||||
isTool: true,
|
||||
courseUrl: '/docs/guide/workbench/workflow/ai_chat/',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/ai_chat/',
|
||||
version: '4.9.7',
|
||||
inputs: [
|
||||
Input_Template_SettingAiModel,
|
||||
@@ -121,12 +120,7 @@ export const AiChatModule: FlowNodeTemplateType = {
|
||||
valueType: WorkflowIOValueTypeEnum.string
|
||||
},
|
||||
// settings modal ---
|
||||
{
|
||||
...Input_Template_System_Prompt,
|
||||
label: i18nT('common:core.ai.Prompt'),
|
||||
description: systemPromptTip,
|
||||
placeholder: chatNodeSystemPromptTip
|
||||
},
|
||||
Input_Template_System_Prompt,
|
||||
Input_Template_History,
|
||||
Input_Template_Dataset_Quote,
|
||||
Input_Template_File_Link,
|
||||
|
||||
@@ -17,8 +17,7 @@ export const AssignedAnswerModule: FlowNodeTemplateType = {
|
||||
avatar: 'core/workflow/template/reply',
|
||||
name: i18nT('workflow:assigned_reply'),
|
||||
intro: i18nT('workflow:intro_assigned_reply'),
|
||||
courseUrl: '/docs/guide/workbench/workflow/reply/',
|
||||
version: '481',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/reply/',
|
||||
isTool: true,
|
||||
inputs: [
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
|
||||
intro: i18nT('workflow:intro_question_classification'),
|
||||
showStatus: true,
|
||||
version: '4.9.2',
|
||||
courseUrl: '/docs/guide/workbench/workflow/question_classify/',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/question_classify/',
|
||||
inputs: [
|
||||
{
|
||||
...Input_Template_SelectAIModel,
|
||||
|
||||
@@ -26,7 +26,7 @@ export const ContextExtractModule: FlowNodeTemplateType = {
|
||||
intro: i18nT('workflow:intro_text_content_extraction'),
|
||||
showStatus: true,
|
||||
isTool: true,
|
||||
courseUrl: '/docs/guide/workbench/workflow/content_extract/',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/content_extract/',
|
||||
version: '4.9.2',
|
||||
inputs: [
|
||||
{
|
||||
|
||||
@@ -17,8 +17,7 @@ export const CustomFeedbackNode: FlowNodeTemplateType = {
|
||||
avatar: 'core/workflow/template/customFeedback',
|
||||
name: i18nT('workflow:custom_feedback'),
|
||||
intro: i18nT('workflow:intro_custom_feedback'),
|
||||
courseUrl: '/docs/guide/workbench/workflow/custom_feedback/',
|
||||
version: '486',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/custom_feedback/',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.textareaInput,
|
||||
|
||||
@@ -42,8 +42,7 @@ export const DatasetConcatModule: FlowNodeTemplateType = {
|
||||
intro: i18nT('workflow:intro_knowledge_base_search_merge'),
|
||||
|
||||
showStatus: false,
|
||||
version: '486',
|
||||
courseUrl: '/docs/guide/workbench/workflow/knowledge_base_search_merge/',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/knowledge_base_search_merge/',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.datasetMaxTokens,
|
||||
|
||||
@@ -30,7 +30,7 @@ export const DatasetSearchModule: FlowNodeTemplateType = {
|
||||
intro: Dataset_SEARCH_DESC,
|
||||
showStatus: true,
|
||||
isTool: true,
|
||||
courseUrl: '/docs/guide/workbench/workflow/dataset_search/',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/dataset_search/',
|
||||
version: '4.9.2',
|
||||
inputs: [
|
||||
{
|
||||
|
||||
@@ -27,8 +27,7 @@ export const HttpNode468: FlowNodeTemplateType = {
|
||||
intro: i18nT('workflow:intro_http_request'),
|
||||
showStatus: true,
|
||||
isTool: true,
|
||||
courseUrl: '/docs/guide/workbench/workflow/http/',
|
||||
version: '481',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/http/',
|
||||
inputs: [
|
||||
{
|
||||
...Input_Template_DynamicInput,
|
||||
|
||||
@@ -23,8 +23,7 @@ export const IfElseNode: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:condition_checker'),
|
||||
intro: i18nT('workflow:execute_different_branches_based_on_conditions'),
|
||||
showStatus: true,
|
||||
courseUrl: '/docs/guide/workbench/workflow/tfswitch/',
|
||||
version: '481',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/tfswitch/',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.ifElseList,
|
||||
|
||||
@@ -23,7 +23,6 @@ export const FormInputNode: FlowNodeTemplateType = {
|
||||
name: i18nT('app:workflow.form_input'),
|
||||
intro: i18nT(`app:workflow.form_input_tip`),
|
||||
isTool: true,
|
||||
version: '4811',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.description,
|
||||
|
||||
@@ -24,8 +24,7 @@ export const UserSelectNode: FlowNodeTemplateType = {
|
||||
name: i18nT('app:workflow.user_select'),
|
||||
intro: i18nT(`app:workflow.user_select_tip`),
|
||||
isTool: true,
|
||||
version: '489',
|
||||
courseUrl: '/docs/guide/workbench/workflow/user-selection/',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/user-selection/',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.description,
|
||||
|
||||
@@ -32,8 +32,7 @@ export const LafModule: FlowNodeTemplateType = {
|
||||
intro: i18nT('workflow:intro_laf_function_call'),
|
||||
showStatus: true,
|
||||
isTool: true,
|
||||
courseUrl: '/docs/guide/workbench/workflow/laf/',
|
||||
version: '481',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/laf/',
|
||||
inputs: [
|
||||
{
|
||||
...Input_Template_DynamicInput,
|
||||
|
||||
@@ -29,8 +29,7 @@ export const LoopNode: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:loop'),
|
||||
intro: i18nT('workflow:intro_loop'),
|
||||
showStatus: true,
|
||||
version: '4811',
|
||||
courseUrl: '/docs/guide/workbench/workflow/loop/',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/loop/',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.loopInputArray,
|
||||
|
||||
@@ -19,7 +19,6 @@ export const LoopEndNode: FlowNodeTemplateType = {
|
||||
avatar: 'core/workflow/template/loopEnd',
|
||||
name: i18nT('workflow:loop_end'),
|
||||
showStatus: false,
|
||||
version: '4811',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.loopEndInput,
|
||||
|
||||
@@ -24,7 +24,6 @@ export const LoopStartNode: FlowNodeTemplateType = {
|
||||
unique: true,
|
||||
forbidDelete: true,
|
||||
showStatus: false,
|
||||
version: '4811',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.loopStartInput,
|
||||
|
||||
@@ -15,7 +15,6 @@ export const PluginConfigNode: FlowNodeTemplateType = {
|
||||
intro: '',
|
||||
unique: true,
|
||||
forbidDelete: true,
|
||||
version: '4811',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
||||
@@ -16,7 +16,6 @@ export const PluginInputModule: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:plugin_input'),
|
||||
intro: i18nT('workflow:intro_plugin_input'),
|
||||
showStatus: false,
|
||||
version: '481',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
||||
@@ -16,7 +16,6 @@ export const PluginOutputModule: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:template.plugin_output'),
|
||||
intro: i18nT('workflow:intro_custom_plugin_output'),
|
||||
showStatus: false,
|
||||
version: '481',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@ export const RunAppNode: FlowNodeTemplateType = {
|
||||
name: '',
|
||||
showStatus: false,
|
||||
isTool: false,
|
||||
version: '481',
|
||||
inputs: [], // [{key:'pluginId'},...]
|
||||
outputs: []
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@ export const RunPluginModule: FlowNodeTemplateType = {
|
||||
name: '',
|
||||
showStatus: false,
|
||||
isTool: true,
|
||||
version: '481',
|
||||
inputs: [], // [{key:'pluginId'},...]
|
||||
outputs: []
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@ export const RunToolNode: FlowNodeTemplateType = {
|
||||
name: '',
|
||||
showStatus: false,
|
||||
isTool: true,
|
||||
version: '4.9.6',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@ export const RunToolSetNode: FlowNodeTemplateType = {
|
||||
name: '',
|
||||
showStatus: false,
|
||||
isTool: true,
|
||||
version: '4.9.6',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
||||
@@ -26,8 +26,7 @@ export const CodeNode: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:code_execution'),
|
||||
intro: i18nT('workflow:execute_a_simple_script_code_usually_for_complex_data_processing'),
|
||||
showStatus: true,
|
||||
courseUrl: '/docs/guide/workbench/workflow/sandbox/',
|
||||
version: '482',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/sandbox/',
|
||||
inputs: [
|
||||
{
|
||||
...Input_Template_DynamicInput,
|
||||
|
||||
@@ -13,7 +13,6 @@ export const StopToolNode: FlowNodeTemplateType = {
|
||||
avatar: 'core/workflow/template/stopTool',
|
||||
name: i18nT('workflow:tool_call_termination'),
|
||||
intro: i18nT('workflow:intro_tool_call_termination'),
|
||||
version: '481',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
||||
@@ -15,7 +15,6 @@ export const SystemConfigNode: FlowNodeTemplateType = {
|
||||
intro: '',
|
||||
unique: true,
|
||||
forbidDelete: true,
|
||||
version: '481',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
||||
@@ -23,8 +23,7 @@ export const TextEditorNode: FlowNodeTemplateType = {
|
||||
avatar: 'core/workflow/template/textConcat',
|
||||
name: i18nT('workflow:text_concatenation'),
|
||||
intro: i18nT('workflow:intro_text_concatenation'),
|
||||
courseUrl: '/docs/guide/workbench/workflow/text_editor/',
|
||||
version: '4813',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/text_editor/',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.textareaInput,
|
||||
|
||||
@@ -13,7 +13,6 @@ export const ToolParamsNode: FlowNodeTemplateType = {
|
||||
avatar: 'core/workflow/template/toolParams',
|
||||
name: i18nT('workflow:tool_custom_field'),
|
||||
intro: i18nT('workflow:intro_tool_params_config'),
|
||||
version: '4811',
|
||||
isTool: true,
|
||||
inputs: [],
|
||||
outputs: []
|
||||
|
||||
@@ -32,7 +32,7 @@ export const ToolModule: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:template.tool_call'),
|
||||
intro: i18nT('workflow:template.tool_call_intro'),
|
||||
showStatus: true,
|
||||
courseUrl: '/docs/guide/workbench/workflow/tool/',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/tool/',
|
||||
version: '4.9.2',
|
||||
inputs: [
|
||||
{
|
||||
|
||||
@@ -19,8 +19,7 @@ export const VariableUpdateNode: FlowNodeTemplateType = {
|
||||
intro: i18nT('workflow:update_specified_node_output_or_global_variable'),
|
||||
showStatus: false,
|
||||
isTool: true,
|
||||
version: '481',
|
||||
courseUrl: '/docs/guide/workbench/workflow/variable_update/',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/variable_update/',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.updateList,
|
||||
|
||||
@@ -30,7 +30,6 @@ export const WorkflowStart: FlowNodeTemplateType = {
|
||||
intro: '',
|
||||
forbidDelete: true,
|
||||
unique: true,
|
||||
version: '481',
|
||||
inputs: [{ ...Input_Template_UserChatInput, toolDescription: i18nT('workflow:user_question') }],
|
||||
outputs: [
|
||||
{
|
||||
|
||||
@@ -37,7 +37,10 @@ export type WorkflowTemplateType = {
|
||||
intro?: string;
|
||||
author?: string;
|
||||
courseUrl?: string;
|
||||
version: string;
|
||||
|
||||
version?: string;
|
||||
versionLabel?: string;
|
||||
isLatestVersion?: boolean;
|
||||
|
||||
showStatus?: boolean;
|
||||
weight?: number;
|
||||
|
||||
4
packages/global/core/workflow/type/io.d.ts
vendored
4
packages/global/core/workflow/type/io.d.ts
vendored
@@ -63,6 +63,8 @@ export type FlowNodeInputItemType = InputComponentPropsType & {
|
||||
canSelectFile?: boolean;
|
||||
canSelectImg?: boolean;
|
||||
maxFiles?: number;
|
||||
|
||||
deprecated?: boolean;
|
||||
};
|
||||
|
||||
export type FlowNodeOutputItemType = {
|
||||
@@ -86,6 +88,8 @@ export type FlowNodeOutputItemType = {
|
||||
|
||||
// component params
|
||||
customFieldConfig?: CustomFieldConfigType;
|
||||
|
||||
deprecated?: boolean;
|
||||
};
|
||||
|
||||
export type ReferenceItemValueType = [string, string | undefined];
|
||||
|
||||
21
packages/global/core/workflow/type/node.d.ts
vendored
21
packages/global/core/workflow/type/node.d.ts
vendored
@@ -20,11 +20,17 @@ import { RuntimeNodeItemType } from '../runtime/type';
|
||||
import { PluginTypeEnum } from '../../plugin/constants';
|
||||
import { RuntimeEdgeItemType, StoreEdgeItemType } from './edge';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { AppDetailType, AppSchema } from '../../app/type';
|
||||
import type { AppDetailType, AppSchema, McpToolConfigType } from '../../app/type';
|
||||
import type { ParentIdType } from 'common/parentFolder/type';
|
||||
import { AppTypeEnum } from 'core/app/constants';
|
||||
import { AppTypeEnum } from '../../app/constants';
|
||||
import type { WorkflowInteractiveResponseType } from '../template/system/interactive/type';
|
||||
|
||||
export type NodeToolConfigType = {
|
||||
mcpTool?: McpToolConfigType & {
|
||||
url: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type FlowNodeCommonType = {
|
||||
parentNodeId?: string;
|
||||
flowNodeType: FlowNodeTypeEnum; // render node card
|
||||
@@ -34,7 +40,10 @@ export type FlowNodeCommonType = {
|
||||
name: string;
|
||||
intro?: string; // template list intro
|
||||
showStatus?: boolean; // chatting response step status
|
||||
version: string;
|
||||
|
||||
version?: string;
|
||||
versionLabel?: string; // Just ui show
|
||||
isLatestVersion?: boolean; // Just ui show
|
||||
|
||||
// data
|
||||
inputs: FlowNodeInputItemType[];
|
||||
@@ -43,12 +52,14 @@ export type FlowNodeCommonType = {
|
||||
// plugin data
|
||||
pluginId?: string;
|
||||
isFolder?: boolean;
|
||||
// pluginType?: AppTypeEnum;
|
||||
pluginData?: PluginDataType;
|
||||
|
||||
// tool data
|
||||
toolData?: NodeToolConfigType;
|
||||
};
|
||||
|
||||
export type PluginDataType = {
|
||||
version: string;
|
||||
version?: string;
|
||||
diagram?: string;
|
||||
userGuide?: string;
|
||||
courseUrl?: string;
|
||||
|
||||
1
packages/global/support/user/api.d.ts
vendored
1
packages/global/support/user/api.d.ts
vendored
@@ -9,6 +9,7 @@ import type { TeamMemberItemType } from './team/type';
|
||||
export type PostLoginProps = {
|
||||
username: string;
|
||||
password: string;
|
||||
code: string;
|
||||
};
|
||||
|
||||
export type OauthLoginProps = {
|
||||
|
||||
@@ -3,7 +3,8 @@ export enum UserAuthTypeEnum {
|
||||
findPassword = 'findPassword',
|
||||
wxLogin = 'wxLogin',
|
||||
bindNotification = 'bindNotification',
|
||||
captcha = 'captcha'
|
||||
captcha = 'captcha',
|
||||
login = 'login'
|
||||
}
|
||||
|
||||
export const userAuthTypeMap = {
|
||||
@@ -11,5 +12,6 @@ export const userAuthTypeMap = {
|
||||
[UserAuthTypeEnum.findPassword]: 'findPassword',
|
||||
[UserAuthTypeEnum.wxLogin]: 'wxLogin',
|
||||
[UserAuthTypeEnum.bindNotification]: 'bindNotification',
|
||||
[UserAuthTypeEnum.captcha]: 'captcha'
|
||||
[UserAuthTypeEnum.captcha]: 'captcha',
|
||||
[UserAuthTypeEnum.login]: 'login'
|
||||
};
|
||||
|
||||
10
packages/global/support/user/auth/type.d.ts
vendored
Normal file
10
packages/global/support/user/auth/type.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { UserAuthTypeEnum } from '@fastgpt/global/support/user/auth/constants';
|
||||
|
||||
export type UserAuthSchemaType = {
|
||||
key: string;
|
||||
type: `${UserAuthTypeEnum}`;
|
||||
code?: string;
|
||||
openid?: string;
|
||||
createTime: Date;
|
||||
expiredTime: Date;
|
||||
};
|
||||
1
packages/global/support/user/type.d.ts
vendored
1
packages/global/support/user/type.d.ts
vendored
@@ -14,6 +14,7 @@ export type UserModelSchema = {
|
||||
timezone: string;
|
||||
status: `${UserStatusEnum}`;
|
||||
lastLoginTmbId?: string;
|
||||
passwordUpdateTime?: Date;
|
||||
fastgpt_sem?: {
|
||||
keyword: string;
|
||||
};
|
||||
|
||||
@@ -149,7 +149,7 @@ export const readRawContentByFileBuffer = async ({
|
||||
return await systemParse();
|
||||
})();
|
||||
|
||||
addLog.debug(`Parse file success, time: ${Date.now() - start}ms. Uploading file image.`);
|
||||
addLog.debug(`Parse file success, time: ${Date.now() - start}ms. `);
|
||||
|
||||
// markdown data format
|
||||
if (imageList) {
|
||||
@@ -185,7 +185,7 @@ export const readRawContentByFileBuffer = async ({
|
||||
}
|
||||
}
|
||||
|
||||
addLog.debug(`Upload file image success, time: ${Date.now() - start}ms`);
|
||||
addLog.debug(`Upload file success, time: ${Date.now() - start}ms`);
|
||||
|
||||
return { rawText, formatText, imageList };
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { jsonRes } from '../response';
|
||||
import type { NextApiResponse } from 'next';
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { withNextCors } from './cors';
|
||||
import { type ApiRequestProps } from '../../type/next';
|
||||
import { addLog } from '../system/log';
|
||||
@@ -9,14 +9,21 @@ export type NextApiHandler<T = any> = (
|
||||
res: NextApiResponse<T>
|
||||
) => unknown | Promise<unknown>;
|
||||
|
||||
export const NextEntry = ({ beforeCallback = [] }: { beforeCallback?: Promise<any>[] }) => {
|
||||
export const NextEntry = ({
|
||||
beforeCallback = []
|
||||
}: {
|
||||
beforeCallback?: ((req: NextApiRequest, res: NextApiResponse) => Promise<any>)[];
|
||||
}) => {
|
||||
return (...args: NextApiHandler[]): NextApiHandler => {
|
||||
return async function api(req: ApiRequestProps, res: NextApiResponse) {
|
||||
const start = Date.now();
|
||||
addLog.debug(`Request start ${req.url}`);
|
||||
|
||||
try {
|
||||
await Promise.all([withNextCors(req, res), ...beforeCallback]);
|
||||
await Promise.all([
|
||||
withNextCors(req, res),
|
||||
...beforeCallback.map((item) => item(req, res))
|
||||
]);
|
||||
|
||||
let response = null;
|
||||
for await (const handler of args) {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { getGlobalRedisCacheConnection } from './index';
|
||||
import { getGlobalRedisConnection } from './index';
|
||||
import { addLog } from '../system/log';
|
||||
import { retryFn } from '@fastgpt/global/common/system/utils';
|
||||
|
||||
const redisPrefix = 'cache:';
|
||||
const getCacheKey = (key: string) => `${redisPrefix}${key}`;
|
||||
|
||||
export enum CacheKeyEnum {
|
||||
team_vector_count = 'team_vector_count'
|
||||
}
|
||||
@@ -13,12 +16,12 @@ export const setRedisCache = async (
|
||||
) => {
|
||||
return await retryFn(async () => {
|
||||
try {
|
||||
const redis = getGlobalRedisCacheConnection();
|
||||
const redis = getGlobalRedisConnection();
|
||||
|
||||
if (expireSeconds) {
|
||||
await redis.set(key, data, 'EX', expireSeconds);
|
||||
await redis.set(getCacheKey(key), data, 'EX', expireSeconds);
|
||||
} else {
|
||||
await redis.set(key, data);
|
||||
await redis.set(getCacheKey(key), data);
|
||||
}
|
||||
} catch (error) {
|
||||
addLog.error('Set cache error:', error);
|
||||
@@ -28,11 +31,11 @@ export const setRedisCache = async (
|
||||
};
|
||||
|
||||
export const getRedisCache = async (key: string) => {
|
||||
const redis = getGlobalRedisCacheConnection();
|
||||
return await retryFn(() => redis.get(key));
|
||||
const redis = getGlobalRedisConnection();
|
||||
return await retryFn(() => redis.get(getCacheKey(key)));
|
||||
};
|
||||
|
||||
export const delRedisCache = async (key: string) => {
|
||||
const redis = getGlobalRedisCacheConnection();
|
||||
await retryFn(() => redis.del(key));
|
||||
const redis = getGlobalRedisConnection();
|
||||
await retryFn(() => redis.del(getCacheKey(key)));
|
||||
};
|
||||
|
||||
@@ -27,17 +27,26 @@ export const newWorkerRedisConnection = () => {
|
||||
return redis;
|
||||
};
|
||||
|
||||
export const getGlobalRedisCacheConnection = () => {
|
||||
if (global.redisCache) return global.redisCache;
|
||||
export const FASTGPT_REDIS_PREFIX = 'fastgpt:';
|
||||
export const getGlobalRedisConnection = () => {
|
||||
if (global.redisClient) return global.redisClient;
|
||||
|
||||
global.redisCache = new Redis(REDIS_URL, { keyPrefix: 'fastgpt:cache:' });
|
||||
global.redisClient = new Redis(REDIS_URL, { keyPrefix: FASTGPT_REDIS_PREFIX });
|
||||
|
||||
global.redisCache.on('connect', () => {
|
||||
global.redisClient.on('connect', () => {
|
||||
addLog.info('Redis connected');
|
||||
});
|
||||
global.redisCache.on('error', (error) => {
|
||||
global.redisClient.on('error', (error) => {
|
||||
addLog.error('Redis connection error', error);
|
||||
});
|
||||
|
||||
return global.redisCache;
|
||||
return global.redisClient;
|
||||
};
|
||||
|
||||
export const getAllKeysByPrefix = async (key: string) => {
|
||||
const redis = getGlobalRedisConnection();
|
||||
const keys = (await redis.keys(`${FASTGPT_REDIS_PREFIX}${key}:*`)).map((key) =>
|
||||
key.replace(FASTGPT_REDIS_PREFIX, '')
|
||||
);
|
||||
return keys;
|
||||
};
|
||||
|
||||
2
packages/service/common/redis/type.d.ts
vendored
2
packages/service/common/redis/type.d.ts
vendored
@@ -1,5 +1,5 @@
|
||||
import type Redis from 'ioredis';
|
||||
|
||||
declare global {
|
||||
var redisCache: Redis | null;
|
||||
var redisClient: Redis | null;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export const cheerioToHtml = ({
|
||||
}
|
||||
}
|
||||
});
|
||||
selectDom.find('img').each((i, el) => {
|
||||
selectDom.find('img, video, source, audio, iframe').each((i, el) => {
|
||||
const src = $(el).attr('src');
|
||||
if (src) {
|
||||
if (src.startsWith('//')) {
|
||||
|
||||
@@ -2,26 +2,44 @@ import { SystemConfigsTypeEnum } from '@fastgpt/global/common/system/config/cons
|
||||
import { MongoSystemConfigs } from './schema';
|
||||
import { type FastGPTConfigFileType } from '@fastgpt/global/common/system/types';
|
||||
import { FastGPTProUrl } from '../constants';
|
||||
import { type LicenseDataType } from '@fastgpt/global/common/system/types';
|
||||
|
||||
export const getFastGPTConfigFromDB = async () => {
|
||||
export const getFastGPTConfigFromDB = async (): Promise<{
|
||||
fastgptConfig: FastGPTConfigFileType;
|
||||
licenseData?: LicenseDataType;
|
||||
}> => {
|
||||
if (!FastGPTProUrl) {
|
||||
return {
|
||||
config: {} as FastGPTConfigFileType
|
||||
fastgptConfig: {} as FastGPTConfigFileType
|
||||
};
|
||||
}
|
||||
|
||||
const res = await MongoSystemConfigs.findOne({
|
||||
type: SystemConfigsTypeEnum.fastgpt
|
||||
}).sort({
|
||||
createTime: -1
|
||||
});
|
||||
const [fastgptConfig, licenseConfig] = await Promise.all([
|
||||
MongoSystemConfigs.findOne({
|
||||
type: SystemConfigsTypeEnum.fastgpt
|
||||
}).sort({
|
||||
createTime: -1
|
||||
}),
|
||||
MongoSystemConfigs.findOne({
|
||||
type: SystemConfigsTypeEnum.license
|
||||
}).sort({
|
||||
createTime: -1
|
||||
})
|
||||
]);
|
||||
|
||||
const config = res?.value || {};
|
||||
const config = fastgptConfig?.value || {};
|
||||
const licenseData = licenseConfig?.value?.data as LicenseDataType | undefined;
|
||||
|
||||
const fastgptConfigTime = fastgptConfig?.createTime.getTime().toString();
|
||||
const licenseConfigTime = licenseConfig?.createTime.getTime().toString();
|
||||
// 利用配置文件的创建时间(更新时间)来做缓存,如果前端命中缓存,则不需要再返回配置文件
|
||||
global.systemInitBufferId = res ? res.createTime.getTime().toString() : undefined;
|
||||
global.systemInitBufferId = fastgptConfigTime
|
||||
? `${fastgptConfigTime}-${licenseConfigTime}`
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
config: config as FastGPTConfigFileType
|
||||
fastgptConfig: config as FastGPTConfigFileType,
|
||||
licenseData
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
import { getLLMModel } from './model';
|
||||
import { getLLMDefaultUsage } from '@fastgpt/global/core/ai/constants';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import json5 from 'json5';
|
||||
|
||||
/*
|
||||
Count response max token
|
||||
@@ -54,8 +55,6 @@ type InferCompletionsBody<T> = T extends { stream: true }
|
||||
|
||||
export const llmCompletionsBodyFormat = <T extends CompletionsBodyType>(
|
||||
body: T & {
|
||||
response_format?: any;
|
||||
json_schema?: string;
|
||||
stop?: string;
|
||||
},
|
||||
model: string | LLMModelItemType
|
||||
@@ -65,8 +64,26 @@ export const llmCompletionsBodyFormat = <T extends CompletionsBodyType>(
|
||||
return body as unknown as InferCompletionsBody<T>;
|
||||
}
|
||||
|
||||
const response_format = body.response_format;
|
||||
const json_schema = body.json_schema ?? undefined;
|
||||
const response_format = (() => {
|
||||
if (!body.response_format?.type) return undefined;
|
||||
if (body.response_format.type === 'json_schema') {
|
||||
try {
|
||||
return {
|
||||
type: 'json_schema',
|
||||
json_schema: json5.parse(body.response_format?.json_schema as unknown as string)
|
||||
};
|
||||
} catch (error) {
|
||||
throw new Error('Json schema error');
|
||||
}
|
||||
}
|
||||
if (body.response_format.type) {
|
||||
return {
|
||||
type: body.response_format.type
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
})();
|
||||
|
||||
const stop = body.stop ?? undefined;
|
||||
|
||||
const requestBody: T = {
|
||||
@@ -80,12 +97,7 @@ export const llmCompletionsBodyFormat = <T extends CompletionsBodyType>(
|
||||
})
|
||||
: undefined,
|
||||
...modelData?.defaultConfig,
|
||||
response_format: response_format
|
||||
? {
|
||||
type: response_format,
|
||||
json_schema
|
||||
}
|
||||
: undefined,
|
||||
response_format,
|
||||
stop: stop?.split('|')
|
||||
};
|
||||
|
||||
@@ -123,12 +135,14 @@ export const llmStreamResponseToAnswerText = async (
|
||||
|
||||
// Tool calls
|
||||
if (responseChoice?.tool_calls?.length) {
|
||||
responseChoice.tool_calls.forEach((toolCall) => {
|
||||
const index = toolCall.index;
|
||||
responseChoice.tool_calls.forEach((toolCall, i) => {
|
||||
const index = toolCall.index ?? i;
|
||||
|
||||
if (toolCall.id || callingTool) {
|
||||
// 有 id,代表新 call 工具
|
||||
if (toolCall.id) {
|
||||
// Call new tool
|
||||
const hasNewTool = toolCall?.function?.name || callingTool;
|
||||
if (hasNewTool) {
|
||||
// 有 function name,代表新 call 工具
|
||||
if (toolCall?.function?.name) {
|
||||
callingTool = {
|
||||
name: toolCall.function?.name || '',
|
||||
arguments: toolCall.function?.arguments || ''
|
||||
@@ -209,7 +223,9 @@ export const parseReasoningContent = (text: string): [string, string] => {
|
||||
};
|
||||
|
||||
export const removeDatasetCiteText = (text: string, retainDatasetCite: boolean) => {
|
||||
return retainDatasetCite ? text : text.replace(/\[([a-f0-9]{24})\]\(CITE\)/g, '');
|
||||
return retainDatasetCite
|
||||
? text.replace(/\[id\]\(CITE\)/g, '')
|
||||
: text.replace(/\[([a-f0-9]{24})\](?:\([^\)]*\)?)?/g, '').replace(/\[id\]\(CITE\)/g, '');
|
||||
};
|
||||
|
||||
// Parse llm stream part
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
||||
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
||||
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
||||
import { type ToolType } from '@fastgpt/global/core/app/type';
|
||||
import { type McpToolConfigType } from '@fastgpt/global/core/app/type';
|
||||
import { addLog } from '../../common/system/log';
|
||||
import { retryFn } from '@fastgpt/global/common/system/utils';
|
||||
|
||||
@@ -41,7 +41,7 @@ export class MCPClient {
|
||||
* Get available tools list
|
||||
* @returns List of tools
|
||||
*/
|
||||
public async getTools(): Promise<ToolType[]> {
|
||||
public async getTools(): Promise<McpToolConfigType[]> {
|
||||
try {
|
||||
const client = await this.getConnection();
|
||||
const response = await client.listTools();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { type FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node.d';
|
||||
import { FlowNodeTypeEnum, defaultNodeVersion } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import {
|
||||
appData2FlowNodeIO,
|
||||
pluginData2FlowNodeIO,
|
||||
@@ -14,10 +14,15 @@ import { cloneDeep } from 'lodash';
|
||||
import { MongoApp } from '../schema';
|
||||
import { type SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import { getSystemPluginTemplates } from '../../../../plugins/register';
|
||||
import { getAppLatestVersion, getAppVersionById } from '../version/controller';
|
||||
import {
|
||||
checkIsLatestVersion,
|
||||
getAppLatestVersion,
|
||||
getAppVersionById
|
||||
} from '../version/controller';
|
||||
import { type PluginRuntimeType } from '@fastgpt/global/core/plugin/type';
|
||||
import { MongoSystemPlugin } from './systemPluginSchema';
|
||||
import { PluginErrEnum } from '@fastgpt/global/common/error/code/plugin';
|
||||
import { Types } from 'mongoose';
|
||||
|
||||
/*
|
||||
plugin id rule:
|
||||
@@ -90,20 +95,28 @@ const getSystemPluginTemplateById = async (
|
||||
|
||||
/* Format plugin to workflow preview node data */
|
||||
export async function getChildAppPreviewNode({
|
||||
id
|
||||
appId,
|
||||
versionId
|
||||
}: {
|
||||
id: string;
|
||||
appId: string;
|
||||
versionId?: string;
|
||||
}): Promise<FlowNodeTemplateType> {
|
||||
const app: ChildAppType = await (async () => {
|
||||
const { source, pluginId } = await splitCombinePluginId(id);
|
||||
const { source, pluginId } = await splitCombinePluginId(appId);
|
||||
|
||||
if (source === PluginSourceEnum.personal) {
|
||||
const item = await MongoApp.findById(id).lean();
|
||||
const item = await MongoApp.findById(appId).lean();
|
||||
if (!item) return Promise.reject('plugin not found');
|
||||
|
||||
const version = await getAppLatestVersion(id, item);
|
||||
const version = await getAppVersionById({ appId, versionId, app: item });
|
||||
|
||||
if (!version.versionId) return Promise.reject('App version not found');
|
||||
const isLatest =
|
||||
version.versionId && Types.ObjectId.isValid(version.versionId)
|
||||
? await checkIsLatestVersion({
|
||||
appId,
|
||||
versionId: version.versionId
|
||||
})
|
||||
: true;
|
||||
|
||||
return {
|
||||
id: String(item._id),
|
||||
@@ -118,7 +131,11 @@ export async function getChildAppPreviewNode({
|
||||
chatConfig: version.chatConfig
|
||||
},
|
||||
templateType: FlowNodeTemplateTypeEnum.teamApp,
|
||||
|
||||
version: version.versionId,
|
||||
versionLabel: version?.versionName || '',
|
||||
isLatestVersion: isLatest,
|
||||
|
||||
originCost: 0,
|
||||
currentCost: 0,
|
||||
hasTokenFee: false,
|
||||
@@ -175,7 +192,11 @@ export async function getChildAppPreviewNode({
|
||||
userGuide: app.userGuide,
|
||||
showStatus: app.showStatus,
|
||||
isTool: true,
|
||||
|
||||
version: app.version,
|
||||
versionLabel: app.versionLabel,
|
||||
isLatestVersion: app.isLatestVersion,
|
||||
|
||||
sourceHandle: isToolSet
|
||||
? getHandleConfig(false, false, false, false)
|
||||
: getHandleConfig(true, true, true, true),
|
||||
@@ -224,7 +245,7 @@ export async function getChildAppRuntimeById(
|
||||
templateType: FlowNodeTemplateTypeEnum.teamApp,
|
||||
|
||||
// 用不到
|
||||
version: item?.pluginData?.nodeVersion || defaultNodeVersion,
|
||||
version: item?.pluginData?.nodeVersion,
|
||||
originCost: 0,
|
||||
currentCost: 0,
|
||||
hasTokenFee: false,
|
||||
|
||||
@@ -119,6 +119,7 @@ const AppSchema = new Schema({
|
||||
defaultPermission: Number
|
||||
});
|
||||
|
||||
AppSchema.index({ type: 1 });
|
||||
AppSchema.index({ teamId: 1, updateTime: -1 });
|
||||
AppSchema.index({ teamId: 1, type: 1 });
|
||||
AppSchema.index(
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import { MongoDataset } from '../dataset/schema';
|
||||
import { getEmbeddingModel } from '../ai/model';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import {
|
||||
AppNodeFlowNodeTypeMap,
|
||||
FlowNodeTypeEnum
|
||||
} from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||
import { MongoAppVersion } from './version/schema';
|
||||
import { checkIsLatestVersion } from './version/controller';
|
||||
import { Types } from '../../common/mongo';
|
||||
|
||||
export async function listAppDatasetDataByTeamIdAndDatasetIds({
|
||||
teamId,
|
||||
@@ -35,6 +41,46 @@ export async function rewriteAppWorkflowToDetail({
|
||||
}) {
|
||||
const datasetIdSet = new Set<string>();
|
||||
|
||||
// Add node(App Type) versionlabel and latest sign
|
||||
const appNodes = nodes.filter((node) => AppNodeFlowNodeTypeMap[node.flowNodeType]);
|
||||
const versionIds = appNodes
|
||||
.filter((node) => node.version && Types.ObjectId.isValid(node.version))
|
||||
.map((node) => node.version);
|
||||
|
||||
if (versionIds.length > 0) {
|
||||
const versionDataList = await MongoAppVersion.find(
|
||||
{
|
||||
_id: { $in: versionIds }
|
||||
},
|
||||
'_id versionName appId time'
|
||||
).lean();
|
||||
|
||||
const versionMap: Record<string, any> = {};
|
||||
|
||||
const isLatestChecks = await Promise.all(
|
||||
versionDataList.map(async (version) => {
|
||||
const isLatest = await checkIsLatestVersion({
|
||||
appId: version.appId,
|
||||
versionId: version._id
|
||||
});
|
||||
|
||||
return { versionId: String(version._id), isLatest };
|
||||
})
|
||||
);
|
||||
const isLatestMap = new Map(isLatestChecks.map((item) => [item.versionId, item.isLatest]));
|
||||
versionDataList.forEach((version) => {
|
||||
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
|
||||
nodes.forEach((node) => {
|
||||
if (node.flowNodeType !== FlowNodeTypeEnum.datasetSearchNode) return;
|
||||
|
||||
@@ -15,6 +15,7 @@ export const getAppLatestVersion = async (appId: string, app?: AppSchema) => {
|
||||
if (version) {
|
||||
return {
|
||||
versionId: version._id,
|
||||
versionName: version.versionName,
|
||||
nodes: version.nodes,
|
||||
edges: version.edges,
|
||||
chatConfig: version.chatConfig || app?.chatConfig || {}
|
||||
@@ -22,6 +23,7 @@ export const getAppLatestVersion = async (appId: string, app?: AppSchema) => {
|
||||
}
|
||||
return {
|
||||
versionId: app?.pluginData?.nodeVersion,
|
||||
versionName: app?.name,
|
||||
nodes: app?.modules || [],
|
||||
edges: app?.edges || [],
|
||||
chatConfig: app?.chatConfig || {}
|
||||
@@ -47,6 +49,7 @@ export const getAppVersionById = async ({
|
||||
if (version) {
|
||||
return {
|
||||
versionId: version._id,
|
||||
versionName: version.versionName,
|
||||
nodes: version.nodes,
|
||||
edges: version.edges,
|
||||
chatConfig: version.chatConfig || app?.chatConfig || {}
|
||||
@@ -57,3 +60,22 @@ export const getAppVersionById = async ({
|
||||
// If the version does not exist, the latest version is returned
|
||||
return getAppLatestVersion(appId, app);
|
||||
};
|
||||
|
||||
export const checkIsLatestVersion = async ({
|
||||
appId,
|
||||
versionId
|
||||
}: {
|
||||
appId: string;
|
||||
versionId: string;
|
||||
}) => {
|
||||
const version = await MongoAppVersion.findOne(
|
||||
{
|
||||
appId,
|
||||
isPublish: true,
|
||||
_id: { $gt: versionId }
|
||||
},
|
||||
'_id'
|
||||
).lean();
|
||||
|
||||
return !version;
|
||||
};
|
||||
|
||||
@@ -123,6 +123,7 @@ const DatasetSchema = new Schema({
|
||||
|
||||
try {
|
||||
DatasetSchema.index({ teamId: 1 });
|
||||
DatasetSchema.index({ type: 1 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
@@ -474,7 +474,7 @@ export async function searchDatasetData(
|
||||
).lean()
|
||||
]);
|
||||
|
||||
const set = new Map<string, number>();
|
||||
const set = new Set<string>();
|
||||
const formatResult = results
|
||||
.map((item, index) => {
|
||||
const collection = collections.find((col) => String(col._id) === String(item.collectionId));
|
||||
@@ -507,7 +507,7 @@ export async function searchDatasetData(
|
||||
.filter((item) => {
|
||||
if (!item) return false;
|
||||
if (set.has(item.id)) return false;
|
||||
set.set(item.id, 1);
|
||||
set.add(item.id);
|
||||
return true;
|
||||
})
|
||||
.map((item, index) => {
|
||||
@@ -648,7 +648,17 @@ export async function searchDatasetData(
|
||||
]
|
||||
};
|
||||
})
|
||||
.filter(Boolean) as SearchDataResponseItemType[],
|
||||
.filter((item) => {
|
||||
if (!item) return false;
|
||||
return true;
|
||||
})
|
||||
.map((item, index) => {
|
||||
if (!item) return;
|
||||
return {
|
||||
...item,
|
||||
score: item.score.map((item) => ({ ...item, index }))
|
||||
};
|
||||
}) as SearchDataResponseItemType[],
|
||||
tokenLen: 0
|
||||
};
|
||||
};
|
||||
|
||||
@@ -235,8 +235,10 @@ export const runToolWithFunctionCall = async (
|
||||
max_tokens,
|
||||
top_p: aiChatTopP,
|
||||
stop: aiChatStopSign,
|
||||
response_format: aiChatResponseFormat,
|
||||
json_schema: aiChatJsonSchema
|
||||
response_format: {
|
||||
type: aiChatResponseFormat as any,
|
||||
json_schema: aiChatJsonSchema
|
||||
}
|
||||
},
|
||||
toolModel
|
||||
);
|
||||
|
||||
@@ -47,6 +47,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
||||
query,
|
||||
requestOrigin,
|
||||
chatConfig,
|
||||
lastInteractive,
|
||||
runningUserInfo,
|
||||
externalProvider,
|
||||
params: {
|
||||
@@ -85,18 +86,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
||||
});
|
||||
|
||||
// Check interactive entry
|
||||
const interactiveResponse = (() => {
|
||||
const lastHistory = chatHistories[chatHistories.length - 1];
|
||||
if (isEntry && lastHistory?.obj === ChatRoleEnum.AI) {
|
||||
const lastValue = lastHistory.value[lastHistory.value.length - 1];
|
||||
if (
|
||||
lastValue?.type === ChatItemValueTypeEnum.interactive &&
|
||||
lastValue.interactive?.toolParams
|
||||
) {
|
||||
return lastValue.interactive;
|
||||
}
|
||||
}
|
||||
})();
|
||||
const interactiveResponse = lastInteractive;
|
||||
props.node.isEntry = false;
|
||||
const hasReadFilesTool = toolNodes.some(
|
||||
(item) => item.flowNodeType === FlowNodeTypeEnum.readFiles
|
||||
|
||||
@@ -243,8 +243,10 @@ export const runToolWithPromptCall = async (
|
||||
max_tokens,
|
||||
top_p: aiChatTopP,
|
||||
stop: aiChatStopSign,
|
||||
response_format: aiChatResponseFormat,
|
||||
json_schema: aiChatJsonSchema
|
||||
response_format: {
|
||||
type: aiChatResponseFormat as any,
|
||||
json_schema: aiChatJsonSchema
|
||||
}
|
||||
},
|
||||
toolModel
|
||||
);
|
||||
|
||||
@@ -296,8 +296,10 @@ export const runToolWithToolChoice = async (
|
||||
max_tokens,
|
||||
top_p: aiChatTopP,
|
||||
stop: aiChatStopSign,
|
||||
response_format: aiChatResponseFormat,
|
||||
json_schema: aiChatJsonSchema
|
||||
response_format: {
|
||||
type: aiChatResponseFormat as any,
|
||||
json_schema: aiChatJsonSchema
|
||||
}
|
||||
},
|
||||
toolModel
|
||||
);
|
||||
@@ -721,13 +723,14 @@ async function streamResponse({
|
||||
}
|
||||
// Parse tool calls
|
||||
if (responseChoice?.tool_calls?.length) {
|
||||
responseChoice.tool_calls.forEach((toolCall) => {
|
||||
const index = toolCall.index;
|
||||
responseChoice.tool_calls.forEach((toolCall, i) => {
|
||||
const index = toolCall.index ?? i;
|
||||
|
||||
// Call new tool
|
||||
if (toolCall.id || callingTool) {
|
||||
// 有 id,代表新 call 工具
|
||||
if (toolCall.id) {
|
||||
const hasNewTool = toolCall?.function?.name || callingTool;
|
||||
if (hasNewTool) {
|
||||
// 有 function name,代表新 call 工具
|
||||
if (toolCall?.function?.name) {
|
||||
callingTool = {
|
||||
name: toolCall.function?.name || '',
|
||||
arguments: toolCall.function?.arguments || ''
|
||||
|
||||
@@ -192,8 +192,10 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
||||
max_tokens,
|
||||
top_p: aiChatTopP,
|
||||
stop: aiChatStopSign,
|
||||
response_format: aiChatResponseFormat as any,
|
||||
json_schema: aiChatJsonSchema
|
||||
response_format: {
|
||||
type: aiChatResponseFormat as any,
|
||||
json_schema: aiChatJsonSchema
|
||||
}
|
||||
},
|
||||
modelConstantsData
|
||||
);
|
||||
@@ -462,7 +464,7 @@ async function getChatMessages({
|
||||
aiChatQuoteRole: AiChatQuoteRoleType; // user: replace user prompt; system: replace system prompt
|
||||
datasetQuotePrompt?: string;
|
||||
datasetQuoteText: string;
|
||||
version: string;
|
||||
version?: string;
|
||||
|
||||
useDatasetQuote: boolean;
|
||||
histories: ChatItemType[];
|
||||
|
||||
@@ -268,7 +268,7 @@ export async function dispatchDatasetSearch(
|
||||
nodeDispatchUsages,
|
||||
[DispatchNodeResponseKeyEnum.toolResponses]: {
|
||||
prompt: getDatasetSearchToolResponsePrompt(),
|
||||
quotes: searchRes.map((item) => ({
|
||||
cites: searchRes.map((item) => ({
|
||||
id: item.id,
|
||||
sourceName: item.sourceName,
|
||||
updateTime: item.updateTime,
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
SystemVariablesType
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import type { FlowNodeOutputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import type {
|
||||
AIChatItemValueItemType,
|
||||
ChatHistoryItemResType,
|
||||
@@ -549,7 +550,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
// Skip some special key
|
||||
if (
|
||||
[NodeInputKeyEnum.childrenNodeIdList, NodeInputKeyEnum.httpJsonBody].includes(
|
||||
input.key as any
|
||||
input.key as NodeInputKeyEnum
|
||||
)
|
||||
) {
|
||||
params[input.key] = input.value;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"@xmldom/xmldom": "^0.8.10",
|
||||
"@zilliz/milvus2-sdk-node": "2.4.2",
|
||||
"axios": "^1.8.2",
|
||||
"bullmq": "^5.44.0",
|
||||
"bullmq": "^5.52.2",
|
||||
"chalk": "^5.3.0",
|
||||
"cheerio": "1.0.0-rc.12",
|
||||
"cookie": "^0.7.1",
|
||||
|
||||
@@ -20,6 +20,7 @@ import { type MemberGroupSchemaType } from '@fastgpt/global/support/permission/m
|
||||
import { type TeamMemberSchema } from '@fastgpt/global/support/user/team/type';
|
||||
import { type OrgSchemaType } from '@fastgpt/global/support/user/team/org/type';
|
||||
import { getOrgIdSetWithParentByTmbId } from './org/controllers';
|
||||
import { authUserSession } from '../user/session';
|
||||
|
||||
/** get resource permission for a team member
|
||||
* If there is no permission for the team member, it will return undefined
|
||||
@@ -213,51 +214,6 @@ export const delResourcePermission = ({
|
||||
};
|
||||
|
||||
/* 下面代码等迁移 */
|
||||
/* create token */
|
||||
export function createJWT(user: {
|
||||
_id?: string;
|
||||
team?: { teamId?: string; tmbId: string };
|
||||
isRoot?: boolean;
|
||||
}) {
|
||||
const key = process.env.TOKEN_KEY as string;
|
||||
const token = jwt.sign(
|
||||
{
|
||||
userId: String(user._id),
|
||||
teamId: String(user.team?.teamId),
|
||||
tmbId: String(user.team?.tmbId),
|
||||
isRoot: user.isRoot,
|
||||
exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7
|
||||
},
|
||||
key
|
||||
);
|
||||
return token;
|
||||
}
|
||||
|
||||
// auth token
|
||||
export function authJWT(token: string) {
|
||||
return new Promise<{
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
isRoot: boolean;
|
||||
}>((resolve, reject) => {
|
||||
const key = process.env.TOKEN_KEY as string;
|
||||
|
||||
jwt.verify(token, key, (err, decoded: any) => {
|
||||
if (err || !decoded?.userId) {
|
||||
reject(ERROR_ENUM.unAuthorization);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve({
|
||||
userId: decoded.userId,
|
||||
teamId: decoded.teamId || '',
|
||||
tmbId: decoded.tmbId,
|
||||
isRoot: decoded.isRoot
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function parseHeaderCert({
|
||||
req,
|
||||
@@ -275,7 +231,7 @@ export async function parseHeaderCert({
|
||||
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||
}
|
||||
|
||||
return await authJWT(cookieToken);
|
||||
return authUserSession(cookieToken);
|
||||
}
|
||||
// from authorization get apikey
|
||||
async function parseAuthorization(authorization?: string) {
|
||||
@@ -345,6 +301,7 @@ export async function parseHeaderCert({
|
||||
if (authToken && (token || cookie)) {
|
||||
// user token(from fastgpt web)
|
||||
const res = await authCookieToken(cookie, token);
|
||||
|
||||
return {
|
||||
uid: res.userId,
|
||||
teamId: res.teamId,
|
||||
|
||||
@@ -54,23 +54,50 @@ export const checkTeamDatasetLimit = async (teamId: string) => {
|
||||
})
|
||||
]);
|
||||
|
||||
// User check
|
||||
if (standardConstants && datasetCount >= standardConstants.maxDatasetAmount) {
|
||||
return Promise.reject(TeamErrEnum.datasetAmountNotEnough);
|
||||
}
|
||||
|
||||
// System check
|
||||
if (global?.licenseData?.maxDatasets && typeof global?.licenseData?.maxDatasets === 'number') {
|
||||
const totalDatasets = await MongoDataset.countDocuments({
|
||||
type: { $ne: DatasetTypeEnum.folder }
|
||||
});
|
||||
if (totalDatasets >= global.licenseData.maxDatasets) {
|
||||
return Promise.reject(SystemErrEnum.licenseDatasetAmountLimit);
|
||||
}
|
||||
}
|
||||
// Open source check
|
||||
if (!global.feConfigs.isPlus && datasetCount >= 30) {
|
||||
return Promise.reject(SystemErrEnum.communityVersionNumLimit);
|
||||
}
|
||||
};
|
||||
|
||||
export const checkTeamAppLimit = async (teamId: string, amount = 1) => {
|
||||
const [{ standardConstants }, appCount] = await Promise.all([
|
||||
getTeamStandPlan({ teamId }),
|
||||
MongoApp.countDocuments({
|
||||
teamId,
|
||||
type: { $in: [AppTypeEnum.simple, AppTypeEnum.workflow, AppTypeEnum.plugin] }
|
||||
type: {
|
||||
$in: [AppTypeEnum.simple, AppTypeEnum.workflow, AppTypeEnum.plugin, AppTypeEnum.tool]
|
||||
}
|
||||
})
|
||||
]);
|
||||
|
||||
if (standardConstants && appCount + amount >= standardConstants.maxAppAmount) {
|
||||
return Promise.reject(TeamErrEnum.appAmountNotEnough);
|
||||
}
|
||||
|
||||
// System check
|
||||
if (global?.licenseData?.maxApps && typeof global?.licenseData?.maxApps === 'number') {
|
||||
const totalApps = await MongoApp.countDocuments({
|
||||
type: {
|
||||
$in: [AppTypeEnum.simple, AppTypeEnum.workflow, AppTypeEnum.plugin, AppTypeEnum.tool]
|
||||
}
|
||||
});
|
||||
if (totalApps >= global.licenseData.maxApps) {
|
||||
return Promise.reject(SystemErrEnum.licenseAppAmountLimit);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
63
packages/service/support/user/auth/controller.ts
Normal file
63
packages/service/support/user/auth/controller.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import type { UserAuthTypeEnum } from '@fastgpt/global/support/user/auth/constants';
|
||||
import { MongoUserAuth } from './schema';
|
||||
import { i18nT } from '../../../../web/i18n/utils';
|
||||
import { mongoSessionRun } from '../../../common/mongo/sessionRun';
|
||||
|
||||
export const addAuthCode = async ({
|
||||
key,
|
||||
code,
|
||||
openid,
|
||||
type,
|
||||
expiredTime
|
||||
}: {
|
||||
key: string;
|
||||
code?: string;
|
||||
openid?: string;
|
||||
type: `${UserAuthTypeEnum}`;
|
||||
expiredTime?: Date;
|
||||
}) => {
|
||||
return MongoUserAuth.updateOne(
|
||||
{
|
||||
key,
|
||||
type
|
||||
},
|
||||
{
|
||||
code,
|
||||
openid,
|
||||
expiredTime
|
||||
},
|
||||
{
|
||||
upsert: true
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const authCode = async ({
|
||||
key,
|
||||
type,
|
||||
code
|
||||
}: {
|
||||
key: string;
|
||||
type: `${UserAuthTypeEnum}`;
|
||||
code: string;
|
||||
}) => {
|
||||
return mongoSessionRun(async (session) => {
|
||||
const result = await MongoUserAuth.findOne(
|
||||
{
|
||||
key,
|
||||
type,
|
||||
code: { $regex: new RegExp(`^${code}$`, 'i') }
|
||||
},
|
||||
undefined,
|
||||
{ session }
|
||||
);
|
||||
|
||||
if (!result) {
|
||||
return Promise.reject(i18nT('common:error.code_error'));
|
||||
}
|
||||
|
||||
await result.deleteOne({ session });
|
||||
|
||||
return 'SUCCESS';
|
||||
});
|
||||
};
|
||||
41
packages/service/support/user/auth/schema.ts
Normal file
41
packages/service/support/user/auth/schema.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { connectionMongo, getMongoModel } from '../../../common/mongo';
|
||||
const { Schema } = connectionMongo;
|
||||
import type { UserAuthSchemaType } from '@fastgpt/global/support/user/auth/type';
|
||||
import { userAuthTypeMap } from '@fastgpt/global/support/user/auth/constants';
|
||||
import { addMinutes } from 'date-fns';
|
||||
|
||||
const UserAuthSchema = new Schema({
|
||||
key: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
code: {
|
||||
// auth code
|
||||
type: String,
|
||||
length: 6
|
||||
},
|
||||
// wx openid
|
||||
openid: String,
|
||||
type: {
|
||||
type: String,
|
||||
enum: Object.keys(userAuthTypeMap),
|
||||
required: true
|
||||
},
|
||||
createTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
},
|
||||
expiredTime: {
|
||||
type: Date,
|
||||
default: () => addMinutes(new Date(), 5)
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
UserAuthSchema.index({ key: 1, type: 1 });
|
||||
UserAuthSchema.index({ expiredTime: 1 }, { expireAfterSeconds: 0 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
export const MongoUserAuth = getMongoModel<UserAuthSchemaType>('auth_codes', UserAuthSchema);
|
||||
@@ -3,6 +3,7 @@ const { Schema } = connectionMongo;
|
||||
import { hashStr } from '@fastgpt/global/common/string/tools';
|
||||
import type { UserModelSchema } from '@fastgpt/global/support/user/type';
|
||||
import { UserStatusEnum, userStatusMap } from '@fastgpt/global/support/user/constant';
|
||||
import { TeamMemberCollectionName } from '@fastgpt/global/support/user/team/constant';
|
||||
|
||||
export const userCollectionName = 'users';
|
||||
|
||||
@@ -18,9 +19,7 @@ const UserSchema = new Schema({
|
||||
required: true,
|
||||
unique: true // 唯一
|
||||
},
|
||||
phonePrefix: {
|
||||
type: Number
|
||||
},
|
||||
phonePrefix: Number,
|
||||
password: {
|
||||
type: String,
|
||||
required: true,
|
||||
@@ -28,13 +27,14 @@ const UserSchema = new Schema({
|
||||
get: (val: string) => hashStr(val),
|
||||
select: false
|
||||
},
|
||||
passwordUpdateTime: Date,
|
||||
createTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
},
|
||||
promotionRate: {
|
||||
type: Number,
|
||||
default: 15
|
||||
default: 0
|
||||
},
|
||||
openaiAccount: {
|
||||
type: {
|
||||
@@ -47,7 +47,8 @@ const UserSchema = new Schema({
|
||||
default: 'Asia/Shanghai'
|
||||
},
|
||||
lastLoginTmbId: {
|
||||
type: Schema.Types.ObjectId
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamMemberCollectionName
|
||||
},
|
||||
|
||||
inviterId: {
|
||||
|
||||
179
packages/service/support/user/session.ts
Normal file
179
packages/service/support/user/session.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
import { retryFn } from '@fastgpt/global/common/system/utils';
|
||||
import { getAllKeysByPrefix, getGlobalRedisConnection } from '../../common/redis';
|
||||
import { addLog } from '../../common/system/log';
|
||||
import { ERROR_ENUM } from '@fastgpt/global/common/error/errorCode';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
|
||||
const redisPrefix = 'session:';
|
||||
const getSessionKey = (key: string) => `${redisPrefix}${key}`;
|
||||
|
||||
type SessionType = {
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
isRoot?: boolean;
|
||||
createdAt: number;
|
||||
ip?: string | null;
|
||||
};
|
||||
|
||||
/* Session manager */
|
||||
const setSession = async ({
|
||||
key,
|
||||
data,
|
||||
expireSeconds
|
||||
}: {
|
||||
key: string;
|
||||
data: SessionType;
|
||||
expireSeconds: number;
|
||||
}) => {
|
||||
return await retryFn(async () => {
|
||||
try {
|
||||
const redis = getGlobalRedisConnection();
|
||||
const formatKey = getSessionKey(key);
|
||||
|
||||
// 使用 hmset 存储对象字段
|
||||
await redis.hmset(formatKey, {
|
||||
userId: data.userId,
|
||||
teamId: data.teamId,
|
||||
tmbId: data.tmbId,
|
||||
isRoot: data.isRoot ? '1' : '0',
|
||||
createdAt: data.createdAt.toString(),
|
||||
ip: data.ip
|
||||
});
|
||||
|
||||
// 设置过期时间
|
||||
if (expireSeconds) {
|
||||
await redis.expire(formatKey, expireSeconds);
|
||||
}
|
||||
} catch (error) {
|
||||
addLog.error('Set session error:', error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const delSession = (key: string) => {
|
||||
const redis = getGlobalRedisConnection();
|
||||
retryFn(() => redis.del(getSessionKey(key)));
|
||||
};
|
||||
|
||||
const getSession = async (key: string): Promise<SessionType> => {
|
||||
const formatKey = getSessionKey(key);
|
||||
const redis = getGlobalRedisConnection();
|
||||
|
||||
// 使用 hgetall 获取所有字段
|
||||
const data = await retryFn(() => redis.hgetall(formatKey));
|
||||
|
||||
if (!data || Object.keys(data).length === 0) {
|
||||
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||
}
|
||||
|
||||
try {
|
||||
return {
|
||||
userId: data.userId,
|
||||
teamId: data.teamId,
|
||||
tmbId: data.tmbId,
|
||||
isRoot: data.isRoot === '1',
|
||||
createdAt: parseInt(data.createdAt),
|
||||
ip: data.ip
|
||||
};
|
||||
} catch (error) {
|
||||
addLog.error('Parse session error:', error);
|
||||
delSession(formatKey);
|
||||
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||
}
|
||||
};
|
||||
|
||||
export const delUserAllSession = async (userId: string, whileList?: string[]) => {
|
||||
const formatWhileList = whileList?.map((item) => getSessionKey(item));
|
||||
const redis = getGlobalRedisConnection();
|
||||
const keys = (await getAllKeysByPrefix(`${redisPrefix}${userId}`)).filter(
|
||||
(item) => !formatWhileList?.includes(item)
|
||||
);
|
||||
|
||||
if (keys.length > 0) {
|
||||
await redis.del(keys);
|
||||
}
|
||||
};
|
||||
|
||||
// 会根据创建时间,删除超出客户端登录限制的 session
|
||||
const delRedundantSession = async (userId: string) => {
|
||||
// 至少为 1,默认为 10
|
||||
let maxSession = process.env.MAX_LOGIN_SESSION ? Number(process.env.MAX_LOGIN_SESSION) : 10;
|
||||
if (maxSession < 1) {
|
||||
maxSession = 1;
|
||||
}
|
||||
|
||||
const redis = getGlobalRedisConnection();
|
||||
const keys = await getAllKeysByPrefix(`${redisPrefix}${userId}`);
|
||||
|
||||
if (keys.length <= maxSession) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取所有会话的创建时间
|
||||
const sessionList = await Promise.all(
|
||||
keys.map(async (key) => {
|
||||
try {
|
||||
const data = await redis.hgetall(key);
|
||||
if (!data || Object.keys(data).length === 0) return null;
|
||||
|
||||
return {
|
||||
key,
|
||||
createdAt: parseInt(data.createdAt)
|
||||
};
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// 过滤掉无效数据并按创建时间排序
|
||||
const validSessions = sessionList.filter(Boolean) as { key: string; createdAt: number }[];
|
||||
|
||||
validSessions.sort((a, b) => a.createdAt - b.createdAt);
|
||||
|
||||
// 删除最早创建的会话
|
||||
const delKeys = validSessions.slice(0, validSessions.length - maxSession).map((item) => item.key);
|
||||
|
||||
if (delKeys.length > 0) {
|
||||
await redis.del(delKeys);
|
||||
}
|
||||
};
|
||||
export const createUserSession = async ({
|
||||
userId,
|
||||
teamId,
|
||||
tmbId,
|
||||
isRoot,
|
||||
ip
|
||||
}: {
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
isRoot?: boolean;
|
||||
ip?: string | null;
|
||||
}) => {
|
||||
const key = `${String(userId)}:${getNanoid(32)}`;
|
||||
|
||||
await setSession({
|
||||
key,
|
||||
data: {
|
||||
userId: String(userId),
|
||||
teamId: String(teamId),
|
||||
tmbId: String(tmbId),
|
||||
isRoot,
|
||||
createdAt: new Date().getTime(),
|
||||
ip
|
||||
},
|
||||
expireSeconds: 7 * 24 * 60 * 60
|
||||
});
|
||||
|
||||
delRedundantSession(userId);
|
||||
|
||||
return key;
|
||||
};
|
||||
|
||||
export const authUserSession = async (key: string): Promise<SessionType> => {
|
||||
const data = await getSession(key);
|
||||
return data;
|
||||
};
|
||||
7
packages/service/type.d.ts
vendored
7
packages/service/type.d.ts
vendored
@@ -1,4 +1,8 @@
|
||||
import type { FastGPTFeConfigsType, SystemEnvType } from '@fastgpt/global/common/system/types';
|
||||
import type {
|
||||
FastGPTFeConfigsType,
|
||||
LicenseDataType,
|
||||
SystemEnvType
|
||||
} from '@fastgpt/global/common/system/types';
|
||||
import {
|
||||
TTSModelType,
|
||||
RerankModelItemType,
|
||||
@@ -17,6 +21,7 @@ declare global {
|
||||
var feConfigs: FastGPTFeConfigsType;
|
||||
var systemEnv: SystemEnvType;
|
||||
var subPlans: SubPlanType | undefined;
|
||||
var licenseData: LicenseDataType | undefined;
|
||||
|
||||
var workerPoll: Record<WorkerNameEnum, WorkerPool>;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,24 @@ export const html2md = (
|
||||
turndownService.remove(['i', 'script', 'iframe', 'style']);
|
||||
turndownService.use(turndownPluginGfm.gfm);
|
||||
|
||||
// add custom handling for media tag
|
||||
turndownService.addRule('media', {
|
||||
filter: ['video', 'source', 'audio'],
|
||||
replacement: function (content, node) {
|
||||
const mediaNode = node as HTMLVideoElement | HTMLAudioElement | HTMLSourceElement;
|
||||
const src = mediaNode.getAttribute('src');
|
||||
const sources = mediaNode.getElementsByTagName('source');
|
||||
const firstSourceSrc = sources.length > 0 ? sources[0].getAttribute('src') : null;
|
||||
const mediaSrc = src || firstSourceSrc;
|
||||
|
||||
if (mediaSrc) {
|
||||
return `[${mediaSrc}](${mediaSrc}) `;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
});
|
||||
|
||||
// Base64 img to id, otherwise it will occupy memory when going to md
|
||||
const { processedHtml, images } = processBase64Images(html);
|
||||
const md = turndownService.turndown(processedHtml);
|
||||
|
||||
@@ -6,7 +6,6 @@ import MyTooltip from '../MyTooltip';
|
||||
type Props = FlexProps & {
|
||||
icon: string;
|
||||
size?: string;
|
||||
onClick?: () => void;
|
||||
hoverColor?: string;
|
||||
hoverBg?: string;
|
||||
hoverBorderColor?: string;
|
||||
@@ -41,9 +40,9 @@ const MyIconButton = ({
|
||||
color: hoverColor,
|
||||
borderColor: hoverBorderColor
|
||||
}}
|
||||
onClick={() => {
|
||||
onClick={(e) => {
|
||||
if (isLoading) return;
|
||||
onClick?.();
|
||||
onClick?.(e);
|
||||
}}
|
||||
sx={{ userSelect: 'none' }}
|
||||
{...props}
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
useDisclosure,
|
||||
MenuButton,
|
||||
Box,
|
||||
css,
|
||||
Flex,
|
||||
Input
|
||||
} from '@chakra-ui/react';
|
||||
@@ -25,6 +24,7 @@ import { useRequest2 } from '../../../hooks/useRequest';
|
||||
import MyDivider from '../MyDivider';
|
||||
import type { useScrollPagination } from '../../../hooks/useScrollPagination';
|
||||
import Avatar from '../Avatar';
|
||||
import EmptyTip from '../EmptyTip';
|
||||
|
||||
/** 选择组件 Props 类型
|
||||
* value: 选中的值
|
||||
@@ -32,13 +32,16 @@ import Avatar from '../Avatar';
|
||||
* list: 列表数据
|
||||
* isLoading: 是否加载中
|
||||
* ScrollData: 分页滚动数据控制器 [useScrollPagination] 的返回值
|
||||
* customOnOpen: 自定义打开回调
|
||||
* customOnClose: 自定义关闭回调
|
||||
* */
|
||||
export type SelectProps<T = any> = Omit<ButtonProps, 'onChange'> & {
|
||||
value?: T;
|
||||
valueLabel?: string | React.ReactNode;
|
||||
placeholder?: string;
|
||||
isSearch?: boolean;
|
||||
list: {
|
||||
alias?: string;
|
||||
alias?: string | React.ReactNode;
|
||||
icon?: string;
|
||||
iconSize?: string;
|
||||
label: string | React.ReactNode;
|
||||
@@ -49,18 +52,36 @@ export type SelectProps<T = any> = Omit<ButtonProps, 'onChange'> & {
|
||||
isLoading?: boolean;
|
||||
onChange?: (val: T) => any | Promise<any>;
|
||||
ScrollData?: ReturnType<typeof useScrollPagination>['ScrollData'];
|
||||
customOnOpen?: () => void;
|
||||
customOnClose?: () => void;
|
||||
};
|
||||
|
||||
export const menuItemStyles: MenuItemProps = {
|
||||
borderRadius: 'sm',
|
||||
py: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
_hover: {
|
||||
backgroundColor: 'myGray.100'
|
||||
},
|
||||
_notLast: {
|
||||
mb: 1
|
||||
}
|
||||
};
|
||||
|
||||
const MySelect = <T = any,>(
|
||||
{
|
||||
placeholder,
|
||||
value,
|
||||
valueLabel,
|
||||
isSearch = false,
|
||||
width = '100%',
|
||||
list = [],
|
||||
onChange,
|
||||
isLoading = false,
|
||||
ScrollData,
|
||||
customOnOpen,
|
||||
customOnClose,
|
||||
...props
|
||||
}: SelectProps<T>,
|
||||
ref: ForwardedRef<{
|
||||
@@ -72,21 +93,19 @@ const MySelect = <T = any,>(
|
||||
const SelectedItemRef = useRef<HTMLDivElement>(null);
|
||||
const SearchInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const menuItemStyles: MenuItemProps = {
|
||||
borderRadius: 'sm',
|
||||
py: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
_hover: {
|
||||
backgroundColor: 'myGray.100'
|
||||
},
|
||||
_notLast: {
|
||||
mb: 1
|
||||
}
|
||||
};
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const { isOpen, onOpen: defaultOnOpen, onClose: defaultOnClose } = useDisclosure();
|
||||
const selectItem = useMemo(() => list.find((item) => item.value === value), [list, value]);
|
||||
|
||||
const onOpen = () => {
|
||||
defaultOnOpen();
|
||||
customOnOpen?.();
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
defaultOnClose();
|
||||
customOnClose?.();
|
||||
};
|
||||
|
||||
const [search, setSearch] = useState('');
|
||||
const filterList = useMemo(() => {
|
||||
if (!isSearch || !search) {
|
||||
@@ -105,6 +124,7 @@ const MySelect = <T = any,>(
|
||||
}
|
||||
}));
|
||||
|
||||
// Auto scroll
|
||||
useEffect(() => {
|
||||
if (isOpen && MenuListRef.current && SelectedItemRef.current) {
|
||||
const menu = MenuListRef.current;
|
||||
@@ -117,51 +137,57 @@ const MySelect = <T = any,>(
|
||||
}
|
||||
}, [isSearch, isOpen]);
|
||||
|
||||
const { runAsync: onclickChange, loading } = useRequest2((val: T) => onChange?.(val));
|
||||
const { runAsync: onClickChange, loading } = useRequest2((val: T) => onChange?.(val));
|
||||
|
||||
const ListRender = useMemo(() => {
|
||||
return (
|
||||
<>
|
||||
{filterList.map((item, i) => (
|
||||
<Box key={i}>
|
||||
<MenuItem
|
||||
{...menuItemStyles}
|
||||
{...(value === item.value
|
||||
? {
|
||||
ref: SelectedItemRef,
|
||||
color: 'primary.700',
|
||||
bg: 'myGray.100',
|
||||
fontWeight: '600'
|
||||
{filterList.length > 0 ? (
|
||||
filterList.map((item, i) => (
|
||||
<Box key={i}>
|
||||
<MenuItem
|
||||
{...menuItemStyles}
|
||||
{...(value === item.value
|
||||
? {
|
||||
ref: SelectedItemRef,
|
||||
color: 'primary.700',
|
||||
bg: 'myGray.100',
|
||||
fontWeight: '600'
|
||||
}
|
||||
: {
|
||||
color: 'myGray.900'
|
||||
})}
|
||||
onClick={() => {
|
||||
if (value !== item.value) {
|
||||
onClickChange(item.value);
|
||||
}
|
||||
: {
|
||||
color: 'myGray.900'
|
||||
})}
|
||||
onClick={() => {
|
||||
if (value !== item.value) {
|
||||
onclickChange(item.value);
|
||||
}
|
||||
}}
|
||||
whiteSpace={'pre-wrap'}
|
||||
fontSize={'sm'}
|
||||
display={'block'}
|
||||
mb={0.5}
|
||||
>
|
||||
<Flex alignItems={'center'}>
|
||||
{item.icon && <Avatar mr={2} src={item.icon as any} w={item.iconSize ?? '1rem'} />}
|
||||
{item.label}
|
||||
</Flex>
|
||||
{item.description && (
|
||||
<Box color={'myGray.500'} fontSize={'xs'}>
|
||||
{item.description}
|
||||
</Box>
|
||||
)}
|
||||
</MenuItem>
|
||||
{item.showBorder && <MyDivider my={2} />}
|
||||
</Box>
|
||||
))}
|
||||
}}
|
||||
whiteSpace={'pre-wrap'}
|
||||
fontSize={'sm'}
|
||||
display={'block'}
|
||||
mb={0.5}
|
||||
>
|
||||
<Flex alignItems={'center'}>
|
||||
{item.icon && (
|
||||
<Avatar mr={2} src={item.icon as any} w={item.iconSize ?? '1rem'} />
|
||||
)}
|
||||
{item.label}
|
||||
</Flex>
|
||||
{item.description && (
|
||||
<Box color={'myGray.500'} fontSize={'xs'}>
|
||||
{item.description}
|
||||
</Box>
|
||||
)}
|
||||
</MenuItem>
|
||||
{item.showBorder && <MyDivider my={2} />}
|
||||
</Box>
|
||||
))
|
||||
) : (
|
||||
<EmptyTip py={0} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}, [filterList, value]);
|
||||
}, [filterList, onClickChange, value]);
|
||||
|
||||
const isSelecting = loading || isLoading;
|
||||
|
||||
@@ -200,36 +226,48 @@ const MySelect = <T = any,>(
|
||||
: {})}
|
||||
{...props}
|
||||
>
|
||||
<Flex alignItems={'center'}>
|
||||
{isSelecting && <MyIcon mr={2} name={'common/loading'} w={'1rem'} />}
|
||||
{isSearch && isOpen ? (
|
||||
<Input
|
||||
ref={SearchInputRef}
|
||||
autoFocus
|
||||
variant={'unstyled'}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder={
|
||||
selectItem?.alias ||
|
||||
(typeof selectItem?.label === 'string' ? selectItem?.label : placeholder)
|
||||
}
|
||||
size={'sm'}
|
||||
w={'100%'}
|
||||
color={'myGray.700'}
|
||||
onBlur={() => {
|
||||
setTimeout(() => {
|
||||
SearchInputRef?.current?.focus();
|
||||
}, 0);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{selectItem?.icon && (
|
||||
<Avatar mr={2} src={selectItem.icon as any} w={selectItem.iconSize ?? '1rem'} />
|
||||
)}
|
||||
{selectItem?.alias || selectItem?.label || placeholder}
|
||||
</>
|
||||
)}
|
||||
<Flex alignItems={'center'} justifyContent="space-between" w="100%">
|
||||
<Flex alignItems={'center'}>
|
||||
{isSelecting && <MyIcon mr={2} name={'common/loading'} w={'1rem'} />}
|
||||
{valueLabel ? (
|
||||
<>{valueLabel}</>
|
||||
) : (
|
||||
<>
|
||||
{isSearch && isOpen ? (
|
||||
<Input
|
||||
ref={SearchInputRef}
|
||||
autoFocus
|
||||
variant={'unstyled'}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder={
|
||||
(typeof selectItem?.alias === 'string' ? selectItem?.alias : '') ||
|
||||
(typeof selectItem?.label === 'string' ? selectItem?.label : placeholder)
|
||||
}
|
||||
size={'sm'}
|
||||
w={'100%'}
|
||||
color={'myGray.700'}
|
||||
onBlur={() => {
|
||||
setTimeout(() => {
|
||||
SearchInputRef?.current?.focus();
|
||||
}, 0);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{selectItem?.icon && (
|
||||
<Avatar
|
||||
mr={2}
|
||||
src={selectItem.icon as any}
|
||||
w={selectItem.iconSize ?? '1rem'}
|
||||
/>
|
||||
)}
|
||||
{selectItem?.alias || selectItem?.label || placeholder}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</MenuButton>
|
||||
|
||||
@@ -252,7 +290,7 @@ const MySelect = <T = any,>(
|
||||
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
|
||||
}
|
||||
zIndex={99}
|
||||
maxH={'40vh'}
|
||||
maxH={'45vh'}
|
||||
overflowY={'auto'}
|
||||
>
|
||||
{ScrollData ? <ScrollData>{ListRender}</ScrollData> : ListRender}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useCallback, useRef, useState } from 'react';
|
||||
import React, { useEffect, useCallback, useRef, useState, useMemo } from 'react';
|
||||
import Editor, { type Monaco, loader, useMonaco } from '@monaco-editor/react';
|
||||
import { Box, type BoxProps } from '@chakra-ui/react';
|
||||
import MyIcon from '../../Icon';
|
||||
@@ -169,10 +169,26 @@ const JSONEditor = ({
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
}, []);
|
||||
|
||||
const formatedValue = useMemo(() => {
|
||||
if (typeof value === 'string') {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (value === undefined || value === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
return JSON.stringify(value, null, 2);
|
||||
}
|
||||
|
||||
return String(value);
|
||||
}, [value]);
|
||||
|
||||
const onBlur = useCallback(() => {
|
||||
if (!value) return;
|
||||
if (!formatedValue) return;
|
||||
// replace {{xx}} to true
|
||||
const replaceValue = value?.replace(/{{(.*?)}}/g, 'true');
|
||||
const replaceValue = formatedValue?.replace(/{{(.*?)}}/g, 'true');
|
||||
try {
|
||||
JSON.parse(replaceValue);
|
||||
} catch (error) {
|
||||
@@ -181,7 +197,8 @@ const JSONEditor = ({
|
||||
title: t('common:json_parse_error')
|
||||
});
|
||||
}
|
||||
}, [value]);
|
||||
}, [formatedValue, toast, t]);
|
||||
|
||||
const beforeMount = useCallback((monaco: Monaco) => {
|
||||
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
|
||||
validate: false,
|
||||
@@ -241,7 +258,7 @@ const JSONEditor = ({
|
||||
theme="JSONEditorTheme"
|
||||
beforeMount={beforeMount}
|
||||
defaultValue={defaultValue}
|
||||
value={value}
|
||||
value={formatedValue}
|
||||
onChange={(e) => {
|
||||
onChange?.(e || '');
|
||||
if (!e) {
|
||||
|
||||
@@ -9,12 +9,16 @@ export type UserBoxProps = {
|
||||
sourceMember: SourceMemberType;
|
||||
avatarSize?: string;
|
||||
} & StackProps;
|
||||
|
||||
function UserBox({ sourceMember, avatarSize = '1.25rem', ...props }: UserBoxProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<HStack space="1" {...props}>
|
||||
<Avatar src={sourceMember.avatar} w={avatarSize} />
|
||||
<Box>{sourceMember.name}</Box>
|
||||
<Box maxW={'150px'} whiteSpace={'nowrap'} overflow={'hidden'}>
|
||||
{sourceMember.name}
|
||||
</Box>
|
||||
{sourceMember.status === 'leave' && <Tag color="gray">{t('common:user_leaved')}</Tag>}
|
||||
</HStack>
|
||||
);
|
||||
|
||||
@@ -190,6 +190,7 @@ export function useScrollPagination<
|
||||
params = {},
|
||||
EmptyTip,
|
||||
showErrorToast = true,
|
||||
disalbed = false,
|
||||
...props
|
||||
}: {
|
||||
scrollLoadType?: 'top' | 'bottom';
|
||||
@@ -198,6 +199,7 @@ export function useScrollPagination<
|
||||
params?: Record<string, any>;
|
||||
EmptyTip?: React.JSX.Element;
|
||||
showErrorToast?: boolean;
|
||||
disalbed?: boolean;
|
||||
} & Parameters<typeof useRequest2>[1]
|
||||
) {
|
||||
const { t } = useTranslation();
|
||||
@@ -345,6 +347,7 @@ export function useScrollPagination<
|
||||
// Reload data
|
||||
useRequest2(
|
||||
async () => {
|
||||
if (disalbed) return;
|
||||
loadData(true);
|
||||
},
|
||||
{
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"organization_name": "Organization name",
|
||||
"payment_method": "Payment method",
|
||||
"payway_coupon": "Redeem code",
|
||||
"rerank": "Rerank",
|
||||
"save": "save",
|
||||
"save_failed": "Save exception",
|
||||
"save_success": "Saved successfully",
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"package_usage_rules": "Package usage rules: The system will give priority to using more advanced packages, and the original unused packages will take effect later.",
|
||||
"password": "Password",
|
||||
"password_mismatch": "Password Inconsistency: Two passwords are inconsistent",
|
||||
"password_tip": "Password must be at least 6 characters long and contain at least two combinations: numbers, letters, or special characters",
|
||||
"password_tip": "Password must be at least 8 characters long and contain at least two combinations: numbers, letters, or special characters",
|
||||
"password_update_error": "Exception when changing password",
|
||||
"password_update_success": "Password changed successfully",
|
||||
"pending_usage": "To be used",
|
||||
@@ -55,6 +55,7 @@
|
||||
"please_bind_notification_receiving_path": "Please bind the notification receiving method first",
|
||||
"purchase_extra_package": "Upgrade",
|
||||
"reminder_create_bound_notification_account": "Remind the creator to bind the notification account",
|
||||
"reset_password": "reset password",
|
||||
"resource_usage": "Usages",
|
||||
"select_avatar": "Click to select avatar",
|
||||
"standard_package_and_extra_resource_package": "Includes standard and extra plans",
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
"owner": "owner",
|
||||
"permission": "Permissions",
|
||||
"permission_apikeyCreate": "Create API Key",
|
||||
"permission_apikeyCreate_Tip": "Can create global APIKeys",
|
||||
"permission_apikeyCreate_Tip": "You can create global APIKey and MCP services",
|
||||
"permission_appCreate": "Create Application",
|
||||
"permission_appCreate_tip": "Can create applications in the root directory (creation permissions in folders are controlled by the folder)",
|
||||
"permission_datasetCreate": "Create Knowledge Base",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"Click_to_delete_this_field": "Click to delete this field",
|
||||
"Filed_is_deprecated": "This field is deprecated",
|
||||
"MCP_tools_list_is_empty": "MCP tool not resolved",
|
||||
"MCP_tools_parse_failed": "Failed to parse MCP address",
|
||||
"MCP_tools_url": "MCP Address",
|
||||
@@ -6,7 +8,6 @@
|
||||
"MCP_tools_url_placeholder": "After filling in the MCP address, click Analysis",
|
||||
"Role_setting": "Permission",
|
||||
"Run": "Execute",
|
||||
"team_tags_set": "Team tags",
|
||||
"Team_Tags": "Team tags",
|
||||
"ai_point_price": "Billing",
|
||||
"ai_settings": "AI Configuration",
|
||||
@@ -17,7 +18,6 @@
|
||||
"app.modules.click to update": "Click to Refresh",
|
||||
"app.modules.has new version": "New Version Available",
|
||||
"app.modules.not_found": "Not Found",
|
||||
"app.modules.not_found_tips": "This component cannot be found in the system, please delete it, otherwise the process will not run normally",
|
||||
"app.version_current": "Current Version",
|
||||
"app.version_initial": "Initial Version",
|
||||
"app.version_name_tips": "Version name cannot be empty",
|
||||
@@ -106,6 +106,7 @@
|
||||
"no_mcp_tools_list": "No data yet, the MCP address needs to be parsed first",
|
||||
"node_not_intro": "This node is not introduced",
|
||||
"not_json_file": "Please select a JSON file",
|
||||
"not_the_newest": "Not the latest",
|
||||
"oaste_curl_string": "Enter CURL code",
|
||||
"open_auto_execute": "Enable automatic execution",
|
||||
"open_vision_function_tip": "Models with icon switches have image recognition capabilities. \nAfter being turned on, the model will parse the pictures in the file link and automatically parse the pictures in the user's question (user question ≤ 500 words).",
|
||||
@@ -138,6 +139,7 @@
|
||||
"stop_sign_placeholder": "Multiple serial numbers are separated by |, for example: aaa|stop",
|
||||
"stream_response": "Stream",
|
||||
"stream_response_tip": "Turning this switch off forces the model to use non-streaming mode and will not output content directly. \nIn the output of the AI reply, the content output by this model can be obtained for secondary processing.",
|
||||
"team_tags_set": "Team tags",
|
||||
"temperature": "Temperature",
|
||||
"temperature_tip": "Range 0~10. \nThe larger the value, the more divergent the model’s answer is; the smaller the value, the more rigorous the answer.",
|
||||
"template.hard_strict": "Strict Q&A template",
|
||||
@@ -190,6 +192,7 @@
|
||||
"type.error.Workflow data is empty": "No workflow data was obtained",
|
||||
"type.error.workflowresponseempty": "Response content is empty",
|
||||
"type_not_recognized": "App type not recognized",
|
||||
"un_auth": "No permission",
|
||||
"upload_file_max_amount": "Maximum File Quantity",
|
||||
"upload_file_max_amount_tip": "Maximum number of files uploaded in a single round of conversation",
|
||||
"variable.select type_desc": "You can define a global variable that does not need to be filled in by the user.\n\nThe value of this variable can come from the API interface, the Query of the shared link, or assigned through the [Variable Update] module.",
|
||||
|
||||
@@ -1,7 +1,27 @@
|
||||
{
|
||||
"Action": "Action",
|
||||
"Add": "Add",
|
||||
"Add_new_input": "Add new input",
|
||||
"All": "All",
|
||||
"App": "Application",
|
||||
"Cancel": "Cancel",
|
||||
"Choose": "Choose",
|
||||
"Click_to_expand": "Click to expand",
|
||||
"Close": "Close",
|
||||
"Code": "Code",
|
||||
"Config": "Configuration",
|
||||
"Confirm": "Confirm",
|
||||
"Continue_Adding": "Continue adding",
|
||||
"Copy": "Copy",
|
||||
"Creating": "Creating",
|
||||
"Delete": "Delete",
|
||||
"Detail": "Detail",
|
||||
"Documents": "Documents",
|
||||
"Done": "Done",
|
||||
"Download": "Download",
|
||||
"Edit": "Edit",
|
||||
"Error": "Error",
|
||||
"Exit": "Exit",
|
||||
"Export": "Export",
|
||||
"FAQ.ai_point_a": "Each time an AI model is called, a certain amount of AI points will be consumed. \nFor specific calculation standards, please refer to the \"AI integral calculation standards\" above. \nThe system will give priority to the actual usage returned by the model manufacturer. If it is empty, the calculation method of GPT3.5 is used for estimation. 1Token≈0.7 Chinese characters ≈0.9 English words, and the characters that appear continuously may be considered as 1 Tokens.",
|
||||
"FAQ.ai_point_expire_a": "Yes, they will expire. After the current package expires, the AI points will be reset to the new package's AI points. Annual package AI points are valid for one year, not monthly.",
|
||||
@@ -9,7 +29,7 @@
|
||||
"FAQ.ai_point_q": "What are AI points?",
|
||||
"FAQ.check_subscription_a": "Go to Account - Personal Information - Package Details - Usage. You can view the effective and expiration dates of your subscribed packages. After the paid package expires, it will automatically switch to the free version.",
|
||||
"FAQ.check_subscription_q": "Where can I view my subscribed packages?",
|
||||
"FAQ.dataset_compute_a": "1 Dataset storage equals 1 Dataset index. A piece of Dataset data can contain one or more Dataset indexes. In enhanced training, 1 piece of data generates 5 indexes.",
|
||||
"FAQ.dataset_compute_a": "1 knowledge base storage is equal to 1 knowledge base index. \nA single chunked data usually corresponds to multiple indexes. You can see \"n group indexes\" in a single knowledge base collection.",
|
||||
"FAQ.dataset_compute_q": "How is Dataset storage calculated?",
|
||||
"FAQ.dataset_index_a": "No, but if the Dataset index exceeds the limit, you cannot insert or update Dataset content.",
|
||||
"FAQ.dataset_index_q": "Will the Dataset index be deleted if it exceeds the limit?",
|
||||
@@ -19,36 +39,77 @@
|
||||
"FAQ.package_overlay_q": "Can additional resource packs be stacked?",
|
||||
"FAQ.switch_package_a": "The package usage rule is to prioritize the use of higher-level packages. Therefore, if the newly purchased package is higher than the current package, the new package will take effect immediately; otherwise, the current package will continue to be used.",
|
||||
"FAQ.switch_package_q": "Will the subscription package be switched?",
|
||||
"File": "File",
|
||||
"Finish": "Finish",
|
||||
"Folder": "Folder",
|
||||
"FullScreen": "FullScreen",
|
||||
"FullScreenLight": "FullScreenLight",
|
||||
"Import": "Import",
|
||||
"Input": "Input",
|
||||
"Instructions": "Instruction",
|
||||
"Intro": "Introduction",
|
||||
"Loading": "Loading...",
|
||||
"Login": "Login",
|
||||
"More": "More",
|
||||
"Move": "Move",
|
||||
"Name": "Name",
|
||||
"None": "None",
|
||||
"OK": "OK",
|
||||
"Open": "Open",
|
||||
"Operation": "Operation",
|
||||
"Other": "Other",
|
||||
"Output": "Output",
|
||||
"Params": "Parameters",
|
||||
"Parse": "Analysis",
|
||||
"Permission": "Permission",
|
||||
"Permission_tip": "Individual permissions are greater than group permissions",
|
||||
"Preview": "Preview",
|
||||
"Remove": "Remove",
|
||||
"Rename": "Rename",
|
||||
"Required_input": "Required",
|
||||
"Reset": "Reset",
|
||||
"Restart": "Restart",
|
||||
"Resume": "Resume",
|
||||
"Role": "Permission",
|
||||
"Run": "Run",
|
||||
"Running": "Running",
|
||||
"Save": "Save",
|
||||
"Save_and_exit": "Save and Exit",
|
||||
"Search": "Search",
|
||||
"Select_all": "Select all",
|
||||
"Setting": "Setting",
|
||||
"Status": "Status",
|
||||
"Submit": "Submit",
|
||||
"Success": "Success",
|
||||
"Team": "Team",
|
||||
"UnKnow": "Unknown",
|
||||
"Unlimited": "Unlimited",
|
||||
"Update": "Update",
|
||||
"Username": "Username",
|
||||
"Waiting": "Waiting",
|
||||
"Warning": "Warning",
|
||||
"Website": "Website",
|
||||
"action_confirm": "Confirm",
|
||||
"add_new": "add_new",
|
||||
"add_new_param": "Add new param",
|
||||
"add_success": "Added Successfully",
|
||||
"all_quotes": "All quotes",
|
||||
"templateTags.Image_generation": "Image generation",
|
||||
"templateTags.Office_services": "Office Services",
|
||||
"templateTags.Roleplay": "role play",
|
||||
"templateTags.Web_search": "Search online",
|
||||
"templateTags.Writing": "Writing",
|
||||
"all_result": "Full Results",
|
||||
"app_not_version": "This application has not been published, please publish it first",
|
||||
"back": "Back",
|
||||
"base_config": "Basic Configuration",
|
||||
"bill_already_processed": "Order has been processed",
|
||||
"bill_expired": "Order expired",
|
||||
"bill_not_pay_processed": "Non-online orders",
|
||||
"button.extra_dataset_size_tip": "You are purchasing [Extra Knowledge Base Capacity]",
|
||||
"button.extra_points_tip": "You are purchasing [Extra AI Points]",
|
||||
"can_copy_content_tip": "It is not possible to copy automatically using the browser, please manually copy the following content",
|
||||
"choosable": "Choosable",
|
||||
"chose_condition": "Choose Condition",
|
||||
"chosen": "Chosen",
|
||||
"classification": "Classification",
|
||||
"click_drag_tip": "Click to Drag",
|
||||
"click_select_avatar": "Click to Select Avatar",
|
||||
"click_to_copy": "Click to copy",
|
||||
"click_to_resume": "Click to Resume",
|
||||
"code_editor": "Code Editor",
|
||||
@@ -87,6 +148,9 @@
|
||||
"code_error.plugin_error.not_exist": "Plugin Does Not Exist",
|
||||
"code_error.plugin_error.un_auth": "Unauthorized to Operate This Plugin",
|
||||
"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_dataset_amount_limit": "Exceed the maximum number of knowledge bases in the system",
|
||||
"code_error.system_error.license_user_amount_limit": "Exceed the maximum number of users in the system",
|
||||
"code_error.team_error.ai_points_not_enough": "Insufficient AI Points",
|
||||
"code_error.team_error.app_amount_not_enough": "Application Limit Reached",
|
||||
"code_error.team_error.cannot_delete_default_group": "Cannot delete default group",
|
||||
@@ -116,163 +180,21 @@
|
||||
"code_error.user_error.balance_not_enough": "Insufficient Account Balance",
|
||||
"code_error.user_error.bin_visitor_guest": "You Are Currently a Guest, Unauthorized to Operate",
|
||||
"code_error.user_error.un_auth_user": "User Not Found",
|
||||
"commercial_function_tip": "Please Upgrade to the Commercial Version to Use This Feature: https://doc.fastgpt.cn/docs/commercial/intro/",
|
||||
"Action": "Action",
|
||||
"Add": "Add",
|
||||
"Add Success": "Added Successfully",
|
||||
"Add_new_input": "Add new input",
|
||||
"All": "All",
|
||||
"Cancel": "Cancel",
|
||||
"Choose": "Choose",
|
||||
"Close": "Close",
|
||||
"Code": "Code",
|
||||
"Config": "Configuration",
|
||||
"Confirm": "Confirm",
|
||||
"comfirn_create": "Confirm Creation",
|
||||
"comfirm_import": "comfirm_import",
|
||||
"confirm_move": "Move Here",
|
||||
"confirm_update": "confirm_update",
|
||||
"comfirm_leave_page": "Confirm to Leave This Page?",
|
||||
"Continue_Adding": "Continue adding",
|
||||
"Copy": "Copy",
|
||||
"copy_successful": "Copied Successfully",
|
||||
"create_failed": "Creation Failed",
|
||||
"create_success": "Created Successfully",
|
||||
"create_time": "Creation Time",
|
||||
"Creating": "Creating",
|
||||
"custom_title": "Custom Title",
|
||||
"Delete": "Delete",
|
||||
"delete_failed": "Deletion Failed",
|
||||
"delete_success": "Deleted Successfully",
|
||||
"delete_warning": "Deletion Warning",
|
||||
"delete_folder": "Delete Folder",
|
||||
"Detail": "Detail",
|
||||
"Documents": "Documents",
|
||||
"Done": "Done",
|
||||
"Edit": "Edit",
|
||||
"Error": "Error",
|
||||
"Exit": "Exit",
|
||||
"exit_directly": "exit_directly",
|
||||
"expired_time": "Expiration Time",
|
||||
"File": "File",
|
||||
"Finish": "Finish",
|
||||
"FullScreen": "FullScreen",
|
||||
"FullScreenLight": "FullScreenLight",
|
||||
"Import": "Import",
|
||||
"import_failed": "Import Failed",
|
||||
"import_success": "Imported Successfully",
|
||||
"Input": "Input",
|
||||
"folder_description": "Folder Description",
|
||||
"input_name": "Enter a Name",
|
||||
"Intro": "Introduction",
|
||||
"last_step": "Previous",
|
||||
"last_use_time": "Last Use Time",
|
||||
"load_failed": "load_failed",
|
||||
"Loading": "Loading...",
|
||||
"More": "More",
|
||||
"no_select_data": "No Data Available",
|
||||
"next_step": "Next",
|
||||
"no_more_data": "No More Data",
|
||||
"not_open": "Not Open",
|
||||
"OK": "OK",
|
||||
"Open": "Open",
|
||||
"Other": "Other",
|
||||
"Output": "Output",
|
||||
"Params": "Parameters",
|
||||
"Parse": "Analysis",
|
||||
"psw_inconsistency": "Passwords Do Not Match",
|
||||
"Permission": "Permission",
|
||||
"Permission_tip": "Individual permissions are greater than group permissions",
|
||||
"Please Input Name": "Please Enter a Name",
|
||||
"Preview": "Preview",
|
||||
"read_doc": "Read Document",
|
||||
"Remove": "Remove",
|
||||
"Rename": "Rename",
|
||||
"request_error": "request_error",
|
||||
"Reset": "Reset",
|
||||
"Restart": "Restart",
|
||||
"Role": "Permission",
|
||||
"root_folder": "Root Folder",
|
||||
"Run": "Run",
|
||||
"Save": "Save",
|
||||
"save_failed": "save_failed",
|
||||
"save_success": "Saved Successfully",
|
||||
"Save_and_exit": "Save and Exit",
|
||||
"Search": "Search",
|
||||
"select_file_failed": "File Selection Failed",
|
||||
"select_template": "Select Template",
|
||||
"set_avatar": "Click to set_avatar",
|
||||
"Setting": "Setting",
|
||||
"Status": "Status",
|
||||
"submit_failed": "Submission Failed",
|
||||
"Success": "Success",
|
||||
"sync_success": "Synced Successfully",
|
||||
"Team": "Team",
|
||||
"un_used": "Unused",
|
||||
"UnKnow": "Unknown",
|
||||
"unknow_source": "Unknown Source",
|
||||
"Unlimited": "Unlimited",
|
||||
"Update": "Update",
|
||||
"update_failed": "Update Failed",
|
||||
"update_success": "Updated Successfully",
|
||||
"Username": "Username",
|
||||
"Waiting": "Waiting",
|
||||
"Warning": "Warning",
|
||||
"Website": "Website",
|
||||
"all_result": "Full Results",
|
||||
"click_select_avatar": "Click to Select Avatar",
|
||||
"base_config": "Basic Configuration",
|
||||
"choosable": "Choosable",
|
||||
"action_confirm": "Confirm",
|
||||
"copy_to_clipboard": "Copy to Clipboard",
|
||||
"read_course": "Read Course",
|
||||
"error.unKnow": "An Unexpected Error Occurred",
|
||||
"export_to_json": "Export to JSON",
|
||||
"failed": "Failed",
|
||||
"click_drag_tip": "Click to Drag",
|
||||
"move_success": "Moved Successfully",
|
||||
"move_to": "Move to",
|
||||
"no_child_folder": "No Subdirectories, Place Here",
|
||||
"open_folder": "Open Folder",
|
||||
"folder.empty": "No More Items in This Directory",
|
||||
"folder.open_dataset": "Open Dataset",
|
||||
"have_done": "Completed",
|
||||
"input.Repeat Value": "Duplicate Value",
|
||||
"is_requesting": "Requesting...",
|
||||
"json_parse_error": "Possible JSON Error, Please Check Carefully",
|
||||
"json_config": "JSON Configuration",
|
||||
"link.UnValid": "Invalid Link",
|
||||
"month": "Month",
|
||||
"name_is_empty": "Name Cannot Be Empty",
|
||||
"no_intro": "No Introduction Available",
|
||||
"not_support": "Not Supported",
|
||||
"page_center": "Page Center",
|
||||
"redo_tip": "Redo ctrl shift z",
|
||||
"redo_tip_mac": "Redo ⌘ shift z",
|
||||
"request_end": "All Loaded",
|
||||
"request_more": "Click to Load More",
|
||||
"speech_error_tip": "Speech to Text Failed",
|
||||
"speech_not_support": "Your Browser Does Not Support Speech Input",
|
||||
"submit_success": "Submitted Successfully",
|
||||
"submitted": "Submitted",
|
||||
"support": "Support",
|
||||
"system_help_chatbot": "Help Chatbot",
|
||||
"use_helper": "Use Helper",
|
||||
"ui.textarea.Magnifying": "Magnifying",
|
||||
"undo_tip": "Undo ctrl z",
|
||||
"undo_tip_mac": "Undo ⌘ z ",
|
||||
"upload_file": "Upload File",
|
||||
"zoomin_tip": "Zoom Out ctrl -",
|
||||
"zoomin_tip_mac": "Zoom Out ⌘ -",
|
||||
"zoomout_tip": "Zoom In ctrl +",
|
||||
"zoomout_tip_mac": "Zoom In ⌘ +",
|
||||
"comfirn_create": "Confirm Creation",
|
||||
"commercial_function_tip": "Please Upgrade to the Commercial Version to Use This Feature: https://doc.fastgpt.cn/docs/commercial/intro/",
|
||||
"comon.Continue_Adding": "Continue Adding",
|
||||
"compliance.chat": "The content is generated by third-party AI and cannot be guaranteed to be true and accurate. It is for reference only.",
|
||||
"compliance.compliance.dataset": "Please ensure that your content strictly complies with relevant laws and regulations and avoid containing any illegal or infringing content. \nPlease be careful when uploading materials that may contain sensitive information.",
|
||||
"compliance.dataset": "Please ensure that your content strictly complies with relevant laws and regulations and avoid containing any illegal or infringing content. \nPlease be careful when uploading materials that may contain sensitive information.",
|
||||
"confirm_choice": "Confirm Choice",
|
||||
"confirm_move": "Move Here",
|
||||
"confirm_update": "confirm_update",
|
||||
"contact_way": "Notification Received",
|
||||
"contribute_app_template": "Contribute Template",
|
||||
"copy_successful": "Copied Successfully",
|
||||
"copy_to_clipboard": "Copy to Clipboard",
|
||||
"core.Chat": "Chat",
|
||||
"core.ai.Max context": "Max Context",
|
||||
"core.ai.Model": "Model",
|
||||
@@ -492,7 +414,6 @@
|
||||
"core.chat.response.user_select_result": "User Selection Result",
|
||||
"core.chat.retry": "Regenerate",
|
||||
"core.chat.tts.Stop Speech": "Stop",
|
||||
"core.tip.leave page": "Content has been modified, confirm to leave the page?",
|
||||
"core.dataset.Choose Dataset": "Associate Dataset",
|
||||
"core.dataset.Collection": "Dataset",
|
||||
"core.dataset.Create dataset": "Create a {{name}}",
|
||||
@@ -567,7 +488,6 @@
|
||||
"core.dataset.import.Custom text desc": "Manually enter a piece of text as a dataset",
|
||||
"core.dataset.import.Data process params": "Data Processing Parameters",
|
||||
"core.dataset.import.Down load csv template": "Click to Download CSV Template",
|
||||
"core.dataset.import.import_success": "Import Successful, Please Wait for Training",
|
||||
"core.dataset.import.Link name": "Web Link",
|
||||
"core.dataset.import.Link name placeholder": "Only supports static links. If the data is empty after uploading, the link may not be readable\nEach line one, up to 10 links at a time",
|
||||
"core.dataset.import.Local file": "Local File",
|
||||
@@ -588,6 +508,7 @@
|
||||
"core.dataset.import.Upload status": "Status",
|
||||
"core.dataset.import.Web link": "Web Link",
|
||||
"core.dataset.import.Web link desc": "Read static web page content as a dataset",
|
||||
"core.dataset.import.import_success": "Import Successful, Please Wait for Training",
|
||||
"core.dataset.link": "Link",
|
||||
"core.dataset.search.Dataset Search Params": "Dataset Search Configuration",
|
||||
"core.dataset.search.Empty result response": "Empty Search Response",
|
||||
@@ -769,6 +690,7 @@
|
||||
"core.plugin.Get Plugin Module Detail Failed": "Failed to Retrieve Plugin Information",
|
||||
"core.plugin.Http plugin intro placeholder": "For display only, no actual effect",
|
||||
"core.plugin.cost": "Points Consumption:",
|
||||
"core.tip.leave page": "Content has been modified, confirm to leave the page?",
|
||||
"core.view_chat_detail": "View Chat Details",
|
||||
"core.workflow.Can not delete node": "This Node Cannot Be Deleted",
|
||||
"core.workflow.Change input type tip": "Changing the input type will clear the filled values, please confirm!",
|
||||
@@ -822,12 +744,17 @@
|
||||
"core.workflow.value": "Value",
|
||||
"core.workflow.variable": "Variable",
|
||||
"create": "Create",
|
||||
"create_failed": "Creation Failed",
|
||||
"create_success": "Created Successfully",
|
||||
"create_time": "Creation Time",
|
||||
"cron_job_run_app": "Scheduled Task",
|
||||
"custom_title": "Custom Title",
|
||||
"data_index_custom": "Custom index",
|
||||
"data_index_default": "Default index",
|
||||
"data_index_image": "Image Index",
|
||||
"data_index_question": "Inferred question index",
|
||||
"data_index_summary": "Summary Index",
|
||||
"data_not_found": "Data can't be found",
|
||||
"dataset.Confirm move the folder": "Confirm to Move to This Directory",
|
||||
"dataset.Confirm to delete the data": "Confirm to Delete This Data?",
|
||||
"dataset.Confirm to delete the file": "Confirm to Delete This File and All Its Data?",
|
||||
@@ -872,6 +799,10 @@
|
||||
"dataset_text_model_tip": "Used for text processing in the knowledge base preprocessing stage, such as automatic supplementary indexing, Q&A pair extraction.",
|
||||
"deep_rag_search": "In-depth search",
|
||||
"delete_api": "Are you sure you want to delete this API key? \nAfter deletion, the key will become invalid immediately and the corresponding conversation log will not be deleted. Please confirm!",
|
||||
"delete_failed": "Deletion Failed",
|
||||
"delete_folder": "Delete Folder",
|
||||
"delete_success": "Deleted Successfully",
|
||||
"delete_warning": "Deletion Warning",
|
||||
"embedding_model_not_config": "No index model is detected",
|
||||
"error.Create failed": "Create failed",
|
||||
"error.code_error": "Verification code error",
|
||||
@@ -881,6 +812,7 @@
|
||||
"error.missingParams": "Insufficient parameters",
|
||||
"error.send_auth_code_too_frequently": "Please do not obtain verification code frequently",
|
||||
"error.too_many_request": "Too many request",
|
||||
"error.unKnow": "An Unexpected Error Occurred",
|
||||
"error.upload_file_error_filename": "{{name}} Upload Failed",
|
||||
"error.upload_image_error": "File upload failed",
|
||||
"error.username_empty": "Account cannot be empty",
|
||||
@@ -890,13 +822,23 @@
|
||||
"error_llm_not_config": "Unconfigured file understanding model",
|
||||
"error_un_permission": "No permission to operate",
|
||||
"error_vlm_not_config": "Image comprehension model not configured",
|
||||
"exit_directly": "exit_directly",
|
||||
"expired_time": "Expiration Time",
|
||||
"export_to_json": "Export to JSON",
|
||||
"extraction_results": "Extraction Results",
|
||||
"failed": "Failed",
|
||||
"field_name": "Field Name",
|
||||
"folder.empty": "No More Items in This Directory",
|
||||
"folder.open_dataset": "Open Dataset",
|
||||
"folder_description": "Folder Description",
|
||||
"free": "Free",
|
||||
"get_QR_failed": "Failed to Get QR Code",
|
||||
"get_app_failed": "Failed to Retrieve App",
|
||||
"get_laf_failed": "Failed to Retrieve Laf Function List",
|
||||
"has_verification": "Verified, Click to Unbind",
|
||||
"have_done": "Completed",
|
||||
"import_failed": "Import Failed",
|
||||
"import_success": "Imported Successfully",
|
||||
"info.buy_extra": "Buy Extra Package",
|
||||
"info.csv_download": "Click to Download Batch Test Template",
|
||||
"info.csv_message": "Read the first column of the CSV file for batch testing, supporting up to 100 groups of data at a time.",
|
||||
@@ -908,14 +850,23 @@
|
||||
"info.open_api_notice": "You can fill in the relevant keys of OpenAI/OneAPI. If you fill in this content, the 'AI Chat', 'Question Classification', and 'Content Extraction' on the online platform will use the key you filled in and will not be charged. Please check if your key has access to the corresponding model. GPT models can choose FastAI.",
|
||||
"info.open_api_placeholder": "Request address, default is the official OpenAI. You can fill in the transit address, 'v1' will not be automatically completed",
|
||||
"info.resource": "Resource Usage",
|
||||
"input.Repeat Value": "Duplicate Value",
|
||||
"input_name": "Enter a Name",
|
||||
"invalid_variable": "Invalid Variable",
|
||||
"is_open": "Is Open",
|
||||
"is_requesting": "Requesting...",
|
||||
"is_using": "In Use",
|
||||
"item_description": "Field Description",
|
||||
"item_name": "Field Name",
|
||||
"json_config": "JSON Configuration",
|
||||
"json_parse_error": "Possible JSON Error, Please Check Carefully",
|
||||
"just_now": "just",
|
||||
"key_repetition": "Key Repetition",
|
||||
"last_step": "Previous",
|
||||
"last_use_time": "Last Use Time",
|
||||
"link.UnValid": "Invalid Link",
|
||||
"llm_model_not_config": "No language model was detected",
|
||||
"load_failed": "load_failed",
|
||||
"max_quote_tokens": "Quote cap",
|
||||
"max_quote_tokens_tips": "The maximum number of tokens in a single search, about 1 character in Chinese = 1.7 tokens, and about 1 character in English = 1 token",
|
||||
"mcp_server": "MCP Services",
|
||||
@@ -948,7 +899,11 @@
|
||||
"model_sparkdesk": "SprkDesk",
|
||||
"model_stepfun": "StepFun",
|
||||
"model_yi": "Yi",
|
||||
"month": "Month",
|
||||
"move.confirm": "Confirm move",
|
||||
"move_success": "Moved Successfully",
|
||||
"move_to": "Move to",
|
||||
"name_is_empty": "Name Cannot Be Empty",
|
||||
"navbar.Account": "Account",
|
||||
"navbar.Chat": "Chat",
|
||||
"navbar.Datasets": "Dataset",
|
||||
@@ -956,13 +911,22 @@
|
||||
"navbar.Toolkit": "Toolkit",
|
||||
"navbar.Tools": "Tools",
|
||||
"new_create": "Create New",
|
||||
"next_step": "Next",
|
||||
"no": "No",
|
||||
"no_child_folder": "No Subdirectories, Place Here",
|
||||
"no_intro": "No Introduction Available",
|
||||
"no_laf_env": "System Not Configured with Laf Environment",
|
||||
"no_more_data": "No More Data",
|
||||
"no_pay_way": "There is no suitable payment channel in the system",
|
||||
"no_select_data": "No Data Available",
|
||||
"not_model_config": "No related model configured",
|
||||
"not_open": "Not Open",
|
||||
"not_permission": "The current subscription package does not support team operation logs",
|
||||
"not_support": "Not Supported",
|
||||
"not_yet_introduced": "No Introduction Yet",
|
||||
"open_folder": "Open Folder",
|
||||
"option": "Option",
|
||||
"page_center": "Page Center",
|
||||
"pay.amount": "Amount",
|
||||
"pay.error_desc": "There was a problem when converting payment routes",
|
||||
"pay.noclose": "After payment is completed, please wait for the system to update automatically",
|
||||
@@ -1001,6 +965,7 @@
|
||||
"permission.manager": "administrator",
|
||||
"permission.read": "Read permission",
|
||||
"permission.write": "write permission",
|
||||
"please_input_name": "Please Enter a Name",
|
||||
"plugin.App": "Select App",
|
||||
"plugin.Currentapp": "Current App",
|
||||
"plugin.Description": "Description",
|
||||
@@ -1025,14 +990,34 @@
|
||||
"plugin.path": "Path",
|
||||
"price_over_wx_limit": "Exceed payment provider limit: WeChat Pay only supports less than 6,000 yuan",
|
||||
"prompt_input_placeholder": "Please enter the prompt word",
|
||||
"psw_inconsistency": "Passwords Do Not Match",
|
||||
"question_feedback": "Work order",
|
||||
"read_course": "Read Course",
|
||||
"read_doc": "Read Document",
|
||||
"read_quote": "View citations",
|
||||
"redo_tip": "Redo ctrl shift z",
|
||||
"redo_tip_mac": "Redo ⌘ shift z",
|
||||
"request_end": "All Loaded",
|
||||
"request_error": "request_error",
|
||||
"request_more": "Click to Load More",
|
||||
"required": "Required",
|
||||
"rerank_weight": "Rearrange weights",
|
||||
"resume_failed": "Resume Failed",
|
||||
"root_folder": "Root Folder",
|
||||
"save_failed": "save_failed",
|
||||
"save_success": "Saved Successfully",
|
||||
"scan_code": "Scan the QR code to pay",
|
||||
"select_file_failed": "File Selection Failed",
|
||||
"select_reference_variable": "Select Reference Variable",
|
||||
"select_template": "Select Template",
|
||||
"set_avatar": "Click to set_avatar",
|
||||
"share_link": "Share Link",
|
||||
"speech_error_tip": "Speech to Text Failed",
|
||||
"speech_not_support": "Your Browser Does Not Support Speech Input",
|
||||
"submit_failed": "Submission Failed",
|
||||
"submit_success": "Submitted Successfully",
|
||||
"submitted": "Submitted",
|
||||
"support": "Support",
|
||||
"support.account.Individuation": "Personalization",
|
||||
"support.inform.Read": "Read",
|
||||
"support.openapi.Api baseurl": "API Base URL",
|
||||
@@ -1210,18 +1195,34 @@
|
||||
"support.wallet.usage.Usage Detail": "Usage Details",
|
||||
"support.wallet.usage.Whisper": "Voice Input",
|
||||
"sync_link": "Sync Link",
|
||||
"sync_success": "Synced Successfully",
|
||||
"system.Concat us": "Contact Us",
|
||||
"system.Help Document": "Help Document",
|
||||
"system_help_chatbot": "Help Chatbot",
|
||||
"tag_list": "Tag List",
|
||||
"team_tag": "Team Tag",
|
||||
"templateTags.Image_generation": "Image generation",
|
||||
"templateTags.Office_services": "Office Services",
|
||||
"templateTags.Roleplay": "role play",
|
||||
"templateTags.Web_search": "Search online",
|
||||
"templateTags.Writing": "Writing",
|
||||
"template_market": "Template Market",
|
||||
"textarea_variable_picker_tip": "Enter \"/\" to select a variable",
|
||||
"ui.textarea.Magnifying": "Magnifying",
|
||||
"un_used": "Unused",
|
||||
"unauth_token": "The certificate has expired, please log in again",
|
||||
"undo_tip": "Undo ctrl z",
|
||||
"undo_tip_mac": "Undo ⌘ z ",
|
||||
"unit.character": "Character",
|
||||
"unit.minute": "Minute",
|
||||
"unit.seconds": "Second",
|
||||
"unknow_source": "Unknown Source",
|
||||
"unusable_variable": "No Usable Variables",
|
||||
"update_failed": "Update Failed",
|
||||
"update_success": "Updated Successfully",
|
||||
"upload_file": "Upload File",
|
||||
"upload_file_error": "File Upload Failed",
|
||||
"use_helper": "Use Helper",
|
||||
"user.Account": "Account",
|
||||
"user.Amount of earnings": "Earnings (¥)",
|
||||
"user.Amount of inviter": "Total Number of Invites",
|
||||
@@ -1235,11 +1236,13 @@
|
||||
"user.Laf Account Setting": "Laf Account Configuration",
|
||||
"user.Language": "Language",
|
||||
"user.Member Name": "Nickname",
|
||||
"user.No_right_to_reset_password": "You do not have the right to reset the password",
|
||||
"user.Notification Receive": "Notification Receive",
|
||||
"user.Notification Receive Bind": "Please bind the notification receive method first",
|
||||
"user.Old password is error": "Old Password is Incorrect",
|
||||
"user.OpenAI Account Setting": "OpenAI Account Configuration",
|
||||
"user.Password": "Password",
|
||||
"user.Password has no change": "New password is the same as the old password",
|
||||
"user.Pay": "Recharge",
|
||||
"user.Promotion": "Promotion",
|
||||
"user.Promotion Rate": "Cashback Rate",
|
||||
@@ -1254,12 +1257,16 @@
|
||||
"user.Update password successful": "Password Updated Successfully",
|
||||
"user.apikey.key": "API Key",
|
||||
"user.confirm_password": "Confirm Password",
|
||||
"user.init_password": "Please initialize password",
|
||||
"user.new_password": "New Password",
|
||||
"user.no_invite_records": "No Invite Records",
|
||||
"user.no_notice": "No Notices",
|
||||
"user.no_usage_records": "No Usage Records",
|
||||
"user.old_password": "Old Password",
|
||||
"user.password_message": "Password must be at least 4 characters and at most 60 characters",
|
||||
"user.password_tip": "Password must be at least 8 characters long and contain at least two combinations: numbers, letters, or special characters",
|
||||
"user.reset_password": "Reset Password",
|
||||
"user.reset_password_tip": "The initial password is not set/the password has not been modified for a long time, please reset the password",
|
||||
"user.team.Balance": "Team Balance",
|
||||
"user.team.Check Team": "Switch",
|
||||
"user.team.Confirm Invite": "Confirm Invite",
|
||||
@@ -1299,5 +1306,9 @@
|
||||
"xx_search_result": "{{key}} Search Results",
|
||||
"yes": "Yes",
|
||||
"yesterday": "yesterday",
|
||||
"yesterday_detail_time": "Yesterday {{time}}"
|
||||
"yesterday_detail_time": "Yesterday {{time}}",
|
||||
"zoomin_tip": "Zoom Out ctrl -",
|
||||
"zoomin_tip_mac": "Zoom Out ⌘ -",
|
||||
"zoomout_tip": "Zoom In ctrl +",
|
||||
"zoomout_tip_mac": "Zoom In ⌘ +"
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user