Compare commits
8 Commits
v4.9.4
...
v4.9.5-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16a22bc76a | ||
|
|
b51a87f5b7 | ||
|
|
bc1ca66b66 | ||
|
|
c9e12bb608 | ||
|
|
4e7fa29087 | ||
|
|
ec3bcfa124 | ||
|
|
199f454b6b | ||
|
|
80f41dd2a9 |
3
.github/workflows/fastgpt-test.yaml
vendored
3
.github/workflows/fastgpt-test.yaml
vendored
@@ -15,6 +15,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<a href="./README_ja.md">日语</a>
|
||||
</p>
|
||||
|
||||
FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力。同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的问答场景!
|
||||
FastGPT 是一个 AI Agent 构建平台,提供开箱即用的数据处理、模型调用等能力,同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的应用场景!
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -126,15 +126,15 @@ services:
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.3 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.3 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.4 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.4 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.3 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.3 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.9.4 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.4 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
@@ -184,6 +184,8 @@ services:
|
||||
- ALLOWED_ORIGINS=
|
||||
# 是否开启IP限制,默认不开启
|
||||
- USE_IP_LIMIT=false
|
||||
# 对话文件过期天数
|
||||
- CHAT_FILE_EXPIRE_TIME=7
|
||||
volumes:
|
||||
- ./config.json:/app/data/config.json
|
||||
|
||||
|
||||
202
deploy/docker/docker-compose-oceanbase/docker-compose.yml
Normal file
202
deploy/docker/docker-compose-oceanbase/docker-compose.yml
Normal file
@@ -0,0 +1,202 @@
|
||||
# 数据库的默认账号和密码仅首次运行时设置有效
|
||||
# 如果修改了账号密码,记得改数据库和项目连接参数,别只改一处~
|
||||
# 该配置文件只是给快速启动,测试使用。正式使用,记得务必修改账号密码,以及调整合适的知识库参数,共享内存等。
|
||||
# 如何无法访问 dockerhub 和 git,可以用阿里云(阿里云没有arm包)
|
||||
|
||||
version: '3.3'
|
||||
services:
|
||||
# vector db
|
||||
ob:
|
||||
image: oceanbase/oceanbase-ce # docker hub
|
||||
# image: quay.io/oceanbase/oceanbase-ce:4.3.5.1-101000042025031818 # 镜像
|
||||
container_name: ob
|
||||
restart: always
|
||||
# ports: # 生产环境建议不要暴露
|
||||
# - 2881:2881
|
||||
networks:
|
||||
- fastgpt
|
||||
environment:
|
||||
# 这里的配置只有首次运行生效。修改后,重启镜像是不会生效的。需要把持久化数据删除再重启,才有效果
|
||||
- OB_SYS_PASSWORD=obsyspassword
|
||||
# 不同于传统数据库,OceanBase 数据库的账号包含更多字段,包括用户名、租户名和集群名。经典格式为“用户名@租户名#集群名”
|
||||
# 比如用mysql客户端连接时,根据本文件的默认配置,应该指定 “-uroot@tenantname”
|
||||
- OB_TENANT_NAME=tenantname
|
||||
- OB_TENANT_PASSWORD=tenantpassword
|
||||
# MODE分为MINI和NORMAL, 后者会最大程度使用主机资源
|
||||
- MODE=NORMAL
|
||||
- OB_SERVER_IP=127.0.0.1
|
||||
# 更多环境变量配置见oceanbase官方文档: https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002013494
|
||||
volumes:
|
||||
- ./ob/data:/root/ob
|
||||
- ./ob/config:/root/.obd/cluster
|
||||
- ./init.sql:/root/boot/init.d/init.sql
|
||||
healthcheck:
|
||||
# obclient -h127.0.0.1 -P2881 -uroot@tenantname -ptenantpassword -e "SELECT 1;"
|
||||
test: ["CMD-SHELL", "obclient -h$OB_SERVER_IP -P2881 -uroot@$OB_TENANT_NAME -p$OB_TENANT_PASSWORD -e \"SELECT 1;\""]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 1000
|
||||
start_period: 10s
|
||||
mongo:
|
||||
image: mongo:5.0.18 # dockerhub
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 # 阿里云
|
||||
# image: mongo:4.4.29 # cpu不支持AVX时候使用
|
||||
container_name: mongo
|
||||
restart: always
|
||||
# ports:
|
||||
# - 27017:27017
|
||||
networks:
|
||||
- fastgpt
|
||||
command: mongod --keyFile /data/mongodb.key --replSet rs0
|
||||
environment:
|
||||
- MONGO_INITDB_ROOT_USERNAME=myusername
|
||||
- MONGO_INITDB_ROOT_PASSWORD=mypassword
|
||||
volumes:
|
||||
- ./mongo/data:/data/db
|
||||
entrypoint:
|
||||
- bash
|
||||
- -c
|
||||
- |
|
||||
openssl rand -base64 128 > /data/mongodb.key
|
||||
chmod 400 /data/mongodb.key
|
||||
chown 999:999 /data/mongodb.key
|
||||
echo 'const isInited = rs.status().ok === 1
|
||||
if(!isInited){
|
||||
rs.initiate({
|
||||
_id: "rs0",
|
||||
members: [
|
||||
{ _id: 0, host: "mongo:27017" }
|
||||
]
|
||||
})
|
||||
}' > /data/initReplicaSet.js
|
||||
# 启动MongoDB服务
|
||||
exec docker-entrypoint.sh "$$@" &
|
||||
|
||||
# 等待MongoDB服务启动
|
||||
until mongo -u myusername -p mypassword --authenticationDatabase admin --eval "print('waited for connection')"; do
|
||||
echo "Waiting for MongoDB to start..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# 执行初始化副本集的脚本
|
||||
mongo -u myusername -p mypassword --authenticationDatabase admin /data/initReplicaSet.js
|
||||
|
||||
# 等待docker-entrypoint.sh脚本执行的MongoDB服务进程
|
||||
wait $$!
|
||||
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.3 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.3 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.3 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.3 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
- fastgpt
|
||||
depends_on:
|
||||
mongo:
|
||||
condition: service_started
|
||||
ob:
|
||||
condition: service_healthy
|
||||
sandbox:
|
||||
condition: service_started
|
||||
restart: always
|
||||
environment:
|
||||
# 前端外部可访问的地址,用于自动补全文件资源路径。例如 https:fastgpt.cn,不能填 localhost。这个值可以不填,不填则发给模型的图片会是一个相对路径,而不是全路径,模型可能伪造Host。
|
||||
- FE_DOMAIN=
|
||||
# root 密码,用户名为: root。如果需要修改 root 密码,直接修改这个环境变量,并重启即可。
|
||||
- DEFAULT_ROOT_PSW=1234
|
||||
# # AI Proxy 的地址,如果配了该地址,优先使用
|
||||
# - AIPROXY_API_ENDPOINT=http://aiproxy:3000
|
||||
# # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
|
||||
# - AIPROXY_API_TOKEN=aiproxy
|
||||
# 模型中转地址(如果用了 AI Proxy,下面 2 个就不需要了,旧版 OneAPI 用户,使用下面的变量)
|
||||
- # openai 基本地址,可用作中转。
|
||||
- OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
|
||||
- # OpenAI API Key
|
||||
- CHAT_API_KEY=sk-8990fa15a34b464a805237cfe9561f11
|
||||
# 数据库最大连接数
|
||||
- DB_MAX_LINK=30
|
||||
# 登录凭证密钥
|
||||
- TOKEN_KEY=any
|
||||
# root的密钥,常用于升级时候的初始化请求
|
||||
- ROOT_KEY=root_key
|
||||
# 文件阅读加密
|
||||
- FILE_TOKEN_KEY=filetoken
|
||||
# MongoDB 连接参数. 用户名myusername,密码mypassword。
|
||||
- MONGODB_URI=mongodb://myusername:mypassword@mongo:27017/fastgpt?authSource=admin
|
||||
# OceanBase 向量库连接参数
|
||||
- OCEANBASE_URL=mysql://root%40tenantname:tenantpassword@ob:2881/test
|
||||
# sandbox 地址
|
||||
- SANDBOX_URL=http://sandbox:3000
|
||||
# 日志等级: debug, info, warn, error
|
||||
- LOG_LEVEL=info
|
||||
- STORE_LOG_LEVEL=warn
|
||||
# 工作流最大运行次数
|
||||
- WORKFLOW_MAX_RUN_TIMES=1000
|
||||
# 批量执行节点,最大输入长度
|
||||
- WORKFLOW_MAX_LOOP_TIMES=100
|
||||
# 自定义跨域,不配置时,默认都允许跨域(多个域名通过逗号分割)
|
||||
- ALLOWED_ORIGINS=
|
||||
# 是否开启IP限制,默认不开启
|
||||
- USE_IP_LIMIT=false
|
||||
volumes:
|
||||
- ./config.json:/app/data/config.json
|
||||
|
||||
# AI Proxy
|
||||
aiproxy:
|
||||
image: ghcr.io/labring/aiproxy:v0.1.5
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/labring/aiproxy:v0.1.3 # 阿里云
|
||||
container_name: aiproxy
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
aiproxy_pg:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- fastgpt
|
||||
environment:
|
||||
# 对应 fastgpt 里的AIPROXY_API_TOKEN
|
||||
- ADMIN_KEY=aiproxy
|
||||
# 错误日志详情保存时间(小时)
|
||||
- LOG_DETAIL_STORAGE_HOURS=1
|
||||
# 数据库连接地址
|
||||
- SQL_DSN=postgres://postgres:aiproxy@aiproxy_pg:5432/aiproxy
|
||||
# 最大重试次数
|
||||
- RETRY_TIMES=3
|
||||
# 不需要计费
|
||||
- BILLING_ENABLED=false
|
||||
# 不需要严格检测模型
|
||||
- DISABLE_MODEL_CONFIG=true
|
||||
healthcheck:
|
||||
test: ['CMD', 'curl', '-f', 'http://localhost:3000/api/status']
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
aiproxy_pg:
|
||||
image: pgvector/pgvector:0.8.0-pg15 # docker hub
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.8.0-pg15 # 阿里云
|
||||
restart: unless-stopped
|
||||
container_name: aiproxy_pg
|
||||
volumes:
|
||||
- ./aiproxy_pg:/var/lib/postgresql/data
|
||||
networks:
|
||||
- fastgpt
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: aiproxy
|
||||
POSTGRES_PASSWORD: aiproxy
|
||||
healthcheck:
|
||||
test: ['CMD', 'pg_isready', '-U', 'postgres', '-d', 'aiproxy']
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
fastgpt:
|
||||
2
deploy/docker/docker-compose-oceanbase/init.sql
Normal file
2
deploy/docker/docker-compose-oceanbase/init.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER SYSTEM SET ob_vector_memory_limit_percentage = 30;
|
||||
|
||||
@@ -85,15 +85,15 @@ services:
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.3 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.3 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.4 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.4 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.3 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.3 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.9.4 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.4 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
@@ -142,6 +142,8 @@ services:
|
||||
- ALLOWED_ORIGINS=
|
||||
# 是否开启IP限制,默认不开启
|
||||
- USE_IP_LIMIT=false
|
||||
# 对话文件过期天数
|
||||
- CHAT_FILE_EXPIRE_TIME=7
|
||||
volumes:
|
||||
- ./config.json:/app/data/config.json
|
||||
|
||||
|
||||
@@ -66,15 +66,15 @@ services:
|
||||
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.3 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.3 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.4 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.4 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.3 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.3 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.9.4 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.4 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
@@ -123,6 +123,8 @@ services:
|
||||
- ALLOWED_ORIGINS=
|
||||
# 是否开启IP限制,默认不开启
|
||||
- USE_IP_LIMIT=false
|
||||
# 对话文件过期天数
|
||||
- CHAT_FILE_EXPIRE_TIME=7
|
||||
volumes:
|
||||
- ./config.json:/app/data/config.json
|
||||
|
||||
|
||||
@@ -135,6 +135,9 @@ curl -O https://raw.githubusercontent.com/labring/FastGPT/main/projects/app/data
|
||||
|
||||
# pgvector 版本(测试推荐,简单快捷)
|
||||
curl -o docker-compose.yml https://raw.githubusercontent.com/labring/FastGPT/main/deploy/docker/docker-compose-pgvector.yml
|
||||
# oceanbase 版本(需要将init.sql和docker-compose.yml放在同一个文件夹,方便挂载)
|
||||
# curl -o docker-compose.yml https://raw.githubusercontent.com/labring/FastGPT/main/deploy/docker/docker-compose-oceanbase/docker-compose.yml
|
||||
# curl -o init.sql https://raw.githubusercontent.com/labring/FastGPT/main/deploy/docker/docker-compose-oceanbase/init.sql
|
||||
# milvus 版本
|
||||
# curl -o docker-compose.yml https://raw.githubusercontent.com/labring/FastGPT/main/deploy/docker/docker-compose-milvus.yml
|
||||
# zilliz 版本
|
||||
@@ -151,6 +154,13 @@ curl -o docker-compose.yml https://raw.githubusercontent.com/labring/FastGPT/mai
|
||||
|
||||
无需操作
|
||||
|
||||
{{< /markdownify >}}
|
||||
{{< /tab >}}
|
||||
{{< tab tabName="Oceanbase版本" >}}
|
||||
{{< markdownify >}}
|
||||
|
||||
无需操作
|
||||
|
||||
{{< /markdownify >}}
|
||||
{{< /tab >}}
|
||||
{{< tab tabName="Milvus版本" >}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: 'V4.9.4(进行中)'
|
||||
title: 'V4.9.4'
|
||||
description: 'FastGPT V4.9.4 更新说明'
|
||||
icon: 'upgrade'
|
||||
draft: false
|
||||
@@ -11,7 +11,7 @@ weight: 796
|
||||
|
||||
### 1. 做好数据备份
|
||||
|
||||
### 1. 安装 Redis
|
||||
### 2. 安装 Redis
|
||||
|
||||
* docker 部署的用户,参考最新的 `docker-compose.yml` 文件增加 Redis 配置。增加一个 redis 容器,并配置`fastgpt`,`fastgpt-pro`的环境变量,增加 `REDIS_URL` 环境变量。
|
||||
* Sealos 部署的用户,在数据库里新建一个`redis`数据库,并复制`内网地址的 connection` 作为 `redis` 的链接串。然后配置`fastgpt`,`fastgpt-pro`的环境变量,增加 `REDIS_URL` 环境变量。
|
||||
@@ -20,14 +20,14 @@ weight: 796
|
||||
| --- | --- | --- |
|
||||
|  |  |  |
|
||||
|
||||
### 2. 更新镜像 tag
|
||||
### 3. 更新镜像 tag
|
||||
|
||||
- 更新 FastGPT 镜像 tag: v4.9.4-alpha
|
||||
- 更新 FastGPT 商业版镜像 tag: v4.9.4-alpha
|
||||
- 更新 FastGPT 镜像 tag: v4.9.4
|
||||
- 更新 FastGPT 商业版镜像 tag: v4.9.4
|
||||
- Sandbox 无需更新
|
||||
- AIProxy 无需更新
|
||||
|
||||
### 3. 执行升级脚本
|
||||
### 4. 执行升级脚本
|
||||
|
||||
该脚本仅需商业版用户执行。
|
||||
|
||||
@@ -49,8 +49,8 @@ curl --location --request POST 'https://{{host}}/api/admin/initv494' \
|
||||
2. SMTP 发送邮件插件
|
||||
3. BullMQ 消息队列。
|
||||
4. 利用 redis 进行部分数据缓存。
|
||||
5. 站点同步支持配置训练参数。
|
||||
6. AI 对话/工具调用,增加返回模型 finish_reason 字段。
|
||||
5. 站点同步支持配置训练参数和增量同步。
|
||||
6. AI 对话/工具调用,增加返回模型 finish_reason 字段,便于追踪模型输出中断原因。
|
||||
7. 移动端语音输入交互调整
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
28
docSite/content/zh-cn/docs/development/upgrading/495.md
Normal file
28
docSite/content/zh-cn/docs/development/upgrading/495.md
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: 'V4.9.5(进行中)'
|
||||
description: 'FastGPT V4.9.5 更新说明'
|
||||
icon: 'upgrade'
|
||||
draft: false
|
||||
toc: true
|
||||
weight: 795
|
||||
---
|
||||
|
||||
|
||||
## 🚀 新增内容
|
||||
|
||||
1. 团队成员权限细分,可分别控制是否可创建在根目录应用/知识库以及 API Key
|
||||
2. 支持交互节点在嵌套工作流中使用。
|
||||
3. 团队成员操作日志。
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
1. 繁体中文翻译。
|
||||
|
||||
|
||||
## 🐛 修复
|
||||
|
||||
1. password 检测规则错误。
|
||||
2. 分享链接无法隐藏知识库检索结果。
|
||||
3. IOS 低版本正则兼容问题。
|
||||
4. 修复问答提取队列错误后,计数器未清零问题,导致问答提取队列失效。
|
||||
5. Debug 模式交互节点下一步可能造成死循环。
|
||||
12
package.json
12
package.json
@@ -12,27 +12,29 @@
|
||||
"previewIcon": "node ./scripts/icon/index.js",
|
||||
"api:gen": "tsc ./scripts/openapi/index.ts && node ./scripts/openapi/index.js && npx @redocly/cli build-docs ./scripts/openapi/openapi.json -o ./projects/app/public/openapi/index.html",
|
||||
"create:i18n": "node ./scripts/i18n/index.js",
|
||||
"test": "vitest run --exclude 'test/cases/spec'",
|
||||
"test:all": "vitest run",
|
||||
"test": "vitest run",
|
||||
"test:workflow": "vitest run workflow"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@chakra-ui/cli": "^2.4.1",
|
||||
"@vitest/coverage-v8": "^3.0.2",
|
||||
"@vitest/coverage-v8": "^3.0.9",
|
||||
"husky": "^8.0.3",
|
||||
"i18next": "23.16.8",
|
||||
"lint-staged": "^13.3.0",
|
||||
"next-i18next": "15.4.2",
|
||||
"prettier": "3.2.4",
|
||||
"react-i18next": "14.1.2",
|
||||
"vitest": "^3.0.2",
|
||||
"vitest-mongodb": "^1.0.1",
|
||||
"vitest": "^3.0.9",
|
||||
"mongodb-memory-server": "^10.1.4",
|
||||
"zhlint": "^0.7.4"
|
||||
},
|
||||
"lint-staged": {
|
||||
"./**/**/*.{ts,tsx,scss}": "npm run format-code",
|
||||
"./docSite/**/**/*.md": "npm run format-doc"
|
||||
},
|
||||
"resolutions": {
|
||||
"mdast-util-gfm-autolink-literal": "2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.16.0",
|
||||
"pnpm": ">=9.0.0"
|
||||
|
||||
@@ -77,6 +77,13 @@ export const getHistoryPreview = (
|
||||
});
|
||||
};
|
||||
|
||||
export const filterModuleTypeList: any[] = [
|
||||
FlowNodeTypeEnum.pluginModule,
|
||||
FlowNodeTypeEnum.datasetSearchNode,
|
||||
FlowNodeTypeEnum.tools,
|
||||
FlowNodeTypeEnum.pluginOutput
|
||||
];
|
||||
|
||||
export const filterPublicNodeResponseData = ({
|
||||
flowResponses = [],
|
||||
responseDetail = false
|
||||
@@ -87,12 +94,6 @@ export const filterPublicNodeResponseData = ({
|
||||
const filedList = responseDetail
|
||||
? ['quoteList', 'moduleType', 'pluginOutput', 'runningTime']
|
||||
: ['moduleType', 'pluginOutput', 'runningTime'];
|
||||
const filterModuleTypeList: any[] = [
|
||||
FlowNodeTypeEnum.pluginModule,
|
||||
FlowNodeTypeEnum.datasetSearchNode,
|
||||
FlowNodeTypeEnum.tools,
|
||||
FlowNodeTypeEnum.pluginOutput
|
||||
];
|
||||
|
||||
return flowResponses
|
||||
.filter((item) => filterModuleTypeList.includes(item.moduleType))
|
||||
|
||||
@@ -23,7 +23,7 @@ import { WorkflowResponseType } from '../../../../service/core/workflow/dispatch
|
||||
import { AiChatQuoteRoleType } from '../template/system/aiChat/type';
|
||||
import { LafAccountType, OpenaiAccountType } from '../../../support/user/team/type';
|
||||
import { CompletionFinishReason } from '../../ai/type';
|
||||
|
||||
import { WorkflowInteractiveResponseType } from '../template/system/interactive/type';
|
||||
export type ExternalProviderType = {
|
||||
openaiAccount?: OpenaiAccountType;
|
||||
externalWorkflowVariables?: Record<string, string>;
|
||||
@@ -55,12 +55,14 @@ export type ChatDispatchProps = {
|
||||
variables: Record<string, any>; // global variable
|
||||
query: UserChatItemValueItemType[]; // trigger query
|
||||
chatConfig: AppSchema['chatConfig'];
|
||||
lastInteractive?: WorkflowInteractiveResponseType; // last interactive response
|
||||
stream: boolean;
|
||||
maxRunTimes: number;
|
||||
isToolCall?: boolean;
|
||||
workflowStreamResponse?: WorkflowResponseType;
|
||||
workflowDispatchDeep?: number;
|
||||
version?: 'v1' | 'v2';
|
||||
responseDetail?: boolean;
|
||||
};
|
||||
|
||||
export type ModuleDispatchProps<T> = ChatDispatchProps & {
|
||||
|
||||
@@ -10,7 +10,19 @@ import { FlowNodeOutputItemType, ReferenceValueType } from '../type/io';
|
||||
import { ChatItemType, NodeOutputItemType } from '../../../core/chat/type';
|
||||
import { ChatItemValueTypeEnum, ChatRoleEnum } from '../../../core/chat/constants';
|
||||
import { replaceVariable, valToStr } from '../../../common/string/tools';
|
||||
import {
|
||||
InteractiveNodeResponseType,
|
||||
WorkflowInteractiveResponseType
|
||||
} from '../template/system/interactive/type';
|
||||
|
||||
export const extractDeepestInteractive = (
|
||||
interactive: WorkflowInteractiveResponseType
|
||||
): WorkflowInteractiveResponseType => {
|
||||
if (interactive?.type === 'childrenInteractive' && interactive.params?.childrenResponse) {
|
||||
return extractDeepestInteractive(interactive.params.childrenResponse);
|
||||
}
|
||||
return interactive;
|
||||
};
|
||||
export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number => {
|
||||
let limit = 10;
|
||||
nodes.forEach((node) => {
|
||||
@@ -34,7 +46,9 @@ export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number
|
||||
1. Get the interactive data
|
||||
2. Check that the workflow starts at the interaction node
|
||||
*/
|
||||
export const getLastInteractiveValue = (histories: ChatItemType[]) => {
|
||||
export const getLastInteractiveValue = (
|
||||
histories: ChatItemType[]
|
||||
): WorkflowInteractiveResponseType | undefined => {
|
||||
const lastAIMessage = [...histories].reverse().find((item) => item.obj === ChatRoleEnum.AI);
|
||||
|
||||
if (lastAIMessage) {
|
||||
@@ -45,7 +59,11 @@ export const getLastInteractiveValue = (histories: ChatItemType[]) => {
|
||||
lastValue.type !== ChatItemValueTypeEnum.interactive ||
|
||||
!lastValue.interactive
|
||||
) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastValue.interactive.type === 'childrenInteractive') {
|
||||
return lastValue.interactive;
|
||||
}
|
||||
|
||||
// Check is user select
|
||||
@@ -62,38 +80,29 @@ export const getLastInteractiveValue = (histories: ChatItemType[]) => {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return;
|
||||
};
|
||||
|
||||
export const initWorkflowEdgeStatus = (
|
||||
edges: StoreEdgeItemType[] | RuntimeEdgeItemType[],
|
||||
histories?: ChatItemType[]
|
||||
edges: StoreEdgeItemType[],
|
||||
lastInteractive?: WorkflowInteractiveResponseType
|
||||
): RuntimeEdgeItemType[] => {
|
||||
// If there is a history, use the last interactive value
|
||||
if (histories && histories.length > 0) {
|
||||
const memoryEdges = getLastInteractiveValue(histories)?.memoryEdges;
|
||||
|
||||
if (lastInteractive) {
|
||||
const memoryEdges = lastInteractive.memoryEdges || [];
|
||||
if (memoryEdges && memoryEdges.length > 0) {
|
||||
return memoryEdges;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
edges?.map((edge) => ({
|
||||
...edge,
|
||||
status: 'waiting'
|
||||
})) || []
|
||||
);
|
||||
return edges?.map((edge) => ({ ...edge, status: 'waiting' })) || [];
|
||||
};
|
||||
|
||||
export const getWorkflowEntryNodeIds = (
|
||||
nodes: (StoreNodeItemType | RuntimeNodeItemType)[],
|
||||
histories?: ChatItemType[]
|
||||
lastInteractive?: WorkflowInteractiveResponseType
|
||||
) => {
|
||||
// If there is a history, use the last interactive entry node
|
||||
if (histories && histories.length > 0) {
|
||||
const entryNodeIds = getLastInteractiveValue(histories)?.entryNodeIds;
|
||||
|
||||
if (lastInteractive) {
|
||||
const entryNodeIds = lastInteractive.entryNodeIds || [];
|
||||
if (Array.isArray(entryNodeIds) && entryNodeIds.length > 0) {
|
||||
return entryNodeIds;
|
||||
}
|
||||
@@ -396,10 +405,10 @@ export const textAdaptGptResponse = ({
|
||||
|
||||
/* Update runtimeNode's outputs with interactive data from history */
|
||||
export function rewriteNodeOutputByHistories(
|
||||
histories: ChatItemType[],
|
||||
runtimeNodes: RuntimeNodeItemType[]
|
||||
runtimeNodes: RuntimeNodeItemType[],
|
||||
lastInteractive?: InteractiveNodeResponseType
|
||||
) {
|
||||
const interactive = getLastInteractiveValue(histories);
|
||||
const interactive = lastInteractive;
|
||||
if (!interactive?.nodeOutputs) {
|
||||
return runtimeNodes;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { NodeOutputItemType } from '../../../../chat/type';
|
||||
import type { FlowNodeOutputItemType } from '../../../type/io';
|
||||
import type { RuntimeEdgeItemType } from '../../../runtime/type';
|
||||
import { FlowNodeInputTypeEnum } from 'core/workflow/node/constant';
|
||||
import { WorkflowIOValueTypeEnum } from 'core/workflow/constants';
|
||||
import type { ChatCompletionMessageParam } from '../../../../ai/type';
|
||||
@@ -9,7 +8,6 @@ type InteractiveBasicType = {
|
||||
entryNodeIds: string[];
|
||||
memoryEdges: RuntimeEdgeItemType[];
|
||||
nodeOutputs: NodeOutputItemType[];
|
||||
|
||||
toolParams?: {
|
||||
entryNodeIds: string[]; // 记录工具中,交互节点的 Id,而不是起始工作流的入口
|
||||
memoryMessages: ChatCompletionMessageParam[]; // 这轮工具中,产生的新的 messages
|
||||
@@ -23,6 +21,13 @@ type InteractiveNodeType = {
|
||||
nodeOutputs?: NodeOutputItemType[];
|
||||
};
|
||||
|
||||
type ChildrenInteractive = InteractiveNodeType & {
|
||||
type: 'childrenInteractive';
|
||||
params: {
|
||||
childrenResponse?: WorkflowInteractiveResponseType;
|
||||
};
|
||||
};
|
||||
|
||||
export type UserSelectOptionItemType = {
|
||||
key: string;
|
||||
value: string;
|
||||
@@ -62,5 +67,9 @@ type UserInputInteractive = InteractiveNodeType & {
|
||||
submitted?: boolean;
|
||||
};
|
||||
};
|
||||
export type InteractiveNodeResponseType = UserSelectInteractive | UserInputInteractive;
|
||||
|
||||
export type InteractiveNodeResponseType =
|
||||
| UserSelectInteractive
|
||||
| UserInputInteractive
|
||||
| ChildrenInteractive;
|
||||
export type WorkflowInteractiveResponseType = InteractiveBasicType & InteractiveNodeResponseType;
|
||||
|
||||
14
packages/global/support/operationLog/constants.ts
Normal file
14
packages/global/support/operationLog/constants.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export enum OperationLogEventEnum {
|
||||
LOGIN = 'LOGIN',
|
||||
CREATE_INVITATION_LINK = 'CREATE_INVITATION_LINK',
|
||||
JOIN_TEAM = 'JOIN_TEAM',
|
||||
CHANGE_MEMBER_NAME = 'CHANGE_MEMBER_NAME',
|
||||
KICK_OUT_TEAM = 'KICK_OUT_TEAM',
|
||||
CREATE_DEPARTMENT = 'CREATE_DEPARTMENT',
|
||||
CHANGE_DEPARTMENT = 'CHANGE_DEPARTMENT',
|
||||
DELETE_DEPARTMENT = 'DELETE_DEPARTMENT',
|
||||
RELOCATE_DEPARTMENT = 'RELOCATE_DEPARTMENT',
|
||||
CREATE_GROUP = 'CREATE_GROUP',
|
||||
DELETE_GROUP = 'DELETE_GROUP',
|
||||
ASSIGN_PERMISSION = 'ASSIGN_PERMISSION'
|
||||
}
|
||||
19
packages/global/support/operationLog/type.d.ts
vendored
Normal file
19
packages/global/support/operationLog/type.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import { SourceMemberType } from '../user/type';
|
||||
import { OperationLogEventEnum } from './constants';
|
||||
|
||||
export type OperationLogSchema = {
|
||||
_id: string;
|
||||
tmbId: string;
|
||||
teamId: string;
|
||||
timestamp: Date;
|
||||
event: `${OperationLogEventEnum}`;
|
||||
metadata?: Record<string, string>;
|
||||
};
|
||||
|
||||
export type OperationListItemType = {
|
||||
_id: string;
|
||||
sourceMember: SourceMemberType;
|
||||
event: `${OperationLogEventEnum}`;
|
||||
timestamp: Date;
|
||||
metadata: Record<string, string>;
|
||||
};
|
||||
@@ -13,12 +13,15 @@ export type CollaboratorItemType = {
|
||||
orgId: string;
|
||||
}>;
|
||||
|
||||
export type UpdateClbPermissionProps = {
|
||||
export type UpdateClbPermissionProps<addOnly = false> = {
|
||||
members?: string[];
|
||||
groups?: string[];
|
||||
orgs?: string[];
|
||||
permission: PermissionValueType;
|
||||
};
|
||||
} & (addOnly extends true
|
||||
? {}
|
||||
: {
|
||||
permission: PermissionValueType;
|
||||
});
|
||||
|
||||
export type DeletePermissionQuery = RequireOnlyOne<{
|
||||
tmbId?: string;
|
||||
|
||||
@@ -5,15 +5,16 @@ export type PerConstructPros = {
|
||||
per?: PermissionValueType;
|
||||
isOwner?: boolean;
|
||||
permissionList?: PermissionListType;
|
||||
childUpdatePermissionCallback?: () => void;
|
||||
};
|
||||
|
||||
// the Permission helper class
|
||||
export class Permission {
|
||||
value: PermissionValueType;
|
||||
isOwner: boolean;
|
||||
hasManagePer: boolean;
|
||||
hasWritePer: boolean;
|
||||
hasReadPer: boolean;
|
||||
isOwner: boolean = false;
|
||||
hasManagePer: boolean = false;
|
||||
hasWritePer: boolean = false;
|
||||
hasReadPer: boolean = false;
|
||||
_permissionList: PermissionListType;
|
||||
|
||||
constructor(props?: PerConstructPros) {
|
||||
@@ -24,11 +25,8 @@ export class Permission {
|
||||
this.value = per;
|
||||
}
|
||||
|
||||
this.isOwner = isOwner;
|
||||
this._permissionList = permissionList;
|
||||
this.hasManagePer = this.checkPer(this._permissionList['manage'].value);
|
||||
this.hasWritePer = this.checkPer(this._permissionList['write'].value);
|
||||
this.hasReadPer = this.checkPer(this._permissionList['read'].value);
|
||||
this.updatePermissions();
|
||||
}
|
||||
|
||||
// add permission(s)
|
||||
@@ -68,10 +66,21 @@ export class Permission {
|
||||
return (this.value & perm) === perm;
|
||||
}
|
||||
|
||||
private updatePermissionCallback?: () => void;
|
||||
setUpdatePermissionCallback(callback: () => void) {
|
||||
callback();
|
||||
this.updatePermissionCallback = callback;
|
||||
}
|
||||
|
||||
private updatePermissions() {
|
||||
this.isOwner = this.value === OwnerPermissionVal;
|
||||
this.hasManagePer = this.checkPer(this._permissionList['manage'].value);
|
||||
this.hasWritePer = this.checkPer(this._permissionList['write'].value);
|
||||
this.hasReadPer = this.checkPer(this._permissionList['read'].value);
|
||||
this.updatePermissionCallback?.();
|
||||
}
|
||||
|
||||
toBinary() {
|
||||
return this.value.toString(2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,23 +17,23 @@ type GroupMemberSchemaType = {
|
||||
role: `${GroupMemberRole}`;
|
||||
};
|
||||
|
||||
type MemberGroupListItemType<T extends boolean | undefined> = MemberGroupSchemaType & {
|
||||
members: T extends true
|
||||
type MemberGroupListItemType<WithMembers extends boolean | undefined> = MemberGroupSchemaType & {
|
||||
members: WithMembers extends true
|
||||
? {
|
||||
tmbId: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
}[]
|
||||
: undefined;
|
||||
count: T extends true ? number : undefined;
|
||||
owner?: T extends true
|
||||
count: WithMembers extends true ? number : undefined;
|
||||
owner?: WithMembers extends true
|
||||
? {
|
||||
tmbId: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
}
|
||||
: undefined;
|
||||
permission: T extends true ? Permission : undefined;
|
||||
permission: WithMembers extends true ? Permission : undefined;
|
||||
};
|
||||
|
||||
type GroupMemberItemType = {
|
||||
|
||||
@@ -1,22 +1,50 @@
|
||||
import { PermissionKeyEnum } from '../constant';
|
||||
import { PermissionListType } from '../type';
|
||||
import { PermissionList } from '../constant';
|
||||
export const TeamPermissionList: PermissionListType = {
|
||||
import { i18nT } from '../../../../web/i18n/utils';
|
||||
export enum TeamPermissionKeyEnum {
|
||||
appCreate = 'appCreate',
|
||||
datasetCreate = 'datasetCreate',
|
||||
apikeyCreate = 'apikeyCreate'
|
||||
}
|
||||
|
||||
export const TeamPermissionList: PermissionListType<TeamPermissionKeyEnum> = {
|
||||
[PermissionKeyEnum.read]: {
|
||||
...PermissionList[PermissionKeyEnum.read],
|
||||
value: 0b100
|
||||
value: 0b000100
|
||||
},
|
||||
[PermissionKeyEnum.write]: {
|
||||
...PermissionList[PermissionKeyEnum.write],
|
||||
value: 0b010
|
||||
value: 0b000010
|
||||
},
|
||||
[PermissionKeyEnum.manage]: {
|
||||
...PermissionList[PermissionKeyEnum.manage],
|
||||
value: 0b001
|
||||
value: 0b000001
|
||||
},
|
||||
[TeamPermissionKeyEnum.appCreate]: {
|
||||
checkBoxType: 'multiple',
|
||||
description: '',
|
||||
name: i18nT('account_team:permission_appCreate'),
|
||||
value: 0b001000
|
||||
},
|
||||
[TeamPermissionKeyEnum.datasetCreate]: {
|
||||
checkBoxType: 'multiple',
|
||||
description: '',
|
||||
name: i18nT('account_team:permission_datasetCreate'),
|
||||
value: 0b010000
|
||||
},
|
||||
[TeamPermissionKeyEnum.apikeyCreate]: {
|
||||
checkBoxType: 'multiple',
|
||||
description: '',
|
||||
name: i18nT('account_team:permission_apikeyCreate'),
|
||||
value: 0b100000
|
||||
}
|
||||
};
|
||||
|
||||
export const TeamReadPermissionVal = TeamPermissionList['read'].value;
|
||||
export const TeamWritePermissionVal = TeamPermissionList['write'].value;
|
||||
export const TeamManagePermissionVal = TeamPermissionList['manage'].value;
|
||||
export const TeamAppCreatePermissionVal = TeamPermissionList['appCreate'].value;
|
||||
export const TeamDatasetCreatePermissionVal = TeamPermissionList['datasetCreate'].value;
|
||||
export const TeamApikeyCreatePermissionVal = TeamPermissionList['apikeyCreate'].value;
|
||||
export const TeamDefaultPermissionVal = TeamReadPermissionVal;
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
import { PerConstructPros, Permission } from '../controller';
|
||||
import { TeamDefaultPermissionVal, TeamPermissionList } from './constant';
|
||||
import {
|
||||
TeamApikeyCreatePermissionVal,
|
||||
TeamAppCreatePermissionVal,
|
||||
TeamDatasetCreatePermissionVal,
|
||||
TeamDefaultPermissionVal,
|
||||
TeamPermissionList
|
||||
} from './constant';
|
||||
|
||||
export class TeamPermission extends Permission {
|
||||
hasAppCreatePer: boolean = false;
|
||||
hasDatasetCreatePer: boolean = false;
|
||||
hasApikeyCreatePer: boolean = false;
|
||||
|
||||
constructor(props?: PerConstructPros) {
|
||||
if (!props) {
|
||||
props = {
|
||||
@@ -12,5 +22,11 @@ export class TeamPermission extends Permission {
|
||||
}
|
||||
props.permissionList = TeamPermissionList;
|
||||
super(props);
|
||||
|
||||
this.setUpdatePermissionCallback(() => {
|
||||
this.hasAppCreatePer = this.checkPer(TeamAppCreatePermissionVal);
|
||||
this.hasDatasetCreatePer = this.checkPer(TeamDatasetCreatePermissionVal);
|
||||
this.hasApikeyCreatePer = this.checkPer(TeamApikeyCreatePermissionVal);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ const addCommonMiddleware = (schema: mongoose.Schema) => {
|
||||
|
||||
export const getMongoModel = <T>(name: string, schema: mongoose.Schema) => {
|
||||
if (connectionMongo.models[name]) return connectionMongo.models[name] as Model<T>;
|
||||
console.log('Load model======', name);
|
||||
if (process.env.NODE_ENV !== 'test') console.log('Load model======', name);
|
||||
addCommonMiddleware(schema);
|
||||
|
||||
const model = connectionMongo.model<T>(name, schema);
|
||||
|
||||
@@ -16,6 +16,7 @@ import { mergeChatResponseData } from '@fastgpt/global/core/chat/utils';
|
||||
import { pushChatLog } from './pushChatLog';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { extractDeepestInteractive } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
|
||||
type Props = {
|
||||
chatId: string;
|
||||
@@ -209,34 +210,24 @@ export const updateInteractiveChat = async ({
|
||||
}
|
||||
})();
|
||||
|
||||
if (interactiveValue.interactive.type === 'userSelect') {
|
||||
interactiveValue.interactive = {
|
||||
...interactiveValue.interactive,
|
||||
params: {
|
||||
...interactiveValue.interactive.params,
|
||||
userSelectedVal: userInteractiveVal
|
||||
}
|
||||
};
|
||||
let finalInteractive = extractDeepestInteractive(interactiveValue.interactive);
|
||||
|
||||
if (finalInteractive.type === 'userSelect') {
|
||||
finalInteractive.params.userSelectedVal = userInteractiveVal;
|
||||
} else if (
|
||||
interactiveValue.interactive.type === 'userInput' &&
|
||||
finalInteractive.type === 'userInput' &&
|
||||
typeof parsedUserInteractiveVal === 'object'
|
||||
) {
|
||||
interactiveValue.interactive = {
|
||||
...interactiveValue.interactive,
|
||||
params: {
|
||||
...interactiveValue.interactive.params,
|
||||
inputForm: interactiveValue.interactive.params.inputForm.map((item) => {
|
||||
const itemValue = parsedUserInteractiveVal[item.label];
|
||||
return itemValue !== undefined
|
||||
? {
|
||||
...item,
|
||||
value: itemValue
|
||||
}
|
||||
: item;
|
||||
}),
|
||||
submitted: true
|
||||
}
|
||||
};
|
||||
finalInteractive.params.inputForm = finalInteractive.params.inputForm.map((item) => {
|
||||
const itemValue = parsedUserInteractiveVal[item.label];
|
||||
return itemValue !== undefined
|
||||
? {
|
||||
...item,
|
||||
value: itemValue
|
||||
}
|
||||
: item;
|
||||
});
|
||||
finalInteractive.params.submitted = true;
|
||||
}
|
||||
|
||||
if (aiResponse.customFeedbacks) {
|
||||
|
||||
@@ -73,6 +73,7 @@ import { dispatchLoopStart } from './loop/runLoopStart';
|
||||
import { dispatchFormInput } from './interactive/formInput';
|
||||
import { dispatchToolParams } from './agent/runTool/toolParams';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { filterModuleTypeList } from '@fastgpt/global/core/chat/utils';
|
||||
|
||||
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
||||
@@ -140,6 +141,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
} else {
|
||||
props.workflowDispatchDeep += 1;
|
||||
}
|
||||
const isRootRuntime = props.workflowDispatchDeep === 1;
|
||||
|
||||
if (props.workflowDispatchDeep > 20) {
|
||||
return {
|
||||
@@ -160,25 +162,28 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
let workflowRunTimes = 0;
|
||||
|
||||
// set sse response headers
|
||||
if (stream && res) {
|
||||
res.setHeader('Content-Type', 'text/event-stream;charset=utf-8');
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('X-Accel-Buffering', 'no');
|
||||
res.setHeader('Cache-Control', 'no-cache, no-transform');
|
||||
if (isRootRuntime) {
|
||||
res?.setHeader('Connection', 'keep-alive'); // Set keepalive for long connection
|
||||
if (stream && res) {
|
||||
res.setHeader('Content-Type', 'text/event-stream;charset=utf-8');
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('X-Accel-Buffering', 'no');
|
||||
res.setHeader('Cache-Control', 'no-cache, no-transform');
|
||||
|
||||
// 10s sends a message to prevent the browser from thinking that the connection is disconnected
|
||||
const sendStreamTimerSign = () => {
|
||||
setTimeout(() => {
|
||||
props?.workflowStreamResponse?.({
|
||||
event: SseResponseEventEnum.answer,
|
||||
data: textAdaptGptResponse({
|
||||
text: ''
|
||||
})
|
||||
});
|
||||
sendStreamTimerSign();
|
||||
}, 10000);
|
||||
};
|
||||
sendStreamTimerSign();
|
||||
// 10s sends a message to prevent the browser from thinking that the connection is disconnected
|
||||
const sendStreamTimerSign = () => {
|
||||
setTimeout(() => {
|
||||
props?.workflowStreamResponse?.({
|
||||
event: SseResponseEventEnum.answer,
|
||||
data: textAdaptGptResponse({
|
||||
text: ''
|
||||
})
|
||||
});
|
||||
sendStreamTimerSign();
|
||||
}, 10000);
|
||||
};
|
||||
sendStreamTimerSign();
|
||||
}
|
||||
}
|
||||
|
||||
variables = {
|
||||
@@ -324,10 +329,9 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
});
|
||||
|
||||
if (props.mode === 'debug') {
|
||||
debugNextStepRunNodes = debugNextStepRunNodes.concat([
|
||||
...nextStepActiveNodes,
|
||||
...nextStepSkipNodes
|
||||
]);
|
||||
debugNextStepRunNodes = debugNextStepRunNodes.concat(
|
||||
props.lastInteractive ? nextStepActiveNodes : [...nextStepActiveNodes, ...nextStepSkipNodes]
|
||||
);
|
||||
return {
|
||||
nextStepActiveNodes: [],
|
||||
nextStepSkipNodes: []
|
||||
@@ -373,7 +377,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
};
|
||||
|
||||
// Tool call, not need interactive response
|
||||
if (!props.isToolCall) {
|
||||
if (!props.isToolCall && isRootRuntime) {
|
||||
props.workflowStreamResponse?.({
|
||||
event: SseResponseEventEnum.interactive,
|
||||
data: { interactive: interactiveResult }
|
||||
@@ -427,14 +431,6 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
})();
|
||||
|
||||
if (!nodeRunResult) return [];
|
||||
if (res?.closed) {
|
||||
addLog.warn('Request is closed', {
|
||||
appId: props.runningAppInfo.id,
|
||||
nodeId: node.nodeId,
|
||||
nodeName: node.name
|
||||
});
|
||||
return [];
|
||||
}
|
||||
|
||||
/*
|
||||
特殊情况:
|
||||
@@ -491,6 +487,15 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
await Promise.all(nextStepSkipNodes.map((node) => checkNodeCanRun(node, skippedNodeIdList)))
|
||||
).flat();
|
||||
|
||||
if (res?.closed) {
|
||||
addLog.warn('Request is closed', {
|
||||
appId: props.runningAppInfo.id,
|
||||
nodeId: node.nodeId,
|
||||
nodeName: node.name
|
||||
});
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
...nextStepActiveNodes,
|
||||
...nextStepSkipNodes,
|
||||
@@ -631,8 +636,9 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
if (
|
||||
version === 'v2' &&
|
||||
!props.isToolCall &&
|
||||
!props.runningAppInfo.isChildApp &&
|
||||
formatResponseData
|
||||
isRootRuntime &&
|
||||
formatResponseData &&
|
||||
!(!props.responseDetail && filterModuleTypeList.includes(formatResponseData.moduleType))
|
||||
) {
|
||||
props.workflowStreamResponse?.({
|
||||
event: SseResponseEventEnum.flowNodeResponse,
|
||||
@@ -719,7 +725,9 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
entryNodeIds: nodeInteractiveResponse.entryNodeIds,
|
||||
interactiveResponse: nodeInteractiveResponse.interactiveResponse
|
||||
});
|
||||
chatAssistantResponse.push(interactiveAssistant);
|
||||
if (isRootRuntime) {
|
||||
chatAssistantResponse.push(interactiveAssistant);
|
||||
}
|
||||
return interactiveAssistant.interactive;
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -10,7 +10,6 @@ import type {
|
||||
UserInputInteractive
|
||||
} from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||
import { addLog } from '../../../../common/system/log';
|
||||
import { getLastInteractiveValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.description]: string;
|
||||
@@ -29,13 +28,13 @@ export const dispatchFormInput = async (props: Props): Promise<FormInputResponse
|
||||
histories,
|
||||
node,
|
||||
params: { description, userInputForms },
|
||||
query
|
||||
query,
|
||||
lastInteractive
|
||||
} = props;
|
||||
const { isEntry } = node;
|
||||
const interactive = getLastInteractiveValue(histories);
|
||||
|
||||
// Interactive node is not the entry node, return interactive result
|
||||
if (!isEntry || interactive?.type !== 'userInput') {
|
||||
if (!isEntry || lastInteractive?.type !== 'userInput') {
|
||||
return {
|
||||
[DispatchNodeResponseKeyEnum.interactive]: {
|
||||
type: 'userInput',
|
||||
|
||||
@@ -10,7 +10,6 @@ import type {
|
||||
UserSelectOptionItemType
|
||||
} from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||
import { getLastInteractiveValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.description]: string;
|
||||
@@ -27,13 +26,13 @@ export const dispatchUserSelect = async (props: Props): Promise<UserSelectRespon
|
||||
histories,
|
||||
node,
|
||||
params: { description, userSelectOptions },
|
||||
query
|
||||
query,
|
||||
lastInteractive
|
||||
} = props;
|
||||
const { nodeId, isEntry } = node;
|
||||
const interactive = getLastInteractiveValue(histories);
|
||||
|
||||
// Interactive node is not the entry node, return interactive result
|
||||
if (!isEntry || interactive?.type !== 'userSelect') {
|
||||
if (!isEntry || lastInteractive?.type !== 'userSelect') {
|
||||
return {
|
||||
[DispatchNodeResponseKeyEnum.interactive]: {
|
||||
type: 'userSelect',
|
||||
|
||||
@@ -18,6 +18,7 @@ import { authAppByTmbId } from '../../../../support/permission/app/auth';
|
||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { getAppVersionById } from '../../../app/version/controller';
|
||||
import { parseUrlToFileType } from '@fastgpt/global/common/file/tools';
|
||||
import { ChildrenInteractive } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.userChatInput]: string;
|
||||
@@ -27,6 +28,7 @@ type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.fileUrlList]?: string[];
|
||||
}>;
|
||||
type Response = DispatchNodeResultType<{
|
||||
[DispatchNodeResponseKeyEnum.interactive]?: ChildrenInteractive;
|
||||
[NodeOutputKeyEnum.answerText]: string;
|
||||
[NodeOutputKeyEnum.history]: ChatItemType[];
|
||||
}>;
|
||||
@@ -36,6 +38,7 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
|
||||
runningAppInfo,
|
||||
histories,
|
||||
query,
|
||||
lastInteractive,
|
||||
node: { pluginId: appId, version },
|
||||
workflowStreamResponse,
|
||||
params,
|
||||
@@ -100,31 +103,41 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
|
||||
appId: String(appData._id)
|
||||
};
|
||||
|
||||
const { flowResponses, flowUsages, assistantResponses, runTimes } = await dispatchWorkFlow({
|
||||
...props,
|
||||
// Rewrite stream mode
|
||||
...(system_forbid_stream
|
||||
? {
|
||||
stream: false,
|
||||
workflowStreamResponse: undefined
|
||||
}
|
||||
: {}),
|
||||
runningAppInfo: {
|
||||
id: String(appData._id),
|
||||
teamId: String(appData.teamId),
|
||||
tmbId: String(appData.tmbId),
|
||||
isChildApp: true
|
||||
},
|
||||
runtimeNodes: storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes)),
|
||||
runtimeEdges: initWorkflowEdgeStatus(edges),
|
||||
histories: chatHistories,
|
||||
variables: childrenRunVariables,
|
||||
query: runtimePrompt2ChatsValue({
|
||||
files: userInputFiles,
|
||||
text: userChatInput
|
||||
}),
|
||||
chatConfig
|
||||
});
|
||||
const childrenInteractive =
|
||||
lastInteractive?.type === 'childrenInteractive'
|
||||
? lastInteractive.params.childrenResponse
|
||||
: undefined;
|
||||
const entryNodeIds = getWorkflowEntryNodeIds(nodes, childrenInteractive || undefined);
|
||||
const runtimeNodes = storeNodes2RuntimeNodes(nodes, entryNodeIds);
|
||||
const runtimeEdges = initWorkflowEdgeStatus(edges, childrenInteractive);
|
||||
const theQuery = childrenInteractive
|
||||
? query
|
||||
: runtimePrompt2ChatsValue({ files: userInputFiles, text: userChatInput });
|
||||
|
||||
const { flowResponses, flowUsages, assistantResponses, runTimes, workflowInteractiveResponse } =
|
||||
await dispatchWorkFlow({
|
||||
...props,
|
||||
lastInteractive: childrenInteractive,
|
||||
// Rewrite stream mode
|
||||
...(system_forbid_stream
|
||||
? {
|
||||
stream: false,
|
||||
workflowStreamResponse: undefined
|
||||
}
|
||||
: {}),
|
||||
runningAppInfo: {
|
||||
id: String(appData._id),
|
||||
teamId: String(appData.teamId),
|
||||
tmbId: String(appData.tmbId),
|
||||
isChildApp: true
|
||||
},
|
||||
runtimeNodes,
|
||||
runtimeEdges,
|
||||
histories: chatHistories,
|
||||
variables: childrenRunVariables,
|
||||
query: theQuery,
|
||||
chatConfig
|
||||
});
|
||||
|
||||
const completeMessages = chatHistories.concat([
|
||||
{
|
||||
@@ -142,6 +155,14 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
|
||||
const usagePoints = flowUsages.reduce((sum, item) => sum + (item.totalPoints || 0), 0);
|
||||
|
||||
return {
|
||||
[DispatchNodeResponseKeyEnum.interactive]: workflowInteractiveResponse
|
||||
? {
|
||||
type: 'childrenInteractive',
|
||||
params: {
|
||||
childrenResponse: workflowInteractiveResponse
|
||||
}
|
||||
}
|
||||
: undefined,
|
||||
assistantResponses: system_forbid_stream ? [] : assistantResponses,
|
||||
[DispatchNodeResponseKeyEnum.runTimes]: runTimes,
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
|
||||
26
packages/service/support/operationLog/addOperationLog.ts
Normal file
26
packages/service/support/operationLog/addOperationLog.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { MongoOperationLog } from './schema';
|
||||
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
|
||||
import { TemplateParamsMap } from './constants';
|
||||
import { retryFn } from '../../../global/common/system/utils';
|
||||
|
||||
export function addOperationLog<T extends OperationLogEventEnum>({
|
||||
teamId,
|
||||
tmbId,
|
||||
event,
|
||||
params
|
||||
}: {
|
||||
tmbId: string;
|
||||
teamId: string;
|
||||
event: T;
|
||||
params?: TemplateParamsMap[T];
|
||||
}) {
|
||||
console.log('Insert log');
|
||||
retryFn(() =>
|
||||
MongoOperationLog.create({
|
||||
tmbId: tmbId,
|
||||
teamId: teamId,
|
||||
event,
|
||||
metadata: params
|
||||
})
|
||||
);
|
||||
}
|
||||
85
packages/service/support/operationLog/constants.ts
Normal file
85
packages/service/support/operationLog/constants.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
|
||||
import { i18nT } from '../../../web/i18n/utils';
|
||||
|
||||
export const operationLogI18nMap = {
|
||||
[OperationLogEventEnum.LOGIN]: {
|
||||
content: i18nT('account_team:log_login'),
|
||||
typeLabel: i18nT('account_team:login')
|
||||
},
|
||||
[OperationLogEventEnum.CREATE_INVITATION_LINK]: {
|
||||
content: i18nT('account_team:log_create_invitation_link'),
|
||||
typeLabel: i18nT('account_team:create_invitation_link')
|
||||
},
|
||||
[OperationLogEventEnum.JOIN_TEAM]: {
|
||||
content: i18nT('account_team:log_join_team'),
|
||||
typeLabel: i18nT('account_team:join_team')
|
||||
},
|
||||
[OperationLogEventEnum.CHANGE_MEMBER_NAME]: {
|
||||
content: i18nT('account_team:log_change_member_name'),
|
||||
typeLabel: i18nT('account_team:change_member_name')
|
||||
},
|
||||
[OperationLogEventEnum.KICK_OUT_TEAM]: {
|
||||
content: i18nT('account_team:log_kick_out_team'),
|
||||
typeLabel: i18nT('account_team:kick_out_team')
|
||||
},
|
||||
[OperationLogEventEnum.CREATE_DEPARTMENT]: {
|
||||
content: i18nT('account_team:log_create_department'),
|
||||
typeLabel: i18nT('account_team:create_department')
|
||||
},
|
||||
[OperationLogEventEnum.CHANGE_DEPARTMENT]: {
|
||||
content: i18nT('account_team:log_change_department'),
|
||||
typeLabel: i18nT('account_team:change_department_name')
|
||||
},
|
||||
[OperationLogEventEnum.DELETE_DEPARTMENT]: {
|
||||
content: i18nT('account_team:log_delete_department'),
|
||||
typeLabel: i18nT('account_team:delete_department')
|
||||
},
|
||||
[OperationLogEventEnum.RELOCATE_DEPARTMENT]: {
|
||||
content: i18nT('account_team:log_relocate_department'),
|
||||
typeLabel: i18nT('account_team:relocate_department')
|
||||
},
|
||||
[OperationLogEventEnum.CREATE_GROUP]: {
|
||||
content: i18nT('account_team:log_create_group'),
|
||||
typeLabel: i18nT('account_team:create_group')
|
||||
},
|
||||
[OperationLogEventEnum.DELETE_GROUP]: {
|
||||
content: i18nT('account_team:log_delete_group'),
|
||||
typeLabel: i18nT('account_team:delete_group')
|
||||
},
|
||||
[OperationLogEventEnum.ASSIGN_PERMISSION]: {
|
||||
content: i18nT('account_team:log_assign_permission'),
|
||||
typeLabel: i18nT('account_team:assign_permission')
|
||||
}
|
||||
} as const;
|
||||
|
||||
export type TemplateParamsMap = {
|
||||
[OperationLogEventEnum.LOGIN]: { name?: string };
|
||||
[OperationLogEventEnum.CREATE_INVITATION_LINK]: { name?: string; link: string };
|
||||
[OperationLogEventEnum.JOIN_TEAM]: { name?: string; link: string };
|
||||
[OperationLogEventEnum.CHANGE_MEMBER_NAME]: {
|
||||
name?: string;
|
||||
memberName: string;
|
||||
newName: string;
|
||||
};
|
||||
[OperationLogEventEnum.KICK_OUT_TEAM]: {
|
||||
name?: string;
|
||||
memberName: string;
|
||||
};
|
||||
[OperationLogEventEnum.CREATE_DEPARTMENT]: { name?: string; departmentName: string };
|
||||
[OperationLogEventEnum.CHANGE_DEPARTMENT]: {
|
||||
name?: string;
|
||||
departmentName: string;
|
||||
};
|
||||
[OperationLogEventEnum.DELETE_DEPARTMENT]: { name?: string; departmentName: string };
|
||||
[OperationLogEventEnum.RELOCATE_DEPARTMENT]: {
|
||||
name?: string;
|
||||
departmentName: string;
|
||||
};
|
||||
[OperationLogEventEnum.CREATE_GROUP]: { name?: string; groupName: string };
|
||||
[OperationLogEventEnum.DELETE_GROUP]: { name?: string; groupName: string };
|
||||
[OperationLogEventEnum.ASSIGN_PERMISSION]: {
|
||||
name?: string;
|
||||
objectName: string;
|
||||
permission: string;
|
||||
};
|
||||
};
|
||||
40
packages/service/support/operationLog/schema.ts
Normal file
40
packages/service/support/operationLog/schema.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Schema, getMongoLogModel } from '../../common/mongo';
|
||||
import type { OperationLogSchema } from '@fastgpt/global/support/operationLog/type';
|
||||
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
|
||||
export const OperationLogCollectionName = 'operationLog';
|
||||
|
||||
const OperationLogSchema = new Schema({
|
||||
tmbId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamMemberCollectionName,
|
||||
required: true
|
||||
},
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName,
|
||||
required: true
|
||||
},
|
||||
timestamp: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
},
|
||||
event: {
|
||||
type: String,
|
||||
enum: Object.values(OperationLogEventEnum),
|
||||
required: true
|
||||
},
|
||||
metadata: {
|
||||
type: Object,
|
||||
default: {}
|
||||
}
|
||||
});
|
||||
|
||||
export const MongoOperationLog = getMongoLogModel<OperationLogSchema>(
|
||||
OperationLogCollectionName,
|
||||
OperationLogSchema
|
||||
);
|
||||
@@ -2,7 +2,7 @@ import { TeamPermission } from '@fastgpt/global/support/permission/user/controll
|
||||
import { AuthModeType, AuthResponseType } from '../type';
|
||||
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
|
||||
import { authUserPer } from '../user/auth';
|
||||
import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { TeamManagePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
|
||||
/*
|
||||
Team manager can control org
|
||||
@@ -15,7 +15,7 @@ export const authOrgMember = async ({
|
||||
} & AuthModeType): Promise<AuthResponseType> => {
|
||||
const result = await authUserPer({
|
||||
...props,
|
||||
per: ManagePermissionVal
|
||||
per: TeamManagePermissionVal
|
||||
});
|
||||
const { teamId, tmbId, isRoot, tmb } = result;
|
||||
|
||||
|
||||
@@ -104,8 +104,11 @@ export async function addSourceMember<T extends { tmbId: string }>({
|
||||
const tmb = tmbList.find((tmb) => String(tmb._id) === String(item.tmbId));
|
||||
if (!tmb) return;
|
||||
|
||||
// @ts-ignore
|
||||
const formatItem = typeof item.toObject === 'function' ? item.toObject() : item;
|
||||
|
||||
return {
|
||||
...item,
|
||||
...formatItem,
|
||||
sourceMember: { name: tmb.name, avatar: tmb.avatar, status: tmb.status }
|
||||
};
|
||||
})
|
||||
|
||||
@@ -5,17 +5,23 @@
|
||||
"7days": "7 Days",
|
||||
"accept": "accept",
|
||||
"action": "operate",
|
||||
"assign_permission": "Permission change",
|
||||
"change_department_name": "Department Editor",
|
||||
"change_member_name": "Member name change",
|
||||
"confirm_delete_group": "Confirm to delete group?",
|
||||
"confirm_delete_member": "Confirm to delete member?",
|
||||
"confirm_delete_org": "Confirm to delete organization?",
|
||||
"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_department": "Create a sub-department",
|
||||
"create_group": "Create group",
|
||||
"create_invitation_link": "Create Invitation Link",
|
||||
"create_org": "Create organization",
|
||||
"create_sub_org": "Create sub-organization",
|
||||
"delete": "delete",
|
||||
"delete_department": "Delete sub-department",
|
||||
"delete_group": "Delete a group",
|
||||
"delete_org": "Delete organization",
|
||||
"edit_info": "Edit information",
|
||||
"edit_member": "Edit user",
|
||||
@@ -37,21 +43,51 @@
|
||||
"invitation_link_list": "Invitation link list",
|
||||
"invite_member": "Invite members",
|
||||
"invited": "Invited",
|
||||
"join_team": "Join the team",
|
||||
"kick_out_team": "Remove members",
|
||||
"label_sync": "Tag sync",
|
||||
"leave_team_failed": "Leaving the team exception",
|
||||
"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_create_department": "【{{name}}】Department【{{departmentName}}】",
|
||||
"log_create_group": "【{{name}}】Created group [{{groupName}}]",
|
||||
"log_create_invitation_link": "【{{name}}】Created invitation link【{{link}}】",
|
||||
"log_delete_department": "{{name}} deleted department {{departmentName}}",
|
||||
"log_delete_group": "{{name}} deleted group {{groupName}}",
|
||||
"log_details": "Details",
|
||||
"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_relocate_department": "【{{name}}】Displayed department【{{departmentName}}】",
|
||||
"log_time": "Operation time",
|
||||
"log_type": "Operation Type",
|
||||
"log_user": "Operator",
|
||||
"login": "Log in",
|
||||
"manage_member": "Managing members",
|
||||
"member": "member",
|
||||
"member_group": "Belonging to member group",
|
||||
"move_member": "Move member",
|
||||
"move_org": "Move organization",
|
||||
"operation_log": "log",
|
||||
"org": "organization",
|
||||
"org_description": "Organization description",
|
||||
"org_name": "Organization name",
|
||||
"owner": "owner",
|
||||
"permission": "Permissions",
|
||||
"permission_apikeyCreate": "Create API Key",
|
||||
"permission_apikeyCreate_Tip": "Can create global APIKeys",
|
||||
"permission_appCreate": "Create Application",
|
||||
"permission_appCreate_tip": "Can create applications in the root directory (creation permissions in folders are controlled by the folder)",
|
||||
"permission_datasetCreate": "Create Knowledge Base",
|
||||
"permission_datasetCreate_Tip": "Can create knowledge bases in the root directory (creation permissions in folders are controlled by the folder)",
|
||||
"permission_manage": "Admin",
|
||||
"permission_manage_tip": "Can manage members, create groups, manage all groups, and assign permissions to groups and members",
|
||||
"relocate_department": "Department Mobile",
|
||||
"remark": "remark",
|
||||
"remove_tip": "Confirm to remove {{username}} from the team?",
|
||||
"retain_admin_permissions": "Keep administrator rights",
|
||||
"search_log": "Search log",
|
||||
"search_member_group_name": "Search member/group name",
|
||||
"total_team_members": "{{amount}} members in total",
|
||||
"transfer_ownership": "transfer owner",
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
"team.group.manage_tip": "Can manage members, create groups, manage all groups, assign permissions to groups and members",
|
||||
"team.group.members": "member",
|
||||
"team.group.name": "Group name",
|
||||
"team.group.permission.manage": "administrator",
|
||||
"team.group.permission.write": "Workbench/knowledge base creation",
|
||||
"team.group.permission_tip": "Members with individually configured permissions will follow the individual permission configuration and will no longer be affected by group permissions.\n\nIf a member is in multiple permission groups, the member's permissions are combined.",
|
||||
"team.group.role.admin": "administrator",
|
||||
@@ -112,5 +111,6 @@
|
||||
"team.manage_collaborators": "Manage Collaborators",
|
||||
"team.no_collaborators": "No Collaborators",
|
||||
"team.org.org": "Organization",
|
||||
"team.write_role_member": ""
|
||||
"team.write_role_member": "Write Permission",
|
||||
"team.collaborator.added": "Added"
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
"7days": "7天",
|
||||
"accept": "接受",
|
||||
"action": "操作",
|
||||
"assign_permission": "权限变更",
|
||||
"change_department_name": "部门编辑",
|
||||
"change_member_name": "成员改名",
|
||||
"confirm_delete_from_org": "确认将 {{username}} 移出部门?",
|
||||
"confirm_delete_from_team": "确认将 {{username}} 移出团队?",
|
||||
"confirm_delete_group": "确认删除群组?",
|
||||
@@ -12,13 +15,16 @@
|
||||
"confirm_forbidden": "确认停用",
|
||||
"confirm_leave_team": "确认离开该团队? \n退出后,您在该团队所有的资源均转让给团队所有者。",
|
||||
"copy_link": "复制链接",
|
||||
"create_department": "创建子部门",
|
||||
"create_group": "创建群组",
|
||||
"create_invitation_link": "创建邀请链接",
|
||||
"create_org": "创建部门",
|
||||
"create_sub_org": "创建子部门",
|
||||
"delete": "删除",
|
||||
"delete_department": "删除子部门",
|
||||
"delete_from_org": "移出部门",
|
||||
"delete_from_team": "移出团队",
|
||||
"delete_group": "删除群组",
|
||||
"delete_org": "删除部门",
|
||||
"edit_info": "编辑信息",
|
||||
"edit_member": "编辑用户",
|
||||
@@ -41,27 +47,37 @@
|
||||
"invitation_link_list": "链接列表",
|
||||
"invite_member": "邀请成员",
|
||||
"invited": "已邀请",
|
||||
"join_team": "加入团队",
|
||||
"join_update_time": "加入/更新时间",
|
||||
"kick_out_team": "移除成员",
|
||||
"label_sync": "标签同步",
|
||||
"leave": "已离职",
|
||||
"leave_team_failed": "离开团队异常",
|
||||
"log_details": "详情",
|
||||
"log_time": "操作时间",
|
||||
"log_type": "操作类型",
|
||||
"log_user": "操作人员",
|
||||
"login": "登录",
|
||||
"manage_member": "管理成员",
|
||||
"member": "成员",
|
||||
"member_group": "所属群组",
|
||||
"move_member": "移动成员",
|
||||
"move_org": "移动部门",
|
||||
"notification_recieve": "团队通知接收",
|
||||
"operation_log": "日志",
|
||||
"org": "部门",
|
||||
"org_description": "介绍",
|
||||
"org_name": "部门名称",
|
||||
"owner": "所有者",
|
||||
"permission": "权限",
|
||||
"please_bind_contact": "请绑定联系方式",
|
||||
"relocate_department": "部门移动",
|
||||
"remark": "备注",
|
||||
"remove_tip": "确认将 {{username}} 移出团队?成员将被标记为“已离职”,不删除操作数据,账号下资源自动转让给团队所有者。",
|
||||
"restore_tip": "确认将 {{username}} 加入团队吗?仅恢复该成员账号可用性及相关权限,无法恢复账号下资源。",
|
||||
"restore_tip_title": "恢复确认",
|
||||
"retain_admin_permissions": "保留管理员权限",
|
||||
"search_log": "搜索日志",
|
||||
"search_member": "搜索成员",
|
||||
"search_member_group_name": "搜索成员/群组名称",
|
||||
"search_org": "搜索部门",
|
||||
@@ -77,5 +93,25 @@
|
||||
"user_team_invite_member": "邀请成员",
|
||||
"user_team_leave_team": "离开团队",
|
||||
"user_team_leave_team_failed": "离开团队失败",
|
||||
"waiting": "待接受"
|
||||
"waiting": "待接受",
|
||||
"permission_appCreate": "创建应用",
|
||||
"permission_datasetCreate": "创建知识库",
|
||||
"permission_apikeyCreate": "创建 API 密钥",
|
||||
"permission_appCreate_tip": "可以在根目录创建应用,(文件夹下的创建权限由文件夹控制)",
|
||||
"permission_datasetCreate_Tip": "可以在根目录创建知识库,(文件夹下的创建权限由文件夹控制)",
|
||||
"permission_apikeyCreate_Tip": "可以创建全局的 APIKey",
|
||||
"permission_manage": "管理员",
|
||||
"permission_manage_tip": "可以管理成员、创建群组、管理所有群组、为群组和成员分配权限",
|
||||
"log_login": "【{{name}}】登录了系统",
|
||||
"log_create_invitation_link": "【{{name}}】创建了邀请链接【{{link}}】",
|
||||
"log_join_team": "【{{name}}】通过邀请链接【{{link}}】加入团队",
|
||||
"log_change_member_name": "【{{name}}】将成员【{{memberName}}】重命名为【{{newName}}】",
|
||||
"log_kick_out_team": "【{{name}}】移除了成员【{{memberName}}】",
|
||||
"log_create_department": "【{{name}}】创建了部门【{{departmentName}}】",
|
||||
"log_change_department": "【{{name}}】更新了部门【{{departmentName}}】",
|
||||
"log_delete_department": "【{{name}}】删除了部门【{{departmentName}}】",
|
||||
"log_relocate_department": "【{{name}}】移动了部门【{{departmentName}}】",
|
||||
"log_create_group": "【{{name}}】创建了群组【{{groupName}}】",
|
||||
"log_delete_group": "【{{name}}】删除了群组【{{groupName}}】",
|
||||
"log_assign_permission": "【{{name}}】更新了【{{objectName}}】的权限:[应用创建:【{{appCreate}}】, 知识库:【{{datasetCreate}}】, API密钥:【{{apiKeyCreate}}】, 管理:【{{manage}}】]"
|
||||
}
|
||||
|
||||
@@ -98,11 +98,9 @@
|
||||
"team.group.keep_admin": "保留管理员权限",
|
||||
"team.group.manage_member": "管理成员",
|
||||
"team.group.manage_tip": "可以管理成员、创建群组、管理所有群组、为群组和成员分配权限",
|
||||
"team.group.permission_tip": "单独配置权限的成员,将遵循个人权限配置,不再受群组权限影响。\n若成员在多个权限组,则该成员的权限取并集。",
|
||||
"team.group.members": "成员",
|
||||
"team.group.name": "群组名称",
|
||||
"team.group.permission.manage": "管理员",
|
||||
"team.group.permission.write": "工作台/知识库创建",
|
||||
"team.group.permission_tip": "单独配置权限的成员,将遵循个人权限配置,不再受群组权限影响。\n若成员在多个权限组,则该成员的权限取并集。",
|
||||
"team.group.role.admin": "管理员",
|
||||
"team.group.role.member": "成员",
|
||||
"team.group.role.owner": "所有者",
|
||||
@@ -112,5 +110,6 @@
|
||||
"team.manage_collaborators": "管理协作者",
|
||||
"team.no_collaborators": "暂无协作者",
|
||||
"team.org.org": "部门",
|
||||
"team.write_role_member": "可写权限"
|
||||
"team.write_role_member": "可写权限",
|
||||
"team.collaborator.added": "已添加"
|
||||
}
|
||||
|
||||
@@ -3,30 +3,30 @@
|
||||
"add_default_model": "新增預設模型",
|
||||
"api_key": "API 金鑰",
|
||||
"bills_and_invoices": "帳單與發票",
|
||||
"channel": "模型渠道",
|
||||
"config_model": "模型配置",
|
||||
"confirm_logout": "確認登出登入?",
|
||||
"channel": "模型管道",
|
||||
"config_model": "模型設定",
|
||||
"confirm_logout": "確認登出登入?",
|
||||
"create_channel": "新增頻道",
|
||||
"create_model": "新增模型",
|
||||
"custom_model": "自訂模型",
|
||||
"default_model": "預設模型",
|
||||
"default_model_config": "預設模型配置",
|
||||
"default_model_config": "預設模型設定",
|
||||
"logout": "登出",
|
||||
"model.active": "啟用",
|
||||
"model.alias": "別名",
|
||||
"model.alias_tip": "模型在系統中展示的名字,方便使用者理解",
|
||||
"model.censor_tip": "如果需要進行敏感校驗,則開啟該開關",
|
||||
"model.charsPointsPrice": "模型綜合價格",
|
||||
"model.charsPointsPrice_tip": "將模型輸入和輸出合併起來進行 Token 計費,語言模型如果單獨配置了輸入和輸出計費,則按輸入和輸出分別計算",
|
||||
"model.charsPointsPrice_tip": "將模型輸入和輸出合併起來進行 Token 計費,語言模型如果單獨設定了輸入和輸出計費,則按輸入和輸出分別計算",
|
||||
"model.custom_cq_prompt": "自訂問題分類提示詞",
|
||||
"model.custom_cq_prompt_tip": "覆蓋系統預設的問題分類提示詞,預設為:\n\"\"\"\n{{prompt}}\n\"\"\"",
|
||||
"model.custom_extract_prompt": "自訂內容提取提示詞",
|
||||
"model.custom_extract_prompt_tip": "覆蓋系統的提示詞,默認為:\n\"\"\"\n{{prompt}}\n\"\"\"",
|
||||
"model.custom_extract_prompt_tip": "覆蓋系統的提示詞,預設為:\n\"\"\"\n{{prompt}}\n\"\"\"",
|
||||
"model.dataset_process": "用於知識庫文件處理",
|
||||
"model.defaultConfig": "額外 Body 參數",
|
||||
"model.defaultConfig_tip": "每次請求時候,都會攜帶該額外 Body 參數",
|
||||
"model.default_config": "Body 額外字段",
|
||||
"model.default_config_tip": "發起對話請求時候,合併該配置。例如:\n\"\"\"\n{\n \"temperature\": 1,\n \"max_tokens\": null\n}\n\"\"\"",
|
||||
"model.default_config": "Body 額外欄位",
|
||||
"model.default_config_tip": "發起對話請求時候,合併該設定。例如:\n\"\"\"\n{\n \"temperature\": 1,\n \"max_tokens\": null\n}\n\"\"\"",
|
||||
"model.default_model": "預設模型",
|
||||
"model.default_system_chat_prompt": "預設提示詞",
|
||||
"model.default_system_chat_prompt_tip": "模型對話時,都會攜帶該預設提示詞",
|
||||
@@ -34,35 +34,35 @@
|
||||
"model.default_token_tip": "索引模型預設文字分塊的長度,必須小於最大上文",
|
||||
"model.delete_model_confirm": "確認刪除該模型?",
|
||||
"model.edit_model": "模型參數編輯",
|
||||
"model.function_call": "支援函數調用",
|
||||
"model.function_call_tip": "如果模型支援函數調用,則開啟該開關。\n工具呼叫優先權更高。",
|
||||
"model.function_call": "支援函式呼叫",
|
||||
"model.function_call_tip": "如果模型支援函式呼叫,則開啟該開關。\n工具呼叫優先權更高。",
|
||||
"model.input_price": "模型輸入價格",
|
||||
"model.input_price_tip": "語言模型輸入價格,如果配置了該項,則模型綜合價格會失效",
|
||||
"model.input_price_tip": "語言模型輸入價格,如果設定了該項,則模型綜合價格會失效",
|
||||
"model.json_config": "設定檔",
|
||||
"model.json_config_confirm": "確認使用該配置進行覆蓋?",
|
||||
"model.json_config_tip": "透過設定檔設定模型,點選確認後,會使用輸入的配置進行全量覆蓋,請確保設定檔輸入正確。\n建議操作前,複製目前設定檔進行備份。",
|
||||
"model.json_config_confirm": "確認使用該設定進行覆蓋?",
|
||||
"model.json_config_tip": "透過設定檔設定模型,點選確認後,會使用輸入的設定進行全量覆蓋,請確保設定檔輸入正確。\n建議操作前,複製目前設定檔進行備份。",
|
||||
"model.max_quote": "知識庫最大引用",
|
||||
"model.max_temperature": "最大溫度",
|
||||
"model.model_id": "模型ID",
|
||||
"model.model_id_tip": "模型的唯一標識,也就是實際請求到服務商model 的值,需要與 OneAPI 頻道中的模型對應。",
|
||||
"model.model_id": "模型 ID",
|
||||
"model.model_id_tip": "模型的唯一標識,也就是實際請求到服務商 model 的值,需要與 OneAPI 頻道中的模型對應。",
|
||||
"model.normalization": "歸一化處理",
|
||||
"model.normalization_tip": "如果Embedding API 未對向量值進行歸一化,可以啟用該開關,系統會進行歸一化處理。\n\n未歸一化的 API,表現為向量檢索得分會大於 1。",
|
||||
"model.normalization_tip": "如果 Embedding API 未對向量值進行歸一化,可以啟用該開關,系統會進行歸一化處理。\n\n未歸一化的 API,表現為向量檢索得分會大於 1。",
|
||||
"model.output_price": "模型輸出價格",
|
||||
"model.output_price_tip": "語言模型輸出價格,如果配置了該項,則模型綜合價格會失效",
|
||||
"model.param_name": "參數名",
|
||||
"model.reasoning": "支持輸出思考",
|
||||
"model.output_price_tip": "語言模型輸出價格,如果設定了該項,則模型綜合價格會失效",
|
||||
"model.param_name": "參數名稱",
|
||||
"model.reasoning": "支援輸出思考",
|
||||
"model.reasoning_tip": "例如 Deepseek-reasoner,可以輸出思考過程。",
|
||||
"model.request_auth": "自訂請求 Key",
|
||||
"model.request_auth_tip": "向自訂請求地址發起請求時候,攜帶請求頭:Authorization: Bearer xxx 進行請求",
|
||||
"model.request_url": "自訂請求地址",
|
||||
"model.request_url_tip": "如果填寫該值,則會直接向該地址發起請求,不經過 OneAPI。\n需要遵循 OpenAI 的 API格式,並填寫完整請求地址,例如:\n\nLLM: {{host}}/v1/chat/completions\n\nEmbedding: {{host}}/v1/embeddings\n\nSTT: {{host}}/v1/audio/transcriptions\n\nTTS: {{host}}/v1/audio/speech\n\nRerank: {{host}}/v1/rerank",
|
||||
"model.request_url_tip": "如果填寫該值,則會直接向該地址發起請求,不經過 OneAPI。\n需要遵循 OpenAI 的 API 格式,並填寫完整請求地址,例如:\n\nLLM: {{host}}/v1/chat/completions\n\nEmbedding: {{host}}/v1/embeddings\n\nSTT: {{host}}/v1/audio/transcriptions\n\nTTS: {{host}}/v1/audio/speech\n\nRerank: {{host}}/v1/rerank",
|
||||
"model.response_format": "響應格式",
|
||||
"model.show_stop_sign": "展示停止序列參數",
|
||||
"model.show_top_p": "展示 Top-p 參數",
|
||||
"model.test_model": "模型測試",
|
||||
"model.tool_choice": "支援工具調用",
|
||||
"model.tool_choice_tag": "工具調用",
|
||||
"model.tool_choice_tip": "如果該模型支援工具調用,則開啟該開關",
|
||||
"model.tool_choice": "支援工具呼叫",
|
||||
"model.tool_choice_tag": "工具呼叫",
|
||||
"model.tool_choice_tip": "如果該模型支援工具呼叫,則開啟該開關",
|
||||
"model.used_in_classify": "用於問題分類",
|
||||
"model.used_in_extract_fields": "用於文字擷取",
|
||||
"model.used_in_tool_call": "用於工具呼叫節點",
|
||||
@@ -70,14 +70,14 @@
|
||||
"model.vision_tag": "視覺",
|
||||
"model.vision_tip": "如果模型支援圖片識別,則開啟該開關。",
|
||||
"model.voices": "聲音角色",
|
||||
"model.voices_tip": "透過一個數組配置多個,例如:\n\n[\n {\n \"label\": \"Alloy\",\n \"value\": \"alloy\"\n },\n {\n \"label\": \"Echo\",\n \"value\": \"echo\"\n }\n]",
|
||||
"model.voices_tip": "透過一個陣列設定多個,例如:\n\n[\n {\n \"label\": \"Alloy\",\n \"value\": \"alloy\"\n },\n {\n \"label\": \"Echo\",\n \"value\": \"echo\"\n }\n]",
|
||||
"model_provider": "模型提供者",
|
||||
"notifications": "通知",
|
||||
"personal_information": "個人資訊",
|
||||
"personalization": "個人化",
|
||||
"promotion_records": "促銷記錄",
|
||||
"reset_default": "恢復默認配置",
|
||||
"reset_default": "恢復預設設定",
|
||||
"team": "團隊管理",
|
||||
"third_party": "第三方账号",
|
||||
"third_party": "第三方賬號",
|
||||
"usage_records": "使用記錄"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"back": "返回",
|
||||
"bank_account": "開戶帳號",
|
||||
"bank_name": "開戶銀行",
|
||||
"bill_detail": "帳單詳情",
|
||||
"bill_detail": "帳單詳細資訊",
|
||||
"bill_record": "帳單記錄",
|
||||
"company_address": "公司地址",
|
||||
"company_phone": "公司電話",
|
||||
@@ -12,15 +12,15 @@
|
||||
"contact_phone": "聯絡電話",
|
||||
"contact_phone_void": "聯絡電話格式錯誤",
|
||||
"default_header": "預設抬頭",
|
||||
"detail": "詳情",
|
||||
"detail": "詳細資訊",
|
||||
"email_address": "郵件地址",
|
||||
"extra_ai_points": "AI 積分運算標準",
|
||||
"extra_dataset_size": "額外知識庫容量",
|
||||
"generation_time": "生成時間",
|
||||
"has_invoice": "是否已開票",
|
||||
"invoice_amount": "開票金額",
|
||||
"invoice_detail": "發票詳情",
|
||||
"invoice_sending_info": "發票將在 3-7 個工作天內發送至郵箱,請耐心等待",
|
||||
"invoice_detail": "發票詳細資訊",
|
||||
"invoice_sending_info": "發票將在 3-7 個工作天內傳送至郵箱,請耐心等待",
|
||||
"mm": "毫米",
|
||||
"need_special_invoice": "是否需要專票",
|
||||
"no": "否",
|
||||
@@ -31,8 +31,8 @@
|
||||
"organization_name": "組織名稱",
|
||||
"payment_method": "支付方式",
|
||||
"save": "儲存",
|
||||
"save_failed": "保存異常",
|
||||
"save_success": "保存成功",
|
||||
"save_failed": "儲存異常",
|
||||
"save_success": "儲存成功",
|
||||
"status": "狀態",
|
||||
"submit_failed": "提交失敗",
|
||||
"submit_success": "提交成功",
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
"exchange_success": "兌換成功",
|
||||
"expiration_time": "到期時間",
|
||||
"expired": "已過期",
|
||||
"general_info": "通用信息",
|
||||
"general_info": "通用資訊",
|
||||
"group": "群組",
|
||||
"help_chatbot": "機器人助手",
|
||||
"help_document": "幫助文檔",
|
||||
"help_document": "幫助文件",
|
||||
"knowledge_base_capacity": "知識庫容量",
|
||||
"manage": "管理",
|
||||
"member_name": "成員名",
|
||||
@@ -39,36 +39,36 @@
|
||||
"new_password": "新密碼",
|
||||
"notification_receiving": "通知接收",
|
||||
"old_password": "舊密碼",
|
||||
"openai_account_configuration": "OpenAI 帳號配置",
|
||||
"openai_account_configuration": "OpenAI 帳號設定",
|
||||
"openai_account_setting_exception": "設定 OpenAI 帳號異常",
|
||||
"package_and_usage": "套餐與用量",
|
||||
"package_details": "套餐詳情",
|
||||
"package_details": "套餐詳細資訊",
|
||||
"package_expiry_time": "套餐到期時間",
|
||||
"package_usage_rules": "套餐使用規則:系統優先使用更進階的套餐,原未用完的套餐將延遲生效",
|
||||
"password": "密碼",
|
||||
"password_mismatch": "密碼不一致: 兩次密碼不一致",
|
||||
"password_tip": "密碼至少 6 位,且至少包含兩種組合:數字、字母或特殊字符",
|
||||
"password_mismatch": "密碼不一致:兩次密碼不一致",
|
||||
"password_tip": "密碼至少 6 位,且至少包含兩種組合:數字、字母或特殊字元",
|
||||
"password_update_error": "修改密碼異常",
|
||||
"password_update_success": "修改密碼成功",
|
||||
"pending_usage": "待使用",
|
||||
"phone_label": "手機號",
|
||||
"please_bind_notification_receiving_path": "請先綁定通知接收途徑",
|
||||
"purchase_extra_package": "購買額外套餐",
|
||||
"reminder_create_bound_notification_account": "提醒創建者綁定通知帳號",
|
||||
"reminder_create_bound_notification_account": "提醒建立者綁定通知帳號",
|
||||
"resource_usage": "資源用量",
|
||||
"select_avatar": "點選選擇頭像",
|
||||
"standard_package_and_extra_resource_package": "包含標準套餐與額外資源包",
|
||||
"storage_capacity": "儲存量",
|
||||
"team_balance": "團隊餘額",
|
||||
"team_info": "團隊信息",
|
||||
"team_info": "團隊資訊",
|
||||
"token_validity_period": "積分有效期限一年",
|
||||
"tokens": "積分",
|
||||
"type": "類型",
|
||||
"unlimited": "無限制",
|
||||
"update_password": "修改密碼",
|
||||
"update_success_tip": "更新數據成功",
|
||||
"update_success_tip": "更新資料成功",
|
||||
"upgrade_package": "升級套餐",
|
||||
"usage_balance": "使用餘額: 使用餘額",
|
||||
"usage_balance": "使用餘額:使用餘額",
|
||||
"usage_balance_notice": "由於系統升級,原「自動續費從餘額扣款」模式取消,餘額儲值入口關閉。\n您的餘額可用於購買積分",
|
||||
"user_account": "帳號",
|
||||
"user_team_team_name": "團隊",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"notification_detail": "通知詳情",
|
||||
"notification_detail": "通知詳細資訊",
|
||||
"no_notifications": "暫無通知",
|
||||
"read": "已讀",
|
||||
"system": "官方",
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
{
|
||||
"Hunyuan": "騰訊混元",
|
||||
"api_key": "API 密鑰",
|
||||
"api_key": "API 金鑰",
|
||||
"azure": "Azure",
|
||||
"base_url": "代理地址",
|
||||
"channel_name": "渠道名",
|
||||
"channel_priority": "優先級",
|
||||
"channel_priority_tip": "優先級越高的渠道,越容易被請求到",
|
||||
"channel_name": "管道名稱",
|
||||
"channel_priority": "優先順序",
|
||||
"channel_priority_tip": "優先順序越高的管道,越容易被請求到",
|
||||
"channel_status": "狀態",
|
||||
"channel_status_auto_disabled": "自動禁用",
|
||||
"channel_status_disabled": "禁用",
|
||||
"channel_status_auto_disabled": "自動停用",
|
||||
"channel_status_disabled": "停用",
|
||||
"channel_status_enabled": "啟用",
|
||||
"channel_status_unknown": "未知",
|
||||
"channel_type": "廠商",
|
||||
"clear_model": "清空模型",
|
||||
"confirm_delete_channel": "確認刪除 【{{name}}】渠道?",
|
||||
"copy_model_id_success": "已復制模型id",
|
||||
"create_channel": "新增渠道",
|
||||
"default_url": "默認地址",
|
||||
"detail": "詳情",
|
||||
"edit_channel": "渠道配置",
|
||||
"confirm_delete_channel": "確認刪除【{{name}}】管道?",
|
||||
"copy_model_id_success": "已復制模型 id",
|
||||
"create_channel": "新增管道",
|
||||
"default_url": "預設地址",
|
||||
"detail": "詳細資訊",
|
||||
"edit_channel": "管道設定",
|
||||
"enable_channel": "啟用",
|
||||
"forbid_channel": "禁用",
|
||||
"key_type": "API key 格式:",
|
||||
"log": "調用日誌",
|
||||
"log_detail": "日誌詳情",
|
||||
"log_request_id_search": "根據 requestId 搜索",
|
||||
"forbid_channel": "停用",
|
||||
"key_type": "API key 格式:",
|
||||
"log": "呼叫日誌",
|
||||
"log_detail": "日誌詳細資訊",
|
||||
"log_request_id_search": "根據 requestId 搜尋",
|
||||
"log_status": "狀態",
|
||||
"mapping": "模型映射",
|
||||
"mapping_tip": "需填寫一個有效 Json。\n可在向實際地址發送請求時,對模型進行映射。\n例如:\n{\n \n \"gpt-4o\": \"gpt-4o-test\"\n\n}\n\n當 FastGPT 請求 gpt-4o 模型時,會向實際地址發送 gpt-4o-test 的模型,而不是 gpt-4o。",
|
||||
"maxToken_tip": "模型 max_tokens 參數,如果留空,則代表模型不支持該參數。",
|
||||
"max_temperature_tip": "模型 temperature 參數,不填則代表模型不支持 temperature 參數。",
|
||||
"mapping": "模型對映",
|
||||
"mapping_tip": "需填寫一個有效 Json。\n可在向實際地址傳送請求時,對模型進行對映。\n例如:\n{\n \n \"gpt-4o\": \"gpt-4o-test\"\n\n}\n\n當 FastGPT 請求 gpt-4o 模型時,會向實際地址傳送 gpt-4o-test 的模型,而不是 gpt-4o。",
|
||||
"maxToken_tip": "模型 max_tokens 參數,如果留空,則代表模型不支援該參數。",
|
||||
"max_temperature_tip": "模型 temperature 參數,不填則代表模型不支援 temperature 參數。",
|
||||
"model": "模型",
|
||||
"model_name": "模型名",
|
||||
"model_test": "模型測試",
|
||||
"model_tokens": "輸入/輸出 Tokens",
|
||||
"request_at": "請求時間",
|
||||
"request_duration": "請求時長: {{duration}}s",
|
||||
"request_duration": "請求時長:{{duration}}s",
|
||||
"retry_times": "重試次數",
|
||||
"running_test": "測試中",
|
||||
"search_model": "搜索模型",
|
||||
"select_channel": "選擇渠道名",
|
||||
"search_model": "搜尋模型",
|
||||
"select_channel": "選擇管道名稱",
|
||||
"select_model": "選擇模型",
|
||||
"select_model_placeholder": "選擇該渠道下可用的模型",
|
||||
"select_provider_placeholder": "搜索廠商",
|
||||
"select_model_placeholder": "選擇該管道下可用的模型",
|
||||
"select_provider_placeholder": "搜尋廠商",
|
||||
"selected_model_empty": "至少選擇一個模型",
|
||||
"start_test": "批量測試{{num}}個模型",
|
||||
"start_test": "批次測試{{num}}個模型",
|
||||
"test_failed": "有{{num}}個模型報錯",
|
||||
"vlm_model": "圖片理解模型",
|
||||
"vlm_model_tip": "用於知識庫中對文檔中的圖片進行額外的索引生成",
|
||||
"vlm_model_tip": "用於知識庫中對文件中的圖片進行額外的索引生成",
|
||||
"waiting_test": "等待測試"
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"copy_invite_link": "複製邀請連結",
|
||||
"earnings": "收益(¥)",
|
||||
"invite_url": "邀請連結",
|
||||
"invite_url_tip": "透過該連結註冊的好友將永久與你綁定,其儲值時你會獲得一定餘額獎勵。\n \n此外,好友使用手機號碼註冊時,你將立即獲得 5 元獎勵。\n \n獎勵會發送到您的預設團隊。",
|
||||
"invite_url_tip": "透過該連結註冊的好友將永久與你綁定,其儲值時你會獲得一定餘額獎勵。\n \n此外,好友使用手機號碼註冊時,你將立即獲得 5 元獎勵。\n \n獎勵會傳送到您的預設團隊。",
|
||||
"no_invite_records": "暫無邀請紀錄",
|
||||
"time": "時間",
|
||||
"total_invited": "累計邀請人數",
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
"language": "語言",
|
||||
"personalization": "個人化",
|
||||
"timezone": "時區",
|
||||
"update_data_success": "更新數據成功"
|
||||
"update_data_success": "更新資料成功"
|
||||
}
|
||||
@@ -1,28 +1,34 @@
|
||||
{
|
||||
"1person": "1人",
|
||||
"1year": "1年",
|
||||
"30mins": "30分鐘",
|
||||
"7days": "7天",
|
||||
"1person": "1 人",
|
||||
"1year": "1 年",
|
||||
"30mins": "30 分鐘",
|
||||
"7days": "7 天",
|
||||
"accept": "接受",
|
||||
"action": "操作",
|
||||
"assign_permission": "權限變更",
|
||||
"change_department_name": "部門編輯",
|
||||
"change_member_name": "成員改名",
|
||||
"confirm_delete_group": "確認刪除群組?",
|
||||
"confirm_delete_member": "確認刪除成員?",
|
||||
"confirm_delete_org": "確認刪除該部門?",
|
||||
"confirm_forbidden": "確認停用",
|
||||
"confirm_leave_team": "確認離開該團隊? \n退出後,您在該團隊所有的資源轉讓給團隊所有者。",
|
||||
"confirm_leave_team": "確認離開該團隊? \n結束後,您在該團隊所有的資源轉讓給團隊所有者。",
|
||||
"copy_link": "複製連結",
|
||||
"create_department": "創建子部門",
|
||||
"create_group": "建立群組",
|
||||
"create_invitation_link": "建立邀請連結",
|
||||
"create_org": "創建部門",
|
||||
"create_sub_org": "創建子部門",
|
||||
"create_org": "建立部門",
|
||||
"create_sub_org": "建立子部門",
|
||||
"delete": "刪除",
|
||||
"delete_department": "刪除子部門",
|
||||
"delete_group": "刪除群組",
|
||||
"delete_org": "刪除部門",
|
||||
"edit_info": "編輯訊息",
|
||||
"edit_member": "編輯用戶",
|
||||
"edit_member": "編輯使用者",
|
||||
"edit_member_tip": "成員名",
|
||||
"edit_org_info": "編輯部門資訊",
|
||||
"expires": "過期時間",
|
||||
"forbid_hint": "停用後,該邀請連結將失效。 該操作不可撤銷,是否確認停用?",
|
||||
"forbid_hint": "停用後,該邀請連結將失效。該操作不可撤銷,是否確認停用?",
|
||||
"forbid_success": "停用成功",
|
||||
"forbidden": "停用",
|
||||
"group": "群組",
|
||||
@@ -32,26 +38,56 @@
|
||||
"has_invited": "已邀請",
|
||||
"ignore": "忽略",
|
||||
"invitation_copy_link": "【{{systemName}}】 {{userName}} 邀請您加入{{teamName}}團隊,連結:{{url}}",
|
||||
"invitation_link_auto_clean_hint": "已失效連結將在30天後自動清理",
|
||||
"invitation_link_auto_clean_hint": "已失效連結將在 30 天後自動清理",
|
||||
"invitation_link_description": "連結描述",
|
||||
"invitation_link_list": "連結列表",
|
||||
"invite_member": "邀請成員",
|
||||
"invited": "已邀請",
|
||||
"join_team": "加入團隊",
|
||||
"kick_out_team": "移除成員",
|
||||
"label_sync": "標籤同步",
|
||||
"leave_team_failed": "離開團隊異常",
|
||||
"log_assign_permission": "【{{name}}】更新了【{{objectName}}】的權限:[應用創建:【{{appCreate}}】, 知識庫:【{{datasetCreate}}】, API密鑰:【{{apiKeyCreate}}】, 管理:【{{manage}}】]",
|
||||
"log_change_department": "【{{name}}】更新了部門【{{departmentName}}】",
|
||||
"log_change_member_name": "【{{name}}】將成員【{{memberName}}】重命名為【{{newName}}】",
|
||||
"log_create_department": "【{{name}}】創建了部門【{{departmentName}}】",
|
||||
"log_create_group": "【{{name}}】創建了群組【{{groupName}}】",
|
||||
"log_create_invitation_link": "【{{name}}】創建了邀請鏈接【{{link}}】",
|
||||
"log_delete_department": "{{name}} 刪除了部門 {{departmentName}}",
|
||||
"log_delete_group": "{{name}} 刪除了群組 {{groupName}}",
|
||||
"log_details": "詳情",
|
||||
"log_join_team": "【{{name}}】通過邀請鏈接【{{link}}】加入團隊",
|
||||
"log_kick_out_team": "{{name}} 移除了成員 {{memberName}}",
|
||||
"log_login": "【{{name}}】登錄了系統",
|
||||
"log_relocate_department": "【{{name}}】移動了部門【{{departmentName}}】",
|
||||
"log_time": "操作時間",
|
||||
"log_type": "操作類型",
|
||||
"log_user": "操作人員",
|
||||
"login": "登入",
|
||||
"manage_member": "管理成員",
|
||||
"member": "成員",
|
||||
"member_group": "所屬成員組",
|
||||
"move_member": "移動成員",
|
||||
"move_org": "行動部門",
|
||||
"operation_log": "紀錄",
|
||||
"org": "組織",
|
||||
"org_description": "介紹",
|
||||
"org_name": "部門名稱",
|
||||
"owner": "擁有者",
|
||||
"permission": "權限",
|
||||
"permission_apikeyCreate": "建立 API 密鑰",
|
||||
"permission_apikeyCreate_Tip": "可以建立全域的 APIKey",
|
||||
"permission_appCreate": "建立應用程式",
|
||||
"permission_appCreate_tip": "可以在根目錄建立應用程式,(資料夾下的建立權限由資料夾控制)",
|
||||
"permission_datasetCreate": "建立知識庫",
|
||||
"permission_datasetCreate_Tip": "可以在根目錄建立知識庫,(資料夾下的建立權限由資料夾控制)",
|
||||
"permission_manage": "管理員",
|
||||
"permission_manage_tip": "可以管理成員、建立群組、管理所有群組、為群組和成員分配權限",
|
||||
"relocate_department": "部門移動",
|
||||
"remark": "備註",
|
||||
"remove_tip": "確認將 {{username}} 移出團隊?",
|
||||
"retain_admin_permissions": "保留管理員權限",
|
||||
"search_log": "搜索日誌",
|
||||
"search_member_group_name": "搜尋成員/群組名稱",
|
||||
"total_team_members": "共 {{amount}} 名成員",
|
||||
"transfer_ownership": "轉讓所有者",
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"configured": "已配置",
|
||||
"error.no_permission": "請聯繫管理員配置",
|
||||
"configured": "已設定",
|
||||
"error.no_permission": "請聯絡管理員設定",
|
||||
"laf_account": "af 帳號",
|
||||
"no_intro": "暫無說明",
|
||||
"not_configured": "未配置",
|
||||
"open_api_notice": "可以填寫 OpenAI/OneAPI 的相關金鑰。\n如果你填寫了該內容,在線上平台使用【 AI 對話】、【問題分類】和【內容提取】將會走你填寫的 Key,不會計費用。\n請注意你的 Key 是否有存取對應模型的權限。 \nGPT 模型可以選擇 FastAI 。",
|
||||
"not_configured": "未設定",
|
||||
"open_api_notice": "可以填寫 OpenAI/OneAPI 的相關金鑰。\n如果你填寫了該內容,在線上平臺使用【AI 對話】、【問題分類】和【內容提取】將會走你填寫的 Key,不會計費用。\n請注意你的 Key 是否有存取對應模型的權限。 \nGPT 模型可以選擇 FastAI。",
|
||||
"openai_account_configuration": "OpenAI/OneAPI 帳號",
|
||||
"request_address_notice": "請求地址,預設為 openai 官方。可填中轉位址,未自動補全 \"v1\"",
|
||||
"third_party_account": "第三方帳號",
|
||||
"third_party_account_desc": "管理員可以在這裡配置第三方帳號或變量,該帳號將被團隊所有人使用",
|
||||
"third_party_account_desc": "管理員可以在這裡設定第三方帳號或變數,該帳號將被團隊所有人使用",
|
||||
"unavailable": "取得使用量異常",
|
||||
"usage": "使用量:",
|
||||
"value_not_return_tip": "參數配置後,不會再次返回前端,無需洩漏給其他成員",
|
||||
"value_placeholder": "輸入參數值。\n輸入空值表示刪除該配置。"
|
||||
"value_not_return_tip": "參數設定後,不會再次返回前端,無需洩漏給其他成員",
|
||||
"value_placeholder": "輸入參數值。\n輸入空值表示刪除該設定。"
|
||||
}
|
||||
|
||||
@@ -4,17 +4,17 @@
|
||||
"app_name": "應用程式名",
|
||||
"auto_index": "索引增強",
|
||||
"billing_module": "扣費模組",
|
||||
"confirm_export": "共篩選出 {{total}} 條數據,是否確認導出?",
|
||||
"current_filter_conditions": "當前篩選條件:",
|
||||
"confirm_export": "共篩選出 {{total}} 條資料,是否確認匯出?",
|
||||
"current_filter_conditions": "目前篩選條件:",
|
||||
"dashboard": "儀表板",
|
||||
"details": "詳情",
|
||||
"details": "詳細資訊",
|
||||
"dingtalk": "釘釘",
|
||||
"duration_seconds": "時長(秒)",
|
||||
"embedding_index": "索引生成",
|
||||
"every_day": "天",
|
||||
"every_month": "月",
|
||||
"export_confirm": "導出確認",
|
||||
"export_confirm_tip": "當前共 {{total}} 筆使用記錄,確認導出?",
|
||||
"export_confirm": "匯出確認",
|
||||
"export_confirm_tip": "目前共 {{total}} 筆使用記錄,確認匯出?",
|
||||
"export_title": "時間,成員,類型,項目名,AI 積分消耗",
|
||||
"feishu": "飛書",
|
||||
"generation_time": "生成時間",
|
||||
@@ -42,7 +42,7 @@
|
||||
"total_points": "AI 積分消耗",
|
||||
"total_points_consumed": "AI 積分消耗",
|
||||
"total_usage": "總消耗",
|
||||
"usage_detail": "使用詳情",
|
||||
"usage_detail": "使用詳細資訊",
|
||||
"user_type": "類型",
|
||||
"wecom": "企業微信"
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
"Run": "執行",
|
||||
"Team Tags Set": "團隊標籤",
|
||||
"Team_Tags": "團隊標籤",
|
||||
"ai_point_price": "AI積分計費",
|
||||
"ai_point_price": "AI 積分計費",
|
||||
"ai_settings": "AI 設定",
|
||||
"all_apps": "所有應用程式",
|
||||
"app.Version name": "版本名稱",
|
||||
"app.error.publish_unExist_app": "發布失敗,請檢查工具調用是否正常",
|
||||
"app.error.unExist_app": "部分組件缺失,請刪除",
|
||||
"app.error.publish_unExist_app": "發布失敗,請檢查工具呼叫是否正常",
|
||||
"app.error.unExist_app": "部分元件遺失,請刪除",
|
||||
"app.modules.click to update": "點選更新",
|
||||
"app.modules.has new version": "有新版本",
|
||||
"app.modules.not_found": "組件缺失",
|
||||
"app.modules.not_found_tips": "系統內無法查找到該組件,請刪除,否則流程無法正常運行",
|
||||
"app.modules.not_found": "元件遺失",
|
||||
"app.modules.not_found_tips": "系統內無法查詢到該元件,請刪除,否則流程無法正常運作",
|
||||
"app.version_current": "目前版本",
|
||||
"app.version_initial": "初始版本",
|
||||
"app.version_name_tips": "版本名稱不能空白",
|
||||
@@ -20,23 +20,23 @@
|
||||
"app.version_publish_tips": "此版本將儲存至團隊雲端,同步給整個團隊,同時更新所有發布通道的應用程式版本",
|
||||
"app_detail": "應用程式詳細資訊",
|
||||
"auto_execute": "自動執行",
|
||||
"auto_execute_default_prompt_placeholder": "自動執行時,發送的預設問題",
|
||||
"auto_execute_default_prompt_placeholder": "自動執行時,傳送的預設問題",
|
||||
"auto_execute_tip": "開啟後,使用者進入對話式介面將自動觸發工作流程。\n執行順序:1、對話開場白;2、全域變數;3、自動執行。",
|
||||
"auto_save": "自動儲存",
|
||||
"chat_debug": "聊天預覽",
|
||||
"chat_logs": "對話紀錄",
|
||||
"chat_logs_tips": "紀錄會記錄此應用程式的線上、分享和 API(需填寫 chatId)對話紀錄",
|
||||
"config_ai_model_params": "點選配置 AI 模型相關屬性",
|
||||
"config_ai_model_params": "點選設定 AI 模型相關屬性",
|
||||
"config_file_upload": "點選設定檔案上傳規則",
|
||||
"config_question_guide": "配置猜你想問",
|
||||
"config_question_guide": "設定猜你想問",
|
||||
"confirm_copy_app_tip": "系統將為您建立一個相同設定的應用程式,但權限不會複製,請確認!",
|
||||
"confirm_del_app_tip": "確認刪除【{{name}}】及其所有聊天紀錄?",
|
||||
"confirm_delete_folder_tip": "確認刪除這個資料夾?將會刪除它底下所有應用程式及對應的對話紀錄,請確認!",
|
||||
"copy_one_app": "建立副本",
|
||||
"core.app.QG.Switch": "啟用猜你想問",
|
||||
"core.dataset.import.Custom prompt": "自訂提示詞",
|
||||
"create_by_curl": "從 CURL 創建",
|
||||
"create_by_template": "從模板創建",
|
||||
"create_by_curl": "從 CURL 建立",
|
||||
"create_by_template": "從範本建立",
|
||||
"create_copy_success": "建立副本成功",
|
||||
"create_empty_app": "建立空白應用程式",
|
||||
"create_empty_plugin": "建立空白外掛",
|
||||
@@ -74,22 +74,22 @@
|
||||
"interval.4_hours": "每 4 小時",
|
||||
"interval.6_hours": "每 6 小時",
|
||||
"interval.per_hour": "每小時",
|
||||
"intro": "FastGPT 是一個基於大型語言模型的知識庫平臺,提供開箱即用的資料處理、向量檢索和視覺化 AI 工作流程編排等功能,讓您可以輕鬆開發和部署複雜的問答系統,而無需繁瑣的設定或配置。",
|
||||
"intro": "FastGPT 是一個基於大型語言模型的知識庫平臺,提供開箱即用的資料處理、向量檢索和視覺化 AI 工作流程編排等功能,讓您可以輕鬆開發和部署複雜的問答系統,而無需繁瑣的設定或設定。",
|
||||
"invalid_json_format": "JSON 格式錯誤",
|
||||
"llm_not_support_vision": "這個模型不支援圖片辨識",
|
||||
"llm_use_vision": "圖片辨識",
|
||||
"llm_use_vision_tip": "點選模型選擇後,可以看到模型是否支援圖片辨識以及控制是否啟用圖片辨識的功能。啟用圖片辨識後,模型會讀取檔案連結中的圖片內容,並且如果使用者問題少於 500 字,會自動解析使用者問題中的圖片。",
|
||||
"logs_chat_user": "使用者",
|
||||
"logs_empty": "還沒有紀錄喔~",
|
||||
"logs_export_confirm_tip": "當前共 {{total}} 條對話記錄,確認導出?",
|
||||
"logs_export_title": "時間,來源,使用者,聯繫方式,標題,消息總數,用戶贊同反饋,用戶反對反饋,自定義反饋,標註答案,對話詳情",
|
||||
"logs_export_confirm_tip": "目前共 {{total}} 條對話記錄,確認匯出?",
|
||||
"logs_export_title": "時間,來源,使用者,聯絡方式,標題,訊息總數,使用者贊同回饋,使用者反對回饋,自定義回饋,標註答案,對話詳細資訊",
|
||||
"logs_message_total": "訊息總數",
|
||||
"logs_source": "来源",
|
||||
"logs_source": "來源",
|
||||
"logs_title": "標題",
|
||||
"look_ai_point_price": "查看所有模型計費標準",
|
||||
"look_ai_point_price": "檢視所有模型計費標準",
|
||||
"mark_count": "標記答案數量",
|
||||
"max_histories_number": "記憶輪數",
|
||||
"max_histories_number_tip": "模型最多攜帶多少輪對話進入記憶中,如果記憶超出模型上下文,系統會強制截斷。\n所以儘管配置 30 輪對話,實際運行時候,不一定會達到 30 輪。",
|
||||
"max_histories_number_tip": "模型最多攜帶多少輪對話進入記憶中,如果記憶超出模型上下文,系統會強制截斷。\n所以儘管設定 30 輪對話,實際運作時候,不一定會達到 30 輪。",
|
||||
"max_tokens": "回覆上限",
|
||||
"module.Custom Title Tip": "這個標題會顯示在對話過程中",
|
||||
"module.No Modules": "找不到外掛",
|
||||
@@ -104,10 +104,10 @@
|
||||
"open_auto_execute": "啟用自動執行",
|
||||
"open_vision_function_tip": "有圖示開關的模型即擁有圖片辨識功能。若開啟,模型會解析檔案連結中的圖片,並自動解析使用者問題中的圖片(使用者問題 ≤ 500 字時生效)。",
|
||||
"or_drag_JSON": "或拖曳 JSON 檔案",
|
||||
"paste_config_or_drag": "貼上配置或拖入 JSON 文件",
|
||||
"pdf_enhance_parse": "PDF增強解析",
|
||||
"paste_config_or_drag": "貼上設定或拖入 JSON 文件",
|
||||
"pdf_enhance_parse": "PDF 增強解析",
|
||||
"pdf_enhance_parse_price": "{{price}}積分/頁",
|
||||
"pdf_enhance_parse_tips": "調用 PDF 識別模型進行解析,可以將其轉換成 Markdown 並保留文檔中的圖片,同時也可以對掃描件進行識別,識別時間較長。",
|
||||
"pdf_enhance_parse_tips": "呼叫 PDF 識別模型進行解析,可以將其轉換成 Markdown 並保留文件中的圖片,同時也可以對掃描件進行識別,識別時間較長。",
|
||||
"permission.des.manage": "在寫入權限基礎上,可以設定發布通道、檢視對話紀錄、分配這個應用程式的權限",
|
||||
"permission.des.read": "可以使用這個應用程式進行對話",
|
||||
"permission.des.write": "可以檢視和編輯應用程式",
|
||||
@@ -120,16 +120,16 @@
|
||||
"publish_success": "發布成功",
|
||||
"question_guide_tip": "對話結束後,會為你產生 3 個引導性問題。",
|
||||
"reasoning_response": "輸出思考",
|
||||
"response_format": "回复格式",
|
||||
"saved_success": "保存成功!\n如需在外部使用該版本,請點擊“儲存並發布”",
|
||||
"response_format": "回覆格式",
|
||||
"saved_success": "儲存成功!\n如需在外部使用該版本,請點選“儲存並發布”",
|
||||
"search_app": "搜尋應用程式",
|
||||
"setting_app": "應用程式設定",
|
||||
"setting_plugin": "外掛設定",
|
||||
"show_top_p_tip": "用溫度採樣的替代方法,稱為Nucleus採樣,該模型考慮了具有TOP_P概率質量質量的令牌的結果。\n因此,0.1表示僅考慮包含最高概率質量的令牌。\n默認為 1。",
|
||||
"simple_tool_tips": "該插件含有特殊輸入,暫不支持被簡易應用調用",
|
||||
"show_top_p_tip": "用溫度取樣的替代方法,稱為 Nucleus 取樣,該模型考慮了具有 TOP_P 機率質量質量的令牌的結果。\n因此,0.1 表示僅考慮包含最高機率質量的令牌。\n預設為 1。",
|
||||
"simple_tool_tips": "該外掛含有特殊輸入,暫不支援被簡易應用呼叫",
|
||||
"source_updateTime": "更新時間",
|
||||
"stop_sign": "停止序列",
|
||||
"stop_sign_placeholder": "多個序列號通過 | 隔開,例如:aaa|stop",
|
||||
"stop_sign_placeholder": "多個序列號透過 | 隔開,例如:aaa|stop",
|
||||
"stream_response": "流輸出",
|
||||
"stream_response_tip": "關閉該開關,可以強制模型使用非流模式,並且不會直接進行內容輸出。\n可在 AI 回覆的輸出中,取得本次模型輸出的內容進行二次處理。",
|
||||
"temperature": "溫度",
|
||||
@@ -152,7 +152,7 @@
|
||||
"templateMarket.templateTags.Roleplay": "角色扮演",
|
||||
"templateMarket.templateTags.Web_search": "網路搜尋",
|
||||
"templateMarket.templateTags.Writing": "文字創作",
|
||||
"templateMarket.template_guide": "模板說明",
|
||||
"templateMarket.template_guide": "範本說明",
|
||||
"template_market": "範本市集",
|
||||
"template_market_description": "在範本市集探索更多玩法,設定教學與使用指引,帶您理解並上手各種應用程式",
|
||||
"template_market_empty_data": "找不到合適的範本",
|
||||
@@ -162,7 +162,7 @@
|
||||
"transition_to_workflow_create_new_placeholder": "建立新的應用程式,而不是修改目前應用程式",
|
||||
"transition_to_workflow_create_new_tip": "轉換成工作流程後,將無法轉換回簡易模式,請確認!",
|
||||
"tts_ai_model": "使用語音合成模型",
|
||||
"tts_browser": "瀏覽器自帶(免費)",
|
||||
"tts_browser": "瀏覽器自帶 (免費)",
|
||||
"tts_close": "關閉",
|
||||
"type.All": "全部",
|
||||
"type.Create http plugin tip": "透過 OpenAPI Schema 批次建立外掛,相容 GPTs 格式",
|
||||
@@ -173,7 +173,7 @@
|
||||
"type.Create workflow bot": "建立工作流程",
|
||||
"type.Create workflow tip": "透過低程式碼的方式,建立邏輯複雜的多輪對話 AI 應用程式,建議進階使用者使用",
|
||||
"type.Http plugin": "HTTP 外掛",
|
||||
"type.Import from json": "導入 JSON 配置",
|
||||
"type.Import from json": "匯入 JSON 設定",
|
||||
"type.Import from json tip": "透過 JSON 設定文件,直接建立應用",
|
||||
"type.Plugin": "外掛",
|
||||
"type.Simple bot": "簡易應用程式",
|
||||
|
||||
@@ -5,20 +5,20 @@
|
||||
"ai_reasoning": "思考過程",
|
||||
"back_to_text": "返回輸入",
|
||||
"chat.quote.No Data": "找不到該文件",
|
||||
"chat.quote.deleted": "該數據已被刪除~",
|
||||
"chat.quote.deleted": "該資料已被刪除~",
|
||||
"chat_history": "對話紀錄",
|
||||
"chat_input_guide_lexicon_is_empty": "尚未設定詞彙庫",
|
||||
"chat_test_app": "調試-{{name}}",
|
||||
"chat_test_app": "除錯-{{name}}",
|
||||
"citations": "{{num}} 筆引用",
|
||||
"click_contextual_preview": "點選檢視上下文預覽",
|
||||
"completion_finish_close": "連接斷開",
|
||||
"completion_finish_content_filter": "觸發安全風控",
|
||||
"completion_finish_function_call": "函數調用",
|
||||
"completion_finish_length": "超出回复限制",
|
||||
"completion_finish_function_call": "函式呼叫",
|
||||
"completion_finish_length": "超出回覆限制",
|
||||
"completion_finish_null": "未知",
|
||||
"completion_finish_reason": "完成原因",
|
||||
"completion_finish_stop": "正常完成",
|
||||
"completion_finish_tool_calls": "工具調用",
|
||||
"completion_finish_tool_calls": "工具呼叫",
|
||||
"config_input_guide": "設定輸入導引",
|
||||
"config_input_guide_lexicon": "設定詞彙庫",
|
||||
"config_input_guide_lexicon_title": "設定詞彙庫",
|
||||
@@ -27,10 +27,10 @@
|
||||
"contextual_preview": "上下文預覽 {{num}} 筆",
|
||||
"csv_input_lexicon_tip": "僅支援 CSV 批次匯入,點選下載範本",
|
||||
"custom_input_guide_url": "自訂詞彙庫網址",
|
||||
"data_source": "來源知識庫: {{name}}",
|
||||
"data_source": "來源知識庫:{{name}}",
|
||||
"dataset_quote_type error": "知識庫引用類型錯誤,正確類型:{ datasetId: string }[]",
|
||||
"delete_all_input_guide_confirm": "確定要清除輸入導引詞彙庫嗎?",
|
||||
"download_chunks": "下載數據",
|
||||
"download_chunks": "下載資料",
|
||||
"empty_directory": "此目錄中已無項目可選~",
|
||||
"file_amount_over": "超出檔案數量上限 {{max}}",
|
||||
"file_input": "檔案輸入",
|
||||
@@ -52,12 +52,12 @@
|
||||
"not_select_file": "尚未選取檔案",
|
||||
"plugins_output": "外掛程式輸出",
|
||||
"press_to_speak": "按住說話",
|
||||
"query_extension_IO_tokens": "問題優化輸入/輸出 Tokens",
|
||||
"query_extension_IO_tokens": "問題最佳化輸入/輸出 Tokens",
|
||||
"question_tip": "由上至下,各個模組的回應順序",
|
||||
"read_raw_source": "打開原文",
|
||||
"read_raw_source": "開啟原文",
|
||||
"reasoning_text": "思考過程",
|
||||
"release_cancel": "鬆開取消",
|
||||
"release_send": "鬆開發送,上滑取消",
|
||||
"release_send": "鬆開傳送,上滑取消",
|
||||
"response.child total points": "子工作流程點數消耗",
|
||||
"response.dataset_concat_length": "合併總數",
|
||||
"response.node_inputs": "節點輸入",
|
||||
@@ -72,7 +72,7 @@
|
||||
"to_dataset": "前往知識庫",
|
||||
"unsupported_file_type": "不支援的檔案類型",
|
||||
"upload": "上傳",
|
||||
"variable_invisable_in_share": "自定義變量在免登錄鏈接中不可見",
|
||||
"variable_invisable_in_share": "自定義變數在免登入連結中不可見",
|
||||
"view_citations": "檢視引用",
|
||||
"web_site_sync": "網站同步"
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"App": "應用程式",
|
||||
"Click_to_expand": "點擊查看詳情",
|
||||
"Click_to_expand": "點選檢視詳細資訊",
|
||||
"Download": "下載",
|
||||
"Export": "匯出",
|
||||
"FAQ.ai_point_a": "每次呼叫 AI 模型時,都會消耗一定數量的 AI 點數。詳細的計算標準請參考上方的「AI 點數計算標準」。\nToken 計算採用與 GPT3.5 相同的公式,1 Token ≈ 0.7 個中文字 ≈ 0.9 個英文單字,連續出現的字元可能會被視為 1 個 Token。",
|
||||
"FAQ.ai_point_expire_a": "會過期。目前方案過期後,AI 點數將會清空並更新為新方案的 AI 點數。年度方案的 AI 點數有效期為一年,而不是每個月重置。",
|
||||
"FAQ.ai_point_expire_a": "會過期。目前方案過期後,AI 點數將會清空並更新為新方案的 AI 點數。年度方案的 AI 點數有效期為一年,而不是每個月重設。",
|
||||
"FAQ.ai_point_expire_q": "AI 點數會過期嗎?",
|
||||
"FAQ.ai_point_q": "什麼是 AI 點數?",
|
||||
"FAQ.check_subscription_a": "帳號 - 個人資訊 - 方案詳細資訊 - 使用狀況。您可以檢視已訂閱方案的生效和到期時間。當付費方案到期後,將自動切換為免費版。",
|
||||
@@ -46,7 +46,7 @@
|
||||
"click_to_resume": "點選繼續",
|
||||
"code_editor": "程式碼編輯器",
|
||||
"code_error.account_error": "帳號名稱或密碼錯誤",
|
||||
"code_error.account_not_found": "用戶未註冊",
|
||||
"code_error.account_not_found": "使用者未註冊",
|
||||
"code_error.app_error.invalid_app_type": "無效的應用程式類型",
|
||||
"code_error.app_error.invalid_owner": "非法的應用程式擁有者",
|
||||
"code_error.app_error.not_exist": "應用程式不存在",
|
||||
@@ -90,7 +90,7 @@
|
||||
"code_error.team_error.group_name_duplicate": "群組名稱重複",
|
||||
"code_error.team_error.group_name_empty": "群組名稱不能為空",
|
||||
"code_error.team_error.group_not_exist": "群組不存在",
|
||||
"code_error.team_error.invitation_link_invalid": "邀請鏈接已失效",
|
||||
"code_error.team_error.invitation_link_invalid": "邀請連結已失效",
|
||||
"code_error.team_error.not_user": "找不到該成員",
|
||||
"code_error.team_error.org_member_duplicated": "重複的組織成員",
|
||||
"code_error.team_error.org_member_not_exist": "組織成員不存在",
|
||||
@@ -102,7 +102,7 @@
|
||||
"code_error.team_error.too_many_invitations": "您的有效邀請連結數已達上限,請先清理連結",
|
||||
"code_error.team_error.un_auth": "無權操作此團隊",
|
||||
"code_error.team_error.user_not_active": "使用者未接受或已離開團隊",
|
||||
"code_error.team_error.website_sync_not_enough": "免費版無法使用Web站點同步~",
|
||||
"code_error.team_error.website_sync_not_enough": "免費版無法使用 Web 站點同步~",
|
||||
"code_error.team_error.you_have_been_in_the_team": "你已經在該團隊中",
|
||||
"code_error.token_error_code.403": "登入狀態無效,請重新登入",
|
||||
"code_error.user_error.balance_not_enough": "帳戶餘額不足",
|
||||
@@ -118,7 +118,7 @@
|
||||
"common.Cancel": "取消",
|
||||
"common.Choose": "選擇",
|
||||
"common.Close": "關閉",
|
||||
"common.Code": "源碼",
|
||||
"common.Code": "原始碼",
|
||||
"common.Config": "設定",
|
||||
"common.Confirm": "確認",
|
||||
"common.Confirm Create": "確認建立",
|
||||
@@ -291,7 +291,7 @@
|
||||
"core.app.Chat Variable": "對話變數",
|
||||
"core.app.Config schedule plan": "設定排程執行",
|
||||
"core.app.Config whisper": "設定語音輸入",
|
||||
"core.app.Config_auto_execute": "點選配置自動執行規則",
|
||||
"core.app.Config_auto_execute": "點選設定自動執行規則",
|
||||
"core.app.Interval timer config": "排程執行設定",
|
||||
"core.app.Interval timer run": "排程執行",
|
||||
"core.app.Interval timer tip": "可排程執行應用程式",
|
||||
@@ -304,7 +304,7 @@
|
||||
"core.app.QG.Custom prompt tip1": "為確保生成的內容遵循正確格式,",
|
||||
"core.app.QG.Custom prompt tip2": "【黃色部分提示詞】",
|
||||
"core.app.QG.Custom prompt tip3": "不允許修改",
|
||||
"core.app.QG.Fixed Prompt": "請嚴格遵循格式規則:以 JSON 格式返回題目:\n['問題1','問題2','問題3']。",
|
||||
"core.app.QG.Fixed Prompt": "請嚴格遵循格式規則:以 JSON 格式返回題目:\n['問題 1','問題 2','問題 3']。",
|
||||
"core.app.Question Guide": "猜你想問",
|
||||
"core.app.Quote prompt": "引用範本提示詞",
|
||||
"core.app.Quote templates": "引用內容範本",
|
||||
@@ -373,7 +373,7 @@
|
||||
"core.app.tip.Add a intro to app": "快來為應用程式寫一個介紹",
|
||||
"core.app.tip.chatNodeSystemPromptTip": "在此輸入提示詞",
|
||||
"core.app.tip.systemPromptTip": "模型固定的引導詞,透過調整此內容,可以引導模型對話方向。此內容會固定在上下文的開頭。可透過輸入 / 插入變數。\n如果關聯了知識庫,您還可以透過適當的描述,引導模型何時去呼叫知識庫搜尋。例如:\n您是電影《星際效應》的助手,當使用者詢問與《星際效應》相關的內容時,請搜尋知識庫並根據搜尋結果回答。",
|
||||
"core.app.tip.variableTip": "可以在對話開始前,要求用戶填寫一些內容作為本輪對話的特定變量。\n該模塊位於開場引導之後。\n\n輸入框中,可通過 / 激活變量選擇,例如:提示詞、限定詞等",
|
||||
"core.app.tip.variableTip": "可以在對話開始前,要求使用者填寫一些內容作為本輪對話的特定變數。\n該模組位於開場引導之後。\n\n輸入框中,可透過 / 啟用變數選擇,例如:提示詞、限定詞等",
|
||||
"core.app.tip.welcomeTextTip": "每次對話開始前,傳送一段初始內容。支援標準 Markdown 語法。可使用的額外標記:\n[快速按鍵]:使用者點選後可以直接傳送該問題",
|
||||
"core.app.tool_label.doc": "使用文件",
|
||||
"core.app.tool_label.github": "GitHub 網址",
|
||||
@@ -452,7 +452,7 @@
|
||||
"core.chat.markdown.Edit Question": "編輯問題",
|
||||
"core.chat.markdown.Quick Question": "點我立即發問",
|
||||
"core.chat.markdown.Send Question": "傳送問題",
|
||||
"core.chat.module_unexist": "運行失敗:應用缺失組件",
|
||||
"core.chat.module_unexist": "執行失敗:應用遺失元件",
|
||||
"core.chat.quote.Quote Tip": "此處僅顯示實際引用內容,若資料有更新,此處不會即時更新",
|
||||
"core.chat.quote.Read Quote": "檢視引用",
|
||||
"core.chat.quote.afterUpdate": "更新後",
|
||||
@@ -625,10 +625,10 @@
|
||||
"core.dataset.search.score.reRank desc": "透過重新排名模型計算句子之間的關聯度,範圍為 0 到 1。",
|
||||
"core.dataset.search.score.rrf": "綜合排名",
|
||||
"core.dataset.search.score.rrf desc": "使用倒數排名融合方法,合併多個搜尋結果。",
|
||||
"core.dataset.search.search mode": "搜索方式",
|
||||
"core.dataset.search.search mode": "搜尋方式",
|
||||
"core.dataset.status.active": "已就緒",
|
||||
"core.dataset.status.syncing": "同步中",
|
||||
"core.dataset.status.waiting": "排队中",
|
||||
"core.dataset.status.waiting": "排隊中",
|
||||
"core.dataset.test.Batch test": "批次測試",
|
||||
"core.dataset.test.Batch test Placeholder": "選擇一個 CSV 檔案",
|
||||
"core.dataset.test.Search Test": "搜尋測試",
|
||||
@@ -644,7 +644,7 @@
|
||||
"core.dataset.training.Agent queue": "問答訓練排隊中",
|
||||
"core.dataset.training.Auto mode": "補充索引",
|
||||
"core.dataset.training.Auto mode Tip": "透過子索引以及呼叫模型產生相關問題與摘要,來增加資料區塊的語意豐富度,更有利於檢索。需要消耗更多的儲存空間並增加 AI 呼叫次數。",
|
||||
"core.dataset.training.Chunk mode": "直接分块",
|
||||
"core.dataset.training.Chunk mode": "直接分塊",
|
||||
"core.dataset.training.Full": "預計 20 分鐘以上",
|
||||
"core.dataset.training.Leisure": "閒置",
|
||||
"core.dataset.training.QA mode": "問答對提取",
|
||||
@@ -689,7 +689,7 @@
|
||||
"core.module.Variable": "全域變數",
|
||||
"core.module.Variable Setting": "變數設定",
|
||||
"core.module.edit.Field Name Cannot Be Empty": "欄位名稱不能為空",
|
||||
"core.module.edit.Field Value Type Cannot Be Empty": "可選數據類型不能為空",
|
||||
"core.module.edit.Field Value Type Cannot Be Empty": "可選資料類型不能為空",
|
||||
"core.module.extract.Add field": "新增欄位",
|
||||
"core.module.extract.Enum Description": "列舉此欄位可能的值,每行一個",
|
||||
"core.module.extract.Enum Value": "列舉值",
|
||||
@@ -743,7 +743,7 @@
|
||||
"core.module.template.AI support tool tip": "支援函式呼叫的模型可以更好地使用工具呼叫。",
|
||||
"core.module.template.Basic Node": "基本功能",
|
||||
"core.module.template.Query extension": "問題最佳化",
|
||||
"core.module.template.System Plugin": "系統插件",
|
||||
"core.module.template.System Plugin": "系統外掛",
|
||||
"core.module.template.System input module": "系統輸入模組",
|
||||
"core.module.template.Team app": "團隊應用程式",
|
||||
"core.module.template.Tool module": "工具",
|
||||
@@ -781,7 +781,7 @@
|
||||
"core.view_chat_detail": "檢視對話詳細資料",
|
||||
"core.workflow.Can not delete node": "此節點不允許刪除",
|
||||
"core.workflow.Change input type tip": "修改輸入類型將清空已填寫的值,請確認!",
|
||||
"core.workflow.Check Failed": "工作流校驗失敗,請檢查是否缺失、缺值,連線是否正常",
|
||||
"core.workflow.Check Failed": "工作流校驗失敗,請檢查是否遺失、缺值,連線是否正常",
|
||||
"core.workflow.Confirm stop debug": "確認停止除錯?除錯資訊將不會保留。",
|
||||
"core.workflow.Copy node": "已複製節點",
|
||||
"core.workflow.Custom inputs": "自訂輸入",
|
||||
@@ -826,14 +826,14 @@
|
||||
"core.workflow.template.Interactive": "互動",
|
||||
"core.workflow.template.Multimodal": "多模態",
|
||||
"core.workflow.template.Search": "搜尋",
|
||||
"core.workflow.tool.Handle": "工具連接器",
|
||||
"core.workflow.tool.Handle": "工具聯結器",
|
||||
"core.workflow.tool.Select Tool": "選擇工具",
|
||||
"core.workflow.value": "值",
|
||||
"core.workflow.variable": "變數",
|
||||
"create": "建立",
|
||||
"cron_job_run_app": "排程任務",
|
||||
"data_index_custom": "自定義索引",
|
||||
"data_index_default": "默認索引",
|
||||
"data_index_default": "預設索引",
|
||||
"data_index_image": "圖片索引",
|
||||
"data_index_question": "推測問題索引",
|
||||
"data_index_summary": "摘要索引",
|
||||
@@ -879,25 +879,25 @@
|
||||
"dataset_data_input_chunk_content": "內容",
|
||||
"dataset_data_input_q": "問題",
|
||||
"dataset_data_input_qa": "QA 模式",
|
||||
"dataset_text_model_tip": "用於知識庫預處理階段的文本處理,例如自動補充索引、問答對提取。",
|
||||
"deep_rag_search": "深度搜索",
|
||||
"dataset_text_model_tip": "用於知識庫預處理階段的文字處理,例如自動補充索引、問答對提取。",
|
||||
"deep_rag_search": "深度搜尋",
|
||||
"delete_api": "確認刪除此 API 金鑰?\n刪除後該金鑰將立即失效,對應的對話記錄不會被刪除,請確認!",
|
||||
"embedding_model_not_config": "檢測到沒有可用的索引模型",
|
||||
"embedding_model_not_config": "偵測到沒有可用的索引模型",
|
||||
"error.Create failed": "建立失敗",
|
||||
"error.code_error": "驗證碼錯誤",
|
||||
"error.fileNotFound": "找不到檔案",
|
||||
"error.inheritPermissionError": "繼承權限錯誤",
|
||||
"error.invalid_params": "參數無效",
|
||||
"error.missingParams": "參數不足",
|
||||
"error.send_auth_code_too_frequently": "請勿頻繁獲取驗證碼",
|
||||
"error.send_auth_code_too_frequently": "請勿頻繁取得驗證碼",
|
||||
"error.too_many_request": "請求太頻繁了,請稍後重試",
|
||||
"error.upload_file_error_filename": "{{name}} 上傳失敗",
|
||||
"error.upload_image_error": "上傳文件失敗",
|
||||
"error.username_empty": "帳號不能為空",
|
||||
"error_collection_not_exist": "集合不存在",
|
||||
"error_embedding_not_config": "未配置索引模型",
|
||||
"error_llm_not_config": "未配置文件理解模型",
|
||||
"error_vlm_not_config": "未配置圖片理解模型",
|
||||
"error_embedding_not_config": "未設定索引模型",
|
||||
"error_llm_not_config": "未設定文件理解模型",
|
||||
"error_vlm_not_config": "未設定圖片理解模型",
|
||||
"extraction_results": "提取結果",
|
||||
"field_name": "欄位名稱",
|
||||
"free": "免費",
|
||||
@@ -913,7 +913,7 @@
|
||||
"info.include": "包含標準方案與額外資源包",
|
||||
"info.node_info": "調整此模組會影響工具呼叫的時機。\n您可以透過精確描述此模組功能,引導模型進行工具呼叫。",
|
||||
"info.old_version_attention": "偵測到您的進階編排為舊版本,系統將自動格式化為新版工作流程。\n\n由於版本差異較大,可能導致某些工作流程無法正常排列。請重新手動連接工作流程。如果仍然異常,請嘗試刪除對應節點後重新新增。\n\n您可以直接點選除錯來測試工作流程。除錯完成後,點選發布。直到您點選發布,新工作流程才會真正儲存生效。\n\n在您發布新工作流程之前,自動儲存將不會生效。",
|
||||
"info.open_api_notice": "您可以填寫 OpenAI/OneAPI 的相關金鑰。如果您填寫了此內容,在線上平台使用【AI 對話】、【問題分類】和【內容提取】將使用您填寫的金鑰,不會計費。請確認您的金鑰是否有存取對應模型的權限。GPT 模型可以選擇 FastAI。",
|
||||
"info.open_api_notice": "您可以填寫 OpenAI/OneAPI 的相關金鑰。如果您填寫了此內容,在線上平臺使用【AI 對話】、【問題分類】和【內容提取】將使用您填寫的金鑰,不會計費。請確認您的金鑰是否有存取對應模型的權限。GPT 模型可以選擇 FastAI。",
|
||||
"info.open_api_placeholder": "請求網址,預設為 OpenAI 官方。可填寫中轉網址,未自動補全 \"v1\"",
|
||||
"info.resource": "資源使用量",
|
||||
"invalid_variable": "無效變數",
|
||||
@@ -923,7 +923,7 @@
|
||||
"item_name": "欄位名稱",
|
||||
"just_now": "剛剛",
|
||||
"key_repetition": "鍵值重複",
|
||||
"llm_model_not_config": "檢測到沒有可用的語言模型",
|
||||
"llm_model_not_config": "偵測到沒有可用的語言模型",
|
||||
"max_quote_tokens": "引用上限",
|
||||
"max_quote_tokens_tips": "單次搜尋最大的 token 數量,中文約 1 字=1.7 tokens,英文約 1 字=1 token",
|
||||
"min_similarity": "最低相關度",
|
||||
@@ -964,14 +964,14 @@
|
||||
"new_create": "建立新項目",
|
||||
"no": "否",
|
||||
"no_laf_env": "系統未設定 LAF 環境",
|
||||
"not_model_config": "未配置相關模型",
|
||||
"not_model_config": "未設定相關模型",
|
||||
"not_yet_introduced": "暫無介紹",
|
||||
"option": "選項",
|
||||
"pay.amount": "金額",
|
||||
"pay.package_tip.buy": "您購買的方案等級低於目前方案,該方案將在目前方案過期後生效。\n您可在帳戶 - 個人資訊 - 方案詳細資訊中檢視方案使用情況。",
|
||||
"pay.package_tip.renewal": "您正在續約方案。您可在帳戶 - 個人資訊 - 方案詳細資訊中檢視方案使用情況。",
|
||||
"pay.package_tip.upgrade": "您購買的方案等級高於目前方案,該方案將立即生效,目前方案將延後生效。您可在帳戶 - 個人資訊 - 方案詳細資訊中檢視方案使用情況。",
|
||||
"pay.wechat": "請微信掃碼付款: {{price}}元\n\n付款完成前,請勿關閉頁面",
|
||||
"pay.wechat": "請微信掃碼付款:{{price}}元\n\n付款完成前,請勿關閉頁面",
|
||||
"pay.yuan": "{{amount}} 元",
|
||||
"permission.Collaborator": "協作者",
|
||||
"permission.Default permission": "預設權限",
|
||||
@@ -1022,7 +1022,7 @@
|
||||
"plugin.path": "路徑",
|
||||
"prompt_input_placeholder": "請輸入提示詞",
|
||||
"question_feedback": "工單諮詢",
|
||||
"read_quote": "查看引用",
|
||||
"read_quote": "檢視引用",
|
||||
"required": "必填",
|
||||
"rerank_weight": "重排權重",
|
||||
"resume_failed": "恢復失敗",
|
||||
@@ -1040,7 +1040,7 @@
|
||||
"support.outlink.Max usage points tip": "此連結最多允許使用多少點數,超出後將無法使用。-1 代表無限制。",
|
||||
"support.outlink.Usage points": "點數消耗",
|
||||
"support.outlink.share.Chat_quote_reader": "全文閱讀器",
|
||||
"support.outlink.share.Full_text tips": "允許閱讀該引用片段來源的完整數據集",
|
||||
"support.outlink.share.Full_text tips": "允許閱讀該引用片段來源的完整資料集",
|
||||
"support.outlink.share.Response Quote": "回傳引用",
|
||||
"support.outlink.share.Response Quote tips": "在分享連結中回傳引用內容,但不允許使用者下載原始文件",
|
||||
"support.outlink.share.running_node": "執行節點",
|
||||
@@ -1090,8 +1090,8 @@
|
||||
"support.user.team.Team Tags Async Success": "同步完成",
|
||||
"support.user.team.member": "成員",
|
||||
"support.wallet.Ai point every thousand tokens": "{{points}} 點數/1K tokens",
|
||||
"support.wallet.Ai point every thousand tokens_input": "輸入:{{points}} 积分/1K tokens",
|
||||
"support.wallet.Ai point every thousand tokens_output": "輸出:{{points}} 积分/1K tokens",
|
||||
"support.wallet.Ai point every thousand tokens_input": "輸入:{{points}} 積分/1K tokens",
|
||||
"support.wallet.Ai point every thousand tokens_output": "輸出:{{points}} 積分/1K tokens",
|
||||
"support.wallet.Amount": "金額",
|
||||
"support.wallet.App_amount_not_sufficient": "您的應用數量已達上限,請升級套餐後繼續使用。",
|
||||
"support.wallet.Buy": "購買",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"api_file": "API 檔案庫",
|
||||
"api_url": "介面位址",
|
||||
"auto_indexes": "自動生成補充索引",
|
||||
"auto_indexes_tips": "通過大模型進行額外索引生成,提高語義豐富度,提高檢索的精度。",
|
||||
"auto_indexes_tips": "透過大模型進行額外索引生成,提高語義豐富度,提高檢索的精度。",
|
||||
"auto_training_queue": "增強索引排隊",
|
||||
"chunk_max_tokens": "分塊上限",
|
||||
"chunk_size": "分塊大小",
|
||||
@@ -12,8 +12,8 @@
|
||||
"collection.Create update time": "建立/更新時間",
|
||||
"collection.Training type": "分段模式",
|
||||
"collection.training_type": "處理模式",
|
||||
"collection_data_count": "數據量",
|
||||
"collection_metadata_custom_pdf_parse": "PDF增強解析",
|
||||
"collection_data_count": "資料量",
|
||||
"collection_metadata_custom_pdf_parse": "PDF 增強解析",
|
||||
"collection_metadata_image_parse": "圖片標註",
|
||||
"collection_not_support_retraining": "此集合類型不支援重新調整參數",
|
||||
"collection_not_support_sync": "該集合不支援同步",
|
||||
@@ -22,13 +22,13 @@
|
||||
"collection_tags": "集合標籤",
|
||||
"common_dataset": "通用資料集",
|
||||
"common_dataset_desc": "可透過匯入檔案、網頁連結或手動輸入的方式建立資料集",
|
||||
"config_sync_schedule": "配置定時同步",
|
||||
"config_sync_schedule": "設定定時同步",
|
||||
"confirm_to_rebuild_embedding_tip": "確定要為資料集切換索引嗎?\n切換索引是一個重要的操作,需要對您資料集內所有資料重新建立索引,可能需要較長時間,請確保帳號內剩餘點數充足。\n\n此外,您還需要注意修改使用此資料集的應用程式,避免與其他索引模型資料集混用。",
|
||||
"core.dataset.import.Adjust parameters": "調整參數",
|
||||
"custom_data_process_params": "自訂",
|
||||
"custom_data_process_params_desc": "自訂資料處理規則",
|
||||
"custom_split_sign_tip": "允許你根據自定義的分隔符進行分塊。\n通常用於已處理好的數據,使用特定的分隔符來精確分塊。\n可以使用 | 符號表示多個分割符,例如:“。|.” 表示中英文句號。\n\n盡量避免使用正則相關特殊符號,例如: * () [] {} 等。",
|
||||
"data_amount": "{{dataAmount}} 組數據, {{indexAmount}} 組索引",
|
||||
"custom_split_sign_tip": "允許你根據自定義的分隔符進行分塊。\n通常用於已處理好的資料,使用特定的分隔符來精確分塊。\n可以使用 | 符號表示多個分割符,例如:“。|.”表示中英文句號。\n\n盡量避免使用正則相關特殊符號,例如:* () [] {} 等。",
|
||||
"data_amount": "{{dataAmount}} 組資料,{{indexAmount}} 組索引",
|
||||
"data_error_amount": "{{errorAmount}} 組訓練異常",
|
||||
"data_index_num": "索引 {{index}}",
|
||||
"data_process_params": "處理參數",
|
||||
@@ -37,8 +37,8 @@
|
||||
"dataset.Completed": "完成",
|
||||
"dataset.Delete_Chunk": "刪除",
|
||||
"dataset.Edit_Chunk": "編輯",
|
||||
"dataset.Error_Message": "報錯信息",
|
||||
"dataset.No_Error": "暫無異常信息",
|
||||
"dataset.Error_Message": "報錯資訊",
|
||||
"dataset.No_Error": "暫無異常資訊",
|
||||
"dataset.Operation": "操作",
|
||||
"dataset.ReTrain": "重試",
|
||||
"dataset.Training Process": "訓練狀態",
|
||||
@@ -46,13 +46,13 @@
|
||||
"dataset.Training_Errors": "異常",
|
||||
"dataset.Training_QA": "{{count}} 組問答對訓練中",
|
||||
"dataset.Training_Status": "訓練狀態",
|
||||
"dataset.Training_Waiting": "需等待 {{count}} 組數據",
|
||||
"dataset.Unsupported operation": "操作不支持",
|
||||
"dataset.Training_Waiting": "需等待 {{count}} 組資料",
|
||||
"dataset.Unsupported operation": "操作不支援",
|
||||
"dataset.no_collections": "尚無資料集",
|
||||
"dataset.no_tags": "尚無標籤",
|
||||
"default_params": "預設",
|
||||
"default_params_desc": "使用系統默認的參數和規則",
|
||||
"edit_dataset_config": "編輯知識庫配置",
|
||||
"default_params_desc": "使用系統預設的參數和規則",
|
||||
"edit_dataset_config": "編輯知識庫設定",
|
||||
"enhanced_indexes": "索引增強",
|
||||
"error.collectionNotFound": "找不到集合",
|
||||
"external_file": "外部檔案庫",
|
||||
@@ -62,44 +62,44 @@
|
||||
"external_read_url_tip": "可以設定您檔案庫的讀取網址,方便對使用者進行讀取權限驗證。目前可使用 {{fileId}} 變數來代表外部檔案識別碼。",
|
||||
"external_url": "檔案存取網址",
|
||||
"feishu_dataset": "飛書知識庫",
|
||||
"feishu_dataset_config": "配置飛書知識庫",
|
||||
"feishu_dataset_desc": "可通過配置飛書文檔權限,使用飛書文檔構建知識庫,文檔不會進行二次存儲",
|
||||
"feishu_dataset_config": "設定飛書知識庫",
|
||||
"feishu_dataset_desc": "可透過設定飛書文件權限,使用飛書文件建構知識庫,文件不會進行二次儲存",
|
||||
"file_list": "文件列表",
|
||||
"file_model_function_tip": "用於增強索引和問答生成",
|
||||
"filename": "檔案名稱",
|
||||
"folder_dataset": "資料夾",
|
||||
"image_auto_parse": "圖片自動索引",
|
||||
"image_auto_parse_tips": "調用 VLM 自動標註文檔裡的圖片,並生成額外的檢索索引",
|
||||
"image_auto_parse_tips": "呼叫 VLM 自動標註文件裡的圖片,並生成額外的檢索索引",
|
||||
"image_training_queue": "圖片處理排隊",
|
||||
"immediate_sync": "立即同步",
|
||||
"import.Auto mode Estimated Price Tips": "需呼叫文字理解模型,將消耗較多 AI 點數:{{price}} 點數 / 1K tokens",
|
||||
"import.Embedding Estimated Price Tips": "僅使用索引模型,消耗少量 AI 點數:{{price}} 點數 / 1K tokens",
|
||||
"import_confirm": "確認上傳",
|
||||
"import_data_preview": "數據預覽",
|
||||
"import_data_process_setting": "數據處理方式設置",
|
||||
"import_file_parse_setting": "文件解析設置",
|
||||
"import_data_preview": "資料預覽",
|
||||
"import_data_process_setting": "資料處理方式設定",
|
||||
"import_file_parse_setting": "文件解析設定",
|
||||
"import_model_config": "模型選擇",
|
||||
"import_param_setting": "參數設置",
|
||||
"import_param_setting": "參數設定",
|
||||
"import_select_file": "選擇文件",
|
||||
"import_select_link": "輸入鏈接",
|
||||
"import_select_link": "輸入連結",
|
||||
"index_size": "索引大小",
|
||||
"index_size_tips": "向量化時內容的長度,系統會自動按該大小對分塊進行進一步的分割。",
|
||||
"is_open_schedule": "啟用定時同步",
|
||||
"keep_image": "保留圖片",
|
||||
"move.hint": "移動後,所選資料集/資料夾將繼承新資料夾的權限設定,原先的權限設定將失效。",
|
||||
"open_auto_sync": "開啟定時同步後,系統將每天不定時嘗試同步集合,集合同步期間,會出現無法搜尋到該集合資料現象。",
|
||||
"params_config": "配置",
|
||||
"params_setting": "參數設置",
|
||||
"pdf_enhance_parse": "PDF增強解析",
|
||||
"params_config": "設定",
|
||||
"params_setting": "參數設定",
|
||||
"pdf_enhance_parse": "PDF 增強解析",
|
||||
"pdf_enhance_parse_price": "{{price}}積分/頁",
|
||||
"pdf_enhance_parse_tips": "調用 PDF 識別模型進行解析,可以將其轉換成 Markdown 並保留文檔中的圖片,同時也可以對掃描件進行識別,識別時間較長。",
|
||||
"pdf_enhance_parse_tips": "呼叫 PDF 識別模型進行解析,可以將其轉換成 Markdown 並保留文件中的圖片,同時也可以對掃描件進行識別,識別時間較長。",
|
||||
"permission.des.manage": "可管理整個資料集的資料和資訊",
|
||||
"permission.des.read": "可檢視資料集內容",
|
||||
"permission.des.write": "可新增和變更資料集內容",
|
||||
"preview_chunk": "分塊預覽",
|
||||
"preview_chunk_empty": "文件內容為空",
|
||||
"preview_chunk_intro": "共 {{total}} 個分塊,最多展示 10 個",
|
||||
"preview_chunk_not_selected": "點擊左側文件後進行預覽",
|
||||
"preview_chunk_not_selected": "點選左側文件後進行預覽",
|
||||
"process.Auto_Index": "自動索引生成",
|
||||
"process.Get QA": "問答對提取",
|
||||
"process.Image_Index": "圖片索引生成",
|
||||
@@ -119,13 +119,13 @@
|
||||
"split_sign_break2": "2 個換行符",
|
||||
"split_sign_custom": "自定義",
|
||||
"split_sign_exclamatiob": "驚嘆號",
|
||||
"split_sign_null": "不設置",
|
||||
"split_sign_null": "不設定",
|
||||
"split_sign_period": "句號",
|
||||
"split_sign_question": "問號",
|
||||
"split_sign_semicolon": "分號",
|
||||
"start_sync_website_tip": "確認開始同步資料?\n將會刪除舊資料後重新獲取,請確認!",
|
||||
"status_error": "運行異常",
|
||||
"sync_collection_failed": "同步集合錯誤,請檢查是否能正常存取來源文件",
|
||||
"start_sync_website_tip": "確認開始同步資料?\n將會刪除舊資料後重新取得,請確認!",
|
||||
"status_error": "執行異常",
|
||||
"sync_collection_failed": "同步集合錯誤,請檢查是否能正常存取來原始檔",
|
||||
"sync_schedule": "定時同步",
|
||||
"sync_schedule_tip": "只會同步已存在的集合。\n包括連結集合以及 API 知識庫裡所有集合。\n系統會每天進行輪詢更新,無法確定特定的更新時間。",
|
||||
"tag.Add New": "新增",
|
||||
@@ -144,12 +144,12 @@
|
||||
"training.Normal": "正常",
|
||||
"training_mode": "分段模式",
|
||||
"training_ready": "{{count}} 組",
|
||||
"vector_model_max_tokens_tip": "每個分塊數據,最大長度為 3000 tokens",
|
||||
"vector_model_max_tokens_tip": "每個分塊資料,最大長度為 3000 tokens",
|
||||
"vllm_model": "圖片理解模型",
|
||||
"website_dataset": "網站同步",
|
||||
"website_dataset_desc": "網站同步功能讓您可以直接使用網頁連結建立資料集",
|
||||
"website_info": "網站資訊",
|
||||
"yuque_dataset": "語雀知識庫",
|
||||
"yuque_dataset_config": "配置語雀知識庫",
|
||||
"yuque_dataset_desc": "可通過配置語雀文檔權限,使用語雀文檔構建知識庫,文檔不會進行二次存儲"
|
||||
"yuque_dataset_config": "設定語雀知識庫",
|
||||
"yuque_dataset_desc": "可透過設定語雀文件權限,使用語雀文件建構知識庫,文件不會進行二次儲存"
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"login_success": "登入成功",
|
||||
"no_remind": "不再提醒",
|
||||
"password_condition": "密碼最多 60 個字元",
|
||||
"password_tip": "密碼至少 6 位,且至少包含兩種組合:數字、字母或特殊字符",
|
||||
"password_tip": "密碼至少 6 位,且至少包含兩種組合:數字、字母或特殊字元",
|
||||
"policy_tip": "使用即代表您同意我們的",
|
||||
"privacy": "隱私權政策",
|
||||
"privacy_policy": "隱私權政策",
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
"permission.only_collaborators": "僅協作者可存取",
|
||||
"permission.team_read": "團隊可存取",
|
||||
"permission.team_write": "團隊可編輯",
|
||||
"permission_add_tip": "添加後,您可為其勾選權限。",
|
||||
"permission_add_tip": "新增後,您可為其勾選權限。",
|
||||
"permission_des.manage": "可建立資源、邀請及刪除成員",
|
||||
"permission_des.read": "成員僅能閱讀相關資源,無法建立新資源",
|
||||
"permission_des.write": "除了可讀取資源外,還可以建立新的資源",
|
||||
@@ -75,7 +75,7 @@
|
||||
"synchronization.title": "填寫標籤同步連結,點選同步按鈕即可同步",
|
||||
"team.Add manager": "新增管理員",
|
||||
"team.Confirm Invite": "確認邀請",
|
||||
"team.Create Team": "創建新團隊",
|
||||
"team.Create Team": "建立新團隊",
|
||||
"team.Invite Member Failed Tip": "邀請成員出現異常",
|
||||
"team.Invite Member Result Tip": "邀請結果提示",
|
||||
"team.Invite Member Success Tip": "邀請成員完成\n\n成功:{{success}} 人\n\n使用者名稱無效:{{inValid}}\n\n已在團隊中:{{inTeam}}",
|
||||
@@ -97,10 +97,9 @@
|
||||
"team.group.group": "群組",
|
||||
"team.group.keep_admin": "保留管理員權限",
|
||||
"team.group.manage_member": "管理成員",
|
||||
"team.group.manage_tip": "可以管理成員、創建群組、管理所有群組、為群組和成員分配權限",
|
||||
"team.group.manage_tip": "可以管理成員、建立群組、管理所有群組、為群組和成員分配權限",
|
||||
"team.group.members": "成員",
|
||||
"team.group.name": "群組名稱",
|
||||
"team.group.permission.manage": "管理員",
|
||||
"team.group.permission.write": "工作臺/知識庫建立",
|
||||
"team.group.permission_tip": "單獨設定權限的成員,將依照個人權限設定,不再受群組權限影響。\n若成員屬於多個權限群組,該成員的權限將會合併。",
|
||||
"team.group.role.admin": "管理員",
|
||||
@@ -112,5 +111,6 @@
|
||||
"team.manage_collaborators": "管理協作者",
|
||||
"team.no_collaborators": "目前沒有協作者",
|
||||
"team.org.org": "組織",
|
||||
"team.write_role_member": "可寫入權限"
|
||||
"team.write_role_member": "可寫入權限",
|
||||
"team.collaborator.added": "已新增"
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
"application_call": "應用程式呼叫",
|
||||
"assigned_reply": "指定回覆",
|
||||
"auth_tmb_id": "使用者鑑權",
|
||||
"auth_tmb_id_tip": "開啟後,對外發布應用程式時,也會根據使用者是否有該知識庫權限進行知識庫過濾。\n\n若未開啟,則直接按配置的知識庫進行檢索,不進行權限過濾。",
|
||||
"auth_tmb_id_tip": "開啟後,對外發布應用程式時,也會根據使用者是否有該知識庫權限進行知識庫過濾。\n\n若未開啟,則直接按設定的知識庫進行檢索,不進行權限過濾。",
|
||||
"can_not_loop": "這個節點不能迴圈。",
|
||||
"choose_another_application_to_call": "選擇另一個應用程式來呼叫",
|
||||
"classification_result": "分類結果",
|
||||
"code.Reset template": "重設範本",
|
||||
"code.Reset template confirm": "確定要重設程式碼範本嗎?這將會把所有輸入和輸出重設為範本值。請儲存您目前的程式碼。",
|
||||
"code.Switch language confirm": "切換語言將重置代碼,是否繼續?",
|
||||
"code.Switch language confirm": "切換語言將重設代碼,是否繼續?",
|
||||
"code_execution": "程式碼執行",
|
||||
"collection_metadata_filter": "資料集詮釋資料篩選器",
|
||||
"complete_extraction_result": "完整擷取結果",
|
||||
@@ -52,7 +52,7 @@
|
||||
"execution_error": "執行錯誤",
|
||||
"extraction_requirements_description": "擷取需求描述",
|
||||
"extraction_requirements_description_detail": "提供 AI 相對應的背景知識或需求描述,引導 AI 更好地完成任務。\\n這個輸入框可以使用全域變數。",
|
||||
"extraction_requirements_placeholder": "例如: 1. 目前時間為: {{cTime}}。\n你是實驗室預約助手,你的任務是幫助使用者預約實驗室,從文字中取得對應的預約資訊。\n\n2. 你是Google搜尋助手,需要從文字中提取出合適的搜尋字詞。",
|
||||
"extraction_requirements_placeholder": "例如:1. 目前時間為:{{cTime}}。\n你是實驗室預約助手,你的任務是幫助使用者預約實驗室,從文字中取得對應的預約資訊。\n\n2. 你是 Google 搜尋助手,需要從文字中提取出合適的搜尋字詞。",
|
||||
"feedback_text": "回饋文字",
|
||||
"field_description": "欄位描述",
|
||||
"field_description_placeholder": "描述這個輸入欄位的功能,如果是工具呼叫參數,這個描述會影響模型產生的品質",
|
||||
@@ -84,7 +84,7 @@
|
||||
"intro_http_request": "可以傳送 HTTP 請求,執行更複雜的操作(網路搜尋、資料庫查詢等等)",
|
||||
"intro_knowledge_base_search_merge": "可以合併多個知識庫搜尋結果並輸出。使用 RRF 合併方法進行最終排序輸出。",
|
||||
"intro_laf_function_call": "可以呼叫 Laf 帳號下的雲端函式。",
|
||||
"intro_loop": "輸入一個數組,遍歷數組並將每個數組元素作為輸入元素,執行工作流程。",
|
||||
"intro_loop": "輸入一個陣列,遍歷陣列並將每個陣列元素作為輸入元素,執行工作流程。",
|
||||
"intro_plugin_input": "可以設定外掛程式需要的輸入,並利用這些輸入來執行外掛程式",
|
||||
"intro_question_classification": "根據使用者的歷史紀錄和目前問題判斷這次提問的類型。可以新增多個問題類型,以下是一個範例:\n類型 1:打招呼\n類型 2:關於產品「使用方式」的問題\n類型 3:關於產品「購買」的問題\n類型 4:其他問題",
|
||||
"intro_question_optimization": "使用問題最佳化功能,可以提升知識庫連續對話時的搜尋精準度。使用這個功能後,會先利用 AI 根據脈絡建構一個或多個新的檢索詞彙,這些詞彙更有利於知識庫搜尋。這個模組已內建於知識庫搜尋模組中,如果您只進行一次知識庫搜尋,可以直接使用知識庫內建的自動完成功能。",
|
||||
@@ -134,7 +134,7 @@
|
||||
"question_classification": "問題分類",
|
||||
"question_optimization": "問題最佳化",
|
||||
"quote_content_placeholder": "可以自訂引用內容的結構,以便更好地適應不同場景。可以使用一些變數來設定範本\n{{q}} - 主要內容\n{{a}} - 輔助資料\n{{source}} - 來源名稱\n{{sourceId}} - 來源 ID\n{{index}} - 第 n 個引用",
|
||||
"quote_content_tip": "可以自訂引用內容的結構,以更好的適合不同場景。\n可以使用一些變數來進行模板配置\n\n{{id}} - 引用資料唯一id\n\n{{q}} - 主要內容\n\n{{a}} - 輔助數據\n\n{{source}} - 來源名\n\n{{sourceId}} - 來源ID\n\n{{index}} - 第 n 個引用\n\n他們都是可選的,下面是預設值:\n\n{{default}}",
|
||||
"quote_content_tip": "可以自訂引用內容的結構,以更好的適合不同場景。\n可以使用一些變數來進行範本設定\n\n{{id}} - 引用資料唯一 id\n\n{{q}} - 主要內容\n\n{{a}} - 輔助資料\n\n{{source}} - 來源名\n\n{{sourceId}} - 來源 ID\n\n{{index}} - 第 n 個引用\n\n他們都是可選的,下面是預設值:\n\n{{default}}",
|
||||
"quote_num": "引用數量",
|
||||
"quote_prompt_tip": "可以使用 {{quote}} 來插入引用內容範本,使用 {{question}} 來插入問題(Role=user)。\n以下是預設值:\n{{default}}",
|
||||
"quote_role_system_tip": "請注意從「引用範本提示詞」中移除 {{question}} 變數",
|
||||
@@ -154,7 +154,7 @@
|
||||
"select_another_application_to_call": "可以選擇另一個應用程式來呼叫",
|
||||
"special_array_format": "特殊陣列格式,搜尋結果為空時,回傳空陣列。",
|
||||
"start_with": "開頭為",
|
||||
"support_code_language": "支持import列表:pandas,numpy",
|
||||
"support_code_language": "支援 import 列表:pandas,numpy",
|
||||
"target_fields_description": "由「描述」和「鍵值」組成一個目標欄位,可以擷取多個目標欄位",
|
||||
"template.ai_chat": "AI 對話",
|
||||
"template.ai_chat_intro": "AI 大型語言模型對話",
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
diff --git a/lib/index.js b/lib/index.js
|
||||
index c5ca771c24dd914e342f791716a822431ee32b3a..457d9f8c4625f7d9c7ea1e9ffc13616db1fc6fef 100644
|
||||
--- a/lib/index.js
|
||||
+++ b/lib/index.js
|
||||
@@ -126,8 +126,37 @@ function exitLiteralAutolink(token) {
|
||||
this.exit(token)
|
||||
}
|
||||
|
||||
-/** @type {FromMarkdownTransform} */
|
||||
+// Regex support detector, for backward compatibility
|
||||
+// Ref: https://github.com/syntax-tree/mdast-util-gfm-autolink-literal/pull/14
|
||||
+const regexSupport = {
|
||||
+ lookbehind: (() => {
|
||||
+ try {
|
||||
+ // Using regex literal instead of RegExp constructor
|
||||
+ ;/(?<=x)/.test('x')
|
||||
+ return true
|
||||
+ } catch {
|
||||
+ return false
|
||||
+ }
|
||||
+ })()
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Main transform function that uses the appropriate version based on regex support
|
||||
+ * @type {FromMarkdownTransform}
|
||||
+ */
|
||||
function transformGfmAutolinkLiterals(tree) {
|
||||
+ if (regexSupport.lookbehind) {
|
||||
+ modernAutolinkTransform(tree)
|
||||
+ } else {
|
||||
+ legacyAutolinkTransform(tree)
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Modern version of autolink transform using lookbehind
|
||||
+ * @type {FromMarkdownTransform}
|
||||
+ */
|
||||
+function modernAutolinkTransform(tree) {
|
||||
findAndReplace(
|
||||
tree,
|
||||
[
|
||||
@@ -138,6 +167,35 @@ function transformGfmAutolinkLiterals(tree) {
|
||||
)
|
||||
}
|
||||
|
||||
+
|
||||
+/**
|
||||
+ * Legacy version of autolink transform for older Node.js versions
|
||||
+ * @type {FromMarkdownTransform}
|
||||
+ */
|
||||
+function legacyAutolinkTransform(tree) {
|
||||
+ findAndReplace(
|
||||
+ tree,
|
||||
+ [
|
||||
+ [/(https?:\/\/|www(?=\.))([-.\w]+)([^ \t\r\n]*)/gi, findUrl],
|
||||
+ // [/([-.\w+]+)@([-\w]+(?:\.[-\w]+)+)/g, findEmail] # NOTE: original regex in 2.0.0
|
||||
+ [/(^|\s|\p{P}|\p{S})([-.\w+]+)@([-\w]+(?:\.[-\w]+)+)/gu, findEmailLegacy]
|
||||
+ ],
|
||||
+ {ignore: ['link', 'linkReference']}
|
||||
+ )
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Helper function for legacy email matching
|
||||
+ * @param {string} _ - Unused parameter
|
||||
+ * @param {string} prefix - Email prefix
|
||||
+ * @param {string} name - Email name
|
||||
+ * @param {string} domain - Email domain
|
||||
+ * @returns {*} The processed email
|
||||
+ */
|
||||
+function findEmailLegacy(_, prefix, name, domain) {
|
||||
+ return findEmail(name + '@' + domain)
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* @type {ReplaceFunction}
|
||||
* @param {string} _
|
||||
233
pnpm-lock.yaml
generated
233
pnpm-lock.yaml
generated
@@ -4,10 +4,8 @@ settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
patchedDependencies:
|
||||
mdast-util-gfm-autolink-literal@2.0.1:
|
||||
hash: f63d515781110436299ab612306211a9621c6dfaec1ce1a19e2f27454dc70251
|
||||
path: patches/mdast-util-gfm-autolink-literal@2.0.1.patch
|
||||
overrides:
|
||||
mdast-util-gfm-autolink-literal: 2.0.0
|
||||
|
||||
importers:
|
||||
|
||||
@@ -17,8 +15,8 @@ importers:
|
||||
specifier: ^2.4.1
|
||||
version: 2.5.8(encoding@0.1.13)(react@18.3.1)
|
||||
'@vitest/coverage-v8':
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.8(vitest@3.0.8(@types/debug@4.1.12)(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0))
|
||||
specifier: ^3.0.9
|
||||
version: 3.1.1(vitest@3.1.1(@types/debug@4.1.12)(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0))
|
||||
husky:
|
||||
specifier: ^8.0.3
|
||||
version: 8.0.3
|
||||
@@ -28,9 +26,12 @@ importers:
|
||||
lint-staged:
|
||||
specifier: ^13.3.0
|
||||
version: 13.3.0
|
||||
mongodb-memory-server:
|
||||
specifier: ^10.1.4
|
||||
version: 10.1.4(socks@2.8.4)
|
||||
next-i18next:
|
||||
specifier: 15.4.2
|
||||
version: 15.4.2(i18next@23.16.8)(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
version: 15.4.2(i18next@23.16.8)(next@14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
prettier:
|
||||
specifier: 3.2.4
|
||||
version: 3.2.4
|
||||
@@ -38,11 +39,8 @@ importers:
|
||||
specifier: 14.1.2
|
||||
version: 14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
vitest:
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.8(@types/debug@4.1.12)(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0)
|
||||
vitest-mongodb:
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1(socks@2.8.4)
|
||||
specifier: ^3.0.9
|
||||
version: 3.1.1(@types/debug@4.1.12)(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0)
|
||||
zhlint:
|
||||
specifier: ^0.7.4
|
||||
version: 0.7.4(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0)(typescript@5.8.2)
|
||||
@@ -327,7 +325,7 @@ importers:
|
||||
version: 2.1.1(@chakra-ui/system@2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
'@chakra-ui/next-js':
|
||||
specifier: 2.4.2
|
||||
version: 2.4.2(@chakra-ui/react@2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react@18.3.1)
|
||||
version: 2.4.2(@chakra-ui/react@2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react@18.3.1)
|
||||
'@chakra-ui/react':
|
||||
specifier: 2.10.7
|
||||
version: 2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -390,7 +388,7 @@ importers:
|
||||
version: 4.17.21
|
||||
next-i18next:
|
||||
specifier: 15.4.2
|
||||
version: 15.4.2(i18next@23.16.8)(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
version: 15.4.2(i18next@23.16.8)(next@14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
papaparse:
|
||||
specifier: ^5.4.1
|
||||
version: 5.4.1
|
||||
@@ -451,7 +449,7 @@ importers:
|
||||
version: 2.1.1(@chakra-ui/system@2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
'@chakra-ui/next-js':
|
||||
specifier: 2.4.2
|
||||
version: 2.4.2(@chakra-ui/react@2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react@18.3.1)
|
||||
version: 2.4.2(@chakra-ui/react@2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react@18.3.1)
|
||||
'@chakra-ui/react':
|
||||
specifier: 2.10.7
|
||||
version: 2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -550,7 +548,7 @@ importers:
|
||||
version: 14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1)
|
||||
next-i18next:
|
||||
specifier: 15.4.2
|
||||
version: 15.4.2(i18next@23.16.8)(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
version: 15.4.2(i18next@23.16.8)(next@14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
nprogress:
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0
|
||||
@@ -3565,11 +3563,11 @@ packages:
|
||||
'@ungap/structured-clone@1.3.0':
|
||||
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
|
||||
|
||||
'@vitest/coverage-v8@3.0.8':
|
||||
resolution: {integrity: sha512-y7SAKsQirsEJ2F8bulBck4DoluhI2EEgTimHd6EEUgJBGKy9tC25cpywh1MH4FvDGoG2Unt7+asVd1kj4qOSAw==}
|
||||
'@vitest/coverage-v8@3.1.1':
|
||||
resolution: {integrity: sha512-MgV6D2dhpD6Hp/uroUoAIvFqA8AuvXEFBC2eepG3WFc1pxTfdk1LEqqkWoWhjz+rytoqrnUUCdf6Lzco3iHkLQ==}
|
||||
peerDependencies:
|
||||
'@vitest/browser': 3.0.8
|
||||
vitest: 3.0.8
|
||||
'@vitest/browser': 3.1.1
|
||||
vitest: 3.1.1
|
||||
peerDependenciesMeta:
|
||||
'@vitest/browser':
|
||||
optional: true
|
||||
@@ -3580,6 +3578,9 @@ packages:
|
||||
'@vitest/expect@3.0.8':
|
||||
resolution: {integrity: sha512-Xu6TTIavTvSSS6LZaA3EebWFr6tsoXPetOWNMOlc7LO88QVVBwq2oQWBoDiLCN6YTvNYsGSjqOO8CAdjom5DCQ==}
|
||||
|
||||
'@vitest/expect@3.1.1':
|
||||
resolution: {integrity: sha512-q/zjrW9lgynctNbwvFtQkGK9+vvHA5UzVi2V8APrp1C6fG6/MuYYkmlx4FubuqLycCeSdHD5aadWfua/Vr0EUA==}
|
||||
|
||||
'@vitest/mocker@3.0.8':
|
||||
resolution: {integrity: sha512-n3LjS7fcW1BCoF+zWZxG7/5XvuYH+lsFg+BDwwAz0arIwHQJFUEsKBQ0BLU49fCxuM/2HSeBPHQD8WjgrxMfow==}
|
||||
peerDependencies:
|
||||
@@ -3591,33 +3592,59 @@ packages:
|
||||
vite:
|
||||
optional: true
|
||||
|
||||
'@vitest/mocker@3.1.1':
|
||||
resolution: {integrity: sha512-bmpJJm7Y7i9BBELlLuuM1J1Q6EQ6K5Ye4wcyOpOMXMcePYKSIYlpcrCm4l/O6ja4VJA5G2aMJiuZkZdnxlC3SA==}
|
||||
peerDependencies:
|
||||
msw: ^2.4.9
|
||||
vite: ^5.0.0 || ^6.0.0
|
||||
peerDependenciesMeta:
|
||||
msw:
|
||||
optional: true
|
||||
vite:
|
||||
optional: true
|
||||
|
||||
'@vitest/pretty-format@3.0.8':
|
||||
resolution: {integrity: sha512-BNqwbEyitFhzYMYHUVbIvepOyeQOSFA/NeJMIP9enMntkkxLgOcgABH6fjyXG85ipTgvero6noreavGIqfJcIg==}
|
||||
|
||||
'@vitest/pretty-format@3.1.1':
|
||||
resolution: {integrity: sha512-dg0CIzNx+hMMYfNmSqJlLSXEmnNhMswcn3sXO7Tpldr0LiGmg3eXdLLhwkv2ZqgHb/d5xg5F7ezNFRA1fA13yA==}
|
||||
|
||||
'@vitest/runner@1.6.1':
|
||||
resolution: {integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==}
|
||||
|
||||
'@vitest/runner@3.0.8':
|
||||
resolution: {integrity: sha512-c7UUw6gEcOzI8fih+uaAXS5DwjlBaCJUo7KJ4VvJcjL95+DSR1kova2hFuRt3w41KZEFcOEiq098KkyrjXeM5w==}
|
||||
|
||||
'@vitest/runner@3.1.1':
|
||||
resolution: {integrity: sha512-X/d46qzJuEDO8ueyjtKfxffiXraPRfmYasoC4i5+mlLEJ10UvPb0XH5M9C3gWuxd7BAQhpK42cJgJtq53YnWVA==}
|
||||
|
||||
'@vitest/snapshot@1.6.1':
|
||||
resolution: {integrity: sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==}
|
||||
|
||||
'@vitest/snapshot@3.0.8':
|
||||
resolution: {integrity: sha512-x8IlMGSEMugakInj44nUrLSILh/zy1f2/BgH0UeHpNyOocG18M9CWVIFBaXPt8TrqVZWmcPjwfG/ht5tnpba8A==}
|
||||
|
||||
'@vitest/snapshot@3.1.1':
|
||||
resolution: {integrity: sha512-bByMwaVWe/+1WDf9exFxWWgAixelSdiwo2p33tpqIlM14vW7PRV5ppayVXtfycqze4Qhtwag5sVhX400MLBOOw==}
|
||||
|
||||
'@vitest/spy@1.6.1':
|
||||
resolution: {integrity: sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==}
|
||||
|
||||
'@vitest/spy@3.0.8':
|
||||
resolution: {integrity: sha512-MR+PzJa+22vFKYb934CejhR4BeRpMSoxkvNoDit68GQxRLSf11aT6CTj3XaqUU9rxgWJFnqicN/wxw6yBRkI1Q==}
|
||||
|
||||
'@vitest/spy@3.1.1':
|
||||
resolution: {integrity: sha512-+EmrUOOXbKzLkTDwlsc/xrwOlPDXyVk3Z6P6K4oiCndxz7YLpp/0R0UsWVOKT0IXWjjBJuSMk6D27qipaupcvQ==}
|
||||
|
||||
'@vitest/utils@1.6.1':
|
||||
resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==}
|
||||
|
||||
'@vitest/utils@3.0.8':
|
||||
resolution: {integrity: sha512-nkBC3aEhfX2PdtQI/QwAWp8qZWwzASsU4Npbcd5RdMPBSSLCpkZp52P3xku3s3uA0HIEhGvEcF8rNkBsz9dQ4Q==}
|
||||
|
||||
'@vitest/utils@3.1.1':
|
||||
resolution: {integrity: sha512-1XIjflyaU2k3HMArJ50bwSh3wKWPD6Q47wz/NUSmRV0zNywPc4w79ARjg/i/aNINHwA+mIALhUVqD9/aUvZNgg==}
|
||||
|
||||
'@vue/compiler-core@3.5.13':
|
||||
resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==}
|
||||
|
||||
@@ -6783,8 +6810,8 @@ packages:
|
||||
mdast-util-from-markdown@2.0.2:
|
||||
resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==}
|
||||
|
||||
mdast-util-gfm-autolink-literal@2.0.1:
|
||||
resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==}
|
||||
mdast-util-gfm-autolink-literal@2.0.0:
|
||||
resolution: {integrity: sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==}
|
||||
|
||||
mdast-util-gfm-footnote@2.1.0:
|
||||
resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==}
|
||||
@@ -9330,6 +9357,11 @@ packages:
|
||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||
hasBin: true
|
||||
|
||||
vite-node@3.1.1:
|
||||
resolution: {integrity: sha512-V+IxPAE2FvXpTCHXyNem0M+gWm6J7eRyWPR6vYoG/Gl+IscNOjXzztUhimQgTxaAoUoj40Qqimaa0NLIOOAH4w==}
|
||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||
hasBin: true
|
||||
|
||||
vite@5.4.14:
|
||||
resolution: {integrity: sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
@@ -9401,9 +9433,6 @@ packages:
|
||||
yaml:
|
||||
optional: true
|
||||
|
||||
vitest-mongodb@1.0.1:
|
||||
resolution: {integrity: sha512-a9Mc2F35h8qxI1uOgsrCUH28TglClAd8gdXkn7CBqmC6bLr6D2Ibyxp0Xz6/AU0ukAOfuf/6oqUS+ZN0VlxVyQ==}
|
||||
|
||||
vitest@1.6.1:
|
||||
resolution: {integrity: sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
@@ -9457,6 +9486,34 @@ packages:
|
||||
jsdom:
|
||||
optional: true
|
||||
|
||||
vitest@3.1.1:
|
||||
resolution: {integrity: sha512-kiZc/IYmKICeBAZr9DQ5rT7/6bD9G7uqQEki4fxazi1jdVl2mWGzedtBs5s6llz59yQhVb7FFY2MbHzHCnT79Q==}
|
||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@edge-runtime/vm': '*'
|
||||
'@types/debug': ^4.1.12
|
||||
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
|
||||
'@vitest/browser': 3.1.1
|
||||
'@vitest/ui': 3.1.1
|
||||
happy-dom: '*'
|
||||
jsdom: '*'
|
||||
peerDependenciesMeta:
|
||||
'@edge-runtime/vm':
|
||||
optional: true
|
||||
'@types/debug':
|
||||
optional: true
|
||||
'@types/node':
|
||||
optional: true
|
||||
'@vitest/browser':
|
||||
optional: true
|
||||
'@vitest/ui':
|
||||
optional: true
|
||||
happy-dom:
|
||||
optional: true
|
||||
jsdom:
|
||||
optional: true
|
||||
|
||||
void-elements@3.1.0:
|
||||
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -10740,7 +10797,7 @@ snapshots:
|
||||
'@chakra-ui/system': 2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
|
||||
'@chakra-ui/next-js@2.4.2(@chakra-ui/react@2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react@18.3.1)':
|
||||
'@chakra-ui/next-js@2.4.2(@chakra-ui/react@2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@chakra-ui/react': 2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@emotion/cache': 11.14.0
|
||||
@@ -12846,7 +12903,7 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.3.0': {}
|
||||
|
||||
'@vitest/coverage-v8@3.0.8(vitest@3.0.8(@types/debug@4.1.12)(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0))':
|
||||
'@vitest/coverage-v8@3.1.1(vitest@3.1.1(@types/debug@4.1.12)(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0))':
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.3.0
|
||||
'@bcoe/v8-coverage': 1.0.2
|
||||
@@ -12860,7 +12917,7 @@ snapshots:
|
||||
std-env: 3.8.1
|
||||
test-exclude: 7.0.1
|
||||
tinyrainbow: 2.0.0
|
||||
vitest: 3.0.8(@types/debug@4.1.12)(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0)
|
||||
vitest: 3.1.1(@types/debug@4.1.12)(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -12877,6 +12934,13 @@ snapshots:
|
||||
chai: 5.2.0
|
||||
tinyrainbow: 2.0.0
|
||||
|
||||
'@vitest/expect@3.1.1':
|
||||
dependencies:
|
||||
'@vitest/spy': 3.1.1
|
||||
'@vitest/utils': 3.1.1
|
||||
chai: 5.2.0
|
||||
tinyrainbow: 2.0.0
|
||||
|
||||
'@vitest/mocker@3.0.8(vite@6.2.2(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0))':
|
||||
dependencies:
|
||||
'@vitest/spy': 3.0.8
|
||||
@@ -12885,10 +12949,22 @@ snapshots:
|
||||
optionalDependencies:
|
||||
vite: 6.2.2(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0)
|
||||
|
||||
'@vitest/mocker@3.1.1(vite@6.2.2(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0))':
|
||||
dependencies:
|
||||
'@vitest/spy': 3.1.1
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.17
|
||||
optionalDependencies:
|
||||
vite: 6.2.2(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0)
|
||||
|
||||
'@vitest/pretty-format@3.0.8':
|
||||
dependencies:
|
||||
tinyrainbow: 2.0.0
|
||||
|
||||
'@vitest/pretty-format@3.1.1':
|
||||
dependencies:
|
||||
tinyrainbow: 2.0.0
|
||||
|
||||
'@vitest/runner@1.6.1':
|
||||
dependencies:
|
||||
'@vitest/utils': 1.6.1
|
||||
@@ -12900,6 +12976,11 @@ snapshots:
|
||||
'@vitest/utils': 3.0.8
|
||||
pathe: 2.0.3
|
||||
|
||||
'@vitest/runner@3.1.1':
|
||||
dependencies:
|
||||
'@vitest/utils': 3.1.1
|
||||
pathe: 2.0.3
|
||||
|
||||
'@vitest/snapshot@1.6.1':
|
||||
dependencies:
|
||||
magic-string: 0.30.17
|
||||
@@ -12912,6 +12993,12 @@ snapshots:
|
||||
magic-string: 0.30.17
|
||||
pathe: 2.0.3
|
||||
|
||||
'@vitest/snapshot@3.1.1':
|
||||
dependencies:
|
||||
'@vitest/pretty-format': 3.1.1
|
||||
magic-string: 0.30.17
|
||||
pathe: 2.0.3
|
||||
|
||||
'@vitest/spy@1.6.1':
|
||||
dependencies:
|
||||
tinyspy: 2.2.1
|
||||
@@ -12920,6 +13007,10 @@ snapshots:
|
||||
dependencies:
|
||||
tinyspy: 3.0.2
|
||||
|
||||
'@vitest/spy@3.1.1':
|
||||
dependencies:
|
||||
tinyspy: 3.0.2
|
||||
|
||||
'@vitest/utils@1.6.1':
|
||||
dependencies:
|
||||
diff-sequences: 29.6.3
|
||||
@@ -12933,6 +13024,12 @@ snapshots:
|
||||
loupe: 3.1.3
|
||||
tinyrainbow: 2.0.0
|
||||
|
||||
'@vitest/utils@3.1.1':
|
||||
dependencies:
|
||||
'@vitest/pretty-format': 3.1.1
|
||||
loupe: 3.1.3
|
||||
tinyrainbow: 2.0.0
|
||||
|
||||
'@vue/compiler-core@3.5.13':
|
||||
dependencies:
|
||||
'@babel/parser': 7.26.10
|
||||
@@ -16842,7 +16939,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-gfm-autolink-literal@2.0.1(patch_hash=f63d515781110436299ab612306211a9621c6dfaec1ce1a19e2f27454dc70251):
|
||||
mdast-util-gfm-autolink-literal@2.0.0:
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
ccount: 2.0.1
|
||||
@@ -16890,7 +16987,7 @@ snapshots:
|
||||
mdast-util-gfm@3.1.0:
|
||||
dependencies:
|
||||
mdast-util-from-markdown: 2.0.2
|
||||
mdast-util-gfm-autolink-literal: 2.0.1(patch_hash=f63d515781110436299ab612306211a9621c6dfaec1ce1a19e2f27454dc70251)
|
||||
mdast-util-gfm-autolink-literal: 2.0.0
|
||||
mdast-util-gfm-footnote: 2.1.0
|
||||
mdast-util-gfm-strikethrough: 2.0.0
|
||||
mdast-util-gfm-table: 2.0.0
|
||||
@@ -17647,7 +17744,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
next-i18next@15.4.2(i18next@23.16.8)(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1):
|
||||
next-i18next@15.4.2(i18next@23.16.8)(next@14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.10
|
||||
'@types/hoist-non-react-statics': 3.3.6
|
||||
@@ -19984,6 +20081,27 @@ snapshots:
|
||||
- tsx
|
||||
- yaml
|
||||
|
||||
vite-node@3.1.1(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.4.0
|
||||
es-module-lexer: 1.6.0
|
||||
pathe: 2.0.3
|
||||
vite: 6.2.2(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- jiti
|
||||
- less
|
||||
- lightningcss
|
||||
- sass
|
||||
- sass-embedded
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
- tsx
|
||||
- yaml
|
||||
|
||||
vite@5.4.14(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0):
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
@@ -20006,20 +20124,6 @@ snapshots:
|
||||
sass: 1.85.1
|
||||
terser: 5.39.0
|
||||
|
||||
vitest-mongodb@1.0.1(socks@2.8.4):
|
||||
dependencies:
|
||||
debug: 4.4.0
|
||||
mongodb-memory-server: 10.1.4(socks@2.8.4)
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/credential-providers'
|
||||
- '@mongodb-js/zstd'
|
||||
- gcp-metadata
|
||||
- kerberos
|
||||
- mongodb-client-encryption
|
||||
- snappy
|
||||
- socks
|
||||
- supports-color
|
||||
|
||||
vitest@1.6.1(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0):
|
||||
dependencies:
|
||||
'@vitest/expect': 1.6.1
|
||||
@@ -20093,6 +20197,45 @@ snapshots:
|
||||
- tsx
|
||||
- yaml
|
||||
|
||||
vitest@3.1.1(@types/debug@4.1.12)(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0):
|
||||
dependencies:
|
||||
'@vitest/expect': 3.1.1
|
||||
'@vitest/mocker': 3.1.1(vite@6.2.2(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0))
|
||||
'@vitest/pretty-format': 3.1.1
|
||||
'@vitest/runner': 3.1.1
|
||||
'@vitest/snapshot': 3.1.1
|
||||
'@vitest/spy': 3.1.1
|
||||
'@vitest/utils': 3.1.1
|
||||
chai: 5.2.0
|
||||
debug: 4.4.0
|
||||
expect-type: 1.2.0
|
||||
magic-string: 0.30.17
|
||||
pathe: 2.0.3
|
||||
std-env: 3.8.1
|
||||
tinybench: 2.9.0
|
||||
tinyexec: 0.3.2
|
||||
tinypool: 1.0.2
|
||||
tinyrainbow: 2.0.0
|
||||
vite: 6.2.2(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0)
|
||||
vite-node: 3.1.1(@types/node@20.17.24)(sass@1.85.1)(terser@5.39.0)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/debug': 4.1.12
|
||||
'@types/node': 20.17.24
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
- less
|
||||
- lightningcss
|
||||
- msw
|
||||
- sass
|
||||
- sass-embedded
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
- tsx
|
||||
- yaml
|
||||
|
||||
void-elements@3.1.0: {}
|
||||
|
||||
vue@3.5.13(typescript@5.8.2):
|
||||
|
||||
@@ -2,6 +2,3 @@ packages:
|
||||
- packages/*
|
||||
- projects/*
|
||||
- scripts/icon
|
||||
|
||||
patchedDependencies:
|
||||
mdast-util-gfm-autolink-literal@2.0.1: patches/mdast-util-gfm-autolink-literal@2.0.1.patch
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import { ChatBoxInputType, UserInputFileItemType } from './type';
|
||||
import { getFileIcon } from '@fastgpt/global/common/file/icon';
|
||||
import { ChatItemValueTypeEnum, ChatStatusEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { extractDeepestInteractive } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
|
||||
export const formatChatValue2InputType = (value?: ChatItemValueItemType[]): ChatBoxInputType => {
|
||||
if (!value) {
|
||||
@@ -82,17 +83,19 @@ export const setUserSelectResultToHistories = (
|
||||
i !== item.value.length - 1 ||
|
||||
val.type !== ChatItemValueTypeEnum.interactive ||
|
||||
!val.interactive
|
||||
)
|
||||
) {
|
||||
return val;
|
||||
}
|
||||
|
||||
if (val.interactive.type === 'userSelect') {
|
||||
const finalInteractive = extractDeepestInteractive(val.interactive);
|
||||
if (finalInteractive.type === 'userSelect') {
|
||||
return {
|
||||
...val,
|
||||
interactive: {
|
||||
...val.interactive,
|
||||
...finalInteractive,
|
||||
params: {
|
||||
...val.interactive.params,
|
||||
userSelectedVal: val.interactive.params.userSelectOptions.find(
|
||||
...finalInteractive.params,
|
||||
userSelectedVal: finalInteractive.params.userSelectOptions.find(
|
||||
(item) => item.value === interactiveVal
|
||||
)?.value
|
||||
}
|
||||
@@ -100,13 +103,13 @@ export const setUserSelectResultToHistories = (
|
||||
};
|
||||
}
|
||||
|
||||
if (val.interactive.type === 'userInput') {
|
||||
if (finalInteractive.type === 'userInput') {
|
||||
return {
|
||||
...val,
|
||||
interactive: {
|
||||
...val.interactive,
|
||||
...finalInteractive,
|
||||
params: {
|
||||
...val.interactive.params,
|
||||
...finalInteractive.params,
|
||||
submitted: true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import { isEqual } from 'lodash';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { eventBus, EventNameEnum } from '@/web/common/utils/eventbus';
|
||||
import { SelectOptionsComponent, FormInputComponent } from './Interactive/InteractiveComponents';
|
||||
import { extractDeepestInteractive } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
|
||||
const accordionButtonStyle = {
|
||||
w: 'auto',
|
||||
@@ -245,11 +246,12 @@ const AIResponseBox = ({
|
||||
return <RenderTool showAnimation={isChatting} tools={value.tools} />;
|
||||
}
|
||||
if (value.type === ChatItemValueTypeEnum.interactive && value.interactive) {
|
||||
if (value.interactive.type === 'userSelect') {
|
||||
return <RenderUserSelectInteractive interactive={value.interactive} />;
|
||||
const finalInteractive = extractDeepestInteractive(value.interactive);
|
||||
if (finalInteractive.type === 'userSelect') {
|
||||
return <RenderUserSelectInteractive interactive={finalInteractive} />;
|
||||
}
|
||||
if (value.interactive?.type === 'userInput') {
|
||||
return <RenderUserFormInteractive interactive={value.interactive} />;
|
||||
if (finalInteractive.type === 'userInput') {
|
||||
return <RenderUserFormInteractive interactive={finalInteractive} />;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Box, Checkbox, HStack, VStack } from '@chakra-ui/react';
|
||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||
import PermissionTags from './PermissionTags';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import OrgTags from '../../user/team/OrgTags';
|
||||
import Tag from '@fastgpt/web/components/common/Tag';
|
||||
|
||||
function MemberItemCard({
|
||||
avatar,
|
||||
key,
|
||||
onChange,
|
||||
onChange: _onChange,
|
||||
isChecked,
|
||||
onDelete,
|
||||
name,
|
||||
permission,
|
||||
orgs
|
||||
orgs,
|
||||
addOnly,
|
||||
rightSlot
|
||||
}: {
|
||||
avatar: string;
|
||||
key: string;
|
||||
@@ -23,44 +27,66 @@ function MemberItemCard({
|
||||
onDelete?: () => void;
|
||||
name: string;
|
||||
permission?: PermissionValueType;
|
||||
addOnly?: boolean;
|
||||
orgs?: string[];
|
||||
rightSlot?: React.ReactNode;
|
||||
}) {
|
||||
const isAdded = addOnly && !!permission;
|
||||
const onChange = () => {
|
||||
if (!isAdded) _onChange();
|
||||
};
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<HStack
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
key={key}
|
||||
px="3"
|
||||
py="2"
|
||||
borderRadius="sm"
|
||||
_hover={{
|
||||
bgColor: 'myGray.50',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={onChange}
|
||||
>
|
||||
{isChecked !== undefined && <Checkbox isChecked={isChecked} pointerEvents="none" />}
|
||||
<Avatar src={avatar} w="1.5rem" borderRadius={'50%'} />
|
||||
<HStack
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
key={key}
|
||||
px="3"
|
||||
py="2"
|
||||
borderRadius="sm"
|
||||
_hover={{
|
||||
bgColor: 'myGray.50',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={onChange}
|
||||
>
|
||||
{isChecked !== undefined && (
|
||||
<Checkbox isChecked={isChecked} pointerEvents="none" disabled={isAdded} />
|
||||
)}
|
||||
<Avatar src={avatar} w="1.5rem" borderRadius={'50%'} />
|
||||
|
||||
<Box w="full">
|
||||
<Box fontSize={'sm'}>{name}</Box>
|
||||
<Box lineHeight={1}>{orgs && orgs.length > 0 && <OrgTags orgs={orgs} />}</Box>
|
||||
<Box w="full">
|
||||
<Box fontSize={'sm'} className="textEllipsis" maxW="300px">
|
||||
{name}
|
||||
</Box>
|
||||
{permission && <PermissionTags permission={permission} />}
|
||||
{onDelete !== undefined && (
|
||||
<MyIcon
|
||||
name="common/closeLight"
|
||||
w="1rem"
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
color: 'red.600'
|
||||
}}
|
||||
onClick={onDelete}
|
||||
/>
|
||||
)}
|
||||
</HStack>
|
||||
</>
|
||||
<Box lineHeight={1}>{orgs && orgs.length > 0 && <OrgTags orgs={orgs} />}</Box>
|
||||
</Box>
|
||||
{!isAdded && permission && <PermissionTags permission={permission} />}
|
||||
{isAdded && (
|
||||
<Tag
|
||||
mixBlendMode={'multiply'}
|
||||
colorSchema="blue"
|
||||
border="none"
|
||||
py={2}
|
||||
px={3}
|
||||
fontSize={'xs'}
|
||||
>
|
||||
{t('user:team.collaborator.added')}
|
||||
</Tag>
|
||||
)}
|
||||
{onDelete !== undefined && (
|
||||
<MyIcon
|
||||
name="common/closeLight"
|
||||
w="1rem"
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
color: 'red.600'
|
||||
}}
|
||||
onClick={onDelete}
|
||||
/>
|
||||
)}
|
||||
{rightSlot}
|
||||
</HStack>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { ChevronDownIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Flex,
|
||||
Grid,
|
||||
HStack,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
Tag,
|
||||
Text
|
||||
} from '@chakra-ui/react';
|
||||
import { Box, Button, Flex, Grid, HStack, ModalBody, ModalFooter, Text } from '@chakra-ui/react';
|
||||
import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant';
|
||||
import MyAvatar from '@fastgpt/web/components/common/Avatar';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
@@ -19,27 +8,26 @@ import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
import PermissionSelect from './PermissionSelect';
|
||||
import PermissionTags from './PermissionTags';
|
||||
import {
|
||||
DEFAULT_ORG_AVATAR,
|
||||
DEFAULT_TEAM_AVATAR,
|
||||
DEFAULT_USER_AVATAR
|
||||
} from '@fastgpt/global/common/system/constants';
|
||||
import Path from '@/components/common/folder/Path';
|
||||
import { OrgListItemType, OrgType } from '@fastgpt/global/support/user/team/org/type';
|
||||
import { OrgListItemType } from '@fastgpt/global/support/user/team/org/type';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { CollaboratorContext } from './context';
|
||||
import { getTeamMembers } from '@/web/support/user/team/api';
|
||||
import { getGroupList } from '@/web/support/user/team/group/api';
|
||||
import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination';
|
||||
import MemberItemCard from './MemberItemCard';
|
||||
import { GetSearchUserGroupOrg } from '@/web/support/user/api';
|
||||
import useOrg from '@/web/support/user/team/org/hooks/useOrg';
|
||||
import { TeamMemberItemType } from '@fastgpt/global/support/user/team/type';
|
||||
import { MemberGroupListItemType } from '@fastgpt/global/support/permission/memberGroup/type';
|
||||
import _ from 'lodash';
|
||||
import { UpdateClbPermissionProps } from '@fastgpt/global/support/permission/collaborator';
|
||||
import { ValueOf } from 'next/dist/shared/lib/constants';
|
||||
|
||||
const HoverBoxStyle = {
|
||||
bgColor: 'myGray.50',
|
||||
@@ -131,8 +119,8 @@ function MemberModal({
|
||||
members: selectedMemberList.map((item) => item.tmbId),
|
||||
groups: selectedGroupList.map((item) => item._id),
|
||||
orgs: selectedOrgList.map((item) => item._id),
|
||||
permission: selectedPermission!
|
||||
}),
|
||||
permission: addOnly ? undefined : selectedPermission!
|
||||
} as UpdateClbPermissionProps<ValueOf<typeof addOnly>>),
|
||||
{
|
||||
successToast: t('common:common.Add Success'),
|
||||
onSuccess() {
|
||||
@@ -285,6 +273,7 @@ function MemberModal({
|
||||
const collaborator = collaboratorList?.find((v) => v.tmbId === member.tmbId);
|
||||
return (
|
||||
<MemberItemCard
|
||||
addOnly={addOnly}
|
||||
avatar={member.avatar}
|
||||
key={member.tmbId}
|
||||
name={member.memberName}
|
||||
@@ -321,49 +310,33 @@ function MemberModal({
|
||||
};
|
||||
const collaborator = collaboratorList?.find((v) => v.orgId === org._id);
|
||||
return (
|
||||
<HStack
|
||||
justifyContent="space-between"
|
||||
<MemberItemCard
|
||||
avatar={org.avatar}
|
||||
key={org._id}
|
||||
py="2"
|
||||
px="3"
|
||||
borderRadius="sm"
|
||||
alignItems="center"
|
||||
_hover={HoverBoxStyle}
|
||||
onClick={onChange}
|
||||
>
|
||||
<Checkbox
|
||||
isChecked={!!selectedOrgList.find((v) => v._id === org._id)}
|
||||
pointerEvents="none"
|
||||
/>
|
||||
<MyAvatar src={org.avatar} w="1.5rem" borderRadius={'50%'} />
|
||||
<HStack w="full">
|
||||
<Text>{org.name}</Text>
|
||||
{org.total && (
|
||||
<>
|
||||
<Tag size="sm" my="auto">
|
||||
{org.total}
|
||||
</Tag>
|
||||
</>
|
||||
)}
|
||||
</HStack>
|
||||
<PermissionTags permission={collaborator?.permission.value} />
|
||||
{org.total && (
|
||||
<MyIcon
|
||||
name="core/chat/chevronRight"
|
||||
w="16px"
|
||||
p="4px"
|
||||
rounded={'6px'}
|
||||
_hover={{
|
||||
bgColor: 'myGray.200'
|
||||
}}
|
||||
onClick={(e) => {
|
||||
onClickOrg(org);
|
||||
// setPath(getOrgChildrenPath(org));
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</HStack>
|
||||
name={org.name}
|
||||
onChange={onChange}
|
||||
addOnly={addOnly}
|
||||
permission={collaborator?.permission.value}
|
||||
isChecked={!!selectedOrgList.find((v) => String(v._id) === String(org._id))}
|
||||
rightSlot={
|
||||
org.total && (
|
||||
<MyIcon
|
||||
name="core/chat/chevronRight"
|
||||
w="16px"
|
||||
p="4px"
|
||||
rounded={'6px'}
|
||||
_hover={{
|
||||
bgColor: 'myGray.200'
|
||||
}}
|
||||
onClick={(e) => {
|
||||
onClickOrg(org);
|
||||
// setPath(getOrgChildrenPath(org));
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
});
|
||||
return searchKey ? (
|
||||
@@ -372,6 +345,9 @@ function MemberModal({
|
||||
<OrgMemberScrollData>
|
||||
{Orgs}
|
||||
{orgMembers.map((member) => {
|
||||
const isChecked = !!selectedMemberList.find(
|
||||
(v) => v.tmbId === member.tmbId
|
||||
);
|
||||
return (
|
||||
<MemberItemCard
|
||||
avatar={member.avatar}
|
||||
@@ -385,7 +361,9 @@ function MemberModal({
|
||||
return [...state, member];
|
||||
});
|
||||
}}
|
||||
isChecked={!!selectedMemberList.find((v) => v.tmbId === member.tmbId)}
|
||||
isChecked={isChecked}
|
||||
permission={member.permission.value}
|
||||
addOnly={addOnly && !!member.permission.value}
|
||||
orgs={member.orgs}
|
||||
/>
|
||||
);
|
||||
@@ -414,6 +392,7 @@ function MemberModal({
|
||||
permission={collaborator?.permission.value}
|
||||
onChange={onChange}
|
||||
isChecked={!!selectedGroupList.find((v) => v._id === group._id)}
|
||||
addOnly={addOnly}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -110,7 +110,15 @@ const CollaboratorContextProvider = ({
|
||||
} = useRequest2(
|
||||
async () => {
|
||||
if (feConfigs.isPlus) {
|
||||
return onGetCollaboratorList();
|
||||
const data = await onGetCollaboratorList();
|
||||
return data.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
permission: new Permission({
|
||||
per: item.permission.value
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
return [];
|
||||
},
|
||||
|
||||
@@ -10,7 +10,14 @@ function OrgTags({ orgs, type = 'simple' }: { orgs?: string[]; type?: 'simple' |
|
||||
label={
|
||||
<VStack gap="1" alignItems={'start'}>
|
||||
{orgs.map((org, index) => (
|
||||
<Box key={index} fontSize="sm" fontWeight={400} color="myGray.500">
|
||||
<Box
|
||||
key={index}
|
||||
fontSize="sm"
|
||||
fontWeight={400}
|
||||
color="myGray.500"
|
||||
maxW={'300px'}
|
||||
className="textEllipsis"
|
||||
>
|
||||
{org.slice(1)}
|
||||
</Box>
|
||||
))}
|
||||
|
||||
@@ -91,7 +91,7 @@ const AccountContainer = ({
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(userInfo?.team?.permission.hasManagePer
|
||||
...(userInfo?.team?.permission.hasApikeyCreatePer
|
||||
? [
|
||||
{
|
||||
icon: 'key',
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useTranslation } from 'next-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { updatePasswordByOld } from '@/web/support/user/api';
|
||||
import { PasswordRule } from '@/web/support/user/login/constants';
|
||||
import { checkPasswordRule } from '@/web/support/user/login/constants';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
|
||||
type FormType = {
|
||||
@@ -70,9 +70,11 @@ const UpdatePswModal = ({ onClose }: { onClose: () => void }) => {
|
||||
placeholder={t('account_info:password_tip')}
|
||||
{...register('newPsw', {
|
||||
required: true,
|
||||
pattern: {
|
||||
value: PasswordRule,
|
||||
message: t('account_info:password_tip')
|
||||
validate: (val) => {
|
||||
if (!checkPasswordRule(val)) {
|
||||
return t('login:password_tip');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})}
|
||||
></Input>
|
||||
|
||||
@@ -303,7 +303,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
|
||||
})()}
|
||||
</Td>
|
||||
<Td maxW={'300px'}>
|
||||
<VStack gap={0}>
|
||||
<VStack gap={0} align="start">
|
||||
<Box>{format(new Date(member.createTime), 'yyyy-MM-dd HH:mm:ss')}</Box>
|
||||
<Box>
|
||||
{member.updateTime
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Flex,
|
||||
Table,
|
||||
TableContainer,
|
||||
Tbody,
|
||||
Td,
|
||||
Th,
|
||||
Thead,
|
||||
Tr
|
||||
} from '@chakra-ui/react';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||
import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
|
||||
import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination';
|
||||
import { getOperationLogs } from '@/web/support/user/team/operantionLog/api';
|
||||
import { TeamPermission } from '@fastgpt/global/support/permission/user/controller';
|
||||
import { operationLogI18nMap } from '@fastgpt/service/support/operationLog/constants';
|
||||
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
|
||||
import { formatTime2YMDHMS } from '@fastgpt/global/common/string/time';
|
||||
import UserBox from '@fastgpt/web/components/common/UserBox';
|
||||
|
||||
function OperationLogTable({ Tabs }: { Tabs: React.ReactNode }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [searchKey, setSearchKey] = useState<string>('');
|
||||
const {
|
||||
data: operationLogs = [],
|
||||
isLoading: loadingLogs,
|
||||
ScrollData: LogScrollData
|
||||
} = useScrollPagination(getOperationLogs, {
|
||||
pageSize: 20,
|
||||
refreshDeps: [searchKey],
|
||||
throttleWait: 500,
|
||||
debounceWait: 200
|
||||
});
|
||||
|
||||
const isLoading = loadingLogs;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex justify={'space-between'} align={'center'} pb={'1rem'}>
|
||||
{Tabs}
|
||||
</Flex>
|
||||
|
||||
<MyBox isLoading={isLoading} flex={'1 0 0'} overflow={'auto'}>
|
||||
<LogScrollData>
|
||||
<TableContainer overflow={'unset'} fontSize={'sm'}>
|
||||
<Table overflow={'unset'}>
|
||||
<Thead>
|
||||
<Tr bgColor={'white !important'}>
|
||||
<Th borderLeftRadius="6px" bgColor="myGray.100">
|
||||
{t('account_team:log_user')}
|
||||
</Th>
|
||||
<Th bgColor="myGray.100">{t('account_team:log_time')}</Th>
|
||||
<Th bgColor="myGray.100">{t('account_team:log_type')}</Th>
|
||||
<Th bgColor="myGray.100">{t('account_team:log_details')}</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{operationLogs?.map((log) => {
|
||||
const i18nData = operationLogI18nMap[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 ? '✔' : '✘';
|
||||
}
|
||||
|
||||
return i18nData ? (
|
||||
<Tr key={log._id} overflow={'unset'}>
|
||||
<Td>
|
||||
<UserBox
|
||||
sourceMember={log.sourceMember}
|
||||
fontSize="sm"
|
||||
avatarSize="1rem"
|
||||
spacing={0.5}
|
||||
/>
|
||||
</Td>
|
||||
<Td>{formatTime2YMDHMS(log.timestamp)}</Td>
|
||||
<Td>{t(i18nData.typeLabel)}</Td>
|
||||
<Td>{t(i18nData.content, metadata as any) as string}</Td>
|
||||
</Tr>
|
||||
) : null;
|
||||
})}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</LogScrollData>
|
||||
</MyBox>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default OperationLogTable;
|
||||
@@ -27,6 +27,9 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||
import MemberTag from '../../../../components/support/user/team/Info/MemberTag';
|
||||
import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant';
|
||||
import {
|
||||
TeamApikeyCreatePermissionVal,
|
||||
TeamAppCreatePermissionVal,
|
||||
TeamDatasetCreatePermissionVal,
|
||||
TeamManagePermissionVal,
|
||||
TeamPermissionList,
|
||||
TeamWritePermissionVal
|
||||
@@ -42,6 +45,9 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
|
||||
import { GetSearchUserGroupOrg } from '@/web/support/user/api';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
import { CollaboratorItemType } from '@fastgpt/global/support/permission/collaborator';
|
||||
import { Permission } from '@fastgpt/global/support/permission/controller';
|
||||
|
||||
function PermissionManage({
|
||||
Tabs,
|
||||
@@ -104,19 +110,18 @@ function PermissionManage({
|
||||
}, [collaboratorList, searchResult, searchKey]);
|
||||
|
||||
const { runAsync: onUpdatePermission, loading: addLoading } = useRequest2(
|
||||
async ({ id, type, per }: { id: string; type: 'add' | 'remove'; per: 'write' | 'manage' }) => {
|
||||
async ({ id, type, per }: { id: string; type: 'add' | 'remove'; per: PermissionValueType }) => {
|
||||
const clb = collaboratorList.find(
|
||||
(clb) => clb.tmbId === id || clb.groupId === id || clb.orgId === id
|
||||
);
|
||||
|
||||
if (!clb) return;
|
||||
|
||||
const updatePer = per === 'write' ? TeamWritePermissionVal : TeamManagePermissionVal;
|
||||
const permission = new TeamPermission({ per: clb.permission.value });
|
||||
if (type === 'add') {
|
||||
permission.addPer(updatePer);
|
||||
permission.addPer(per);
|
||||
} else {
|
||||
permission.removePer(updatePer);
|
||||
permission.removePer(per);
|
||||
}
|
||||
|
||||
return onUpdateCollaborators({
|
||||
@@ -132,12 +137,48 @@ function PermissionManage({
|
||||
useRequest2(onDelOneCollaborator);
|
||||
|
||||
const userManage = userInfo?.permission.hasManagePer;
|
||||
const hasDeletePer = (per: TeamPermission) => {
|
||||
const hasDeletePer = (per: Permission) => {
|
||||
if (userInfo?.permission.isOwner) return true;
|
||||
if (userManage && !per.hasManagePer) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
function PermissionCheckBox({
|
||||
isDisabled,
|
||||
per,
|
||||
clbPer,
|
||||
id
|
||||
}: {
|
||||
isDisabled: boolean;
|
||||
per: PermissionValueType;
|
||||
clbPer: Permission;
|
||||
id: string;
|
||||
}) {
|
||||
return (
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={isDisabled}
|
||||
isChecked={clbPer.checkPer(per)}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({
|
||||
id,
|
||||
type: 'add',
|
||||
per
|
||||
})
|
||||
: onUpdatePermission({
|
||||
id,
|
||||
type: 'remove',
|
||||
per
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex justify={'space-between'} align={'center'} pb={'1rem'}>
|
||||
@@ -174,13 +215,26 @@ function PermissionManage({
|
||||
</Th>
|
||||
<Th bg="myGray.100">
|
||||
<Box mx="auto" w="fit-content">
|
||||
{t('user:team.group.permission.write')}
|
||||
{t('account_team:permission_appCreate')}
|
||||
<QuestionTip ml="1" label={t('account_team:permission_appCreate_tip')} />
|
||||
</Box>
|
||||
</Th>
|
||||
<Th bg="myGray.100">
|
||||
<Box mx="auto" w="fit-content">
|
||||
{t('user:team.group.permission.manage')}
|
||||
<QuestionTip ml="1" label={t('user:team.group.manage_tip')} />
|
||||
{t('account_team:permission_datasetCreate')}
|
||||
<QuestionTip ml="1" label={t('account_team:permission_datasetCreate_Tip')} />
|
||||
</Box>
|
||||
</Th>
|
||||
<Th bg="myGray.100">
|
||||
<Box mx="auto" w="fit-content">
|
||||
{t('account_team:permission_apikeyCreate')}
|
||||
<QuestionTip ml="1" label={t('account_team:permission_apikeyCreate_Tip')} />
|
||||
</Box>
|
||||
</Th>
|
||||
<Th bg="myGray.100">
|
||||
<Box mx="auto" w="fit-content">
|
||||
{t('account_team:permission_manage')}
|
||||
<QuestionTip ml="1" label={t('account_team:permission_manage_tip')} />
|
||||
</Box>
|
||||
</Th>
|
||||
<Th bg="myGray.100" borderRightRadius="md">
|
||||
@@ -210,48 +264,30 @@ function PermissionManage({
|
||||
<Box>{member.name}</Box>
|
||||
</HStack>
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={member.permission.isOwner || !userManage}
|
||||
isChecked={member.permission.hasWritePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({
|
||||
id: member.tmbId!,
|
||||
type: 'add',
|
||||
per: 'write'
|
||||
})
|
||||
: onUpdatePermission({
|
||||
id: member.tmbId!,
|
||||
type: 'remove',
|
||||
per: 'write'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={member.permission.isOwner || !userInfo?.permission.isOwner}
|
||||
isChecked={member.permission.hasManagePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({
|
||||
id: member.tmbId!,
|
||||
type: 'add',
|
||||
per: 'manage'
|
||||
})
|
||||
: onUpdatePermission({
|
||||
id: member.tmbId!,
|
||||
type: 'remove',
|
||||
per: 'manage'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<PermissionCheckBox
|
||||
isDisabled={member.permission.isOwner || !userManage}
|
||||
per={TeamAppCreatePermissionVal}
|
||||
clbPer={member.permission}
|
||||
id={member.tmbId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={member.permission.isOwner || !userManage}
|
||||
per={TeamDatasetCreatePermissionVal}
|
||||
clbPer={member.permission}
|
||||
id={member.tmbId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={member.permission.isOwner || !userManage}
|
||||
per={TeamApikeyCreatePermissionVal}
|
||||
clbPer={member.permission}
|
||||
id={member.tmbId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={member.permission.isOwner || !userInfo?.permission.isOwner}
|
||||
per={TeamManagePermissionVal}
|
||||
clbPer={member.permission}
|
||||
id={member.tmbId!}
|
||||
/>
|
||||
<Td>
|
||||
{hasDeletePer(member.permission) &&
|
||||
userInfo?.team.tmbId !== member.tmbId && (
|
||||
@@ -268,7 +304,6 @@ function PermissionManage({
|
||||
</Tr>
|
||||
))}
|
||||
</>
|
||||
|
||||
<>
|
||||
<Tr borderBottom={'1px solid'} borderColor={'myGray.200'} />
|
||||
<Tr userSelect={'none'}>
|
||||
@@ -286,40 +321,30 @@ function PermissionManage({
|
||||
<Td pl={10}>
|
||||
<MemberTag name={org.name} avatar={org.avatar} />
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={!userManage}
|
||||
isChecked={org.permission.hasWritePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({ id: org.orgId!, type: 'add', per: 'write' })
|
||||
: onUpdatePermission({
|
||||
id: org.orgId!,
|
||||
type: 'remove',
|
||||
per: 'write'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={!userInfo?.permission.isOwner}
|
||||
isChecked={org.permission.hasManagePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({ id: org.orgId!, type: 'add', per: 'manage' })
|
||||
: onUpdatePermission({
|
||||
id: org.orgId!,
|
||||
type: 'remove',
|
||||
per: 'manage'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<PermissionCheckBox
|
||||
isDisabled={org.permission.isOwner || !userManage}
|
||||
per={TeamAppCreatePermissionVal}
|
||||
clbPer={org.permission}
|
||||
id={org.orgId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={org.permission.isOwner || !userManage}
|
||||
per={TeamDatasetCreatePermissionVal}
|
||||
clbPer={org.permission}
|
||||
id={org.orgId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={org.permission.isOwner || !userManage}
|
||||
per={TeamApikeyCreatePermissionVal}
|
||||
clbPer={org.permission}
|
||||
id={org.orgId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={org.permission.isOwner || !userInfo?.permission.isOwner}
|
||||
per={TeamManagePermissionVal}
|
||||
clbPer={org.permission}
|
||||
id={org.orgId!}
|
||||
/>
|
||||
<Td>
|
||||
{hasDeletePer(org.permission) && (
|
||||
<Box mx="auto" w="fit-content">
|
||||
@@ -358,48 +383,30 @@ function PermissionManage({
|
||||
avatar={group.avatar}
|
||||
/>
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={!userManage}
|
||||
isChecked={group.permission.hasWritePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({
|
||||
id: group.groupId!,
|
||||
type: 'add',
|
||||
per: 'write'
|
||||
})
|
||||
: onUpdatePermission({
|
||||
id: group.groupId!,
|
||||
type: 'remove',
|
||||
per: 'write'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<Td>
|
||||
<Box mx="auto" w="fit-content">
|
||||
<Checkbox
|
||||
isDisabled={!userInfo?.permission.isOwner}
|
||||
isChecked={group.permission.hasManagePer}
|
||||
onChange={(e) =>
|
||||
e.target.checked
|
||||
? onUpdatePermission({
|
||||
id: group.groupId!,
|
||||
type: 'add',
|
||||
per: 'manage'
|
||||
})
|
||||
: onUpdatePermission({
|
||||
id: group.groupId!,
|
||||
type: 'remove',
|
||||
per: 'manage'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
<PermissionCheckBox
|
||||
isDisabled={group.permission.isOwner || !userManage}
|
||||
per={TeamAppCreatePermissionVal}
|
||||
clbPer={group.permission}
|
||||
id={group.groupId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={group.permission.isOwner || !userManage}
|
||||
per={TeamDatasetCreatePermissionVal}
|
||||
clbPer={group.permission}
|
||||
id={group.groupId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={group.permission.isOwner || !userManage}
|
||||
per={TeamApikeyCreatePermissionVal}
|
||||
clbPer={group.permission}
|
||||
id={group.groupId!}
|
||||
/>
|
||||
<PermissionCheckBox
|
||||
isDisabled={group.permission.isOwner || !userInfo?.permission.isOwner}
|
||||
per={TeamManagePermissionVal}
|
||||
clbPer={group.permission}
|
||||
id={group.groupId!}
|
||||
/>
|
||||
<Td>
|
||||
{hasDeletePer(group.permission) && (
|
||||
<Box mx="auto" w="fit-content">
|
||||
|
||||
@@ -13,7 +13,10 @@ import {
|
||||
SelectOptionsComponent
|
||||
} from '@/components/core/chat/components/Interactive/InteractiveComponents';
|
||||
import { UserInputInteractive } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||
import { initWorkflowEdgeStatus } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import {
|
||||
getLastInteractiveValue,
|
||||
initWorkflowEdgeStatus
|
||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { ChatItemType, UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||
|
||||
@@ -130,10 +133,11 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
|
||||
}
|
||||
];
|
||||
|
||||
const lastInteractive = getLastInteractiveValue(mockHistory);
|
||||
onNextNodeDebug({
|
||||
...workflowDebugData,
|
||||
// Rewrite runtimeEdges
|
||||
runtimeEdges: initWorkflowEdgeStatus(workflowDebugData.runtimeEdges, mockHistory),
|
||||
runtimeEdges: initWorkflowEdgeStatus(workflowDebugData.runtimeEdges, lastInteractive),
|
||||
query: updatedQuery,
|
||||
history: mockHistory
|
||||
});
|
||||
|
||||
@@ -36,6 +36,7 @@ import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
import { useChatStore } from '@/web/core/chat/context/useChatStore';
|
||||
import { RequireOnlyOne } from '@fastgpt/global/common/type/utils';
|
||||
import UserBox from '@fastgpt/web/components/common/UserBox';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
const HttpEditModal = dynamic(() => import('./HttpPluginEditModal'));
|
||||
|
||||
const ListItem = () => {
|
||||
@@ -429,7 +430,7 @@ const ListItem = () => {
|
||||
members?: string[];
|
||||
groups?: string[];
|
||||
orgs?: string[];
|
||||
permission: number;
|
||||
permission: PermissionValueType;
|
||||
}) =>
|
||||
postUpdateAppCollaborators({
|
||||
...props,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { Dispatch } from 'react';
|
||||
import { FormControl, Box, Input, Button } from '@chakra-ui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { LoginPageTypeEnum, PasswordRule } from '@/web/support/user/login/constants';
|
||||
import { LoginPageTypeEnum, checkPasswordRule } from '@/web/support/user/login/constants';
|
||||
import { postFindPassword } from '@/web/support/user/api';
|
||||
import { useSendCode } from '@/web/support/user/hooks/useSendCode';
|
||||
import type { ResLogin } from '@/global/support/api/userRes.d';
|
||||
@@ -138,9 +138,11 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
placeholder={t('login:password_tip')}
|
||||
{...register('password', {
|
||||
required: true,
|
||||
pattern: {
|
||||
value: PasswordRule,
|
||||
message: t('login:password_tip')
|
||||
validate: (val) => {
|
||||
if (!checkPasswordRule(val)) {
|
||||
return t('login:password_tip');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})}
|
||||
></Input>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { Dispatch } from 'react';
|
||||
import { FormControl, Box, Input, Button } from '@chakra-ui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { LoginPageTypeEnum, PasswordRule } from '@/web/support/user/login/constants';
|
||||
import { LoginPageTypeEnum, checkPasswordRule } from '@/web/support/user/login/constants';
|
||||
import { postRegister } from '@/web/support/user/api';
|
||||
import { useSendCode } from '@/web/support/user/hooks/useSendCode';
|
||||
import type { ResLogin } from '@/global/support/api/userRes';
|
||||
@@ -166,9 +166,11 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
placeholder={t('login:password_tip')}
|
||||
{...register('password', {
|
||||
required: true,
|
||||
pattern: {
|
||||
value: PasswordRule,
|
||||
message: t('login:password_tip')
|
||||
validate: (val) => {
|
||||
if (!checkPasswordRule(val)) {
|
||||
return t('login:password_tip');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})}
|
||||
></Input>
|
||||
|
||||
@@ -18,6 +18,7 @@ const MemberTable = dynamic(() => import('@/pageComponents/account/team/MemberTa
|
||||
const PermissionManage = dynamic(
|
||||
() => import('@/pageComponents/account/team/PermissionManage/index')
|
||||
);
|
||||
const OperationLogTable = dynamic(() => import('@/pageComponents/account/team/OperationLog/index'));
|
||||
const GroupManage = dynamic(() => import('@/pageComponents/account/team/GroupManage/index'));
|
||||
const OrgManage = dynamic(() => import('@/pageComponents/account/team/OrgManage/index'));
|
||||
const HandleInviteModal = dynamic(
|
||||
@@ -28,7 +29,8 @@ export enum TeamTabEnum {
|
||||
member = 'member',
|
||||
org = 'org',
|
||||
group = 'group',
|
||||
permission = 'permission'
|
||||
permission = 'permission',
|
||||
operationLog = 'operationLog'
|
||||
}
|
||||
|
||||
const Team = () => {
|
||||
@@ -57,7 +59,8 @@ const Team = () => {
|
||||
{ label: t('account_team:member'), value: TeamTabEnum.member },
|
||||
{ label: t('account_team:org'), value: TeamTabEnum.org },
|
||||
{ label: t('account_team:group'), value: TeamTabEnum.group },
|
||||
{ label: t('account_team:permission'), value: TeamTabEnum.permission }
|
||||
{ label: t('account_team:permission'), value: TeamTabEnum.permission },
|
||||
{ label: t('account_team:operation_log'), value: TeamTabEnum.operationLog }
|
||||
]}
|
||||
px={'1rem'}
|
||||
value={teamTab}
|
||||
@@ -150,6 +153,7 @@ const Team = () => {
|
||||
{teamTab === TeamTabEnum.org && <OrgManage Tabs={Tabs} />}
|
||||
{teamTab === TeamTabEnum.group && <GroupManage Tabs={Tabs} />}
|
||||
{teamTab === TeamTabEnum.permission && <PermissionManage Tabs={Tabs} />}
|
||||
{teamTab === TeamTabEnum.operationLog && <OperationLogTable Tabs={Tabs} />}
|
||||
</Box>
|
||||
</Flex>
|
||||
{invitelinkid && <HandleInviteModal invitelinkid={invitelinkid} />}
|
||||
|
||||
48
projects/app/src/pages/api/admin/initv495.ts
Normal file
48
projects/app/src/pages/api/admin/initv495.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
|
||||
import { TeamPermission } from '@fastgpt/global/support/permission/user/controller';
|
||||
import {
|
||||
TeamApikeyCreatePermissionVal,
|
||||
TeamAppCreatePermissionVal,
|
||||
TeamDatasetCreatePermissionVal
|
||||
} from '@fastgpt/global/support/permission/user/constant';
|
||||
import { retryFn } from '@fastgpt/global/common/system/utils';
|
||||
|
||||
async function handler(req: NextApiRequest, _res: NextApiResponse) {
|
||||
await authCert({ req, authRoot: true });
|
||||
// 更新团队权限:
|
||||
// 目前所有有 TeamWritePermission 的,都需要添加三个新的权限。
|
||||
|
||||
const rps = await MongoResourcePermission.find({
|
||||
resourceType: 'team',
|
||||
teamId: { $exists: true },
|
||||
resourceId: null
|
||||
});
|
||||
|
||||
for await (const rp of rps) {
|
||||
const per = new TeamPermission({ per: rp.permission });
|
||||
console.log(per.hasWritePer, per.value);
|
||||
if (per.hasWritePer) {
|
||||
const newPer = per.addPer(
|
||||
TeamAppCreatePermissionVal,
|
||||
TeamDatasetCreatePermissionVal,
|
||||
TeamApikeyCreatePermissionVal
|
||||
);
|
||||
rp.permission = newPer.value;
|
||||
|
||||
try {
|
||||
await retryFn(async () => {
|
||||
await rp.save();
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('更新权限异常', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
@@ -4,6 +4,7 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import { onCreateApp } from './create';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
|
||||
export type copyAppQuery = {};
|
||||
|
||||
@@ -17,19 +18,16 @@ async function handler(
|
||||
req: ApiRequestProps<copyAppBody, copyAppQuery>,
|
||||
res: ApiResponseType<any>
|
||||
): Promise<copyAppResponse> {
|
||||
const [{ app, tmbId }] = await Promise.all([
|
||||
authApp({
|
||||
req,
|
||||
authToken: true,
|
||||
per: WritePermissionVal,
|
||||
appId: req.body.appId
|
||||
}),
|
||||
authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: WritePermissionVal
|
||||
})
|
||||
]);
|
||||
const { app } = await authApp({
|
||||
req,
|
||||
authToken: true,
|
||||
per: WritePermissionVal,
|
||||
appId: req.body.appId
|
||||
});
|
||||
|
||||
const { tmbId } = app.parentId
|
||||
? await authApp({ req, appId: app.parentId, per: TeamAppCreatePermissionVal, authToken: true })
|
||||
: await authUserPer({ req, authToken: true, per: TeamAppCreatePermissionVal });
|
||||
|
||||
const appId = await onCreateApp({
|
||||
parentId: app.parentId,
|
||||
|
||||
@@ -17,6 +17,7 @@ import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
|
||||
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
|
||||
import { refreshSourceAvatar } from '@fastgpt/service/common/file/image/controller';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
|
||||
export type CreateAppBody = {
|
||||
parentId?: ParentIdType;
|
||||
@@ -36,18 +37,15 @@ async function handler(req: ApiRequestProps<CreateAppBody>) {
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const [{ teamId, tmbId, userId }] = await Promise.all([
|
||||
authUserPer({ req, authToken: true, per: WritePermissionVal }),
|
||||
...(parentId
|
||||
? [authApp({ req, appId: parentId, per: WritePermissionVal, authToken: true })]
|
||||
: [])
|
||||
]);
|
||||
const { teamId, tmbId, userId } = parentId
|
||||
? await authApp({ req, appId: parentId, per: TeamAppCreatePermissionVal, authToken: true })
|
||||
: await authUserPer({ req, authToken: true, per: TeamAppCreatePermissionVal });
|
||||
|
||||
// 上限校验
|
||||
await checkTeamAppLimit(teamId);
|
||||
const tmb = await MongoTeamMember.findById({ _id: tmbId }, 'userId').populate<{
|
||||
user: { avatar: string; username: string };
|
||||
}>('user', 'avatar username');
|
||||
user: { username: string };
|
||||
}>('user', 'username');
|
||||
|
||||
// 创建app
|
||||
const appId = await onCreateApp({
|
||||
@@ -60,7 +58,7 @@ async function handler(req: ApiRequestProps<CreateAppBody>) {
|
||||
chatConfig,
|
||||
teamId,
|
||||
tmbId,
|
||||
userAvatar: tmb?.user?.avatar,
|
||||
userAvatar: tmb?.avatar,
|
||||
username: tmb?.user?.username
|
||||
});
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { syncCollaborators } from '@fastgpt/service/support/permission/inheritPermission';
|
||||
import { getResourceClbsAndGroups } from '@fastgpt/service/support/permission/controller';
|
||||
import { TeamWritePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
|
||||
|
||||
export type CreateAppFolderBody = {
|
||||
@@ -33,21 +33,9 @@ async function handler(req: ApiRequestProps<CreateAppFolderBody>) {
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const { teamId, tmbId } = await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: TeamWritePermissionVal
|
||||
});
|
||||
|
||||
if (parentId) {
|
||||
// if it is not a root folder
|
||||
await authApp({
|
||||
req,
|
||||
appId: parentId,
|
||||
per: WritePermissionVal,
|
||||
authToken: true
|
||||
});
|
||||
}
|
||||
const { teamId, tmbId } = parentId
|
||||
? await authApp({ req, appId: parentId, per: TeamAppCreatePermissionVal, authToken: true })
|
||||
: await authUserPer({ req, authToken: true, per: TeamAppCreatePermissionVal });
|
||||
|
||||
// Create app
|
||||
await mongoSessionRun(async (session) => {
|
||||
|
||||
@@ -9,6 +9,8 @@ import { onCreateApp, type CreateAppBody } from '../create';
|
||||
import { AppSchema } from '@fastgpt/global/core/app/type';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
|
||||
import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
|
||||
export type createHttpPluginQuery = {};
|
||||
|
||||
@@ -29,11 +31,9 @@ async function handler(
|
||||
return Promise.reject('缺少参数');
|
||||
}
|
||||
|
||||
const { teamId, tmbId, userId } = await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: WritePermissionVal
|
||||
});
|
||||
const { teamId, tmbId, userId } = parentId
|
||||
? await authApp({ req, appId: parentId, per: TeamAppCreatePermissionVal, authToken: true })
|
||||
: await authUserPer({ req, authToken: true, per: TeamAppCreatePermissionVal });
|
||||
|
||||
await mongoSessionRun(async (session) => {
|
||||
// create http plugin folder
|
||||
|
||||
@@ -20,7 +20,7 @@ import { ClientSession } from 'mongoose';
|
||||
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
import { getResourceClbsAndGroups } from '@fastgpt/service/support/permission/controller';
|
||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import { TeamWritePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
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';
|
||||
@@ -79,7 +79,7 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
|
||||
await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: TeamWritePermissionVal
|
||||
per: TeamAppCreatePermissionVal
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -98,7 +98,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
const isPlugin = app.type === AppTypeEnum.plugin;
|
||||
|
||||
const userQuestion: UserChatItemType = (() => {
|
||||
const userQuestion: UserChatItemType = await (async () => {
|
||||
if (isPlugin) {
|
||||
return getPluginRunUserQuery({
|
||||
pluginInputs: getPluginInputsFromStoreNodes(app.modules),
|
||||
@@ -107,9 +107,9 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
});
|
||||
}
|
||||
|
||||
const latestHumanChat = chatMessages.pop() as UserChatItemType | undefined;
|
||||
const latestHumanChat = chatMessages.pop() as UserChatItemType;
|
||||
if (!latestHumanChat) {
|
||||
throw new Error('User question is empty');
|
||||
return Promise.reject('User question is empty');
|
||||
}
|
||||
return latestHumanChat;
|
||||
})();
|
||||
@@ -136,14 +136,14 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
}
|
||||
|
||||
const newHistories = concatHistories(histories, chatMessages);
|
||||
|
||||
const interactive = getLastInteractiveValue(newHistories) || undefined;
|
||||
// Get runtimeNodes
|
||||
let runtimeNodes = storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes, newHistories));
|
||||
let runtimeNodes = storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes, interactive));
|
||||
if (isPlugin) {
|
||||
runtimeNodes = updatePluginInputByVariables(runtimeNodes, variables);
|
||||
variables = {};
|
||||
}
|
||||
runtimeNodes = rewriteNodeOutputByHistories(newHistories, runtimeNodes);
|
||||
runtimeNodes = rewriteNodeOutputByHistories(runtimeNodes, interactive);
|
||||
|
||||
const workflowResponseWrite = getWorkflowResponseWrite({
|
||||
res,
|
||||
@@ -175,9 +175,10 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
chatId,
|
||||
responseChatItemId,
|
||||
runtimeNodes,
|
||||
runtimeEdges: initWorkflowEdgeStatus(edges, newHistories),
|
||||
runtimeEdges: initWorkflowEdgeStatus(edges, interactive),
|
||||
variables,
|
||||
query: removeEmptyUserInput(userQuestion.value),
|
||||
lastInteractive: interactive,
|
||||
chatConfig,
|
||||
histories: newHistories,
|
||||
stream: true,
|
||||
|
||||
@@ -6,11 +6,9 @@ import {
|
||||
getLLMModel,
|
||||
getEmbeddingModel,
|
||||
getDatasetModel,
|
||||
getDefaultEmbeddingModel,
|
||||
getVlmModel
|
||||
getDefaultEmbeddingModel
|
||||
} from '@fastgpt/service/core/ai/model';
|
||||
import { checkTeamDatasetLimit } from '@fastgpt/service/support/permission/teamLimit';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import type { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
|
||||
@@ -18,6 +16,7 @@ import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
|
||||
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
|
||||
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
import { refreshSourceAvatar } from '@fastgpt/service/common/file/image/controller';
|
||||
import { TeamDatasetCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
|
||||
export type DatasetCreateQuery = {};
|
||||
export type DatasetCreateBody = CreateDatasetParams;
|
||||
@@ -41,25 +40,20 @@ async function handler(
|
||||
} = req.body;
|
||||
|
||||
// auth
|
||||
const [{ teamId, tmbId, userId }] = await Promise.all([
|
||||
authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: WritePermissionVal
|
||||
}),
|
||||
...(parentId
|
||||
? [
|
||||
authDataset({
|
||||
req,
|
||||
datasetId: parentId,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: WritePermissionVal
|
||||
})
|
||||
]
|
||||
: [])
|
||||
]);
|
||||
const { teamId, tmbId, userId } = parentId
|
||||
? await authDataset({
|
||||
req,
|
||||
datasetId: parentId,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: TeamDatasetCreatePermissionVal
|
||||
})
|
||||
: await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: TeamDatasetCreatePermissionVal
|
||||
});
|
||||
|
||||
// check model valid
|
||||
const vectorModelStore = getEmbeddingModel(vectorModel);
|
||||
|
||||
@@ -5,8 +5,7 @@ import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import {
|
||||
OwnerPermissionVal,
|
||||
PerResourceTypeEnum,
|
||||
WritePermissionVal
|
||||
PerResourceTypeEnum
|
||||
} from '@fastgpt/global/support/permission/constant';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
|
||||
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
@@ -16,6 +15,7 @@ import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { getResourceClbsAndGroups } from '@fastgpt/service/support/permission/controller';
|
||||
import { syncCollaborators } from '@fastgpt/service/support/permission/inheritPermission';
|
||||
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
|
||||
import { TeamDatasetCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
export type DatasetFolderCreateQuery = {};
|
||||
export type DatasetFolderCreateBody = {
|
||||
parentId?: string;
|
||||
@@ -33,20 +33,20 @@ async function handler(
|
||||
return Promise.reject(CommonErrEnum.missingParams);
|
||||
}
|
||||
|
||||
const { tmbId, teamId } = await authUserPer({
|
||||
req,
|
||||
per: WritePermissionVal,
|
||||
authToken: true
|
||||
});
|
||||
|
||||
if (parentId) {
|
||||
await authDataset({
|
||||
datasetId: parentId,
|
||||
per: WritePermissionVal,
|
||||
req,
|
||||
authToken: true
|
||||
});
|
||||
}
|
||||
const { teamId, tmbId } = parentId
|
||||
? await authDataset({
|
||||
req,
|
||||
datasetId: parentId,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: TeamDatasetCreatePermissionVal
|
||||
})
|
||||
: await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: TeamDatasetCreatePermissionVal
|
||||
});
|
||||
|
||||
await mongoSessionRun(async (session) => {
|
||||
const dataset = await MongoDataset.create({
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
syncCollaborators
|
||||
} from '@fastgpt/service/support/permission/inheritPermission';
|
||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import { TeamWritePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { TeamDatasetCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
|
||||
import { MongoDatasetTraining } from '@fastgpt/service/core/dataset/training/schema';
|
||||
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
|
||||
@@ -104,7 +104,7 @@ async function handler(
|
||||
await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: TeamWritePermissionVal
|
||||
per: TeamDatasetCreatePermissionVal
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { NextAPI } from '@/service/middleware/entry';
|
||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { defaultApp } from '@/web/core/app/constants';
|
||||
import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants';
|
||||
import { getLastInteractiveValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
|
||||
async function handler(
|
||||
req: NextApiRequest,
|
||||
@@ -44,6 +45,7 @@ async function handler(
|
||||
|
||||
// auth balance
|
||||
const { timezone, externalProvider } = await getUserChatInfoAndAuthTeamPoints(tmbId);
|
||||
const lastInteractive = getLastInteractiveValue(history);
|
||||
|
||||
/* start process */
|
||||
const { flowUsages, flowResponses, debugResponse, newVariables, workflowInteractiveResponse } =
|
||||
@@ -65,6 +67,7 @@ async function handler(
|
||||
},
|
||||
runtimeNodes: nodes,
|
||||
runtimeEdges: edges,
|
||||
lastInteractive,
|
||||
variables,
|
||||
query: query,
|
||||
chatConfig: defaultApp.chatConfig,
|
||||
|
||||
@@ -4,12 +4,10 @@ import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import type { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import {
|
||||
ManagePermissionVal,
|
||||
WritePermissionVal
|
||||
} from '@fastgpt/global/support/permission/constant';
|
||||
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';
|
||||
|
||||
async function handler(req: ApiRequestProps<EditApiKeyProps>): Promise<string> {
|
||||
const { appId, name, limit } = req.body;
|
||||
@@ -19,7 +17,7 @@ async function handler(req: ApiRequestProps<EditApiKeyProps>): Promise<string> {
|
||||
const { teamId, tmbId } = await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
per: WritePermissionVal
|
||||
per: TeamApikeyCreatePermissionVal
|
||||
});
|
||||
return { teamId, tmbId };
|
||||
} else {
|
||||
|
||||
@@ -9,6 +9,8 @@ import { useIPFrequencyLimit } from '@fastgpt/service/common/middle/reqFrequency
|
||||
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
|
||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { UserErrEnum } from '@fastgpt/global/common/error/code/user';
|
||||
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
|
||||
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { username, password } = req.body as PostLoginProps;
|
||||
@@ -64,6 +66,12 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
setCookie(res, token);
|
||||
|
||||
addOperationLog({
|
||||
tmbId: userDetail.team.tmbId,
|
||||
teamId: userDetail.team.teamId,
|
||||
event: OperationLogEventEnum.LOGIN
|
||||
});
|
||||
|
||||
return {
|
||||
user: userDetail,
|
||||
token
|
||||
|
||||
@@ -139,7 +139,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
// Computed start hook params
|
||||
const startHookText = (() => {
|
||||
// Chat
|
||||
const userQuestion = chatMessages[chatMessages.length - 1] as UserChatItemType | undefined;
|
||||
const userQuestion = chatMessages[chatMessages.length - 1] as UserChatItemType;
|
||||
if (userQuestion) return chatValue2RuntimePrompt(userQuestion.value).text;
|
||||
|
||||
// plugin
|
||||
@@ -245,16 +245,17 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
// Get chat histories
|
||||
const newHistories = concatHistories(histories, chatMessages);
|
||||
const interactive = getLastInteractiveValue(newHistories) || undefined;
|
||||
|
||||
// Get runtimeNodes
|
||||
let runtimeNodes = storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes, newHistories));
|
||||
let runtimeNodes = storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes, interactive));
|
||||
if (isPlugin) {
|
||||
// Assign values to runtimeNodes using variables
|
||||
runtimeNodes = updatePluginInputByVariables(runtimeNodes, variables);
|
||||
// Plugin runtime does not need global variables(It has been injected into the pluginInputNode)
|
||||
variables = {};
|
||||
}
|
||||
runtimeNodes = rewriteNodeOutputByHistories(newHistories, runtimeNodes);
|
||||
runtimeNodes = rewriteNodeOutputByHistories(runtimeNodes, interactive);
|
||||
|
||||
const workflowResponseWrite = getWorkflowResponseWrite({
|
||||
res,
|
||||
@@ -288,7 +289,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
chatId,
|
||||
responseChatItemId,
|
||||
runtimeNodes,
|
||||
runtimeEdges: initWorkflowEdgeStatus(edges, newHistories),
|
||||
runtimeEdges: initWorkflowEdgeStatus(edges, interactive),
|
||||
variables,
|
||||
query: removeEmptyUserInput(userQuestion.value),
|
||||
chatConfig,
|
||||
|
||||
@@ -139,7 +139,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
// Computed start hook params
|
||||
const startHookText = (() => {
|
||||
// Chat
|
||||
const userQuestion = chatMessages[chatMessages.length - 1] as UserChatItemType | undefined;
|
||||
const userQuestion = chatMessages[chatMessages.length - 1] as UserChatItemType;
|
||||
if (userQuestion) return chatValue2RuntimePrompt(userQuestion.value).text;
|
||||
|
||||
// plugin
|
||||
@@ -245,16 +245,16 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
// Get chat histories
|
||||
const newHistories = concatHistories(histories, chatMessages);
|
||||
|
||||
const interactive = getLastInteractiveValue(newHistories) || undefined;
|
||||
// Get runtimeNodes
|
||||
let runtimeNodes = storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes, newHistories));
|
||||
let runtimeNodes = storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes, interactive));
|
||||
if (isPlugin) {
|
||||
// Assign values to runtimeNodes using variables
|
||||
runtimeNodes = updatePluginInputByVariables(runtimeNodes, variables);
|
||||
// Plugin runtime does not need global variables(It has been injected into the pluginInputNode)
|
||||
variables = {};
|
||||
}
|
||||
runtimeNodes = rewriteNodeOutputByHistories(newHistories, runtimeNodes);
|
||||
runtimeNodes = rewriteNodeOutputByHistories(runtimeNodes, interactive);
|
||||
|
||||
const workflowResponseWrite = getWorkflowResponseWrite({
|
||||
res,
|
||||
@@ -288,15 +288,17 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
chatId,
|
||||
responseChatItemId,
|
||||
runtimeNodes,
|
||||
runtimeEdges: initWorkflowEdgeStatus(edges, newHistories),
|
||||
runtimeEdges: initWorkflowEdgeStatus(edges, interactive),
|
||||
variables,
|
||||
query: removeEmptyUserInput(userQuestion.value),
|
||||
lastInteractive: interactive,
|
||||
chatConfig,
|
||||
histories: newHistories,
|
||||
stream,
|
||||
maxRunTimes: WORKFLOW_MAX_RUN_TIMES,
|
||||
workflowStreamResponse: workflowResponseWrite,
|
||||
version: 'v2'
|
||||
version: 'v2',
|
||||
responseDetail
|
||||
});
|
||||
}
|
||||
return Promise.reject('您的工作流版本过低,请重新发布一次');
|
||||
|
||||
@@ -31,6 +31,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import TemplateMarketModal from '@/pageComponents/app/list/TemplateMarketModal';
|
||||
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
|
||||
import JsonImportModal from '@/pageComponents/app/list/JsonImportModal';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
|
||||
const CreateModal = dynamic(() => import('@/pageComponents/app/list/CreateModal'));
|
||||
const EditFolderModal = dynamic(
|
||||
@@ -213,7 +214,7 @@ const MyApps = () => {
|
||||
|
||||
{(folderDetail
|
||||
? folderDetail.permission.hasWritePer && folderDetail?.type !== AppTypeEnum.httpPlugin
|
||||
: userInfo?.team.permission.hasWritePer) && (
|
||||
: userInfo?.team.permission.hasAppCreatePer) && (
|
||||
<MyMenu
|
||||
size="md"
|
||||
Button={
|
||||
@@ -327,7 +328,7 @@ const MyApps = () => {
|
||||
}: {
|
||||
members?: string[];
|
||||
groups?: string[];
|
||||
permission: number;
|
||||
permission: PermissionValueType;
|
||||
}) => {
|
||||
return postUpdateAppCollaborators({
|
||||
members,
|
||||
|
||||
@@ -29,6 +29,7 @@ import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
|
||||
const EditFolderModal = dynamic(
|
||||
() => import('@fastgpt/web/components/common/MyModal/EditFolderModal')
|
||||
@@ -138,7 +139,7 @@ const Dataset = () => {
|
||||
|
||||
{(folderDetail
|
||||
? folderDetail.permission.hasWritePer
|
||||
: userInfo?.team?.permission.hasWritePer) && (
|
||||
: userInfo?.team?.permission.hasDatasetCreatePer) && (
|
||||
<Box pl={[0, 4]}>
|
||||
<MyMenu
|
||||
size="md"
|
||||
@@ -248,7 +249,7 @@ const Dataset = () => {
|
||||
}: {
|
||||
members?: string[];
|
||||
groups?: string[];
|
||||
permission: number;
|
||||
permission: PermissionValueType;
|
||||
}) =>
|
||||
postUpdateDatasetCollaborators({
|
||||
members,
|
||||
|
||||
@@ -33,9 +33,21 @@ const reduceQueue = () => {
|
||||
|
||||
return global.qaQueueLen === 0;
|
||||
};
|
||||
const reduceQueueAndReturn = (delay = 0) => {
|
||||
reduceQueue();
|
||||
if (delay) {
|
||||
setTimeout(() => {
|
||||
generateQA();
|
||||
}, delay);
|
||||
} else {
|
||||
generateQA();
|
||||
}
|
||||
};
|
||||
|
||||
export async function generateQA(): Promise<any> {
|
||||
const max = global.systemEnv?.qaMaxProcess || 10;
|
||||
addLog.debug(`[QA Queue] Queue size: ${global.qaQueueLen}`);
|
||||
|
||||
if (global.qaQueueLen >= max) return;
|
||||
global.qaQueueLen++;
|
||||
|
||||
@@ -98,14 +110,12 @@ export async function generateQA(): Promise<any> {
|
||||
return;
|
||||
}
|
||||
if (error) {
|
||||
reduceQueue();
|
||||
return generateQA();
|
||||
return reduceQueueAndReturn();
|
||||
}
|
||||
|
||||
// auth balance
|
||||
if (!(await checkTeamAiPointsAndLock(data.teamId))) {
|
||||
reduceQueue();
|
||||
return generateQA();
|
||||
return reduceQueueAndReturn();
|
||||
}
|
||||
addLog.info(`[QA Queue] Start`);
|
||||
|
||||
@@ -137,14 +147,8 @@ ${replaceVariable(Prompt_AgentQA.fixedText, { text })}`;
|
||||
|
||||
const qaArr = formatSplitText({ answer, rawText: text, llmModel: modelData }); // 格式化后的QA对
|
||||
|
||||
addLog.info(`[QA Queue] Finish`, {
|
||||
time: Date.now() - startTime,
|
||||
splitLength: qaArr.length,
|
||||
usage: chatResponse.usage
|
||||
});
|
||||
|
||||
// get vector and insert
|
||||
const { insertLen } = await pushDataListToTrainingQueueByCollectionId({
|
||||
await pushDataListToTrainingQueueByCollectionId({
|
||||
teamId: data.teamId,
|
||||
tmbId: data.tmbId,
|
||||
collectionId: data.collectionId,
|
||||
@@ -160,21 +164,21 @@ ${replaceVariable(Prompt_AgentQA.fixedText, { text })}`;
|
||||
await MongoDatasetTraining.findByIdAndDelete(data._id);
|
||||
|
||||
// add bill
|
||||
if (insertLen > 0) {
|
||||
pushQAUsage({
|
||||
teamId: data.teamId,
|
||||
tmbId: data.tmbId,
|
||||
inputTokens: await countGptMessagesTokens(messages),
|
||||
outputTokens: await countPromptTokens(answer),
|
||||
billId: data.billId,
|
||||
model: modelData.model
|
||||
});
|
||||
} else {
|
||||
addLog.info(`QA result 0:`, { answer });
|
||||
}
|
||||
pushQAUsage({
|
||||
teamId: data.teamId,
|
||||
tmbId: data.tmbId,
|
||||
inputTokens: await countGptMessagesTokens(messages),
|
||||
outputTokens: await countPromptTokens(answer),
|
||||
billId: data.billId,
|
||||
model: modelData.model
|
||||
});
|
||||
addLog.info(`[QA Queue] Finish`, {
|
||||
time: Date.now() - startTime,
|
||||
splitLength: qaArr.length,
|
||||
usage: chatResponse.usage
|
||||
});
|
||||
|
||||
reduceQueue();
|
||||
generateQA();
|
||||
return reduceQueueAndReturn();
|
||||
} catch (err: any) {
|
||||
addLog.error(`[QA Queue] Error`, err);
|
||||
await MongoDatasetTraining.updateOne(
|
||||
@@ -188,9 +192,7 @@ ${replaceVariable(Prompt_AgentQA.fixedText, { text })}`;
|
||||
}
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
generateQA();
|
||||
}, 1000);
|
||||
return reduceQueueAndReturn(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ const reduceQueueAndReturn = (delay = 0) => {
|
||||
/* 索引生成队列。每导入一次,就是一个单独的线程 */
|
||||
export async function generateVector(): Promise<any> {
|
||||
const max = global.systemEnv?.vectorMaxProcess || 10;
|
||||
addLog.debug(`[Vector Queue] Queue size: ${global.vectorQueueLen}`);
|
||||
|
||||
if (global.vectorQueueLen >= max) return;
|
||||
global.vectorQueueLen++;
|
||||
const start = Date.now();
|
||||
|
||||
@@ -5,5 +5,21 @@ export enum LoginPageTypeEnum {
|
||||
wechat = 'wechat'
|
||||
}
|
||||
|
||||
export const PasswordRule =
|
||||
/^(?:(?=.*\d)(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])|(?=.*\d)(?=.*[!@#$%^&*_])|(?=.*[a-z])(?=.*[A-Z])|(?=.*[a-z])(?=.*[!@#$%^&*_])|(?=.*[A-Z])(?=.*[!@#$%^&*_]))[\dA-Za-z!@#$%^&*_]{6,}$/;
|
||||
export const checkPasswordRule = (password: string) => {
|
||||
const patterns = [
|
||||
/\d/, // Contains digits
|
||||
/[a-z]/, // Contains lowercase letters
|
||||
/[A-Z]/, // Contains uppercase letters
|
||||
/[!@#$%^&*()_+=-]/ // Contains special characters
|
||||
];
|
||||
const validChars = /^[\dA-Za-z!@#$%^&*()_+=-]{6,100}$/;
|
||||
|
||||
// Check length and valid characters
|
||||
if (!validChars.test(password)) return false;
|
||||
|
||||
// Count how many patterns are satisfied
|
||||
const matchCount = patterns.filter((pattern) => pattern.test(password)).length;
|
||||
|
||||
// Must satisfy at least 2 patterns
|
||||
return matchCount >= 2;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { GET, POST, PUT } from '@/web/common/api/request';
|
||||
import type { PaginationProps, PaginationResponse } from '@fastgpt/web/common/fetch/type';
|
||||
import type { OperationListItemType } from '@fastgpt/global/support/operationLog/type';
|
||||
|
||||
export const getOperationLogs = (props: PaginationProps<PaginationProps>) =>
|
||||
POST<PaginationResponse<OperationListItemType>>(
|
||||
`/proApi/support/user/team/operationLog/list`,
|
||||
props
|
||||
);
|
||||
57
projects/app/test/api/core/app/create.test.ts
Normal file
57
projects/app/test/api/core/app/create.test.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import * as createapi from '@/pages/api/core/app/create';
|
||||
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
|
||||
import { getFakeUsers } from '@test/datas/users';
|
||||
import { Call } from '@test/utils/request';
|
||||
import { expect, it, describe } from 'vitest';
|
||||
|
||||
describe('create api', () => {
|
||||
it('should return 200 when create app success', async () => {
|
||||
const users = await getFakeUsers(2);
|
||||
await MongoResourcePermission.create({
|
||||
resourceType: 'team',
|
||||
teamId: users.members[0].teamId,
|
||||
resourceId: null,
|
||||
tmbId: users.members[0].tmbId,
|
||||
permission: TeamAppCreatePermissionVal
|
||||
});
|
||||
const res = await Call<createapi.CreateAppBody, {}, {}>(createapi.default, {
|
||||
auth: users.members[0],
|
||||
body: {
|
||||
modules: [],
|
||||
name: 'testfolder',
|
||||
type: AppTypeEnum.folder
|
||||
}
|
||||
});
|
||||
expect(res.error).toBeUndefined();
|
||||
expect(res.code).toBe(200);
|
||||
const folderId = res.data as string;
|
||||
|
||||
const res2 = await Call<createapi.CreateAppBody, {}, {}>(createapi.default, {
|
||||
auth: users.members[0],
|
||||
body: {
|
||||
modules: [],
|
||||
name: 'testapp',
|
||||
type: AppTypeEnum.simple,
|
||||
parentId: String(folderId)
|
||||
}
|
||||
});
|
||||
expect(res2.error).toBeUndefined();
|
||||
expect(res2.code).toBe(200);
|
||||
expect(res2.data).toBeDefined();
|
||||
|
||||
const res3 = await Call<createapi.CreateAppBody, {}, {}>(createapi.default, {
|
||||
auth: users.members[1],
|
||||
body: {
|
||||
modules: [],
|
||||
name: 'testapp',
|
||||
type: AppTypeEnum.simple,
|
||||
parentId: String(folderId)
|
||||
}
|
||||
});
|
||||
expect(res3.error).toBe(AppErrEnum.unAuthApp);
|
||||
expect(res3.code).toBe(500);
|
||||
});
|
||||
});
|
||||
54
projects/app/test/api/core/dataset/create.test.ts
Normal file
54
projects/app/test/api/core/dataset/create.test.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import * as createapi from '@/pages/api/core/dataset/create';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { TeamDatasetCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
|
||||
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
|
||||
import { getFakeUsers } from '@test/datas/users';
|
||||
import { Call } from '@test/utils/request';
|
||||
import { vi, describe, it, expect } from 'vitest';
|
||||
|
||||
describe('create dataset', () => {
|
||||
it('should return 200 when create dataset success', async () => {
|
||||
const users = await getFakeUsers(2);
|
||||
await MongoResourcePermission.create({
|
||||
resourceType: 'team',
|
||||
teamId: users.members[0].teamId,
|
||||
resourceId: null,
|
||||
tmbId: users.members[0].tmbId,
|
||||
permission: TeamDatasetCreatePermissionVal
|
||||
});
|
||||
const res = await Call<
|
||||
createapi.DatasetCreateBody,
|
||||
createapi.DatasetCreateQuery,
|
||||
createapi.DatasetCreateResponse
|
||||
>(createapi.default, {
|
||||
auth: users.members[0],
|
||||
body: {
|
||||
name: 'folder',
|
||||
intro: 'intro',
|
||||
avatar: 'avatar',
|
||||
type: DatasetTypeEnum.folder
|
||||
}
|
||||
});
|
||||
expect(res.error).toBeUndefined();
|
||||
expect(res.code).toBe(200);
|
||||
const folderId = res.data as string;
|
||||
|
||||
const res2 = await Call<
|
||||
createapi.DatasetCreateBody,
|
||||
createapi.DatasetCreateQuery,
|
||||
createapi.DatasetCreateResponse
|
||||
>(createapi.default, {
|
||||
auth: users.members[0],
|
||||
body: {
|
||||
name: 'test',
|
||||
intro: 'intro',
|
||||
avatar: 'avatar',
|
||||
type: DatasetTypeEnum.dataset,
|
||||
parentId: folderId
|
||||
}
|
||||
});
|
||||
|
||||
expect(res2.error).toBeUndefined();
|
||||
expect(res2.code).toBe(200);
|
||||
});
|
||||
});
|
||||
64
projects/app/test/api/support/openapi/create.test.ts
Normal file
64
projects/app/test/api/support/openapi/create.test.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { EditApiKeyProps } from '@/global/support/openapi/api';
|
||||
import * as createapi from '@/pages/api/support/openapi/create';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import {
|
||||
TeamApikeyCreatePermissionVal,
|
||||
TeamDatasetCreatePermissionVal
|
||||
} from '@fastgpt/global/support/permission/user/constant';
|
||||
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
|
||||
import { getFakeUsers } from '@test/datas/users';
|
||||
import { Call } from '@test/utils/request';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
describe('create dataset', () => {
|
||||
it('should return 200 when create dataset success', async () => {
|
||||
const users = await getFakeUsers(2);
|
||||
await MongoResourcePermission.create({
|
||||
resourceType: 'team',
|
||||
teamId: users.members[0].teamId,
|
||||
resourceId: null,
|
||||
tmbId: users.members[0].tmbId,
|
||||
permission: TeamApikeyCreatePermissionVal
|
||||
});
|
||||
const res = await Call<EditApiKeyProps>(createapi.default, {
|
||||
auth: users.members[0],
|
||||
body: {
|
||||
name: 'test',
|
||||
limit: {
|
||||
maxUsagePoints: 1000
|
||||
}
|
||||
}
|
||||
});
|
||||
expect(res.error).toBeUndefined();
|
||||
expect(res.code).toBe(200);
|
||||
|
||||
await MongoResourcePermission.create({
|
||||
resourceType: 'app',
|
||||
teamId: users.members[1].teamId,
|
||||
resourceId: null,
|
||||
tmbId: users.members[1].tmbId,
|
||||
permission: ManagePermissionVal
|
||||
});
|
||||
|
||||
const app = await MongoApp.create({
|
||||
name: 'a',
|
||||
type: 'simple',
|
||||
tmbId: users.members[1].tmbId,
|
||||
teamId: users.members[1].teamId
|
||||
});
|
||||
const res2 = await Call<EditApiKeyProps>(createapi.default, {
|
||||
auth: users.members[1],
|
||||
body: {
|
||||
appId: app._id,
|
||||
name: 'test',
|
||||
limit: {
|
||||
maxUsagePoints: 1000
|
||||
}
|
||||
}
|
||||
});
|
||||
expect(res2.error).toBeUndefined();
|
||||
expect(res2.code).toBe(200);
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user