Compare commits

...

13 Commits

Author SHA1 Message Date
f22c22a635 记录个人部署的过程
Some checks failed
Build FastGPT images in Personal warehouse / build-fastgpt-images (push) Has been cancelled
2025-06-09 15:23:09 +08:00
yangxin
59b7c608fd 更改一下systemTitle
Some checks failed
Build FastGPT images in Personal warehouse / build-fastgpt-images (push) Has been cancelled
2025-06-06 21:10:06 +08:00
gggaaallleee
9fb5d05865
add audit (#4923)
* add audit

* update audit

* update audit
2025-06-03 21:28:26 +08:00
dependabot[bot]
b974574157
chore(deps): bump tar-fs in /plugins/webcrawler/SPIDER (#4945)
Bumps [tar-fs](https://github.com/mafintosh/tar-fs) from 3.0.8 to 3.0.9.
- [Commits](https://github.com/mafintosh/tar-fs/compare/v3.0.8...v3.0.9)

---
updated-dependencies:
- dependency-name: tar-fs
  dependency-version: 3.0.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-03 16:02:05 +08:00
gggaaallleee
5a5367d30b
add Bocha search template (#4933)
* add bocha

* Delete packages/service/support/operationLog/util.ts
2025-05-30 21:07:49 +08:00
Archer
8ed35ffe7e
Update dataset.md (#4927) 2025-05-29 18:25:59 +08:00
Archer
0f866fc552
feat: text collecion auto save for a txt file (#4924) 2025-05-29 17:57:27 +08:00
Archer
05c7ba4483
feat: Workflow node search (#4920)
* add node find (#4902)

* add node find

* plugin header

* fix

* fix

* remove

* type

* add searched status

* optimize

* perf: search nodes

---------

Co-authored-by: heheer <heheer@sealos.io>
2025-05-29 14:29:28 +08:00
heheer
fa80ce3a77
fix child app external variables (#4919) 2025-05-29 13:37:59 +08:00
Archer
830358aa72
remove invalid code (#4915) 2025-05-28 22:11:40 +08:00
Archer
02b214b3ec
feat: remove buffer;fix: custom pdf parse (#4914)
* fix: doc

* fix: remove buffer

* fix: pdf parse
2025-05-28 21:48:10 +08:00
Archer
a171c7b11c
perf: buffer;fix: back up split (#4913)
* perf: buffer

* fix: back up split

* fix: app limit

* doc
2025-05-28 18:18:25 +08:00
heheer
802de11363
fix runtool empty message (#4911)
* fix runtool empty message

* del unused code

* fix
2025-05-28 17:48:30 +08:00
103 changed files with 3019 additions and 358 deletions

View File

@ -132,15 +132,15 @@ services:
# fastgpt
sandbox:
container_name: sandbox
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
networks:
- fastgpt
restart: always
fastgpt-mcp-server:
container_name: fastgpt-mcp-server
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
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.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
ports:
- 3000:3000
networks:

View File

@ -109,15 +109,15 @@ services:
# fastgpt
sandbox:
container_name: sandbox
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
networks:
- fastgpt
restart: always
fastgpt-mcp-server:
container_name: fastgpt-mcp-server
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
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.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
ports:
- 3000:3000
networks:

View File

@ -96,15 +96,15 @@ services:
# fastgpt
sandbox:
container_name: sandbox
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
networks:
- fastgpt
restart: always
fastgpt-mcp-server:
container_name: fastgpt-mcp-server
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
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.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
ports:
- 3000:3000
networks:

View File

@ -72,15 +72,15 @@ services:
sandbox:
container_name: sandbox
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
networks:
- fastgpt
restart: always
fastgpt-mcp-server:
container_name: fastgpt-mcp-server
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
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.10 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
ports:
- 3000:3000
networks:

232
dev.md
View File

@ -1,114 +1,118 @@
## Premise
Since FastGPT is managed in the same way as monorepo, it is recommended to install make first during development.
monorepo Project Name:
- app: main project
-......
## Dev
```sh
# Give automatic script code execution permission (on non-Linux systems, you can manually execute the postinstall.sh file content)
chmod -R +x ./scripts/
# Executing under the code root directory installs all dependencies within the root package, projects, and packages
pnpm i
# Not make cmd
cd projects/app
pnpm dev
# Make cmd
make dev name=app
```
Note: If the Node version is >= 20, you need to pass the `--no-node-snapshot` parameter to Node when running `pnpm i`
```sh
NODE_OPTIONS=--no-node-snapshot pnpm i
```
### Jest
https://fael3z0zfze.feishu.cn/docx/ZOI1dABpxoGhS7xzhkXcKPxZnDL
## I18N
### Install i18n-ally Plugin
1. Open the Extensions Marketplace in VSCode, search for and install the `i18n Ally` plugin.
### Code Optimization Examples
#### Fetch Specific Namespace Translations in `getServerSideProps`
```typescript
// pages/yourPage.tsx
export async function getServerSideProps(context: any) {
return {
props: {
currentTab: context?.query?.currentTab || TabEnum.info,
...(await serverSideTranslations(context.locale, ['publish', 'user']))
}
};
}
```
#### Use useTranslation Hook in Page
```typescript
// pages/yourPage.tsx
import { useTranslation } from 'next-i18next';
const YourComponent = () => {
const { t } = useTranslation();
return (
<Button
variant="outline"
size="sm"
mr={2}
onClick={() => setShowSelected(false)}
>
{t('common:close')}
</Button>
);
};
export default YourComponent;
```
#### Handle Static File Translations
```typescript
// utils/i18n.ts
import { i18nT } from '@fastgpt/web/i18n/utils';
const staticContent = {
id: 'simpleChat',
avatar: 'core/workflow/template/aiChat',
name: i18nT('app:template.simple_robot'),
};
export default staticContent;
```
### Standardize Translation Format
- Use the t(namespace:key) format to ensure consistent naming.
- Translation keys should use lowercase letters and underscores, e.g., common.close.
## Build
```sh
# Docker cmd: Build image, not proxy
docker build -f ./projects/app/Dockerfile -t registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 . --build-arg name=app
# Make cmd: Build image, not proxy
make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1
# Docker cmd: Build image with proxy
docker build -f ./projects/app/Dockerfile -t registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 . --build-arg name=app --build-arg proxy=taobao
# Make cmd: Build image with proxy
make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 proxy=taobao
```
## Premise
Since FastGPT is managed in the same way as monorepo, it is recommended to install make first during development.
monorepo Project Name:
- app: main project
-......
## Dev
```sh
# Give automatic script code execution permission (on non-Linux systems, you can manually execute the postinstall.sh file content)
chmod -R +x ./scripts/
# Executing under the code root directory installs all dependencies within the root package, projects, and packages
pnpm i
# Not make cmd
cd projects/app
pnpm dev
# Make cmd
make dev name=app
```
Note: If the Node version is >= 20, you need to pass the `--no-node-snapshot` parameter to Node when running `pnpm i`
```sh
NODE_OPTIONS=--no-node-snapshot pnpm i
```
### Jest
https://fael3z0zfze.feishu.cn/docx/ZOI1dABpxoGhS7xzhkXcKPxZnDL
## I18N
### Install i18n-ally Plugin
1. Open the Extensions Marketplace in VSCode, search for and install the `i18n Ally` plugin.
### Code Optimization Examples
#### Fetch Specific Namespace Translations in `getServerSideProps`
```typescript
// pages/yourPage.tsx
export async function getServerSideProps(context: any) {
return {
props: {
currentTab: context?.query?.currentTab || TabEnum.info,
...(await serverSideTranslations(context.locale, ['publish', 'user']))
}
};
}
```
#### Use useTranslation Hook in Page
```typescript
// pages/yourPage.tsx
import { useTranslation } from 'next-i18next';
const YourComponent = () => {
const { t } = useTranslation();
return (
<Button
variant="outline"
size="sm"
mr={2}
onClick={() => setShowSelected(false)}
>
{t('common:close')}
</Button>
);
};
export default YourComponent;
```
#### Handle Static File Translations
```typescript
// utils/i18n.ts
import { i18nT } from '@fastgpt/web/i18n/utils';
const staticContent = {
id: 'simpleChat',
avatar: 'core/workflow/template/aiChat',
name: i18nT('app:template.simple_robot'),
};
export default staticContent;
```
### Standardize Translation Format
- Use the t(namespace:key) format to ensure consistent naming.
- Translation keys should use lowercase letters and underscores, e.g., common.close.
## audit
Please fill the OperationLogEventEnum and operationLog/audit function is added to the ts, and on the corresponding position to fill i18n, at the same time to add the location of the log using addOpearationLog function add function
## Build
```sh
# Docker cmd: Build image, not proxy
docker build -f ./projects/app/Dockerfile -t registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 . --build-arg name=app
# Make cmd: Build image, not proxy
make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1
# Docker cmd: Build image with proxy
docker build -f ./projects/app/Dockerfile -t registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 . --build-arg name=app --build-arg proxy=taobao
# Make cmd: Build image with proxy
make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 proxy=taobao
```

View File

@ -645,7 +645,7 @@ data 为集合的 ID。
{{< /tab >}}
{{< /tabs >}}
### 创建一个外部文件库集合(商业版
### 创建一个外部文件库集合(弃用
{{< tabs tabTotal="3" >}}
{{< tab tabName="请求示例" >}}

View File

@ -15,8 +15,8 @@ weight: 790
### 2. 更新镜像 tag
- 更新 FastGPT 镜像 tag: v4.9.10
- 更新 FastGPT 商业版镜像 tag: v4.9.10
- 更新 FastGPT 镜像 tag: v4.9.10-fix2
- 更新 FastGPT 商业版镜像 tag: v4.9.10-fix2
- mcp_server 无需更新
- Sandbox 无需更新
- AIProxy 无需更新

View File

@ -10,12 +10,16 @@ weight: 789
## 🚀 新增内容
1. 工作流中,子流程版本控制,可选择“保持最新版本”,无需手动更新。
1. 工作流中增加节点搜索功能。
2. 工作流中,子流程版本控制,可选择“保持最新版本”,无需手动更新。
## ⚙️ 优化
1. 原文缓存改用 gridfs 存储,提高上限。
## 🐛 修复
1. 工作流中,管理员声明的全局系统工具,无法进行版本管理。
1. 工作流中,管理员声明的全局系统工具,无法进行版本管理。
2. 工具调用节点前,有交互节点时,上下文异常。
3. 修复备份导入,小于 1000 字时,无法分块问题。
4. 自定义 PDF 解析,无法保存 base64 图片。

View File

@ -40,5 +40,6 @@ export function getSourceNameIcon({
export const predictDataLimitLength = (mode: TrainingModeEnum, data: any[]) => {
if (mode === TrainingModeEnum.qa) return data.length * 20;
if (mode === TrainingModeEnum.auto) return data.length * 5;
if (mode === TrainingModeEnum.image) return data.length * 2;
return data.length;
};

View File

@ -125,6 +125,7 @@ export type FlowNodeItemType = FlowNodeTemplateType & {
nodeId: string;
parentNodeId?: string;
isError?: boolean;
searchedText?: string;
debugResult?: {
status: 'running' | 'success' | 'skipped' | 'failed';
message?: string;

View File

@ -1,4 +1,5 @@
export enum OperationLogEventEnum {
//Team
LOGIN = 'LOGIN',
CREATE_INVITATION_LINK = 'CREATE_INVITATION_LINK',
JOIN_TEAM = 'JOIN_TEAM',
@ -11,5 +12,52 @@ export enum OperationLogEventEnum {
RELOCATE_DEPARTMENT = 'RELOCATE_DEPARTMENT',
CREATE_GROUP = 'CREATE_GROUP',
DELETE_GROUP = 'DELETE_GROUP',
ASSIGN_PERMISSION = 'ASSIGN_PERMISSION'
ASSIGN_PERMISSION = 'ASSIGN_PERMISSION',
//APP
CREATE_APP = 'CREATE_APP',
UPDATE_APP_INFO = 'UPDATE_APP_INFO',
MOVE_APP = 'MOVE_APP',
DELETE_APP = 'DELETE_APP',
UPDATE_APP_COLLABORATOR = 'UPDATE_APP_COLLABORATOR',
DELETE_APP_COLLABORATOR = 'DELETE_APP_COLLABORATOR',
TRANSFER_APP_OWNERSHIP = 'TRANSFER_APP_OWNERSHIP',
CREATE_APP_COPY = 'CREATE_APP_COPY',
CREATE_APP_FOLDER = 'CREATE_APP_FOLDER',
UPDATE_PUBLISH_APP = 'UPDATE_PUBLISH_APP',
CREATE_APP_PUBLISH_CHANNEL = 'CREATE_APP_PUBLISH_CHANNEL',
UPDATE_APP_PUBLISH_CHANNEL = 'UPDATE_APP_PUBLISH_CHANNEL',
DELETE_APP_PUBLISH_CHANNEL = 'DELETE_APP_PUBLISH_CHANNEL',
EXPORT_APP_CHAT_LOG = 'EXPORT_APP_CHAT_LOG',
//Dataset
CREATE_DATASET = 'CREATE_DATASET',
UPDATE_DATASET = 'UPDATE_DATASET',
DELETE_DATASET = 'DELETE_DATASET',
MOVE_DATASET = 'MOVE_DATASET',
UPDATE_DATASET_COLLABORATOR = 'UPDATE_DATASET_COLLABORATOR',
DELETE_DATASET_COLLABORATOR = 'DELETE_DATASET_COLLABORATOR',
TRANSFER_DATASET_OWNERSHIP = 'TRANSFER_DATASET_OWNERSHIP',
EXPORT_DATASET = 'EXPORT_DATASET',
CREATE_DATASET_FOLDER = 'CREATE_DATASET_FOLDER',
//Collection
CREATE_COLLECTION = 'CREATE_COLLECTION',
UPDATE_COLLECTION = 'UPDATE_COLLECTION',
DELETE_COLLECTION = 'DELETE_COLLECTION',
RETRAIN_COLLECTION = 'RETRAIN_COLLECTION',
//Data
CREATE_DATA = 'CREATE_DATA',
UPDATE_DATA = 'UPDATE_DATA',
DELETE_DATA = 'DELETE_DATA',
//SearchTest
SEARCH_TEST = 'SEARCH_TEST',
//Account
CHANGE_PASSWORD = 'CHANGE_PASSWORD',
CHANGE_NOTIFICATION_SETTINGS = 'CHANGE_NOTIFICATION_SETTINGS',
CHANGE_MEMBER_NAME_ACCOUNT = 'CHANGE_MEMBER_NAME_ACCOUNT',
PURCHASE_PLAN = 'PURCHASE_PLAN',
EXPORT_BILL_RECORDS = 'EXPORT_BILL_RECORDS',
CREATE_INVOICE = 'CREATE_INVOICE',
SET_INVOICE_HEADER = 'SET_INVOICE_HEADER',
CREATE_API_KEY = 'CREATE_API_KEY',
UPDATE_API_KEY = 'UPDATE_API_KEY',
DELETE_API_KEY = 'DELETE_API_KEY'
}

View File

@ -13,6 +13,7 @@ const staticPluginList = [
'WeWorkWebhook',
'google',
'bing',
'bocha',
'delay'
];
// Run in worker thread (Have npm packages)

View File

@ -0,0 +1,677 @@
{
"author": "",
"name": "博查搜索",
"avatar": "core/workflow/template/bocha",
"intro": "使用博查AI搜索引擎进行网络搜索。",
"showStatus": true,
"weight": 10,
"courseUrl": "",
"isTool": true,
"templateType": "search",
"workflow": {
"nodes": [
{
"nodeId": "pluginInput",
"name": "workflow:template.plugin_start",
"intro": "workflow:intro_plugin_input",
"avatar": "core/workflow/template/workflowStart",
"flowNodeType": "pluginInput",
"showStatus": false,
"position": {
"x": 636.3048409085379,
"y": -238.61714728578016
},
"version": "481",
"inputs": [
{
"renderTypeList": [
"input"
],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "apiKey",
"label": "apiKey",
"description": "博查API密钥",
"defaultValue": "",
"required": true
},
{
"renderTypeList": [
"input",
"reference"
],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "query",
"label": "query",
"description": "搜索查询词",
"defaultValue": "",
"required": true,
"toolDescription": "搜索查询词"
},
{
"renderTypeList": [
"input",
"reference"
],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "freshness",
"label": "freshness",
"description": "搜索指定时间范围内的网页。可填值oneDay(一天内)、oneWeek(一周内)、oneMonth(一个月内)、oneYear(一年内)、noLimit(不限,默认)、YYYY-MM-DD..YYYY-MM-DD(日期范围)、YYYY-MM-DD(指定日期)",
"defaultValue": "noLimit",
"required": false,
"toolDescription": "搜索时间范围"
},
{
"renderTypeList": [
"input",
"reference"
],
"selectedTypeIndex": 0,
"valueType": "boolean",
"canEdit": true,
"key": "summary",
"label": "summary",
"description": "是否显示文本摘要。true显示false不显示(默认)",
"defaultValue": false,
"required": false,
"toolDescription": "是否显示文本摘要"
},
{
"renderTypeList": [
"input",
"reference"
],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "include",
"label": "include",
"description": "指定搜索的site范围。多个域名使用|或,分隔最多20个。例如qq.com|m.163.com",
"defaultValue": "",
"required": false,
"toolDescription": "指定搜索的site范围"
},
{
"renderTypeList": [
"input",
"reference"
],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "exclude",
"label": "exclude",
"description": "排除搜索的网站范围。多个域名使用|或,分隔最多20个。例如qq.com|m.163.com",
"defaultValue": "",
"required": false,
"toolDescription": "排除搜索的网站范围"
},
{
"renderTypeList": [
"input",
"reference"
],
"selectedTypeIndex": 0,
"valueType": "number",
"canEdit": true,
"key": "count",
"label": "count",
"description": "返回结果的条数。可填范围1-50默认为10",
"defaultValue": 10,
"required": false,
"min": 1,
"max": 50,
"toolDescription": "返回结果条数"
}
],
"outputs": [
{
"id": "apiKey",
"valueType": "string",
"key": "apiKey",
"label": "apiKey",
"type": "hidden"
},
{
"id": "query",
"valueType": "string",
"key": "query",
"label": "query",
"type": "hidden"
},
{
"id": "freshness",
"valueType": "string",
"key": "freshness",
"label": "freshness",
"type": "hidden"
},
{
"id": "summary",
"valueType": "boolean",
"key": "summary",
"label": "summary",
"type": "hidden"
},
{
"id": "include",
"valueType": "string",
"key": "include",
"label": "include",
"type": "hidden"
},
{
"id": "exclude",
"valueType": "string",
"key": "exclude",
"label": "exclude",
"type": "hidden"
},
{
"id": "count",
"valueType": "number",
"key": "count",
"label": "count",
"type": "hidden"
}
]
},
{
"nodeId": "pluginOutput",
"name": "common:core.module.template.self_output",
"intro": "workflow:intro_custom_plugin_output",
"avatar": "core/workflow/template/pluginOutput",
"flowNodeType": "pluginOutput",
"showStatus": false,
"position": {
"x": 2764.1105686698083,
"y": -30.617147285780163
},
"version": "481",
"inputs": [
{
"renderTypeList": [
"reference"
],
"valueType": "object",
"canEdit": true,
"key": "result",
"label": "result",
"isToolOutput": true,
"description": "",
"value": [
"nyA6oA8mF1iW",
"httpRawResponse"
]
}
],
"outputs": []
},
{
"nodeId": "pluginConfig",
"name": "common:core.module.template.system_config",
"intro": "",
"avatar": "core/workflow/template/systemConfig",
"flowNodeType": "pluginConfig",
"position": {
"x": 184.66337662472682,
"y": -216.05298493910115
},
"version": "4811",
"inputs": [],
"outputs": []
},
{
"nodeId": "nyA6oA8mF1iW",
"name": "HTTP 请求",
"intro": "调用博查搜索API",
"avatar": "core/workflow/template/httpRequest",
"flowNodeType": "httpRequest468",
"showStatus": true,
"position": {
"x": 1335.0647252518884,
"y": -455.9043948565971
},
"version": "481",
"inputs": [
{
"key": "system_addInputParam",
"renderTypeList": [
"addInputParam"
],
"valueType": "dynamic",
"label": "",
"required": false,
"description": "common:core.module.input.description.HTTP Dynamic Input",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectDataset",
"selectApp"
],
"showDescription": false,
"showDefaultValue": true
},
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpMethod",
"renderTypeList": [
"custom"
],
"valueType": "string",
"label": "",
"value": "POST",
"required": true,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpTimeout",
"renderTypeList": [
"custom"
],
"valueType": "number",
"label": "",
"value": 30,
"min": 5,
"max": 600,
"required": true,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpReqUrl",
"renderTypeList": [
"hidden"
],
"valueType": "string",
"label": "",
"description": "common:core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"value": "https://api.bochaai.com/v1/web-search",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpHeader",
"renderTypeList": [
"custom"
],
"valueType": "any",
"value": [
{
"key": "Authorization",
"type": "string",
"value": "Bearer {{$pluginInput.apiKey$}}"
},
{
"key": "Content-Type",
"type": "string",
"value": "application/json"
}
],
"label": "",
"description": "common:core.module.input.description.Http Request Header",
"placeholder": "common:core.module.input.description.Http Request Header",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpParams",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"value": [],
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpJsonBody",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"value": "{\n \"query\": \"{{query}}\",\n \"freshness\": \"{{freshness}}\",\n \"summary\": {{summary}},\n \"include\": \"{{include}}\",\n \"exclude\": \"{{exclude}}\",\n \"count\": {{count}}\n}",
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpFormBody",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"value": [],
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpContentType",
"renderTypeList": [
"hidden"
],
"valueType": "string",
"value": "json",
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"valueType": "string",
"renderTypeList": [
"reference"
],
"key": "query",
"label": "query",
"toolDescription": "博查搜索检索词",
"required": true,
"canEdit": true,
"editField": {
"key": true,
"description": true
},
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"value": [
"pluginInput",
"query"
]
},
{
"valueType": "string",
"renderTypeList": [
"reference"
],
"key": "freshness",
"label": "freshness",
"toolDescription": "搜索时间范围",
"required": false,
"canEdit": true,
"editField": {
"key": true,
"description": true
},
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"value": [
"pluginInput",
"freshness"
]
},
{
"valueType": "boolean",
"renderTypeList": [
"reference"
],
"key": "summary",
"label": "summary",
"toolDescription": "是否显示文本摘要",
"required": false,
"canEdit": true,
"editField": {
"key": true,
"description": true
},
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"value": [
"pluginInput",
"summary"
]
},
{
"valueType": "string",
"renderTypeList": [
"reference"
],
"key": "include",
"label": "include",
"toolDescription": "指定搜索的site范围",
"required": false,
"canEdit": true,
"editField": {
"key": true,
"description": true
},
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"value": [
"pluginInput",
"include"
]
},
{
"valueType": "string",
"renderTypeList": [
"reference"
],
"key": "exclude",
"label": "exclude",
"toolDescription": "排除搜索的网站范围",
"required": false,
"canEdit": true,
"editField": {
"key": true,
"description": true
},
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"value": [
"pluginInput",
"exclude"
]
},
{
"valueType": "number",
"renderTypeList": [
"reference"
],
"key": "count",
"label": "count",
"toolDescription": "返回结果条数",
"required": false,
"canEdit": true,
"editField": {
"key": true,
"description": true
},
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"value": [
"pluginInput",
"count"
]
}
],
"outputs": [
{
"id": "error",
"key": "error",
"label": "workflow:request_error",
"description": "HTTP请求错误信息成功时返回空",
"valueType": "object",
"type": "static"
},
{
"id": "httpRawResponse",
"key": "httpRawResponse",
"required": true,
"label": "workflow:raw_response",
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
"valueType": "any",
"type": "static"
},
{
"id": "system_addOutputParam",
"key": "system_addOutputParam",
"type": "dynamic",
"valueType": "dynamic",
"label": "",
"editField": {
"key": true,
"valueType": true
}
}
]
}
],
"edges": [
{
"source": "pluginInput",
"target": "nyA6oA8mF1iW",
"sourceHandle": "pluginInput-source-right",
"targetHandle": "nyA6oA8mF1iW-target-left"
},
{
"source": "nyA6oA8mF1iW",
"target": "pluginOutput",
"sourceHandle": "nyA6oA8mF1iW-source-right",
"targetHandle": "pluginOutput-target-left"
}
]
},
"chatConfig": {}
}

View File

@ -0,0 +1,178 @@
import { retryFn } from '@fastgpt/global/common/system/utils';
import { connectionMongo } from '../../mongo';
import { MongoRawTextBufferSchema, bucketName } from './schema';
import { addLog } from '../../system/log';
import { setCron } from '../../system/cron';
import { checkTimerLock } from '../../system/timerLock/utils';
import { TimerIdEnum } from '../../system/timerLock/constants';
const getGridBucket = () => {
return new connectionMongo.mongo.GridFSBucket(connectionMongo.connection.db!, {
bucketName: bucketName
});
};
export const addRawTextBuffer = async ({
sourceId,
sourceName,
text,
expiredTime
}: {
sourceId: string;
sourceName: string;
text: string;
expiredTime: Date;
}) => {
const gridBucket = getGridBucket();
const metadata = {
sourceId,
sourceName,
expiredTime
};
const buffer = Buffer.from(text);
const fileSize = buffer.length;
// 单块大小:尽可能大,但不超过 14MB不小于128KB
const chunkSizeBytes = (() => {
// 计算理想块大小:文件大小 ÷ 目标块数(10)。 并且每个块需要小于 14MB
const idealChunkSize = Math.min(Math.ceil(fileSize / 10), 14 * 1024 * 1024);
// 确保块大小至少为128KB
const minChunkSize = 128 * 1024; // 128KB
// 取理想块大小和最小块大小中的较大值
let chunkSize = Math.max(idealChunkSize, minChunkSize);
// 将块大小向上取整到最接近的64KB的倍数使其更整齐
chunkSize = Math.ceil(chunkSize / (64 * 1024)) * (64 * 1024);
return chunkSize;
})();
const uploadStream = gridBucket.openUploadStream(sourceId, {
metadata,
chunkSizeBytes
});
return retryFn(async () => {
return new Promise((resolve, reject) => {
uploadStream.end(buffer);
uploadStream.on('finish', () => {
resolve(uploadStream.id);
});
uploadStream.on('error', (error) => {
addLog.error('addRawTextBuffer error', error);
resolve('');
});
});
});
};
export const getRawTextBuffer = async (sourceId: string) => {
const gridBucket = getGridBucket();
return retryFn(async () => {
const bufferData = await MongoRawTextBufferSchema.findOne(
{
'metadata.sourceId': sourceId
},
'_id metadata'
).lean();
if (!bufferData) {
return null;
}
// Read file content
const downloadStream = gridBucket.openDownloadStream(bufferData._id);
const chunks: Buffer[] = [];
return new Promise<{
text: string;
sourceName: string;
} | null>((resolve, reject) => {
downloadStream.on('data', (chunk) => {
chunks.push(chunk);
});
downloadStream.on('end', () => {
const buffer = Buffer.concat(chunks);
const text = buffer.toString('utf8');
resolve({
text,
sourceName: bufferData.metadata?.sourceName || ''
});
});
downloadStream.on('error', (error) => {
addLog.error('getRawTextBuffer error', error);
resolve(null);
});
});
});
};
export const deleteRawTextBuffer = async (sourceId: string): Promise<boolean> => {
const gridBucket = getGridBucket();
return retryFn(async () => {
const buffer = await MongoRawTextBufferSchema.findOne({ 'metadata.sourceId': sourceId });
if (!buffer) {
return false;
}
await gridBucket.delete(buffer._id);
return true;
});
};
export const updateRawTextBufferExpiredTime = async ({
sourceId,
expiredTime
}: {
sourceId: string;
expiredTime: Date;
}) => {
return retryFn(async () => {
return MongoRawTextBufferSchema.updateOne(
{ 'metadata.sourceId': sourceId },
{ $set: { 'metadata.expiredTime': expiredTime } }
);
});
};
export const clearExpiredRawTextBufferCron = async () => {
const clearExpiredRawTextBuffer = async () => {
addLog.debug('Clear expired raw text buffer start');
const gridBucket = getGridBucket();
return retryFn(async () => {
const data = await MongoRawTextBufferSchema.find(
{
'metadata.expiredTime': { $lt: new Date() }
},
'_id'
).lean();
for (const item of data) {
await gridBucket.delete(item._id);
}
addLog.debug('Clear expired raw text buffer end');
});
};
setCron('*/10 * * * *', async () => {
if (
await checkTimerLock({
timerId: TimerIdEnum.clearExpiredRawTextBuffer,
lockMinuted: 9
})
) {
try {
await clearExpiredRawTextBuffer();
} catch (error) {
addLog.error('clearExpiredRawTextBufferCron error', error);
}
}
});
};

View File

@ -1,33 +1,22 @@
import { getMongoModel, Schema } from '../../mongo';
import { type RawTextBufferSchemaType } from './type';
import { getMongoModel, type Types, Schema } from '../../mongo';
export const collectionName = 'buffer_rawtexts';
export const bucketName = 'buffer_rawtext';
const RawTextBufferSchema = new Schema({
sourceId: {
type: String,
required: true
},
rawText: {
type: String,
default: ''
},
createTime: {
type: Date,
default: () => new Date()
},
metadata: Object
metadata: {
sourceId: { type: String, required: true },
sourceName: { type: String, required: true },
expiredTime: { type: Date, required: true }
}
});
RawTextBufferSchema.index({ 'metadata.sourceId': 'hashed' });
RawTextBufferSchema.index({ 'metadata.expiredTime': -1 });
try {
RawTextBufferSchema.index({ sourceId: 1 });
// 20 minutes
RawTextBufferSchema.index({ createTime: 1 }, { expireAfterSeconds: 20 * 60 });
} catch (error) {
console.log(error);
}
export const MongoRawTextBuffer = getMongoModel<RawTextBufferSchemaType>(
collectionName,
RawTextBufferSchema
);
export const MongoRawTextBufferSchema = getMongoModel<{
_id: Types.ObjectId;
metadata: {
sourceId: string;
sourceName: string;
expiredTime: Date;
};
}>(`${bucketName}.files`, RawTextBufferSchema);

View File

@ -1,8 +0,0 @@
export type RawTextBufferSchemaType = {
sourceId: string;
rawText: string;
createTime: Date;
metadata?: {
filename: string;
};
};

View File

@ -6,13 +6,13 @@ import { type DatasetFileSchema } from '@fastgpt/global/core/dataset/type';
import { MongoChatFileSchema, MongoDatasetFileSchema } from './schema';
import { detectFileEncoding, detectFileEncodingByPath } from '@fastgpt/global/common/file/tools';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { MongoRawTextBuffer } from '../../buffer/rawText/schema';
import { readRawContentByFileBuffer } from '../read/utils';
import { gridFsStream2Buffer, stream2Encoding } from './utils';
import { addLog } from '../../system/log';
import { readFromSecondary } from '../../mongo/utils';
import { parseFileExtensionFromUrl } from '@fastgpt/global/common/string/tools';
import { Readable } from 'stream';
import { addRawTextBuffer, getRawTextBuffer } from '../../buffer/rawText/controller';
import { addMinutes } from 'date-fns';
export function getGFSCollection(bucket: `${BucketNameEnum}`) {
MongoDatasetFileSchema;
@ -223,15 +223,13 @@ export const readFileContentFromMongo = async ({
rawText: string;
filename: string;
}> => {
const bufferId = `${fileId}-${customPdfParse}`;
const bufferId = `${String(fileId)}-${customPdfParse}`;
// read buffer
const fileBuffer = await MongoRawTextBuffer.findOne({ sourceId: bufferId }, undefined, {
...readFromSecondary
}).lean();
const fileBuffer = await getRawTextBuffer(bufferId);
if (fileBuffer) {
return {
rawText: fileBuffer.rawText,
filename: fileBuffer.metadata?.filename || ''
rawText: fileBuffer.text,
filename: fileBuffer?.sourceName
};
}
@ -265,16 +263,13 @@ export const readFileContentFromMongo = async ({
}
});
// < 14M
if (fileBuffers.length < 14 * 1024 * 1024 && rawText.trim()) {
MongoRawTextBuffer.create({
sourceId: bufferId,
rawText,
metadata: {
filename: file.filename
}
});
}
// Add buffer
addRawTextBuffer({
sourceId: bufferId,
sourceName: file.filename,
text: rawText,
expiredTime: addMinutes(new Date(), 20)
});
return {
rawText,

View File

@ -1,16 +1,16 @@
import { Schema, getMongoModel } from '../../mongo';
const DatasetFileSchema = new Schema({});
const ChatFileSchema = new Schema({});
const DatasetFileSchema = new Schema({
metadata: Object
});
const ChatFileSchema = new Schema({
metadata: Object
});
try {
DatasetFileSchema.index({ uploadDate: -1 });
DatasetFileSchema.index({ uploadDate: -1 });
ChatFileSchema.index({ uploadDate: -1 });
ChatFileSchema.index({ 'metadata.chatId': 1 });
} catch (error) {
console.log(error);
}
ChatFileSchema.index({ uploadDate: -1 });
ChatFileSchema.index({ 'metadata.chatId': 1 });
export const MongoDatasetFileSchema = getMongoModel('dataset.files', DatasetFileSchema);
export const MongoChatFileSchema = getMongoModel('chat.files', ChatFileSchema);

View File

@ -1,5 +1,57 @@
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
import { PassThrough } from 'stream';
import { getGridBucket } from './controller';
import { type BucketNameEnum } from '@fastgpt/global/common/file/constants';
import { retryFn } from '@fastgpt/global/common/system/utils';
export const createFileFromText = async ({
bucket,
filename,
text,
metadata
}: {
bucket: `${BucketNameEnum}`;
filename: string;
text: string;
metadata: Record<string, any>;
}) => {
const gridBucket = getGridBucket(bucket);
const buffer = Buffer.from(text);
const fileSize = buffer.length;
// 单块大小:尽可能大,但不超过 14MB不小于128KB
const chunkSizeBytes = (() => {
// 计算理想块大小:文件大小 ÷ 目标块数(10)。 并且每个块需要小于 14MB
const idealChunkSize = Math.min(Math.ceil(fileSize / 10), 14 * 1024 * 1024);
// 确保块大小至少为128KB
const minChunkSize = 128 * 1024; // 128KB
// 取理想块大小和最小块大小中的较大值
let chunkSize = Math.max(idealChunkSize, minChunkSize);
// 将块大小向上取整到最接近的64KB的倍数使其更整齐
chunkSize = Math.ceil(chunkSize / (64 * 1024)) * (64 * 1024);
return chunkSize;
})();
const uploadStream = gridBucket.openUploadStream(filename, {
metadata,
chunkSizeBytes
});
return retryFn(async () => {
return new Promise<{ fileId: string }>((resolve, reject) => {
uploadStream.end(buffer);
uploadStream.on('finish', () => {
resolve({ fileId: String(uploadStream.id) });
});
uploadStream.on('error', reject);
});
});
};
export const gridFsStream2Buffer = (stream: NodeJS.ReadableStream) => {
return new Promise<Buffer>((resolve, reject) => {

View File

@ -110,7 +110,7 @@ export const readRawContentByFileBuffer = async ({
return {
rawText: text,
formatText: rawText,
formatText: text,
imageList
};
};

View File

@ -5,7 +5,8 @@ export enum TimerIdEnum {
clearExpiredSubPlan = 'clearExpiredSubPlan',
updateStandardPlan = 'updateStandardPlan',
scheduleTriggerApp = 'scheduleTriggerApp',
notification = 'notification'
notification = 'notification',
clearExpiredRawTextBuffer = 'clearExpiredRawTextBuffer'
}
export enum LockNotificationEnum {

View File

@ -77,7 +77,10 @@ export const createCollectionAndInsertData = async ({
const chunkSplitter = computeChunkSplitter(createCollectionParams);
const paragraphChunkDeep = computeParagraphChunkDeep(createCollectionParams);
if (trainingType === DatasetCollectionDataProcessModeEnum.qa) {
if (
trainingType === DatasetCollectionDataProcessModeEnum.qa ||
trainingType === DatasetCollectionDataProcessModeEnum.backup
) {
delete createCollectionParams.chunkTriggerType;
delete createCollectionParams.chunkTriggerMinSize;
delete createCollectionParams.dataEnhanceCollectionName;

View File

@ -218,6 +218,10 @@ export const rawText2Chunks = ({
};
};
if (backupParse) {
return parseDatasetBackup2Chunks(rawText).chunks;
}
// Chunk condition
// 1. 选择最大值条件,只有超过了最大值(默认为模型的最大值*0.7),才会触发分块
if (chunkTriggerType === ChunkTriggerConfigTypeEnum.maxSize) {
@ -240,10 +244,6 @@ export const rawText2Chunks = ({
}
}
if (backupParse) {
return parseDatasetBackup2Chunks(rawText).chunks;
}
const { chunks } = splitText2Chunks({
text: rawText,
chunkSize,

View File

@ -86,7 +86,6 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
});
// Check interactive entry
const interactiveResponse = lastInteractive;
props.node.isEntry = false;
const hasReadFilesTool = toolNodes.some(
(item) => item.flowNodeType === FlowNodeTypeEnum.readFiles
@ -143,7 +142,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
})
}
];
if (interactiveResponse) {
if (lastInteractive && isEntry) {
return value.slice(0, -2);
}
return value;
@ -183,7 +182,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
toolModel,
maxRunToolTimes: 30,
messages: adaptMessages,
interactiveEntryToolParams: interactiveResponse?.toolParams
interactiveEntryToolParams: lastInteractive?.toolParams
});
}
if (toolModel.functionCall) {
@ -194,7 +193,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
toolNodes,
toolModel,
messages: adaptMessages,
interactiveEntryToolParams: interactiveResponse?.toolParams
interactiveEntryToolParams: lastInteractive?.toolParams
});
}
@ -224,7 +223,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
toolNodes,
toolModel,
messages: adaptMessages,
interactiveEntryToolParams: interactiveResponse?.toolParams
interactiveEntryToolParams: lastInteractive?.toolParams
});
})();

View File

@ -11,7 +11,6 @@ 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,

View File

@ -17,6 +17,7 @@ import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
import { getPluginRunUserQuery } from '@fastgpt/global/core/workflow/utils';
import { getPluginInputsFromStoreNodes } from '@fastgpt/global/core/app/plugin/utils';
import type { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { getUserChatInfoAndAuthTeamPoints } from '../../../../support/permission/auth/team';
type RunPluginProps = ModuleDispatchProps<{
[NodeInputKeyEnum.forbidStream]?: boolean;
@ -73,9 +74,11 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
};
});
const { externalProvider } = await getUserChatInfoAndAuthTeamPoints(runningAppInfo.tmbId);
const runtimeVariables = {
...filterSystemVariables(props.variables),
appId: String(plugin.id)
appId: String(plugin.id),
...(externalProvider ? externalProvider.externalWorkflowVariables : {})
};
const { flowResponses, flowUsages, assistantResponses, runTimes } = await dispatchWorkFlow({
...props,

View File

@ -20,6 +20,7 @@ import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { getAppVersionById } from '../../../app/version/controller';
import { parseUrlToFileType } from '@fastgpt/global/common/file/tools';
import { type ChildrenInteractive } from '@fastgpt/global/core/workflow/template/system/interactive/type';
import { getUserChatInfoAndAuthTeamPoints } from '../../../../support/permission/auth/team';
type Props = ModuleDispatchProps<{
[NodeInputKeyEnum.userChatInput]: string;
@ -97,11 +98,13 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
// Rewrite children app variables
const systemVariables = filterSystemVariables(variables);
const { externalProvider } = await getUserChatInfoAndAuthTeamPoints(appData.tmbId);
const childrenRunVariables = {
...systemVariables,
...childrenAppVariables,
histories: chatHistories,
appId: String(appData._id)
appId: String(appData._id),
...(externalProvider ? externalProvider.externalWorkflowVariables : {})
};
const childrenInteractive =

View File

@ -5,8 +5,6 @@ import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { type DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
import axios from 'axios';
import { serverRequestBaseUrl } from '../../../../common/api/serverRequest';
import { MongoRawTextBuffer } from '../../../../common/buffer/rawText/schema';
import { readFromSecondary } from '../../../../common/mongo/utils';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { detectFileEncoding, parseUrlToFileType } from '@fastgpt/global/common/file/tools';
import { readRawContentByFileBuffer } from '../../../../common/file/read/utils';
@ -14,6 +12,8 @@ import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { type ChatItemType, type UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
import { parseFileExtensionFromUrl } from '@fastgpt/global/common/string/tools';
import { addLog } from '../../../../common/system/log';
import { addRawTextBuffer, getRawTextBuffer } from '../../../../common/buffer/rawText/controller';
import { addMinutes } from 'date-fns';
type Props = ModuleDispatchProps<{
[NodeInputKeyEnum.fileUrlList]: string[];
@ -158,14 +158,12 @@ export const getFileContentFromLinks = async ({
parseUrlList
.map(async (url) => {
// Get from buffer
const fileBuffer = await MongoRawTextBuffer.findOne({ sourceId: url }, undefined, {
...readFromSecondary
}).lean();
const fileBuffer = await getRawTextBuffer(url);
if (fileBuffer) {
return formatResponseObject({
filename: fileBuffer.metadata?.filename || url,
filename: fileBuffer.sourceName || url,
url,
content: fileBuffer.rawText
content: fileBuffer.text
});
}
@ -220,17 +218,12 @@ export const getFileContentFromLinks = async ({
});
// Add to buffer
try {
if (buffer.length < 14 * 1024 * 1024 && rawText.trim()) {
MongoRawTextBuffer.create({
sourceId: url,
rawText,
metadata: {
filename: filename
}
});
}
} catch (error) {}
addRawTextBuffer({
sourceId: url,
sourceName: filename,
text: rawText,
expiredTime: addMinutes(new Date(), 20)
});
return formatResponseObject({ filename, url, content: rawText });
} catch (error) {

View File

@ -2,6 +2,7 @@ import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/cons
import { i18nT } from '../../../web/i18n/utils';
export const operationLogMap = {
//Team
[OperationLogEventEnum.LOGIN]: {
content: i18nT('account_team:log_login'),
typeLabel: i18nT('account_team:login'),
@ -66,6 +67,309 @@ export const operationLogMap = {
content: i18nT('account_team:log_assign_permission'),
typeLabel: i18nT('account_team:assign_permission'),
params: {} as { name?: string; objectName: string; permission: string }
},
//APP
[OperationLogEventEnum.CREATE_APP]: {
content: i18nT('account_team:log_create_app'),
typeLabel: i18nT('account_team:create_app'),
params: {} as { name?: string; appName: string; appType: string }
},
[OperationLogEventEnum.UPDATE_APP_INFO]: {
content: i18nT('account_team:log_update_app_info'),
typeLabel: i18nT('account_team:update_app_info'),
params: {} as {
name?: string;
appName: string;
newItemNames: string[];
newItemValues: string[];
appType: string;
}
},
[OperationLogEventEnum.MOVE_APP]: {
content: i18nT('account_team:log_move_app'),
typeLabel: i18nT('account_team:move_app'),
params: {} as { name?: string; appName: string; targetFolderName: string; appType: string }
},
[OperationLogEventEnum.DELETE_APP]: {
content: i18nT('account_team:log_delete_app'),
typeLabel: i18nT('account_team:delete_app'),
params: {} as { name?: string; appName: string; appType: string }
},
[OperationLogEventEnum.UPDATE_APP_COLLABORATOR]: {
content: i18nT('account_team:log_update_app_collaborator'),
typeLabel: i18nT('account_team:update_app_collaborator'),
params: {} as {
name?: string;
appName: string;
appType: string;
tmbList: string[];
groupList: string[];
orgList: string[];
permission: string;
}
},
[OperationLogEventEnum.DELETE_APP_COLLABORATOR]: {
content: i18nT('account_team:log_delete_app_collaborator'),
typeLabel: i18nT('account_team:delete_app_collaborator'),
params: {} as {
name?: string;
appName: string;
appType: string;
itemName: string;
itemValueName: string;
}
},
[OperationLogEventEnum.TRANSFER_APP_OWNERSHIP]: {
content: i18nT('account_team:log_transfer_app_ownership'),
typeLabel: i18nT('account_team:transfer_app_ownership'),
params: {} as {
name?: string;
appName: string;
appType: string;
oldOwnerName: string;
newOwnerName: string;
}
},
[OperationLogEventEnum.CREATE_APP_COPY]: {
content: i18nT('account_team:log_create_app_copy'),
typeLabel: i18nT('account_team:create_app_copy'),
params: {} as { name?: string; appName: string; appType: string }
},
[OperationLogEventEnum.CREATE_APP_FOLDER]: {
content: i18nT('account_team:log_create_app_folder'),
typeLabel: i18nT('account_team:create_app_folder'),
params: {} as { name?: string; folderName: string }
},
[OperationLogEventEnum.UPDATE_PUBLISH_APP]: {
content: i18nT('account_team:log_update_publish_app'),
typeLabel: i18nT('account_team:update_publish_app'),
params: {} as {
name?: string;
operationName: string;
appName: string;
appId: string;
appType: string;
}
},
[OperationLogEventEnum.CREATE_APP_PUBLISH_CHANNEL]: {
content: i18nT('account_team:log_create_app_publish_channel'),
typeLabel: i18nT('account_team:create_app_publish_channel'),
params: {} as { name?: string; appName: string; channelName: string; appType: string }
},
[OperationLogEventEnum.UPDATE_APP_PUBLISH_CHANNEL]: {
content: i18nT('account_team:log_update_app_publish_channel'),
typeLabel: i18nT('account_team:update_app_publish_channel'),
params: {} as { name?: string; appName: string; channelName: string; appType: string }
},
[OperationLogEventEnum.DELETE_APP_PUBLISH_CHANNEL]: {
content: i18nT('account_team:log_delete_app_publish_channel'),
typeLabel: i18nT('account_team:delete_app_publish_channel'),
params: {} as { name?: string; appName: string; channelName: string; appType: string }
},
[OperationLogEventEnum.EXPORT_APP_CHAT_LOG]: {
content: i18nT('account_team:log_export_app_chat_log'),
typeLabel: i18nT('account_team:export_app_chat_log'),
params: {} as { name?: string; appName: string; appType: string }
},
//Dataset
[OperationLogEventEnum.CREATE_DATASET]: {
content: i18nT('account_team:log_create_dataset'),
typeLabel: i18nT('account_team:create_dataset'),
params: {} as { name?: string; datasetName: string; datasetType: string }
},
[OperationLogEventEnum.UPDATE_DATASET]: {
content: i18nT('account_team:log_update_dataset'),
typeLabel: i18nT('account_team:update_dataset'),
params: {} as { name?: string; datasetName: string; datasetType: string }
},
[OperationLogEventEnum.DELETE_DATASET]: {
content: i18nT('account_team:log_delete_dataset'),
typeLabel: i18nT('account_team:delete_dataset'),
params: {} as { name?: string; datasetName: string; datasetType: string }
},
[OperationLogEventEnum.MOVE_DATASET]: {
content: i18nT('account_team:log_move_dataset'),
typeLabel: i18nT('account_team:move_dataset'),
params: {} as {
name?: string;
datasetName: string;
targetFolderName: string;
datasetType: string;
}
},
[OperationLogEventEnum.UPDATE_DATASET_COLLABORATOR]: {
content: i18nT('account_team:log_update_dataset_collaborator'),
typeLabel: i18nT('account_team:update_dataset_collaborator'),
params: {} as {
name?: string;
datasetName: string;
datasetType: string;
tmbList: string[];
groupList: string[];
orgList: string[];
permission: string;
}
},
[OperationLogEventEnum.DELETE_DATASET_COLLABORATOR]: {
content: i18nT('account_team:log_delete_dataset_collaborator'),
typeLabel: i18nT('account_team:delete_dataset_collaborator'),
params: {} as {
name?: string;
datasetName: string;
datasetType: string;
itemName: string;
itemValueName: string;
}
},
[OperationLogEventEnum.TRANSFER_DATASET_OWNERSHIP]: {
content: i18nT('account_team:log_transfer_dataset_ownership'),
typeLabel: i18nT('account_team:transfer_dataset_ownership'),
params: {} as {
name?: string;
datasetName: string;
datasetType: string;
oldOwnerName: string;
newOwnerName: string;
}
},
[OperationLogEventEnum.EXPORT_DATASET]: {
content: i18nT('account_team:log_export_dataset'),
typeLabel: i18nT('account_team:export_dataset'),
params: {} as { name?: string; datasetName: string; datasetType: string }
},
[OperationLogEventEnum.CREATE_DATASET_FOLDER]: {
content: i18nT('account_team:log_create_dataset_folder'),
typeLabel: i18nT('account_team:create_dataset_folder'),
params: {} as { name?: string; folderName: string }
},
//Collection
[OperationLogEventEnum.CREATE_COLLECTION]: {
content: i18nT('account_team:log_create_collection'),
typeLabel: i18nT('account_team:create_collection'),
params: {} as {
name?: string;
collectionName: string;
datasetName: string;
datasetType: string;
}
},
[OperationLogEventEnum.UPDATE_COLLECTION]: {
content: i18nT('account_team:log_update_collection'),
typeLabel: i18nT('account_team:update_collection'),
params: {} as {
name?: string;
collectionName: string;
datasetName: string;
datasetType: string;
}
},
[OperationLogEventEnum.DELETE_COLLECTION]: {
content: i18nT('account_team:log_delete_collection'),
typeLabel: i18nT('account_team:delete_collection'),
params: {} as {
name?: string;
collectionName: string;
datasetName: string;
datasetType: string;
}
},
[OperationLogEventEnum.RETRAIN_COLLECTION]: {
content: i18nT('account_team:log_retrain_collection'),
typeLabel: i18nT('account_team:retrain_collection'),
params: {} as {
name?: string;
collectionName: string;
datasetName: string;
datasetType: string;
}
},
//Data
[OperationLogEventEnum.CREATE_DATA]: {
content: i18nT('account_team:log_create_data'),
typeLabel: i18nT('account_team:create_data'),
params: {} as {
name?: string;
collectionName: string;
datasetName: string;
datasetType: string;
}
},
[OperationLogEventEnum.UPDATE_DATA]: {
content: i18nT('account_team:log_update_data'),
typeLabel: i18nT('account_team:update_data'),
params: {} as {
name?: string;
collectionName: string;
datasetName: string;
datasetType: string;
}
},
[OperationLogEventEnum.DELETE_DATA]: {
content: i18nT('account_team:log_delete_data'),
typeLabel: i18nT('account_team:delete_data'),
params: {} as {
name?: string;
collectionName: string;
datasetName: string;
datasetType: string;
}
},
//SearchTest
[OperationLogEventEnum.SEARCH_TEST]: {
content: i18nT('account_team:log_search_test'),
typeLabel: i18nT('account_team:search_test'),
params: {} as { name?: string; datasetName: string; datasetType: string }
},
//Account
[OperationLogEventEnum.CHANGE_PASSWORD]: {
content: i18nT('account_team:log_change_password'),
typeLabel: i18nT('account_team:change_password'),
params: {} as { name?: string }
},
[OperationLogEventEnum.CHANGE_NOTIFICATION_SETTINGS]: {
content: i18nT('account_team:log_change_notification_settings'),
typeLabel: i18nT('account_team:change_notification_settings'),
params: {} as { name?: string }
},
[OperationLogEventEnum.CHANGE_MEMBER_NAME_ACCOUNT]: {
content: i18nT('account_team:log_change_member_name_self'),
typeLabel: i18nT('account_team:change_member_name_self'),
params: {} as { name?: string; oldName: string; newName: string }
},
[OperationLogEventEnum.PURCHASE_PLAN]: {
content: i18nT('account_team:log_purchase_plan'),
typeLabel: i18nT('account_team:purchase_plan'),
params: {} as { name?: string }
},
[OperationLogEventEnum.EXPORT_BILL_RECORDS]: {
content: i18nT('account_team:log_export_bill_records'),
typeLabel: i18nT('account_team:export_bill_records'),
params: {} as { name?: string }
},
[OperationLogEventEnum.CREATE_INVOICE]: {
content: i18nT('account_team:log_create_invoice'),
typeLabel: i18nT('account_team:create_invoice'),
params: {} as { name?: string }
},
[OperationLogEventEnum.SET_INVOICE_HEADER]: {
content: i18nT('account_team:log_set_invoice_header'),
typeLabel: i18nT('account_team:set_invoice_header'),
params: {} as { name?: string }
},
[OperationLogEventEnum.CREATE_API_KEY]: {
content: i18nT('account_team:log_create_api_key'),
typeLabel: i18nT('account_team:create_api_key'),
params: {} as { name?: string; keyName: string }
},
[OperationLogEventEnum.UPDATE_API_KEY]: {
content: i18nT('account_team:log_update_api_key'),
typeLabel: i18nT('account_team:update_api_key'),
params: {} as { name?: string; keyName: string }
},
[OperationLogEventEnum.DELETE_API_KEY]: {
content: i18nT('account_team:log_delete_api_key'),
typeLabel: i18nT('account_team:delete_api_key'),
params: {} as { name?: string; keyName: string }
}
} as const;

View File

@ -0,0 +1,36 @@
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { i18nT } from '../../../web/i18n/utils';
export function getI18nAppType(type: AppTypeEnum): string {
if (type === AppTypeEnum.folder) return i18nT('account_team:type.Folder');
if (type === AppTypeEnum.simple) return i18nT('account_team:type.Simple bot');
if (type === AppTypeEnum.workflow) return i18nT('account_team:type.Workflow bot');
if (type === AppTypeEnum.plugin) return i18nT('account_team:type.Plugin');
if (type === AppTypeEnum.httpPlugin) return i18nT('account_team:type.Http plugin');
if (type === AppTypeEnum.toolSet) return i18nT('account_team:type.Tool set');
if (type === AppTypeEnum.tool) return i18nT('account_team:type.Tool');
return i18nT('common:UnKnow');
}
export function getI18nCollaboratorItemType(
tmbId: string | undefined,
groupId: string | undefined,
orgId: string | undefined
): string {
if (tmbId) return i18nT('account_team:member');
if (groupId) return i18nT('account_team:group');
if (orgId) return i18nT('account_team:department');
return i18nT('common:UnKnow');
}
export function getI18nDatasetType(type: DatasetTypeEnum | string): string {
if (type === DatasetTypeEnum.folder) return i18nT('account_team:dataset.folder_dataset');
if (type === DatasetTypeEnum.dataset) return i18nT('account_team:dataset.common_dataset');
if (type === DatasetTypeEnum.websiteDataset) return i18nT('account_team:dataset.website_dataset');
if (type === DatasetTypeEnum.externalFile) return i18nT('account_team:dataset.external_file');
if (type === DatasetTypeEnum.apiDataset) return i18nT('account_team:dataset.api_file');
if (type === DatasetTypeEnum.feishu) return i18nT('account_team:dataset.feishu_dataset');
if (type === DatasetTypeEnum.yuque) return i18nT('account_team:dataset.yuque_dataset');
return i18nT('common:UnKnow');
}

View File

@ -287,6 +287,7 @@ export const iconPaths = {
'core/workflow/template/aiChat': () => import('./icons/core/workflow/template/aiChat.svg'),
'core/workflow/template/baseChart': () => import('./icons/core/workflow/template/baseChart.svg'),
'core/workflow/template/bing': () => import('./icons/core/workflow/template/bing.svg'),
'core/workflow/template/bocha': () => import('./icons/core/workflow/template/bocha.svg'),
'core/workflow/template/codeRun': () => import('./icons/core/workflow/template/codeRun.svg'),
'core/workflow/template/customFeedback': () =>
import('./icons/core/workflow/template/customFeedback.svg'),

View File

@ -0,0 +1,5 @@
<svg width="113" height="97" viewBox="0 0 113 97" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 31.7259C1.80046 29.9255 3.82784 28.3872 5.96621 27.1988C8.10469 26.0103 10.3126 25.1947 12.4634 24.7992C14.6143 24.4037 16.6664 24.4361 18.5022 24.8938C20.2678 25.334 21.7994 26.1604 23.0183 27.3272L23.021 27.3245L47.189 51.4924L33.4778 65.2037L0 31.7259Z" fill="#C4DEFE"/>
<path d="M9.15662 11.5625C11.3617 10.2893 13.7181 9.32825 16.0912 8.73374C18.4645 8.13923 20.8082 7.92284 22.9882 8.09751C25.1681 8.27217 27.1419 8.83457 28.7966 9.75182C30.3881 10.6341 31.6537 11.8287 32.529 13.2712L32.5316 13.2697L32.6082 13.4025C32.6162 13.4162 32.6251 13.4297 32.633 13.4435L49.886 43.3286L33.0941 53.0234L9.15662 11.5625Z" fill="#A6CBFF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.1377 0C33.6839 4.40811e-05 36.2052 0.345872 38.5576 1.01758C40.9099 1.68929 43.0472 2.67394 44.8477 3.91504C46.6482 5.15627 48.0773 6.63021 49.0518 8.25195C49.9888 9.81168 50.4867 11.4792 50.5234 13.166H50.5273V21.4072C56.6623 17.6586 63.874 15.498 71.5898 15.498C93.9304 15.4984 112.042 33.6087 112.042 55.9492C112.042 78.29 93.9305 96.401 71.5898 96.4014C49.3907 96.4014 31.3704 78.5193 31.1426 56.374H31.1377V0ZM71.9473 35.0439C60.1187 35.0441 50.5295 44.6334 50.5293 56.4619C50.5293 63.5338 53.9569 69.8057 59.2412 73.7061C66.4989 79.0625 76.5515 75.3841 85.3955 77.1592C92.613 78.608 97.2369 82.6827 98.3652 83.7686C97.3562 82.731 93.791 78.7138 92.2715 72.3291C89.8011 61.9479 94.8744 49.6043 87.5771 41.8184C83.6695 37.6493 78.1122 35.0441 71.9473 35.0439Z" fill="#006EFF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,17 +1,26 @@
import { Box } from '@chakra-ui/react';
import React from 'react';
import React, { useMemo } from 'react';
const HighlightText = ({
rawText,
matchText,
color = 'primary.600'
color = 'primary.600',
mode = 'text'
}: {
rawText: string;
matchText: string;
color?: string;
mode?: 'text' | 'bg';
}) => {
const regex = new RegExp(`(${matchText})`, 'gi');
const parts = rawText.split(regex);
const { parts } = useMemo(() => {
const regx = new RegExp(`(${matchText})`, 'gi');
const parts = rawText.split(regx);
return {
regx,
parts
};
}, [rawText, matchText]);
return (
<Box>
@ -28,7 +37,17 @@ const HighlightText = ({
}
return (
<Box as="span" key={index} color={highLight ? color : 'inherit'}>
<Box
as="span"
key={index}
{...(mode === 'bg'
? {
bg: highLight ? color : 'transparent'
}
: {
color: highLight ? color : 'inherit'
})}
>
{part}
</Box>
);
@ -37,4 +56,4 @@ const HighlightText = ({
);
};
export default HighlightText;
export default React.memo(HighlightText);

View File

@ -3,6 +3,8 @@ import { useContextSelector } from 'use-context-selector';
export const useSystem = () => {
const isPc = useContextSelector(useSystemStoreContext, (state) => state.isPc);
const isMac =
typeof window !== 'undefined' && window.navigator.userAgent.toLocaleLowerCase().includes('mac');
return { isPc };
return { isPc, isMac };
};

View File

@ -8,6 +8,9 @@
"assign_permission": "Permission change",
"change_department_name": "Department Editor",
"change_member_name": "Member name change",
"change_member_name_self": "Change member name",
"change_notification_settings": "Change the way to receive notifications",
"change_password": "change password",
"confirm_delete_from_org": "Confirm to move {{username}} out of the department?",
"confirm_delete_from_team": "Confirm to move {{username}} out of the team?",
"confirm_delete_group": "Confirm to delete group?",
@ -15,12 +18,29 @@
"confirm_forbidden": "Confirm forbidden",
"confirm_leave_team": "Confirmed to leave the team? \nAfter exiting, all your resources in the team are transferred to the team owner.",
"copy_link": "Copy link",
"create_api_key": "Create API key",
"create_app": "Create an application",
"create_app_copy": "Create a copy of the application",
"create_app_folder": "Create an application folder",
"create_app_publish_channel": "Create a sharing channel",
"create_data": "Insert data",
"create_dataset": "Create a knowledge base",
"create_dataset_folder": "Create a Knowledge Base Folder",
"create_department": "Create a sub-department",
"create_group": "Create group",
"create_invitation_link": "Create Invitation Link",
"create_invoice": "Issuing invoices",
"create_org": "Create organization",
"create_sub_org": "Create sub-organization",
"delete": "delete",
"delete_api_key": "Delete the API key",
"delete_app": "Delete the workbench application",
"delete_app_collaborator": "App permissions delete",
"delete_app_publish_channel": "Delete the publishing channel",
"delete_collection": "Delete a collection",
"delete_data": "Delete data",
"delete_dataset": "Delete the knowledge base",
"delete_dataset_collaborator": "Knowledge Base Permission Deletion",
"delete_department": "Delete sub-department",
"delete_from_org": "Move out of department",
"delete_from_team": "Move out of the team",
@ -31,6 +51,9 @@
"edit_member_tip": "Name",
"edit_org_info": "Edit organization information",
"expires": "Expiration time",
"export_app_chat_log": "Export the app chat history",
"export_bill_records": "Export billing history",
"export_dataset": "Export knowledge base",
"export_members": "Export members",
"forbid_hint": "After forbidden, this invitation link will become invalid. This action is irreversible. Are you sure you want to deactivate?",
"forbid_success": "Forbid success",
@ -56,24 +79,69 @@
"log_assign_permission": "[{{name}}] Updated the permissions of [{{objectName}}]: [Application creation: [{{appCreate}}], Knowledge Base: [{{datasetCreate}}], API Key: [{{apiKeyCreate}}], Management: [{{manage}}]]",
"log_change_department": "【{{name}}】Updated department【{{departmentName}}】",
"log_change_member_name": "【{{name}}】Rename member [{{memberName}}] to 【{{newName}}】",
"log_change_member_name_self": "【{{name}}】Change your member name to 【{{newName}}】",
"log_change_notification_settings": "【{{name}}】A change notification receiving method operation was carried out",
"log_change_password": "【{{name}}】The password change operation was performed",
"log_create_api_key": "【{{name}}】Create an API key named [{{keyName}}]",
"log_create_app": "【{{name}}】Created [{{appType}}] named [{{appName}}]",
"log_create_app_copy": "【{{name}}] Created a copy of [{{appType}}] named [{{appName}}]",
"log_create_app_folder": "【{{name}}】Create a folder named [{{folderName}}]",
"log_create_app_publish_channel": "[{{name}}] Created a channel named [{{channelName}}] for [{{appType}}] called [{{appName}}].",
"log_create_collection": "[{{name}}] Create a collection named [{{collectionName}}] in [{{datasetType}}] called [{{datasetName}}].",
"log_create_data": "[{{name}}] Insert data into a collection named [{{datasetName}}] in [{{datasetType}}] called [{{datasetName}}] into a collection named [{{collectionName}}]",
"log_create_dataset": "【{{name}}】Created 【{{datasetType}}】 named 【{{datasetName}}】",
"log_create_dataset_folder": "【{{name}}】Created a folder named {{folderName}}】",
"log_create_department": "【{{name}}】Department【{{departmentName}}】",
"log_create_group": "【{{name}}】Created group [{{groupName}}]",
"log_create_invitation_link": "【{{name}}】Created invitation link【{{link}}】",
"log_create_invoice": "【{{name}}】Invoice operation was carried out",
"log_delete_api_key": "【{{name}}】Deleted the API key named [{{keyName}}]",
"log_delete_app": "【{{name}}】Delete the [{{appType}}] named [{{appName}}]",
"log_delete_app_collaborator": "【{{name}}】Delete the [itemName] permission named [itemValueName] in [{{appType}}] named [{{appName}}] delete the [itemName] permission named [{{appName}}] named [{{appName}}] named [{{appName}}] deleted the [{{itemName}}] permission named [{{itemValueName}}] named [{{appType}}] named [{{appName}}].",
"log_delete_app_publish_channel": "[{{name}}] [{{appType}}] named [{{appName}}] deleted the channel named [{{channelName}}]",
"log_delete_collection": "[{{name}}] Deleted a collection named [{{collectionName}}] in [{{datasetType}}] named [{{datasetName}}].",
"log_delete_data": "[{{name}}] Delete data in a collection named [{{datasetName}}] in a collection named [{{datasetName}}]",
"log_delete_dataset": "【{{name}}】Deleted 【{{datasetType}}】 named [{{datasetName}}]",
"log_delete_dataset_collaborator": "【{{name}}】Updated the collaborators of 【{{appType}}】 named 【{{appName}}】 to: Organization: 【{{orgList}}】, Group: 【{{groupList}}】, Member 【{{tmbList}}】; updated the permissions to: Read permission: 【{{readPermission}}】, Write permission: 【{{writePermission}}】, Administrator permission: 【{{managePermission}}】",
"log_delete_department": "{{name}} deleted department {{departmentName}}",
"log_delete_group": "{{name}} deleted group {{groupName}}",
"log_details": "Details",
"log_export_app_chat_log": "【{{name}}】Export a chat history called [{{appName}}] called [{{appType}}]",
"log_export_bill_records": "【{{name}}】Export the billing record",
"log_export_dataset": "[{{name}}] Export [{{datasetType}}] called [{{datasetName}}]",
"log_join_team": "【{{name}}】Join the team through the invitation link 【{{link}}】",
"log_kick_out_team": "{{name}} removed member {{memberName}}",
"log_login": "【{{name}}】Logined in the system",
"log_move_app": "【{{name}}】Move [{{appType}}] named [{{appName}}] to [{{targetFolderName}}]",
"log_move_dataset": "【{{name}}】Move [{{datasetType}}] named [{{datasetName}}] to [{{targetFolderName}}]",
"log_recover_team_member": "【{{name}}】Restored member【{{memberName}}】",
"log_relocate_department": "【{{name}}】Displayed department【{{departmentName}}】",
"log_retrain_collection": "[{{name}}] Retrained the collection named [{{collectionName}}] in [{{datasetType}}] called [{{datasetName}}].",
"log_search_test": "【{{name}}】Perform a search test operation on [{{datasetType}}] named [{{datasetName}}]",
"log_set_invoice_header": "【{{name}}】The invoice header operation was set up",
"log_time": "Operation time",
"log_transfer_app_ownership": "【{{name}}] Transfer ownership of [{{appType}}] named [{{appName}}] from [{oldOwnerName}}] to [{{newOwnerName}}]",
"log_transfer_dataset_ownership": "[{{name}}] Transfer ownership of [{{datasetType}}] named [{{datasetName}}] from [{oldOwnerName}}] to [{{newOwnerName}}]",
"log_type": "Operation Type",
"log_update_api_key": "【{{name}}】Updated the API key named [{{keyName}}]",
"log_update_app_collaborator": "[{{name}}] Updated the collaborator named [{{appName}}] to: Organization: [{{orgList}}], Group: [{{groupList}}], Member [{{tmbList}}]; permissions updated to: Read permission: [{{readPermission}}], Write permission: [{{writePermission}}], Administrator permission: [{{managePermission}}]",
"log_update_app_info": "[{{name}}] updated [{{appType}}] named [{{appName}}]: [{{newItemNames}}] to [{{newItemValues}}]",
"log_update_app_publish_channel": "[{{name}}] Updated a channel named [{{channelName}}] for [{{appType}}] called [{{appName}}].",
"log_update_collection": "[{{name}}] Updated a collection named [{{collectionName}}] in [{{datasetType}}] called [{{datasetName}}].",
"log_update_data": "【{{name}}】Update data in a collection named 【{{datasetName}}】[{{datasetType}}] with [{{datasetType}}] with [{{collectionName}}]",
"log_update_dataset": "【{{name}}】Updated [{{datasetType}}] named [{{datasetName}}]",
"log_update_dataset_collaborator": "[{{name}}] Updated the collaborator named [{{datasetName}}] to: Organization: [{{orgList}}], Group: [{{groupList}}], Member [{{tmbList}}]; permissions updated to: [{{readPermission}}], [{{writePermission}}], [{{managePermission}}]",
"log_update_publish_app": "【{{name}}】【{{operationName}}】【{{appType}}】 named [{{appName}}】",
"log_user": "Operator",
"login": "Log in",
"manage_member": "Managing members",
"member": "member",
"department": "department",
"update": "update",
"save_and_publish": "save and publish",
"member_group": "Belonging to member group",
"move_app": "App location movement",
"move_dataset": "Mobile Knowledge Base",
"move_member": "Move member",
"move_org": "Move organization",
"notification_recieve": "Team notification reception",
@ -92,6 +160,7 @@
"permission_manage": "Admin",
"permission_manage_tip": "Can manage members, create groups, manage all groups, and assign permissions to groups and members",
"please_bind_contact": "Please bind the contact information",
"purchase_plan": "Upgrade package",
"recover_team_member": "Member Recovery",
"relocate_department": "Department Mobile",
"remark": "remark",
@ -99,21 +168,49 @@
"restore_tip": "Confirm to join the team {{username}}? \nOnly the availability and related permissions of this member account are restored, and the resources under the account cannot be restored.",
"restore_tip_title": "Recovery confirmation",
"retain_admin_permissions": "Keep administrator rights",
"retrain_collection": "Retrain the set",
"search_log": "Search log",
"search_member": "Search for members",
"search_member_group_name": "Search member/group name",
"search_org": "Search Department",
"search_test": "Search Test",
"set_invoice_header": "Set up invoice header",
"set_name_avatar": "Team avatar",
"sync_immediately": "Synchronize now",
"sync_member_failed": "Synchronization of members failed",
"sync_member_success": "Synchronize members successfully",
"total_team_members": "{{amount}} members in total",
"transfer_ownership": "transfer owner",
"total_team_members": "Total {{amount}} members",
"transfer_app_ownership": "Transfer app ownership",
"transfer_dataset_ownership": "Transfer dataset ownership",
"transfer_ownership": "Transfer ownership",
"type.Folder": "Folder",
"type.Http plugin": "HTTP Plugin",
"type.Plugin": "Plugin",
"type.Simple bot": "Simple App",
"type.Tool": "Tool",
"type.Tool set": "Toolset",
"type.Workflow bot": "Workflow",
"dataset.folder_dataset": "Folder",
"dataset.common_dataset": "Dataset",
"dataset.website_dataset": "Website Sync",
"dataset.external_file": "External File",
"dataset.api_file": "API Import",
"dataset.feishu_dataset": "Feishu Spreadsheet",
"dataset.yuque_dataset": "Yuque Knowledge Base",
"unlimited": "Unlimited",
"update_api_key": "Update API key",
"update_app_collaborator": "Apply permission changes",
"update_app_info": "Application information modification",
"update_app_publish_channel": "Update the release channel",
"update_collection": "Update the collection",
"update_data": "Update data",
"update_dataset": "Update the knowledge base",
"update_dataset_collaborator": "Knowledge Base Permission Changes",
"update_publish_app": "Application update",
"used_times_limit": "Limit",
"user_name": "username",
"user_team_invite_member": "Invite members",
"user_team_leave_team": "Leave the team",
"user_team_leave_team_failed": "Failure to leave the team",
"waiting": "To be accepted"
}
}

View File

@ -197,6 +197,9 @@
"type.MCP tools": "MCP Toolset",
"type.MCP_tools_url": "MCP Address",
"type.Plugin": "Plugin",
"type.Folder": "Folder",
"type.Tool set": "Toolset",
"type.Tool": "Tool",
"type.Simple bot": "Simple App",
"type.Workflow bot": "Workflow",
"type.error.Workflow data is empty": "No workflow data was obtained",
@ -238,4 +241,4 @@
"workflow.user_file_input_desc": "Links to documents and images uploaded by users.",
"workflow.user_select": "User Select",
"workflow.user_select_tip": "This module can configure multiple options for selection during the dialogue. Different options can lead to different workflow branches."
}
}

View File

@ -215,6 +215,7 @@
"core.app.Interval timer run": "Scheduled Execution",
"core.app.Interval timer tip": "Can Execute App on Schedule",
"core.app.Make a brief introduction of your app": "Give Your AI App an Introduction",
"core.app.name": "name",
"core.app.Name and avatar": "Avatar & Name",
"core.app.Publish": "Publish",
"core.app.Publish Confirm": "Confirm to Publish App? This Will Immediately Update the App Status on All Publishing Channels.",
@ -1305,4 +1306,4 @@
"zoomin_tip_mac": "Zoom Out ⌘ -",
"zoomout_tip": "Zoom In ctrl +",
"zoomout_tip_mac": "Zoom In ⌘ +"
}
}

View File

@ -63,6 +63,8 @@
"field_required": "Required",
"field_used_as_tool_input": "Used as Tool Call Parameter",
"filter_description": "Currently supports filtering by tags and creation time. Fill in the format as follows:\n{\n \"tags\": {\n \"$and\": [\"Tag 1\",\"Tag 2\"],\n \"$or\": [\"When there are $and tags, and is effective, or is not effective\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm format, collection creation time greater than this time\",\n \"$lte\": \"YYYY-MM-DD HH:mm format, collection creation time less than this time, can be used with $gte\"\n }\n}",
"find_tip": "Find node ctrl f",
"find_tip_mac": "Find node ⌘ f",
"foldAll": "Collapse all",
"form_input_result": "User complete input result",
"form_input_result_tip": "an object containing the complete result",
@ -123,18 +125,23 @@
"max_tokens": "Maximum Tokens",
"mouse_priority": "Mouse first\n- Press the left button to drag the canvas\n- Hold down shift and left click to select batches",
"new_context": "New Context",
"next": "Next",
"no_match_node": "No results",
"no_node_found": "No node was not found",
"not_contains": "Does Not Contain",
"only_the_reference_type_is_supported": "Only reference type is supported",
"optional_value_type": "Optional Value Type",
"optional_value_type_tip": "You can specify one or more data types. When dynamically adding fields, users can only select the configured types.",
"pan_priority": "Touchpad first\n- Click to batch select\n- Move the canvas with two fingers",
"pass_returned_object_as_output_to_next_nodes": "Pass the object returned in the code as output to the next nodes. The variable name needs to correspond to the return key.",
"please_enter_node_name": "Enter the node name",
"plugin.Instruction_Tip": "You can configure an instruction to explain the purpose of the plugin. This instruction will be displayed each time the plugin is used. Supports standard Markdown syntax.",
"plugin.Instructions": "Instructions",
"plugin.global_file_input": "File links (deprecated)",
"plugin_file_abandon_tip": "Plugin global file upload has been deprecated, please adjust it as soon as possible. \nRelated functions can be achieved through plug-in input and adding image type input.",
"plugin_input": "Plugin Input",
"plugin_output_tool": "When the plug-in is executed as a tool, whether this field responds as a result of the tool",
"previous": "Previous",
"question_classification": "Classify",
"question_optimization": "Query extension",
"quote_content_placeholder": "The structure of the reference content can be customized to better suit different scenarios. \nSome variables can be used for template configuration\n\n{{q}} - main content\n\n{{a}} - auxiliary data\n\n{{source}} - source name\n\n{{sourceId}} - source ID\n\n{{index}} - nth reference",
@ -177,9 +184,9 @@
"text_content_extraction": "Text Extract",
"text_to_extract": "Text to Extract",
"these_variables_will_be_input_parameters_for_code_execution": "These variables will be input parameters for code execution",
"tool.tool_result": "Tool operation results",
"to_add_node": "to add",
"to_connect_node": "to connect",
"tool.tool_result": "Tool operation results",
"tool_call_termination": "Stop ToolCall",
"tool_custom_field": "Custom Tool",
"tool_field": " Tool Field Parameter Configuration",

View File

@ -1,4 +1,5 @@
{
"account_team.delete_dataset": "删除知识库",
"active_model": "可用模型",
"add_default_model": "添加预设模型",
"api_key": "API 密钥",

View File

@ -8,6 +8,9 @@
"assign_permission": "权限变更",
"change_department_name": "部门编辑",
"change_member_name": "成员改名",
"change_member_name_self": "变更成员名",
"change_notification_settings": "变更通知接收途径",
"change_password": "更改密码",
"confirm_delete_from_org": "确认将 {{username}} 移出部门?",
"confirm_delete_from_team": "确认将 {{username}} 移出团队?",
"confirm_delete_group": "确认删除群组?",
@ -15,12 +18,30 @@
"confirm_forbidden": "确认停用",
"confirm_leave_team": "确认离开该团队? \n退出后您在该团队所有的资源均转让给团队所有者。",
"copy_link": "复制链接",
"create_api_key": "创建api密钥",
"create_app": "创建应用",
"create_app_copy": "创建应用副本",
"create_app_folder": "创建应用文件夹",
"create_app_publish_channel": "创建分享渠道",
"create_collection": "创建集合",
"create_data": "插入数据",
"create_dataset": "创建知识库",
"create_dataset_folder": "创建知识库文件夹",
"create_department": "创建子部门",
"create_group": "创建群组",
"create_invitation_link": "创建邀请链接",
"create_invoice": "开发票",
"create_org": "创建部门",
"create_sub_org": "创建子部门",
"delete": "删除",
"delete_api_key": "删除api密钥",
"delete_app": "删除工作台应用",
"delete_app_collaborator": "应用权限删除",
"delete_app_publish_channel": "删除发布渠道",
"delete_collection": "删除集合",
"delete_data": "删除数据",
"delete_dataset": "删除知识库",
"delete_dataset_collaborator": "知识库权限删除",
"delete_department": "删除子部门",
"delete_from_org": "移出部门",
"delete_from_team": "移出团队",
@ -31,6 +52,9 @@
"edit_member_tip": "成员名",
"edit_org_info": "编辑部门信息",
"expires": "过期时间",
"export_app_chat_log": "导出应用聊天记录",
"export_bill_records": "导出账单记录",
"export_dataset": "导出知识库",
"export_members": "导出成员",
"forbid_hint": "停用后,该邀请链接将失效。 该操作不可撤销,是否确认停用?",
"forbid_success": "停用成功",
@ -56,24 +80,70 @@
"log_assign_permission": "【{{name}}】更新了【{{objectName}}】的权限:[应用创建:【{{appCreate}}】, 知识库:【{{datasetCreate}}】, API密钥:【{{apiKeyCreate}}】, 管理:【{{manage}}】]",
"log_change_department": "【{{name}}】更新了部门【{{departmentName}}】",
"log_change_member_name": "【{{name}}】将成员【{{memberName}}】重命名为【{{newName}}】",
"log_change_member_name_self": "【{{name}}】把自己的成员名从【{{oldName}}】变更为【{{newName}}】",
"log_change_notification_settings": "【{{name}}】进行了变更通知接收途径操作",
"log_change_password": "【{{name}}】进行了变更密码操作",
"log_create_api_key": "【{{name}}】创建了名为【{{keyName}}】的api密钥",
"log_create_app": "【{{name}}】创建了名为【{{appName}}】的【{{appType}}】",
"log_create_app_copy": "【{{name}}】给名为【{{appName}}】的【{{appType}}】创建了一个副本",
"log_create_app_folder": "【{{name}}】创建了名为【{{folderName}}】的文件夹",
"log_create_app_publish_channel": "【{{name}}】给名为【{{appName}}】的【{{appType}}】创建了名为【{{channelName}}】的渠道",
"log_create_collection": "【{{name}}】在名为【{{datasetName}}】的【{{datasetType}}】创建了名为【{{collectionName}}】的集合",
"log_create_data": "【{{name}}】在名为【{{datasetName}}】的【{{datasetType}}】往名为【{{collectionName}}】的集合插入数据",
"log_create_dataset": "【{{name}}】创建了名为【{{datasetName}}】的【{{datasetType}}】",
"log_create_dataset_folder": "【{{name}}】创建了名为{{folderName}}】的文件夹",
"log_create_department": "【{{name}}】创建了部门【{{departmentName}}】",
"log_create_group": "【{{name}}】创建了群组【{{groupName}}】",
"log_create_invitation_link": "【{{name}}】创建了邀请链接【{{link}}】",
"log_create_invoice": "【{{name}}】进行了开发票操作",
"log_delete_api_key": "【{{name}}】删除了名为【{{keyName}}】的api密钥",
"log_delete_app": "【{{name}}】将名为【{{appName}}】的【{{appType}}】删除",
"log_delete_app_collaborator": "【{{name}}】将名为【{{appName}}】的【{{appType}}】中名为【{{itemValueName}}】的【{{itemName}}】权限删除",
"log_delete_app_publish_channel": "【{{name}}】名为【{{appName}}】的【{{appType}}】删除了名为【{{channelName}}】的渠道",
"log_delete_collection": "【{{name}}】在名为【{{datasetName}}】的【{{datasetType}}】删除了名为【{{collectionName}}】的集合",
"log_delete_data": "【{{name}}】在名为【{{datasetName}}】的【{{datasetType}}】在名为【{{collectionName}}】的集合删除数据",
"log_delete_dataset": "【{{name}}】删除了名为【{{datasetName}}】的【{{datasetType}}】",
"log_delete_dataset_collaborator": "【{{name}}】将名为【{{datasetName}}】的【{{datasetType}}】中名为【itemValueName】的【itemName】权限删除",
"log_delete_department": "【{{name}}】删除了部门【{{departmentName}}】",
"log_delete_group": "【{{name}}】删除了群组【{{groupName}}】",
"log_details": "详情",
"log_export_app_chat_log": "【{{name}}】导出了名为【{{appName}}】的【{{appType}}】的聊天记录",
"log_export_bill_records": "【{{name}}】导出了账单记录",
"log_export_dataset": "【{{name}}】导出了名为【{{datasetName}}】的【{{datasetType}}】",
"log_join_team": "【{{name}}】通过邀请链接【{{link}}】加入团队",
"log_kick_out_team": "【{{name}}】移除了成员【{{memberName}}】",
"log_login": "【{{name}}】登录了系统",
"log_move_app": "【{{name}}】将名为【{{appName}}】的【{{appType}}】移动到【{{targetFolderName}}】",
"log_move_dataset": "【{{name}}】将名为【{{datasetName}}】的【{{datasetType}}】移动到【{{targetFolderName}}】",
"log_purchase_plan": "【{{name}}】购买了套餐",
"log_recover_team_member": "【{{name}}】恢复了成员【{{memberName}}】",
"log_relocate_department": "【{{name}}】移动了部门【{{departmentName}}】",
"log_retrain_collection": "【{{name}}】在名为【{{datasetName}}】的【{{datasetType}}】重新训练了名为【{{collectionName}}】的集合",
"log_search_test": "【{{name}}】在名为【{{datasetName}}】的【{{datasetType}}】执行搜索测试操作",
"log_set_invoice_header": "【{{name}}】进行了设置发票抬头操作",
"log_time": "操作时间",
"log_transfer_app_ownership": "【{{name}}】将名为【{{appName}}】的【{{appType}}】的所有权从【{{oldOwnerName}}】转移到【{{newOwnerName}}】",
"log_transfer_dataset_ownership": "【{{name}}】将名为【{{datasetName}}】的【{{datasetType}}】的所有权从【{{oldOwnerName}}】转移到【{{newOwnerName}}】",
"log_type": "操作类型",
"log_update_api_key": "【{{name}}】更新了名为【{{keyName}}】的api密钥",
"log_update_app_collaborator": "【{{name}}】将名为【{{appName}}】的【{{appType}}】的合作者更新为:组织:【{{orgList}}】,群组:【{{groupList}}】,成员【{{tmbList}}】;权限更新为:读权限:【{{readPermission}}】,写权限:【{{writePermission}}】,管理员权限:【{{managePermission}}】",
"log_update_app_info": "【{{name}}】更新了名为【{{appName}}】的【{{appType}}】:【{{newItemNames}}】为【{{newItemValues}}】",
"log_update_app_publish_channel": "【{{name}}】给名为【{{appName}}】的【{{appType}}】更新了名为【{{channelName}}】的渠道",
"log_update_collection": "【{{name}}】在名为【{{datasetName}}】的【{{datasetType}}】更新了名为【{{collectionName}}】的集合",
"log_update_data": "【{{name}}】在名为【{{datasetName}}】的【{{datasetType}}】在名为【{{collectionName}}】的集合更新数据",
"log_update_dataset": "【{{name}}】更新了名为【{{datasetName}}】的【{{datasetType}}】",
"log_update_dataset_collaborator": "【{{name}}】将名为【{{datasetName}}】的【{{datasetType}}】的合作者更新为:组织:【{{orgList}}】,群组:【{{groupList}}】,成员【{{tmbList}}】;权限更新为:【{{readPermission}}】,【{{writePermission}}】,【{{managePermission}}】",
"log_update_publish_app": "【{{name}}】【{{operationName}}】名为【{{appName}}】的【{{appType}}】",
"log_user": "操作人员",
"login": "登录",
"manage_member": "管理成员",
"member": "成员",
"department": "部门",
"update": "更新",
"save_and_publish": "保存并发布",
"member_group": "所属群组",
"move_app": "应用位置移动",
"move_dataset": "移动知识库",
"move_member": "移动成员",
"move_org": "移动部门",
"notification_recieve": "团队通知接收",
@ -92,6 +162,7 @@
"permission_manage": "管理员",
"permission_manage_tip": "可以管理成员、创建群组、管理所有群组、为群组和成员分配权限",
"please_bind_contact": "请绑定联系方式",
"purchase_plan": "升级套餐",
"recover_team_member": "成员恢复",
"relocate_department": "部门移动",
"remark": "备注",
@ -99,21 +170,49 @@
"restore_tip": "确认将 {{username}} 加入团队吗?仅恢复该成员账号可用性及相关权限,无法恢复账号下资源。",
"restore_tip_title": "恢复确认",
"retain_admin_permissions": "保留管理员权限",
"retrain_collection": "重新训练集合",
"search_log": "搜索日志",
"search_member": "搜索成员",
"search_member_group_name": "搜索成员/群组名称",
"search_org": "搜索部门",
"search_test": "搜索测试",
"set_invoice_header": "设置发票抬头",
"set_name_avatar": "团队头像 & 团队名",
"sync_immediately": "立即同步",
"sync_member_failed": "同步成员失败",
"sync_member_success": "同步成员成功",
"total_team_members": "共 {{amount}} 名成员",
"transfer_app_ownership": "转移应用所有权",
"transfer_dataset_ownership": "转移知识库所有权",
"transfer_ownership": "转让所有者",
"type.Folder": "文件夹",
"type.Http plugin": "HTTP 插件",
"type.Plugin": "插件",
"type.Simple bot": "简易应用",
"type.Tool": "工具",
"type.Tool set": "工具集",
"type.Workflow bot": "工作流",
"dataset.folder_dataset": "文件夹",
"dataset.common_dataset": "知识库",
"dataset.website_dataset": "网站同步",
"dataset.external_file": "外部文件",
"dataset.api_file": "API导入",
"dataset.feishu_dataset": "飞书多维表格",
"dataset.yuque_dataset": "语雀知识库",
"unlimited": "无限制",
"update_api_key": "更新api密钥",
"update_app_collaborator": "应用权限更改",
"update_app_info": "应用信息修改",
"update_app_publish_channel": "更新发布渠道",
"update_collection": "更新集合",
"update_data": "更新数据",
"update_dataset": "更新知识库",
"update_dataset_collaborator": "知识库权限更改",
"update_publish_app": "应用更新",
"used_times_limit": "有效人数",
"user_name": "用户名",
"user_team_invite_member": "邀请成员",
"user_team_leave_team": "离开团队",
"user_team_leave_team_failed": "离开团队失败",
"waiting": "待接受"
}
}

View File

@ -189,6 +189,7 @@
"type.Create simple bot tip": "通过填表单形式,创建简单的 AI 应用,适合新手",
"type.Create workflow bot": "创建工作流",
"type.Create workflow tip": "通过低代码的方式,构建逻辑复杂的多轮对话 AI 应用,推荐高级玩家使用",
"type.Folder": "文件夹",
"type.Http plugin": "HTTP 插件",
"type.Import from json": "导入 JSON 配置",
"type.Import from json tip": "通过 JSON 配置文件,直接创建应用",
@ -198,6 +199,8 @@
"type.MCP_tools_url": "MCP 地址",
"type.Plugin": "插件",
"type.Simple bot": "简易应用",
"type.Tool": "工具",
"type.Tool set": "工具集",
"type.Workflow bot": "工作流",
"type.error.Workflow data is empty": "没有获取到工作流数据",
"type.error.workflowresponseempty": "响应内容为空",
@ -238,4 +241,4 @@
"workflow.user_file_input_desc": "用户上传的文档和图片链接",
"workflow.user_select": "用户选择",
"workflow.user_select_tip": "该模块可配置多个选项,以供对话时选择。不同选项可导向不同工作流支线"
}
}

View File

@ -215,6 +215,7 @@
"core.app.Interval timer run": "定时执行",
"core.app.Interval timer tip": "可定时执行应用",
"core.app.Make a brief introduction of your app": "给你的 AI 应用一个介绍",
"core.app.name": "名称",
"core.app.Name and avatar": "头像 & 名称",
"core.app.Publish": "发布",
"core.app.Publish Confirm": "确认发布应用?会立即更新所有发布渠道的应用状态。",
@ -1305,4 +1306,4 @@
"zoomin_tip_mac": "缩小 ⌘ -",
"zoomout_tip": "放大 ctrl +",
"zoomout_tip_mac": "放大 ⌘ +"
}
}

View File

@ -63,6 +63,8 @@
"field_required": "必填",
"field_used_as_tool_input": "作为工具调用参数",
"filter_description": "目前支持标签和创建时间过滤,需按照以下格式填写:\n{\n \"tags\": {\n \"$and\": [\"标签 1\",\"标签 2\"],\n \"$or\": [\"有 $and 标签时and 生效or 不生效\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm 格式即可,集合的创建时间大于该时间\",\n \"$lte\": \"YYYY-MM-DD HH:mm 格式即可,集合的创建时间小于该时间,可和 $gte 共同使用\"\n }\n}",
"find_tip": "查找节点 ctrl f",
"find_tip_mac": "查找节点 ⌘ f",
"foldAll": "全部折叠",
"form_input_result": "用户完整输入结果",
"form_input_result_tip": "一个包含完整结果的对象",
@ -123,18 +125,23 @@
"max_tokens": "最大 Tokens",
"mouse_priority": "鼠标优先\n- 左键按下后可拖动画布\n- 按住 shift 后左键可批量选择",
"new_context": "新的上下文",
"next": "下一个",
"no_match_node": "无结果",
"no_node_found": "未搜索到节点",
"not_contains": "不包含",
"only_the_reference_type_is_supported": "仅支持引用类型",
"optional_value_type": "可选的数据类型",
"optional_value_type_tip": "可以指定 1 个或多个数据类型,用户在动态添加字段时,仅可选择配置的类型",
"pan_priority": "触摸板优先\n- 单击批量选择\n- 双指移动画布",
"pass_returned_object_as_output_to_next_nodes": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key",
"please_enter_node_name": "请输入节点名称",
"plugin.Instruction_Tip": "可以配置一段说明,以解释该插件的用途。每次使用插件前,会显示该段说明。支持标准 Markdown 语法。",
"plugin.Instructions": "使用说明",
"plugin.global_file_input": "文件链接(弃用)",
"plugin_file_abandon_tip": "插件全局文件上传已弃用,请尽快调整。可以通过插件输入,添加图片类型输入来实现相关功能。",
"plugin_input": "插件输入",
"plugin_output_tool": "插件作为工具执行时,该字段是否作为工具响应结果",
"previous": "上一个",
"question_classification": "问题分类",
"question_optimization": "问题优化",
"quote_content_placeholder": "可以自定义引用内容的结构,以更好的适配不同场景。可以使用一些变量来进行模板配置\n{{q}} - 主要内容\n{{a}} - 辅助数据\n{{source}} - 来源名\n{{sourceId}} - 来源ID\n{{index}} - 第 n 个引用",

View File

@ -8,6 +8,9 @@
"assign_permission": "權限變更",
"change_department_name": "部門編輯",
"change_member_name": "成員改名",
"change_member_name_self": "變更成員名",
"change_notification_settings": "變更通知接收途徑",
"change_password": "更改密碼",
"confirm_delete_from_org": "確認將 {{username}} 移出部門?",
"confirm_delete_from_team": "確認將 {{username}} 移出團隊?",
"confirm_delete_group": "確認刪除群組?",
@ -15,12 +18,29 @@
"confirm_forbidden": "確認停用",
"confirm_leave_team": "確認離開該團隊? \n結束後您在該團隊所有的資源轉讓給團隊所有者。",
"copy_link": "複製連結",
"create_api_key": "創建api密鑰",
"create_app": "創建應用",
"create_app_copy": "創建應用副本",
"create_app_folder": "創建應用文件夾",
"create_app_publish_channel": "創建分享渠道",
"create_data": "插入數據",
"create_dataset": "創建知識庫",
"create_dataset_folder": "創建知識庫文件夾",
"create_department": "創建子部門",
"create_group": "建立群組",
"create_invitation_link": "建立邀請連結",
"create_invoice": "開發票",
"create_org": "建立部門",
"create_sub_org": "建立子部門",
"delete": "刪除",
"delete_api_key": "刪除api密鑰",
"delete_app": "刪除工作台應用",
"delete_app_collaborator": "應用權限刪除",
"delete_app_publish_channel": "刪除發布渠道",
"delete_collection": "刪除集合",
"delete_data": "刪除數據",
"delete_dataset": "刪除知識庫",
"delete_dataset_collaborator": "知識庫權限刪除",
"delete_department": "刪除子部門",
"delete_from_org": "移出部門",
"delete_from_team": "移出團隊",
@ -31,6 +51,9 @@
"edit_member_tip": "成員名",
"edit_org_info": "編輯部門資訊",
"expires": "過期時間",
"export_app_chat_log": "導出應用聊天記錄",
"export_bill_records": "導出賬單記錄",
"export_dataset": "導出知識庫",
"export_members": "導出成員",
"forbid_hint": "停用後,該邀請連結將失效。該操作不可撤銷,是否確認停用?",
"forbid_success": "停用成功",
@ -56,24 +79,69 @@
"log_assign_permission": "【{{name}}】更新了【{{objectName}}】的權限:[應用創建:【{{appCreate}}】, 知識庫:【{{datasetCreate}}】, API密鑰:【{{apiKeyCreate}}】, 管理:【{{manage}}】]",
"log_change_department": "【{{name}}】更新了部門【{{departmentName}}】",
"log_change_member_name": "【{{name}}】將成員【{{memberName}}】重命名為【{{newName}}】",
"log_change_member_name_self": "【{{name}}】變更自己的成員名為【{{newName}}】",
"log_change_notification_settings": "【{{name}}】進行了變更通知接收途徑操作",
"log_change_password": "【{{name}}】進行了變更密碼操作",
"log_create_api_key": "【{{name}}】創建了名為【{{keyName}}】的api密鑰",
"log_create_app": "【{{name}}】創建了名為【{{appName}}】的【{{appType}}】",
"log_create_app_copy": "【{{name}}】給名為【{{appName}}】的【{{appType}}】創建了一個副本",
"log_create_app_folder": "【{{name}}】創建了名為【{{folderName}}】的文件夾",
"log_create_app_publish_channel": "【{{name}}】給名為【{{appName}}】的【{{appType}}】創建了名為【{{channelName}}】的渠道",
"log_create_collection": "【{{name}}】在名為【{{datasetName}}】的【{{datasetType}}】創建了名為【{{collectionName}}】的集合",
"log_create_data": "【{{name}}】在名為【{{datasetName}}】的【{{datasetType}}】往名為【{{collectionName}}】的集合插入數據",
"log_create_dataset": "【{{name}}】創建了名為【{{datasetName}}】的【{{datasetType}}】",
"log_create_dataset_folder": "【{{name}}】創建了名為{{folderName}}】的文件夾",
"log_create_department": "【{{name}}】創建了部門【{{departmentName}}】",
"log_create_group": "【{{name}}】創建了群組【{{groupName}}】",
"log_create_invitation_link": "【{{name}}】創建了邀請鏈接【{{link}}】",
"log_create_invoice": "【{{name}}】進行了開發票操作",
"log_delete_api_key": "【{{name}}】刪除了名為【{{keyName}}】的api密鑰",
"log_delete_app": "【{{name}}】將名為【{{appName}}】的【{{appType}}】刪除",
"log_delete_app_collaborator": "【{{name}}】將名為【{{appName}}】的【{{appType}}】中名為【{{itemValueName}}】的【{{itemName}}】權限刪除",
"log_delete_app_publish_channel": "【{{name}}】名為【{{appName}}】的【{{appType}}】刪除了名為【{{channelName}}】的渠道",
"log_delete_collection": "【{{name}}】在名為【{{datasetName}}】的【{{datasetType}}】刪除了名為【{{collectionName}}】的集合",
"log_delete_data": "【{{name}}】在名為【{{datasetName}}】的【{{datasetType}}】在名為【{{collectionName}}】的集合刪除數據",
"log_delete_dataset": "【{{name}}】刪除了名為【{{datasetName}}】的【{{datasetType}}】",
"log_delete_dataset_collaborator": "【{{name}}】將名為【{{datasetName}}】的【{{datasetType}}】中名為【itemValueName】的【itemName】權限刪除",
"log_delete_department": "{{name}} 刪除了部門 {{departmentName}}",
"log_delete_group": "{{name}} 刪除了群組 {{groupName}}",
"log_details": "詳情",
"log_export_app_chat_log": "【{{name}}】導出了名為【{{appName}}】的【{{appType}}】的聊天記錄",
"log_export_bill_records": "【{{name}}】導出了賬單記錄",
"log_export_dataset": "【{{name}}】導出了名為【{{datasetName}}】的【{{datasetType}}】",
"log_join_team": "【{{name}}】通過邀請鏈接【{{link}}】加入團隊",
"log_kick_out_team": "{{name}} 移除了成員 {{memberName}}",
"log_login": "【{{name}}】登錄了系統",
"log_move_app": "【{{name}}】將名為【{{appName}}】的【{{appType}}】移動到【{{targetFolderName}}】",
"log_move_dataset": "【{{name}}】將名為【{{datasetName}}】的【{{datasetType}}】移動到【{{targetFolderName}}】",
"log_recover_team_member": "【{{name}}】恢復了成員【{{memberName}}】",
"log_relocate_department": "【{{name}}】移動了部門【{{departmentName}}】",
"log_retrain_collection": "【{{name}}】在名為【{{datasetName}}】的【{{datasetType}}】重新訓練了名為【{{collectionName}}】的集合",
"log_search_test": "【{{name}}】在名為【{{datasetName}}】的【{{datasetType}}】執行搜索測試操作",
"log_set_invoice_header": "【{{name}}】進行了設置發票抬頭操作",
"log_time": "操作時間",
"log_transfer_app_ownership": "【{{name}}】將名為【{{appName}}】的【{{appType}}】的所有權從【{{oldOwnerName}}】轉移到【{{newOwnerName}}】",
"log_transfer_dataset_ownership": "【{{name}}】將名為【{{datasetName}}】的【{{datasetType}}】的所有權從【{{oldOwnerName}}】轉移到【{{newOwnerName}}】",
"log_type": "操作類型",
"log_update_api_key": "【{{name}}】更新了名為【{{keyName}}】的api密鑰",
"log_update_app_collaborator": "【{{name}}】將名為【{{appName}}】的【{{appType}}】的合作者更新為:組織:【{{orgList}}】,群組:【{{groupList}}】,成員【{{tmbList}}】;權限更新為:讀權限:【{{readPermission}}】,寫權限:【{{writePermission}}】,管理員權限:【{{managePermission}}】",
"log_update_app_info": "【{{name}}】更新了名為【{{appName}}】的【{{appType}}】:【{{newItemNames}}】為【{{newItemValues}}】",
"log_update_app_publish_channel": "【{{name}}】給名為【{{appName}}】的【{{appType}}】更新了名為【{{channelName}}】的渠道",
"log_update_collection": "【{{name}}】在名為【{{datasetName}}】的【{{datasetType}}】更新了名為【{{collectionName}}】的集合",
"log_update_data": "【{{name}}】在名為【{{datasetName}}】的【{{datasetType}}】在名為【{{collectionName}}】的集合更新數據",
"log_update_dataset": "【{{name}}】更新了名為【{{datasetName}}】的【{{datasetType}}】",
"log_update_dataset_collaborator": "【{{name}}】將名為【{{datasetName}}】的【{{datasetType}}】的合作者更新為:組織:【{{orgList}}】,群組:【{{groupList}}】,成員【{{tmbList}}】;權限更新為:【{{readPermission}}】,【{{writePermission}}】,【{{managePermission}}】",
"log_update_publish_app": "【{{name}}】【{{operationName}}】名為【{{appName}}】的【{{appType}}】",
"log_user": "操作人員",
"login": "登入",
"manage_member": "管理成員",
"member": "成員",
"department": "部門",
"update": "更新",
"save_and_publish": "儲存並發布",
"member_group": "所屬成員組",
"move_app": "應用位置移動",
"move_dataset": "移動知識庫",
"move_member": "移動成員",
"move_org": "行動部門",
"notification_recieve": "團隊通知接收",
@ -92,6 +160,7 @@
"permission_manage": "管理員",
"permission_manage_tip": "可以管理成員、建立群組、管理所有群組、為群組和成員分配權限",
"please_bind_contact": "請綁定聯繫方式",
"purchase_plan": "升級套餐",
"recover_team_member": "成員恢復",
"relocate_department": "部門移動",
"remark": "備註",
@ -99,21 +168,49 @@
"restore_tip": "確認將 {{username}} 加入團隊嗎?\n僅恢復該成員賬號可用性及相關權限無法恢復賬號下資源。",
"restore_tip_title": "恢復確認",
"retain_admin_permissions": "保留管理員權限",
"retrain_collection": "重新訓練集合",
"search_log": "搜索日誌",
"search_member": "搜索成員",
"search_member_group_name": "搜尋成員/群組名稱",
"search_org": "搜索部門",
"search_test": "搜索測試",
"set_invoice_header": "設置發票抬頭",
"set_name_avatar": "團隊頭像",
"sync_immediately": "立即同步",
"sync_member_failed": "同步成員失敗",
"sync_member_success": "同步成員成功",
"total_team_members": "共 {{amount}} 名成員",
"transfer_app_ownership": "轉移應用程式所有權",
"transfer_dataset_ownership": "轉移知識庫所有權",
"transfer_ownership": "轉讓所有者",
"type.Folder": "資料夾",
"type.Http plugin": "HTTP 外掛",
"type.Plugin": "外掛",
"type.Simple bot": "簡易應用程式",
"type.Tool": "工具",
"type.Tool set": "工具集",
"type.Workflow bot": "工作流程",
"dataset.folder_dataset": "資料夾",
"dataset.common_dataset": "知識庫",
"dataset.website_dataset": "網站同步",
"dataset.external_file": "外部文件",
"dataset.api_file": "API 匯入",
"dataset.feishu_dataset": "飛書多維表格",
"dataset.yuque_dataset": "語雀知識庫",
"unlimited": "無限制",
"update_api_key": "更新api密鑰",
"update_app_collaborator": "應用權限更改",
"update_app_info": "應用信息修改",
"update_app_publish_channel": "更新發布渠道",
"update_collection": "更新集合",
"update_data": "更新數據",
"update_dataset": "更新知識庫",
"update_dataset_collaborator": "知識庫權限更改",
"update_publish_app": "應用更新",
"used_times_limit": "有效人數",
"user_name": "使用者名稱",
"user_team_invite_member": "邀請成員",
"user_team_leave_team": "離開團隊",
"user_team_leave_team_failed": "離開團隊失敗",
"waiting": "待接受"
}
}

View File

@ -198,6 +198,9 @@
"type.MCP_tools_url": "MCP 地址",
"type.Plugin": "外掛",
"type.Simple bot": "簡易應用程式",
"type.Folder": "資料夾",
"type.Tool set": "工具集",
"type.Tool": "工具",
"type.Workflow bot": "工作流程",
"type.error.Workflow data is empty": "沒有獲取到工作流數據",
"type.error.workflowresponseempty": "響應內容為空",
@ -238,4 +241,4 @@
"workflow.user_file_input_desc": "使用者上傳的檔案和圖片連結",
"workflow.user_select": "使用者選擇",
"workflow.user_select_tip": "這個模組可以設定多個選項,供對話時選擇。不同選項可以導向不同的工作流程支線"
}
}

View File

@ -215,6 +215,7 @@
"core.app.Interval timer run": "排程執行",
"core.app.Interval timer tip": "可排程執行應用程式",
"core.app.Make a brief introduction of your app": "為您的 AI 應用程式寫一段介紹",
"core.app.name": "名稱",
"core.app.Name and avatar": "頭像與名稱",
"core.app.Publish": "發布",
"core.app.Publish Confirm": "確認發布應用程式?這將立即更新所有發布管道的應用程式狀態。",
@ -1305,4 +1306,4 @@
"zoomin_tip_mac": "縮小 ⌘ -",
"zoomout_tip": "放大 ctrl +",
"zoomout_tip_mac": "放大 ⌘ +"
}
}

View File

@ -63,6 +63,8 @@
"field_required": "必填",
"field_used_as_tool_input": "作為工具呼叫參數",
"filter_description": "目前支援標籤和建立時間篩選,需按照以下格式填寫:\n{\n \"tags\": {\n \"$and\": [\"標籤 1\",\"標籤 2\"],\n \"$or\": [\"當有 $and 標籤時,$and 才會生效,$or 不會生效\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm 格式,資料集的建立時間大於這個時間\",\n \"$lte\": \"YYYY-MM-DD HH:mm 格式,資料集的建立時間小於這個時間,可以和 $gte 一起使用\"\n }\n}",
"find_tip": "查找節點 ctrl f",
"find_tip_mac": "查找節點 ⌘ f",
"foldAll": "全部折疊",
"form_input_result": "使用者完整輸入結果",
"form_input_result_tip": "一個包含完整結果的物件",
@ -123,18 +125,23 @@
"max_tokens": "最大 Token 數",
"mouse_priority": "滑鼠優先\n- 按下左鍵拖曳畫布\n- 按住 Shift 鍵並點選左鍵可批次選取",
"new_context": "新的脈絡",
"next": "下一個",
"no_match_node": "無結果",
"no_node_found": "未搜索到節點",
"not_contains": "不包含",
"only_the_reference_type_is_supported": "僅支援引用類型",
"optional_value_type": "可選的資料類型",
"optional_value_type_tip": "可以指定一或多個資料類型,使用者在動態新增欄位時,只能選擇已設定的類型",
"pan_priority": "觸控板優先\n- 點選可批次選取\n- 使用兩指移動畫布",
"pass_returned_object_as_output_to_next_nodes": "將程式碼中 return 的物件作為輸出,傳遞給後續的節點。變數名稱需要對應 return 的鍵值",
"please_enter_node_name": "請輸入節點名稱",
"plugin.Instruction_Tip": "您可以設定一段說明來解釋這個外掛程式的用途。每次使用外掛程式前,都會顯示這段說明。支援標準 Markdown 語法。",
"plugin.Instructions": "使用說明",
"plugin.global_file_input": "檔案連結(已淘汰)",
"plugin_file_abandon_tip": "外掛程式全域檔案上傳功能已淘汰,請儘速調整。您可以透過外掛程式輸入,新增圖片類型輸入來達成相關功能。",
"plugin_input": "外掛程式輸入",
"plugin_output_tool": "外掛程式作為工具執行時,這個欄位是否作為工具的回應結果",
"previous": "上一個",
"question_classification": "問題分類",
"question_optimization": "問題最佳化",
"quote_content_placeholder": "可以自訂引用內容的結構,以便更好地適應不同場景。可以使用一些變數來設定範本\n{{q}} - 主要內容\n{{a}} - 輔助資料\n{{source}} - 來源名稱\n{{sourceId}} - 來源 ID\n{{index}} - 第 n 個引用",
@ -177,9 +184,9 @@
"text_content_extraction": "文字內容擷取",
"text_to_extract": "要擷取的文字",
"these_variables_will_be_input_parameters_for_code_execution": "這些變數會作為程式碼執行的輸入參數",
"tool.tool_result": "工具運行結果",
"to_add_node": "添加節點",
"to_connect_node": "連接節點",
"tool.tool_result": "工具運行結果",
"tool_call_termination": "工具呼叫終止",
"tool_custom_field": "自訂工具變數",
"tool_field": "工具參數設定",

View File

@ -4992,9 +4992,10 @@
}
},
"node_modules/tar-fs": {
"version": "3.0.8",
"resolved": "https://registry.npmmirror.com/tar-fs/-/tar-fs-3.0.8.tgz",
"integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==",
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.9.tgz",
"integrity": "sha512-XF4w9Xp+ZQgifKakjZYmFdkLoSWd34VGKcsTCwlNWM7QG3ZbaxnTsaBwnjFZqHRf/rROxaR8rXnbtwdvaDI+lA==",
"license": "MIT",
"dependencies": {
"pump": "^3.0.0",
"tar-stream": "^3.1.5"

View File

@ -85,10 +85,10 @@ RUN chown -R nextjs:nodejs /app/data
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV PORT=3001
ENV NEXT_PUBLIC_BASE_URL=$base_url
EXPOSE 3000
EXPOSE 3001
USER nextjs

View File

@ -2,7 +2,9 @@
{
"feConfigs": {
"lafEnv": "https://laf.dev", // laf https://laf.run ,laf使 Laf openapi laf
"mcpServerProxyEndpoint": "" // mcp server http://localhost:3005
"mcpServerProxyEndpoint": "", // mcp server http://localhost:3005
"show_git":false,
"system_Title":"Test"
},
"systemEnv": {
"vectorMaxProcess": 10, // 线

View File

@ -0,0 +1,38 @@
version: '3.3'
services:
martin-gpt:
image: martingpt:v4.8.1 # 个人构建的镜像
container_name: martin-fastgpt
ports:
- '3001:3001'
networks:
- q00k04kgc8wk4k8okwog8owc_fastgpt
restart: always
environment:
- FE_DOMAIN=
- DEFAULT_ROOT_PSW=Pllh@123
- 'AIPROXY_API_ENDPOINT=http://aiproxy:3000'
- AIPROXY_API_TOKEN=aiproxy
- DB_MAX_LINK=30
- TOKEN_KEY=any
- ROOT_KEY=root_key
- FILE_TOKEN_KEY=filetoken
- 'MONGODB_URI=mongodb://myusername:mypassword@mongo:27017/fastgpt?authSource=admin'
- 'PG_URL=postgresql://username:password@pg:5432/postgres'
- 'REDIS_URL=redis://default:mypassword@redis:6379'
- 'SANDBOX_URL=http://sandbox:3000'
- LOG_LEVEL=info
- STORE_LOG_LEVEL=warn
- WORKFLOW_MAX_RUN_TIMES=1000
- WORKFLOW_MAX_LOOP_TIMES=100
- ALLOWED_ORIGINS=
- USE_IP_LIMIT=false
- CHAT_FILE_EXPIRE_TIME=7
volumes:
- '/data/martingpt/config.json:/app/data/config.json'
networks:
q00k04kgc8wk4k8okwog8owc_fastgpt:
external: true # 声明使用外部网络

View File

@ -3,9 +3,9 @@
"version": "4.9.10",
"private": false,
"scripts": {
"dev": "next dev",
"dev": "next dev -p 3001",
"build": "next build",
"start": "next start",
"start": "next start -p 3001",
"lint": "next lint"
},
"dependencies": {

View File

@ -39,6 +39,12 @@ export async function register() {
systemStartCb();
initGlobalVariables();
try {
await preLoadWorker();
} catch (error) {
console.error('Preload worker error', error);
}
// Connect to MongoDB
await connectMongo(connectionMongo, MONGO_URL);
connectMongo(connectionLogMongo, MONGO_LOG_URL);
@ -54,12 +60,6 @@ export async function register() {
startCron();
startTrainingQueue(true);
try {
await preLoadWorker();
} catch (error) {
console.error('Preload worker error', error);
}
console.log('Init system success');
}
} catch (error) {

View File

@ -26,6 +26,7 @@ import MultipleSelect, {
} from '@fastgpt/web/components/common/MySelect/MultipleSelect';
import Avatar from '@fastgpt/web/components/common/Avatar';
import { getTeamMembers } from '@/web/support/user/team/api';
import { createMetadataProcessorMap, type MetadataProcessor } from './processors';
function OperationLogTable({ Tabs }: { Tabs: React.ReactNode }) {
const { t } = useTranslation();
@ -58,6 +59,14 @@ function OperationLogTable({ Tabs }: { Tabs: React.ReactNode }) {
[t]
);
const processMetadataByEvent = useMemo(() => {
const metadataProcessorMap = createMetadataProcessorMap();
return (event: string, metadata: any) => {
const processor = metadataProcessorMap[event as OperationLogEventEnum];
return processor ? processor(metadata, t) : metadata;
};
}, [t]);
const {
data: operationLogs = [],
isLoading: loadingLogs,
@ -159,17 +168,7 @@ function OperationLogTable({ Tabs }: { Tabs: React.ReactNode }) {
<Tbody>
{operationLogs?.map((log) => {
const i18nData = operationLogMap[log.event];
const metadata = { ...log.metadata };
if (log.event === OperationLogEventEnum.ASSIGN_PERMISSION) {
const permissionValue = parseInt(metadata.permission, 10);
const permission = new TeamPermission({ per: permissionValue });
metadata.appCreate = permission.hasAppCreatePer ? '✔' : '✘';
metadata.datasetCreate = permission.hasDatasetCreatePer ? '✔' : '✘';
metadata.apiKeyCreate = permission.hasApikeyCreatePer ? '✔' : '✘';
metadata.manage = permission.hasManagePer ? '✔' : '✘';
}
const metadata = processMetadataByEvent(log.event, { ...log.metadata });
return i18nData ? (
<Tr key={log._id} overflow={'unset'}>

View File

@ -0,0 +1,17 @@
import { AppPermission } from '@fastgpt/global/support/permission/app/controller';
import { createSpecialProcessor } from './commonProcessor';
export const processUpdateAppCollaboratorSpecific = (metadata: any) => {
const permissionValue = parseInt(metadata.permission, 10);
const permission = new AppPermission({ per: permissionValue });
return {
...metadata,
readPermission: permission.hasReadPer ? '✔' : '✘',
writePermission: permission.hasWritePer ? '✔' : '✘',
managePermission: permission.hasManagePer ? '✔' : '✘'
};
};
export const createAppProcessors = () => ({
UPDATE_APP_COLLABORATOR: createSpecialProcessor(processUpdateAppCollaboratorSpecific)
});

View File

@ -0,0 +1,43 @@
export interface CommonMetadataFields {
appType?: string;
datasetType?: string;
operationName?: string;
itemName?: string;
newItemNames?: string[] | string;
[key: string]: any;
}
export const defaultMetadataProcessor = (metadata: CommonMetadataFields, t: any): any => {
const result = { ...metadata };
const translatableFields = ['appType', 'datasetType', 'operationName', 'itemName'];
Object.entries(metadata)
.filter(([key, value]) => translatableFields.includes(key) && value)
.forEach(([key, value]) => {
result[key] = t(value as any);
});
if (metadata.newItemNames) {
if (Array.isArray(metadata.newItemNames)) {
result.newItemNames = metadata.newItemNames
.map((itemName: string) => t(itemName as any))
.join(',');
} else if (typeof metadata.newItemNames === 'string') {
result.newItemNames = metadata.newItemNames
.split(',')
.map((itemName: string) => t(itemName as any))
.join(',');
}
}
return result;
};
export const createSpecialProcessor = (specificProcessor: (metadata: any) => any) => {
return (metadata: any, t: any) => {
let processedMetadata = defaultMetadataProcessor(metadata, t);
processedMetadata = specificProcessor(processedMetadata);
return processedMetadata;
};
};

View File

@ -0,0 +1,17 @@
import { DatasetPermission } from '@fastgpt/global/support/permission/dataset/controller';
import { createSpecialProcessor } from './commonProcessor';
export const processUpdateDatasetCollaboratorSpecific = (metadata: any) => {
const permissionValue = parseInt(metadata.permission, 10);
const permission = new DatasetPermission({ per: permissionValue });
return {
...metadata,
readPermission: permission.hasReadPer ? '✔' : '✘',
writePermission: permission.hasWritePer ? '✔' : '✘',
managePermission: permission.hasManagePer ? '✔' : '✘'
};
};
export const createDatasetProcessors = () => ({
UPDATE_DATASET_COLLABORATOR: createSpecialProcessor(processUpdateDatasetCollaboratorSpecific)
});

View File

@ -0,0 +1,30 @@
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { defaultMetadataProcessor } from './commonProcessor';
import { createTeamProcessors } from './teamProcessors';
import { createAppProcessors } from './appProcessors';
import { createDatasetProcessors } from './datasetProcessors';
export type MetadataProcessor = (metadata: any, t: any) => any;
export const createMetadataProcessorMap = (): Record<OperationLogEventEnum, MetadataProcessor> => {
const specialProcessors: Partial<Record<OperationLogEventEnum, MetadataProcessor>> = {
...createTeamProcessors(),
...createAppProcessors(),
...createDatasetProcessors()
};
const processorMap = {} as Record<OperationLogEventEnum, MetadataProcessor>;
Object.values(OperationLogEventEnum).forEach((event) => {
processorMap[event] =
specialProcessors[event] ||
((metadata: any, t: any) => defaultMetadataProcessor(metadata, t));
});
return processorMap;
};
export * from './commonProcessor';
export * from './teamProcessors';
export * from './appProcessors';
export * from './datasetProcessors';

View File

@ -0,0 +1,19 @@
import { TeamPermission } from '@fastgpt/global/support/permission/user/controller';
import { createSpecialProcessor } from './commonProcessor';
export const processAssignPermissionSpecific = (metadata: any) => {
const permissionValue = parseInt(metadata.permission, 10);
const permission = new TeamPermission({ per: permissionValue });
return {
...metadata,
appCreate: permission.hasAppCreatePer ? '✔' : '✘',
datasetCreate: permission.hasDatasetCreatePer ? '✔' : '✘',
apiKeyCreate: permission.hasApikeyCreatePer ? '✔' : '✘',
manage: permission.hasManagePer ? '✔' : '✘'
};
};
export const createTeamProcessors = () => ({
ASSIGN_PERMISSION: createSpecialProcessor(processAssignPermissionSpecific)
});

View File

@ -25,16 +25,20 @@ import MyModal from '@fastgpt/web/components/common/MyModal';
import { formatTime2YMDHMS } from '@fastgpt/global/common/string/time';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import SaveButton from '../Workflow/components/SaveButton';
import PublishHistories from '../PublishHistoriesSlider';
import { WorkflowEventContext } from '../WorkflowComponents/context/workflowEventContext';
import { WorkflowStatusContext } from '../WorkflowComponents/context/workflowStatusContext';
import SaveButton from '../Workflow/components/SaveButton';
const Header = () => {
const { t } = useTranslation();
const { isPc } = useSystem();
const router = useRouter();
const { toast } = useToast();
const { toast: backSaveToast } = useToast({
containerStyle: {
mt: '60px'
}
});
const { appDetail, onSaveApp, currentTab } = useContextSelector(AppContext, (v) => v);
const isV2Workflow = appDetail?.version === 'v2';
@ -183,6 +187,7 @@ const Header = () => {
size={'sm'}
leftIcon={<MyIcon name={'core/workflow/debug'} w={['14px', '16px']} />}
variant={'whitePrimary'}
flexShrink={0}
onClick={() => {
const data = flowData2StoreDataAndCheck();
if (data) {
@ -211,12 +216,12 @@ const Header = () => {
onBack,
onOpenBackConfirm,
isV2Workflow,
showHistoryModal,
t,
showHistoryModal,
loading,
onClickSave,
flowData2StoreDataAndCheck,
setShowHistoryModal,
flowData2StoreDataAndCheck,
setWorkflowTestData
]);
@ -229,10 +234,11 @@ const Header = () => {
setShowHistoryModal(false);
}}
past={past}
onSwitchTmpVersion={onSwitchTmpVersion}
onSwitchCloudVersion={onSwitchCloudVersion}
onSwitchTmpVersion={onSwitchTmpVersion}
/>
)}
<MyModal
isOpen={isOpenBackConfirm}
onClose={onCloseBackConfirm}
@ -254,7 +260,7 @@ const Header = () => {
await onClickSave({});
onCloseBackConfirm();
onBack();
toast({
backSaveToast({
status: 'success',
title: t('app:saved_success'),
position: 'top-right'

View File

@ -13,7 +13,7 @@ import { useTranslation } from 'next-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '../WorkflowComponents/context';
import { WorkflowContext, type WorkflowSnapshotsType } from '../WorkflowComponents/context';
import { AppContext, TabEnum } from '../context';
import RouteTab from '../RouteTab';
import { useRouter } from 'next/router';
@ -25,10 +25,10 @@ import MyModal from '@fastgpt/web/components/common/MyModal';
import { formatTime2YMDHMS } from '@fastgpt/global/common/string/time';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import SaveButton from './components/SaveButton';
import PublishHistories from '../PublishHistoriesSlider';
import { WorkflowEventContext } from '../WorkflowComponents/context/workflowEventContext';
import { WorkflowStatusContext } from '../WorkflowComponents/context/workflowStatusContext';
import SaveButton from '../Workflow/components/SaveButton';
const Header = () => {
const { t } = useTranslation();
@ -187,6 +187,7 @@ const Header = () => {
size={'sm'}
leftIcon={<MyIcon name={'core/workflow/debug'} w={['14px', '16px']} />}
variant={'whitePrimary'}
flexShrink={0}
onClick={() => {
const data = flowData2StoreDataAndCheck();
if (data) {
@ -215,12 +216,12 @@ const Header = () => {
onBack,
onOpenBackConfirm,
isV2Workflow,
showHistoryModal,
t,
showHistoryModal,
loading,
onClickSave,
flowData2StoreDataAndCheck,
setShowHistoryModal,
flowData2StoreDataAndCheck,
setWorkflowTestData
]);
@ -228,7 +229,7 @@ const Header = () => {
<>
{Render}
{showHistoryModal && isV2Workflow && currentTab === TabEnum.appEdit && (
<PublishHistories
<PublishHistories<WorkflowSnapshotsType>
onClose={() => {
setShowHistoryModal(false);
}}

View File

@ -43,6 +43,7 @@ const SaveButton = ({
Trigger={
<Button
size={'sm'}
flexShrink={0}
rightIcon={
<MyIcon
name={isSave ? 'core/chat/chevronUp' : 'core/chat/chevronDown'}

View File

@ -0,0 +1,220 @@
import React, { useState, useCallback } from 'react';
import { Box, Flex, Button, IconButton, type ButtonProps, Input } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { useContextSelector } from 'use-context-selector';
import { WorkflowNodeEdgeContext } from '../../WorkflowComponents/context/workflowInitContext';
import { useReactFlow } from 'reactflow';
import { useKeyPress, useThrottleEffect } from 'ahooks';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
const SearchButton = (props: ButtonProps) => {
const { t } = useTranslation();
const setNodes = useContextSelector(WorkflowNodeEdgeContext, (state) => state.setNodes);
const { fitView } = useReactFlow();
const { isMac } = useSystem();
const [keyword, setKeyword] = useState<string>();
const [searchIndex, setSearchIndex] = useState<number>(0);
const [searchedNodeCount, setSearchedNodeCount] = useState(0);
useKeyPress(['ctrl.f', 'meta.f'], (e) => {
e.preventDefault();
e.stopPropagation();
setKeyword('');
});
useKeyPress(['esc'], (e) => {
e.preventDefault();
e.stopPropagation();
setKeyword(undefined);
});
const onSearch = useCallback(() => {
setNodes((nodes) => {
if (!keyword) {
setSearchIndex(0);
setSearchedNodeCount(0);
return nodes.map((node) => ({
...node,
data: {
...node.data,
searchedText: undefined
}
}));
}
const searchResult = nodes.filter((node) => {
const nodeName = t(node.data.name as any);
return nodeName.toLowerCase().includes(keyword.toLowerCase());
});
if (searchResult.length === 0) {
return nodes.map((node) => ({
...node,
data: {
...node.data,
searchedText: undefined
}
}));
}
setSearchedNodeCount(searchResult.length);
const searchedNode = searchResult[searchIndex] ?? searchResult[0];
if (searchedNode) {
fitView({ nodes: [searchedNode], padding: 0.4 });
}
return nodes.map((node) => ({
...node,
selected: node.id === searchedNode.id,
data: {
...node.data,
searchedText: searchResult.find((item) => item.id === node.id) ? keyword : undefined
}
}));
});
}, [keyword, searchIndex]);
useThrottleEffect(
() => {
onSearch();
},
[onSearch],
{
wait: 500
}
);
const goToNextMatch = useCallback(() => {
if (searchIndex === searchedNodeCount - 1) {
setSearchIndex(0);
} else {
setSearchIndex(searchIndex + 1);
}
}, [searchIndex, searchedNodeCount]);
const goToPreviousMatch = useCallback(() => {
if (searchIndex === 0) {
setSearchIndex(searchedNodeCount - 1);
} else {
setSearchIndex(searchIndex - 1);
}
}, [searchIndex, searchedNodeCount]);
const clearSearch = useCallback(() => {
setKeyword(undefined);
setSearchIndex(0);
setSearchedNodeCount(0);
}, []);
if (keyword === undefined) {
return (
<Box position={'absolute'} top={'72px'} left={6} zIndex={1}>
<MyTooltip label={isMac ? t('workflow:find_tip_mac') : t('workflow:find_tip')}>
<IconButton
icon={<MyIcon name="common/searchLight" w="20px" color={'#8A95A7'} />}
aria-label=""
variant="whitePrimary"
size={'mdSquare'}
borderRadius={'50%'}
bg={'white'}
_hover={{ bg: 'white', borderColor: 'primary.300' }}
boxShadow={'0px 4px 10px 0px rgba(19, 51, 107, 0.20)'}
{...props}
onClick={() => setKeyword('')}
/>
</MyTooltip>
</Box>
);
}
return (
<Flex
position="absolute"
top={3}
left="50%"
transform="translateX(-50%)"
pl={5}
pr={4}
py={4}
zIndex={1}
borderRadius={'lg'}
bg={'white'}
alignItems={'center'}
boxShadow={
'0px 20px 24px -8px rgba(19, 51, 107, 0.15), 0px 0px 1px 0px rgba(19, 51, 107, 0.15)'
}
border={'0.5px solid rgba(0, 0, 0, 0.13)'}
maxW={['90vw', '550px']}
w={'100%'}
>
<Input
flex="1 0 0"
h={8}
border={'none'}
px={0}
_focus={{
border: 'none',
boxShadow: 'none'
}}
fontSize={'16px'}
value={keyword}
placeholder={t('workflow:please_enter_node_name')}
autoFocus
onFocus={onSearch}
onChange={(e) => setKeyword(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
e.stopPropagation();
goToNextMatch();
}
}}
/>
<Box fontSize="sm" color="myGray.600" whiteSpace={'nowrap'} userSelect={'none'}>
{searchedNodeCount > 0
? `${searchIndex + 1} / ${searchedNodeCount}`
: t('workflow:no_match_node')}
</Box>
{/* Border */}
<Box h={5} w={'1px'} bg={'myGray.250'} ml={3} mr={2} />
<Button
size="xs"
variant="grayGhost"
px={2}
isDisabled={searchedNodeCount <= 1}
onClick={goToPreviousMatch}
>
{t('workflow:previous')}
</Button>
<Button
size="xs"
variant="grayGhost"
px={2}
isDisabled={searchedNodeCount <= 1}
onClick={goToNextMatch}
>
{t('workflow:next')}
</Button>
<Flex
ml={2}
borderRadius="sm"
_hover={{ bg: 'myGray.100' }}
p={'1'}
cursor="pointer"
onClick={clearSearch}
>
<MyIcon name="common/closeLight" w="1.2rem" />
</Flex>
</Flex>
);
};
export default React.memo(SearchButton);

View File

@ -1,7 +1,6 @@
import React from 'react';
import ReactFlow, { type NodeProps, SelectionMode } from 'reactflow';
import { Box, IconButton, useDisclosure } from '@chakra-ui/react';
import { SmallCloseIcon } from '@chakra-ui/icons';
import { EDGE_TYPE, FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import dynamic from 'next/dynamic';
@ -20,6 +19,8 @@ import ContextMenu from './components/ContextMenu';
import { WorkflowNodeEdgeContext, WorkflowInitContext } from '../context/workflowInitContext';
import { WorkflowEventContext } from '../context/workflowEventContext';
import NodeTemplatesPopover from './NodeTemplatesPopover';
import SearchButton from '../../Workflow/components/SearchButton';
import MyIcon from '@fastgpt/web/components/common/Icon';
const NodeSimple = dynamic(() => import('./nodes/NodeSimple'));
const nodeTypes: Record<FlowNodeTypeEnum, any> = {
@ -113,20 +114,22 @@ const Workflow = () => {
<>
<IconButton
position={'absolute'}
top={5}
left={5}
top={6}
left={6}
size={'mdSquare'}
borderRadius={'50%'}
icon={<SmallCloseIcon fontSize={'26px'} />}
transform={isOpenTemplate ? '' : 'rotate(135deg)'}
icon={<MyIcon name="common/addLight" w={'26px'} />}
transition={'0.2s ease'}
aria-label={''}
zIndex={1}
boxShadow={'2px 2px 6px #85b1ff'}
boxShadow={
'0px 4px 10px 0px rgba(19, 51, 107, 0.20), 0px 0px 1px 0px rgba(19, 51, 107, 0.50)'
}
onClick={() => {
isOpenTemplate ? onCloseTemplate() : onOpenTemplate();
}}
/>
<SearchButton />
<NodeTemplatesModal isOpen={isOpenTemplate} onClose={onCloseTemplate} />
<NodeTemplatesPopover />
</>

View File

@ -36,6 +36,7 @@ import MyTag from '@fastgpt/web/components/common/Tag/index';
import MySelect from '@fastgpt/web/components/common/MySelect';
import { useCreation } from 'ahooks';
import { formatToolError } from '@fastgpt/global/core/app/utils';
import HighlightText from '@fastgpt/web/components/common/String/HighlightText';
type Props = FlowNodeItemType & {
children?: React.ReactNode | React.ReactNode[] | string;
@ -45,6 +46,7 @@ type Props = FlowNodeItemType & {
w?: string | number;
h?: string | number;
selected?: boolean;
searchedText?: string;
menuForbid?: {
debug?: boolean;
copy?: boolean;
@ -70,6 +72,7 @@ const NodeCard = (props: Props) => {
h = 'full',
nodeId,
selected,
searchedText,
menuForbid,
isTool = false,
isError = false,
@ -187,7 +190,12 @@ const NodeCard = (props: Props) => {
h={'24px'}
/>
<Box ml={2} fontSize={'18px'} fontWeight={'medium'} color={'myGray.900'}>
{t(name as any)}
<HighlightText
rawText={t(name as any)}
matchText={searchedText ?? ''}
mode={'bg'}
color={'#ffe82d'}
/>
</Box>
<Button
display={'none'}
@ -280,6 +288,7 @@ const NodeCard = (props: Props) => {
nodeId,
isFolded,
avatar,
searchedText,
t,
name,
showVersion,

View File

@ -49,7 +49,7 @@ const CustomTextInput = () => {
createStatus: 'waiting',
rawText: data.value,
sourceName: data.name,
icon: 'file/fill/manual'
icon: 'file/fill/txt'
}
]);
goToNext();

View File

@ -165,7 +165,7 @@ const FormLayout = ({ children, setPageType, pageType }: Props) => {
<MyImage src={LOGO_ICON} w={['22.5px', '36px']} alt={'icon'} />
</Flex>
<Box ml={[3, 5]} fontSize={['lg', 'xl']} fontWeight={'bold'} color={'myGray.900'}>
{feConfigs?.systemTitle}
FastGPT
</Box>
</Flex>
{!isPc && <I18nLngSelector />}

View File

@ -5,7 +5,10 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { onCreateApp } from './create';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
export type copyAppQuery = {};
export type copyAppBody = { appId: string };
@ -18,7 +21,7 @@ async function handler(
req: ApiRequestProps<copyAppBody, copyAppQuery>,
res: ApiResponseType<any>
): Promise<copyAppResponse> {
const { app } = await authApp({
const { app, teamId } = await authApp({
req,
authToken: true,
per: WritePermissionVal,
@ -42,6 +45,17 @@ async function handler(
tmbId,
pluginData: app.pluginData
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_APP_COPY,
params: {
appName: app.name,
appType: getI18nAppType(app.type)
}
});
})();
return { appId };
}

View File

@ -19,6 +19,9 @@ import { checkTeamAppLimit } from '@fastgpt/service/support/permission/teamLimit
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
import { type ApiRequestProps } from '@fastgpt/service/type/next';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
export type CreateAppBody = {
parentId?: ParentIdType;
@ -148,6 +151,17 @@ export const onCreateApp = async ({
{ session, ordered: true }
);
}
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_APP,
params: {
appName: name!,
appType: getI18nAppType(type!)
}
});
})();
await refreshSourceAvatar(avatar, undefined, session);

View File

@ -19,7 +19,10 @@ import { deleteChatFiles } from '@fastgpt/service/core/chat/controller';
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
import { MongoOpenApi } from '@fastgpt/service/support/openapi/schema';
import { removeImageByPath } from '@fastgpt/service/common/file/image/controller';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string };
@ -39,6 +42,17 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
teamId,
appId
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_APP,
params: {
appName: app.name,
appType: getI18nAppType(app.type)
}
});
})();
// Tracks
pushTrack.countAppNodes({ teamId, tmbId, uid: userId, appId });

View File

@ -18,7 +18,8 @@ import { syncCollaborators } from '@fastgpt/service/support/permission/inheritPe
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import { type ApiRequestProps } from '@fastgpt/service/type/next';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
export type CreateAppFolderBody = {
parentId?: ParentIdType;
name: string;
@ -83,6 +84,16 @@ async function handler(req: ApiRequestProps<CreateAppFolderBody>) {
);
}
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_APP_FOLDER,
params: {
folderName: name
}
});
})();
}
export default NextAPI(handler);

View File

@ -13,6 +13,9 @@ import { parsePaginationRequest } from '@fastgpt/service/common/api/pagination';
import { type PaginationResponse } from '@fastgpt/web/common/fetch/type';
import { addSourceMember } from '@fastgpt/service/support/user/utils';
import { replaceRegChars } from '@fastgpt/global/common/string/tools';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
async function handler(
req: NextApiRequest,
@ -33,7 +36,12 @@ async function handler(
}
// 凭证校验
const { teamId } = await authApp({ req, authToken: true, appId, per: WritePermissionVal });
const { teamId, tmbId, app } = await authApp({
req,
authToken: true,
appId,
per: WritePermissionVal
});
const where = {
teamId: new Types.ObjectId(teamId),
@ -139,6 +147,18 @@ async function handler(
const listWithoutTmbId = list.filter((item) => !item.tmbId);
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.EXPORT_APP_CHAT_LOG,
params: {
appName: app.name,
appType: getI18nAppType(app.type)
}
});
})();
return {
list: listWithSourceMember.concat(listWithoutTmbId),
total

View File

@ -138,18 +138,20 @@ async function handler(req: ApiRequestProps<ListAppBody>): Promise<AppListItemTy
})();
const limit = (() => {
if (getRecentlyChat) return 15;
if (searchKey) return 20;
return 1000;
if (searchKey) return 50;
return;
})();
const myApps = await MongoApp.find(
findAppsQuery,
'_id parentId avatar type name intro tmbId updateTime pluginData inheritPermission'
'_id parentId avatar type name intro tmbId updateTime pluginData inheritPermission',
{
limit: limit
}
)
.sort({
updateTime: -1
})
.limit(limit)
.lean();
// Add app permission and filter apps by read permission

View File

@ -24,6 +24,10 @@ import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/u
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
import { refreshSourceAvatar } from '@fastgpt/service/common/file/image/controller';
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
import { i18nT } from '@fastgpt/web/i18n/utils';
export type AppUpdateQuery = {
appId: string;
@ -54,7 +58,7 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
// this step is to get the app and its permission, and we will check the permission manually for
// different cases
const { app, permission } = await authApp({
const { app, permission, teamId, tmbId } = await authApp({
req,
authToken: true,
appId,
@ -65,11 +69,23 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
Promise.reject(AppErrEnum.unExist);
}
let targetName = '';
if (isMove) {
if (parentId) {
// move to a folder, check the target folder's permission
await authApp({ req, authToken: true, appId: parentId, per: ManagePermissionVal });
const { app: targetApp } = await authApp({
req,
authToken: true,
appId: parentId,
per: ManagePermissionVal
});
targetName = targetApp.name;
} else {
targetName = 'root';
}
if (app.parentId) {
// move from a folder, check the (old) folder's permission
await authApp({ req, authToken: true, appId: app.parentId, per: ManagePermissionVal });
@ -160,6 +176,7 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
session
});
} else {
logAppMove({ tmbId, teamId, app, targetName });
// Not folder, delete all clb
await MongoResourcePermission.deleteMany(
{ resourceType: PerResourceTypeEnum.app, teamId: app.teamId, resourceId: app._id },
@ -169,8 +186,85 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
return onUpdate(session);
});
} else {
logAppUpdate({ tmbId, teamId, app, name, intro });
return onUpdate();
}
}
export default NextAPI(handler);
const logAppMove = ({
tmbId,
teamId,
app,
targetName
}: {
tmbId: string;
teamId: string;
app: any;
targetName: string;
}) => {
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.MOVE_APP,
params: {
appName: app.name,
targetFolderName: targetName,
appType: getI18nAppType(app.type)
}
});
})();
};
const logAppUpdate = ({
tmbId,
teamId,
app,
name,
intro
}: {
tmbId: string;
teamId: string;
app: any;
name?: string;
intro?: string;
}) => {
(async () => {
const getUpdateItems = () => {
const names: string[] = [];
const values: string[] = [];
if (name !== undefined) {
names.push(i18nT('common:core.app.name'));
values.push(name);
}
if (intro !== undefined) {
names.push(i18nT('common:Intro'));
values.push(intro);
}
return {
names,
values
};
};
const { names: newItemNames, values: newItemValues } = getUpdateItems();
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_APP_INFO,
params: {
appName: app.name,
newItemNames: newItemNames,
newItemValues: newItemValues,
appType: getI18nAppType(app.type)
}
});
})();
};

View File

@ -11,12 +11,20 @@ import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'
import { type ApiRequestProps } from '@fastgpt/service/type/next';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { rewriteAppWorkflowToSimple } from '@fastgpt/service/core/app/utils';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
import { i18nT } from '@fastgpt/web/i18n/utils';
async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string };
const { nodes = [], edges = [], chatConfig, isPublish, versionName, autoSave } = req.body;
const { app, tmbId } = await authApp({ appId, req, per: WritePermissionVal, authToken: true });
const { app, tmbId, teamId } = await authApp({
appId,
req,
per: WritePermissionVal,
authToken: true
});
const { nodes: formatNodes } = beforeUpdateAppFormat({
nodes,
@ -26,12 +34,26 @@ async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiRe
await rewriteAppWorkflowToSimple(formatNodes);
if (autoSave) {
return MongoApp.findByIdAndUpdate(appId, {
await MongoApp.findByIdAndUpdate(appId, {
modules: formatNodes,
edges,
chatConfig,
updateTime: new Date()
});
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_PUBLISH_APP,
params: {
appName: app.name,
operationName: i18nT('account_team:update'),
appId,
appType: getI18nAppType(app.type)
}
});
return;
}
await mongoSessionRun(async (session) => {
@ -79,6 +101,22 @@ async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiRe
}
);
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_PUBLISH_APP,
params: {
appName: app.name,
operationName: isPublish
? i18nT('account_team:save_and_publish')
: i18nT('account_team:update'),
appId,
appType: getI18nAppType(app.type)
}
});
})();
}
export default NextAPI(handler);

View File

@ -4,11 +4,14 @@ import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
import { createOneCollection } from '@fastgpt/service/core/dataset/collection/controller';
import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) {
const body = req.body as CreateDatasetCollectionParams;
const { teamId, tmbId } = await authDataset({
const { teamId, tmbId, dataset } = await authDataset({
req,
authToken: true,
authApiKey: true,
@ -21,6 +24,20 @@ async function handler(req: NextApiRequest) {
teamId,
tmbId
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_COLLECTION,
params: {
collectionName: body.name,
datasetName: dataset.name,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
return _id;
}

View File

@ -4,11 +4,11 @@ import { type FileIdCreateDatasetCollectionParams } from '@fastgpt/global/core/d
import { createCollectionAndInsertData } from '@fastgpt/service/core/dataset/collection/controller';
import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
import { MongoRawTextBuffer } from '@fastgpt/service/common/buffer/rawText/schema';
import { NextAPI } from '@/service/middleware/entry';
import { type ApiRequestProps } from '@fastgpt/service/type/next';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { type CreateCollectionResponse } from '@/global/core/dataset/api';
import { deleteRawTextBuffer } from '@fastgpt/service/common/buffer/rawText/controller';
async function handler(
req: ApiRequestProps<FileIdCreateDatasetCollectionParams>
@ -52,7 +52,7 @@ async function handler(
});
// remove buffer
await MongoRawTextBuffer.deleteOne({ sourceId: fileId });
await deleteRawTextBuffer(fileId);
return {
collectionId,

View File

@ -14,6 +14,9 @@ import { authDatasetCollection } from '@fastgpt/service/support/permission/datas
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { i18nT } from '@fastgpt/web/i18n/utils';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
type RetrainingCollectionResponse = {
collectionId: string;
@ -124,6 +127,19 @@ async function handler(
}
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.RETRAIN_COLLECTION,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
return { collectionId };
});
}

View File

@ -6,6 +6,7 @@ import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constant
import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { type CreateCollectionResponse } from '@/global/core/dataset/api';
import { createFileFromText } from '@fastgpt/service/common/file/gridfs/utils';
async function handler(req: NextApiRequest): CreateCollectionResponse {
const { name, text, ...body } = req.body as TextCreateDatasetCollectionParams;
@ -18,6 +19,18 @@ async function handler(req: NextApiRequest): CreateCollectionResponse {
per: WritePermissionVal
});
// 1. Create file from text
const filename = `${name}.txt`;
const { fileId } = await createFileFromText({
bucket: 'dataset',
filename,
text,
metadata: {
teamId,
uid: tmbId
}
});
const { collectionId, insertResults } = await createCollectionAndInsertData({
dataset,
rawText: text,
@ -25,9 +38,9 @@ async function handler(req: NextApiRequest): CreateCollectionResponse {
...body,
teamId,
tmbId,
type: DatasetCollectionTypeEnum.virtual,
name
type: DatasetCollectionTypeEnum.file,
fileId,
name: filename
}
});

View File

@ -6,7 +6,9 @@ import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) {
const { id: collectionId } = req.query as { id: string };
@ -14,7 +16,7 @@ async function handler(req: NextApiRequest) {
return Promise.reject(CommonErrEnum.missingParams);
}
const { teamId, collection } = await authDatasetCollection({
const { teamId, collection, tmbId } = await authDatasetCollection({
req,
authToken: true,
authApiKey: true,
@ -39,6 +41,19 @@ async function handler(req: NextApiRequest) {
session
})
);
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_COLLECTION,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
}
export default NextAPI(handler);

View File

@ -12,7 +12,9 @@ import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constant
import { type ClientSession } from '@fastgpt/service/common/mongo';
import { type CollectionWithDatasetType } from '@fastgpt/global/core/dataset/type';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
export type UpdateDatasetCollectionParams = {
id?: string;
parentId?: string;
@ -88,7 +90,7 @@ async function handler(req: ApiRequestProps<UpdateDatasetCollectionParams>) {
}
// 凭证校验
const { collection, teamId } = await authDatasetCollection({
const { collection, teamId, tmbId } = await authDatasetCollection({
req,
authToken: true,
authApiKey: true,
@ -131,6 +133,19 @@ async function handler(req: ApiRequestProps<UpdateDatasetCollectionParams>) {
});
}
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_COLLECTION,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
}
export default NextAPI(handler);

View File

@ -18,6 +18,9 @@ import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
import { checkTeamDatasetLimit } from '@fastgpt/service/support/permission/teamLimit';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
export type DatasetCreateQuery = {};
export type DatasetCreateBody = CreateDatasetParams;
@ -102,6 +105,18 @@ async function handler(
uid: userId
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_DATASET,
params: {
datasetName: name,
datasetType: getI18nDatasetType(type)
}
});
})();
return datasetId;
}
export default NextAPI(handler);

View File

@ -4,7 +4,9 @@ import { deleteDatasetData } from '@/service/core/dataset/data/controller';
import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) {
const { id: dataId } = req.query as {
id: string;
@ -15,7 +17,7 @@ async function handler(req: NextApiRequest) {
}
// 凭证校验
const { datasetData } = await authDatasetData({
const { datasetData, tmbId, teamId, collection } = await authDatasetData({
req,
authToken: true,
authApiKey: true,
@ -24,7 +26,18 @@ async function handler(req: NextApiRequest) {
});
await deleteDatasetData(datasetData);
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_DATA,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
return 'success';
}

View File

@ -17,6 +17,9 @@ import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { getLLMMaxChunkSize } from '@fastgpt/global/core/dataset/training/utils';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) {
const { collectionId, q, a, indexes } = req.body as InsertOneDatasetDataProps;
@ -30,7 +33,7 @@ async function handler(req: NextApiRequest) {
}
// 凭证校验
const { teamId, tmbId } = await authDatasetCollection({
const { teamId, tmbId, collection } = await authDatasetCollection({
req,
authToken: true,
authApiKey: true,
@ -96,6 +99,18 @@ async function handler(req: NextApiRequest) {
model: vectorModelData.model
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_DATA,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
return insertId;
}

View File

@ -5,7 +5,9 @@ import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { authDatasetData } from '@fastgpt/service/support/permission/dataset/auth';
import { type ApiRequestProps } from '@fastgpt/service/type/next';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: ApiRequestProps<UpdateDatasetDataProps>) {
const { dataId, q, a, indexes = [] } = req.body;
@ -15,7 +17,8 @@ async function handler(req: ApiRequestProps<UpdateDatasetDataProps>) {
dataset: { vectorModel }
},
teamId,
tmbId
tmbId,
collection
} = await authDatasetData({
req,
authToken: true,
@ -39,6 +42,19 @@ async function handler(req: ApiRequestProps<UpdateDatasetDataProps>) {
inputTokens: tokens,
model: vectorModel
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_DATA,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
} else {
// await MongoDatasetData.findByIdAndUpdate(dataId, {
// ...(forbid !== undefined && { forbid })

View File

@ -11,6 +11,9 @@ import { MongoDatasetCollectionTags } from '@fastgpt/service/core/dataset/tag/sc
import { removeImageByPath } from '@fastgpt/service/common/file/image/controller';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { removeWebsiteSyncJobScheduler } from '@fastgpt/service/core/dataset/websiteSync';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) {
const { id: datasetId } = req.query as {
@ -22,7 +25,7 @@ async function handler(req: NextApiRequest) {
}
// auth owner
const { teamId } = await authDataset({
const { teamId, tmbId, dataset } = await authDataset({
req,
authToken: true,
authApiKey: true,
@ -66,6 +69,18 @@ async function handler(req: NextApiRequest) {
await removeImageByPath(dataset.avatar, session);
}
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_DATASET,
params: {
datasetName: dataset.name,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
}
export default NextAPI(handler);

View File

@ -17,6 +17,8 @@ import { syncCollaborators } from '@fastgpt/service/support/permission/inheritPe
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
export type DatasetFolderCreateQuery = {};
export type DatasetFolderCreateBody = {
parentId?: string;
@ -92,6 +94,16 @@ async function handler(
);
}
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_DATASET_FOLDER,
params: {
folderName: name
}
});
})();
return {};
}

View File

@ -14,7 +14,9 @@ import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { useIPFrequencyLimit } from '@fastgpt/service/common/middle/reqFrequencyLimit';
import { type ApiRequestProps } from '@fastgpt/service/type/next';
import { getRerankModel } from '@fastgpt/service/core/ai/model';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: ApiRequestProps<SearchTestProps>): Promise<SearchTestResponse> {
const {
datasetId,
@ -130,6 +132,17 @@ async function handler(req: ApiRequestProps<SearchTestProps>): Promise<SearchTes
totalPoints: embeddingTotalPoints + reRankTotalPoints
});
}
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.SEARCH_TEST,
params: {
datasetName: dataset.name,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
return {
list: searchRes,

View File

@ -37,6 +37,9 @@ import {
} from '@fastgpt/service/core/dataset/websiteSync';
import { delDatasetRelevantData } from '@fastgpt/service/core/dataset/controller';
import { isEqual } from 'lodash';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
export type DatasetUpdateQuery = {};
export type DatasetUpdateResponse = any;
@ -79,16 +82,27 @@ async function handler(
const isMove = parentId !== undefined;
const { dataset, permission } = await authDataset({
const { dataset, permission, tmbId, teamId } = await authDataset({
req,
authToken: true,
datasetId: id,
per: ReadPermissionVal
});
let targetName = '';
if (isMove) {
if (parentId) {
// move to a folder, check the target folder's permission
await authDataset({ req, authToken: true, datasetId: parentId, per: ManagePermissionVal });
const { dataset: targetDataset } = await authDataset({
req,
authToken: true,
datasetId: parentId,
per: ManagePermissionVal
});
targetName = targetDataset.name;
} else {
targetName = 'root';
}
if (dataset.parentId) {
// move from a folder, check the (old) folder's permission
@ -221,7 +235,9 @@ async function handler(
collaborators: parentClbsAndGroups,
session
});
logDatasetMove({ tmbId, teamId, dataset, targetName });
} else {
logDatasetMove({ tmbId, teamId, dataset, targetName });
// Not folder, delete all clb
await MongoResourcePermission.deleteMany(
{ resourceId: id, teamId: dataset.teamId, resourceType: PerResourceTypeEnum.dataset },
@ -230,6 +246,7 @@ async function handler(
}
return onUpdate(session);
} else {
logDatasetUpdate({ tmbId, teamId, dataset });
return onUpdate(session);
}
});
@ -315,3 +332,50 @@ const updateSyncSchedule = async ({
}
}
};
const logDatasetMove = ({
tmbId,
teamId,
dataset,
targetName
}: {
tmbId: string;
teamId: string;
dataset: any;
targetName: string;
}) => {
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.MOVE_DATASET,
params: {
datasetName: dataset.name,
targetFolderName: targetName,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
};
const logDatasetUpdate = ({
tmbId,
teamId,
dataset
}: {
tmbId: string;
teamId: string;
dataset: any;
}) => {
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_DATASET,
params: {
datasetName: dataset.name,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
};

View File

@ -8,7 +8,8 @@ import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { OpenApiErrEnum } from '@fastgpt/global/common/error/code/openapi';
import { TeamApikeyCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
async function handler(req: ApiRequestProps<EditApiKeyProps>): Promise<string> {
const { appId, name, limit } = req.body;
const { tmbId, teamId } = await (async () => {
@ -48,6 +49,18 @@ async function handler(req: ApiRequestProps<EditApiKeyProps>): Promise<string> {
name,
limit
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_API_KEY,
params: {
keyName: name
}
});
})();
return apiKey;
}

View File

@ -4,7 +4,8 @@ import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant'
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
export type OpenAPIDeleteQuery = { id: string };
export type OpenAPIDeleteBody = {};
export type OpenAPIDeleteResponse = {};
@ -19,9 +20,26 @@ async function handler(
return Promise.reject(CommonErrEnum.missingParams);
}
await authOpenApiKeyCrud({ req, authToken: true, id, per: OwnerPermissionVal });
const { tmbId, teamId, openapi } = await authOpenApiKeyCrud({
req,
authToken: true,
id,
per: OwnerPermissionVal
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_API_KEY,
params: {
keyName: openapi.name
}
});
})();
await MongoOpenApi.deleteOne({ _id: id });
return {};
}

View File

@ -4,11 +4,28 @@ import { authOpenApiKeyCrud } from '@fastgpt/service/support/permission/auth/ope
import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant';
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
async function handler(req: ApiRequestProps<EditApiKeyProps & { _id: string }>): Promise<void> {
const { _id, name, limit } = req.body;
await authOpenApiKeyCrud({ req, authToken: true, id: _id, per: OwnerPermissionVal });
const { tmbId, teamId } = await authOpenApiKeyCrud({
req,
authToken: true,
id: _id,
per: OwnerPermissionVal
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_API_KEY,
params: {
keyName: name
}
});
})();
await MongoOpenApi.findByIdAndUpdate(_id, {
...(name && { name }),

View File

@ -6,7 +6,9 @@ import type { PublishChannelEnum } from '@fastgpt/global/support/outLink/constan
import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant';
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
/* create a shareChat */
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
@ -23,7 +25,7 @@ async function handler(
): Promise<OutLinkCreateResponse> {
const { appId, ...props } = req.body;
const { teamId, tmbId } = await authApp({
const { teamId, tmbId, app } = await authApp({
req,
authToken: true,
appId,
@ -39,6 +41,19 @@ async function handler(
...props
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_APP_PUBLISH_CHANNEL,
params: {
appName: app.name,
channelName: props.name,
appType: getI18nAppType(app.type)
}
});
})();
return shareId;
}

View File

@ -3,6 +3,9 @@ import { authOutLinkCrud } from '@fastgpt/service/support/permission/publish/aut
import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant';
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
export type OutLinkDeleteQuery = {
id: string;
@ -15,8 +18,28 @@ async function handler(
req: ApiRequestProps<OutLinkDeleteBody, OutLinkDeleteQuery>
): Promise<OutLinkDeleteResponse> {
const { id } = req.query;
await authOutLinkCrud({ req, outLinkId: id, authToken: true, per: OwnerPermissionVal });
const { tmbId, teamId, outLink, app } = await authOutLinkCrud({
req,
outLinkId: id,
authToken: true,
per: OwnerPermissionVal
});
await MongoOutLink.findByIdAndDelete(id);
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_APP_PUBLISH_CHANNEL,
params: {
appName: app.name,
channelName: outLink.name,
appType: getI18nAppType(app.type)
}
});
})();
return {};
}

View File

@ -5,7 +5,9 @@ import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
export type OutLinkUpdateQuery = {};
// {
@ -30,7 +32,17 @@ async function handler(
return Promise.reject(CommonErrEnum.missingParams);
}
await authOutLinkCrud({ req, outLinkId: _id, authToken: true, per: ManagePermissionVal });
const {
tmbId,
teamId,
outLink,
app: logApp
} = await authOutLinkCrud({
req,
outLinkId: _id,
authToken: true,
per: ManagePermissionVal
});
await MongoOutLink.findByIdAndUpdate(_id, {
name,
@ -41,6 +53,19 @@ async function handler(
limit,
app
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_APP_PUBLISH_CHANNEL,
params: {
appName: logApp.name,
channelName: outLink.name,
appType: getI18nAppType(logApp.type)
}
});
})();
return {};
}
export default NextAPI(handler);

View File

@ -5,7 +5,8 @@ import { MongoUser } from '@fastgpt/service/support/user/schema';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
import { i18nT } from '@fastgpt/web/i18n/utils';
import { NextAPI } from '@/service/middleware/entry';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { oldPsw, newPsw } = req.body as { oldPsw: string; newPsw: string };
@ -13,7 +14,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
return Promise.reject('Params is missing');
}
const { tmbId } = await authCert({ req, authToken: true });
const { tmbId, teamId } = await authCert({ req, authToken: true });
const tmb = await MongoTeamMember.findById(tmbId);
if (!tmb) {
return Promise.reject('can not find it');
@ -39,6 +40,14 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
passwordUpdateTime: new Date()
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CHANGE_PASSWORD,
params: {}
});
})();
return user;
}

View File

@ -3,6 +3,9 @@ import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
import { checkExportDatasetLimit } from '@fastgpt/service/support/user/utils';
import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) {
const { datasetId } = req.query as {
@ -14,7 +17,7 @@ async function handler(req: NextApiRequest) {
}
// 凭证校验
const { teamId } = await authDataset({
const { teamId, tmbId, dataset } = await authDataset({
req,
authToken: true,
datasetId,
@ -25,6 +28,18 @@ async function handler(req: NextApiRequest) {
teamId,
limitMinutes: global.feConfigs?.limit?.exportDatasetLimitMinutes
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.EXPORT_DATASET,
params: {
datasetName: dataset.name,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
}
export default NextAPI(handler);

View File

@ -11,6 +11,7 @@ import { checkTimerLock } from '@fastgpt/service/common/system/timerLock/utils';
import { TimerIdEnum } from '@fastgpt/service/common/system/timerLock/constants';
import { addHours } from 'date-fns';
import { getScheduleTriggerApp } from '@/service/core/app/utils';
import { clearExpiredRawTextBufferCron } from '@fastgpt/service/common/buffer/rawText/controller';
// Try to run train every minute
const setTrainingQueueCron = () => {
@ -83,4 +84,5 @@ export const startCron = () => {
setClearTmpUploadFilesCron();
clearInvalidDataCron();
scheduleTriggerAppCron();
clearExpiredRawTextBufferCron();
};

View File

@ -2,7 +2,7 @@ import { MongoDatasetTraining } from '@fastgpt/service/core/dataset/training/sch
import { pushQAUsage } from '@/service/support/wallet/usage/push';
import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constants';
import { createChatCompletion } from '@fastgpt/service/core/ai/config';
import type { ChatCompletionMessageParam, StreamChatType } from '@fastgpt/global/core/ai/type.d';
import type { ChatCompletionMessageParam } from '@fastgpt/global/core/ai/type.d';
import { addLog } from '@fastgpt/service/common/system/log';
import { splitText2Chunks } from '@fastgpt/global/common/string/textSplitter';
import { replaceVariable } from '@fastgpt/global/common/string/tools';

Some files were not shown because too many files have changed in this diff Show More