Compare commits
19 Commits
test-openG
...
test-gate
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
361e255af8 | ||
|
|
2b888fb0fa | ||
|
|
2128d306ad | ||
|
|
e59816aba4 | ||
|
|
ded0383ac4 | ||
|
|
81202c53a8 | ||
|
|
e74ab643fe | ||
|
|
3b0f0a8108 | ||
|
|
165b783a95 | ||
|
|
d7b9f94270 | ||
|
|
5a5367d30b | ||
|
|
8ed35ffe7e | ||
|
|
0f866fc552 | ||
|
|
05c7ba4483 | ||
|
|
fa80ce3a77 | ||
|
|
830358aa72 | ||
|
|
02b214b3ec | ||
|
|
a171c7b11c | ||
|
|
802de11363 |
3
.vscode/settings.json
vendored
@@ -27,5 +27,8 @@
|
||||
},
|
||||
"markdown.copyFiles.destination": {
|
||||
"/docSite/content/**/*": "${documentWorkspaceFolder}/docSite/assets/imgs/"
|
||||
},
|
||||
"[svg]": {
|
||||
"editor.defaultFormatter": "jock.svg"
|
||||
}
|
||||
}
|
||||
@@ -132,15 +132,15 @@ services:
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
|
||||
ports:
|
||||
- 3005:3000
|
||||
networks:
|
||||
@@ -150,8 +150,8 @@ services:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -109,15 +109,15 @@ services:
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
|
||||
ports:
|
||||
- 3005:3000
|
||||
networks:
|
||||
@@ -127,8 +127,8 @@ services:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -1,218 +0,0 @@
|
||||
# 数据库的默认账号和密码仅首次运行时设置有效
|
||||
# 如果修改了账号密码,记得改数据库和项目连接参数,别只改一处~
|
||||
# 该配置文件只是给快速启动,测试使用。正式使用,记得务必修改账号密码,以及调整合适的知识库参数,共享内存等。
|
||||
# 如何无法访问 dockerhub 和 git,可以用阿里云(阿里云没有arm包)
|
||||
|
||||
version: '3.3'
|
||||
services:
|
||||
# db
|
||||
gs:
|
||||
image: opengauss/opengauss:7.0.0-RC1 # docker hub
|
||||
container_name: gs
|
||||
restart: always
|
||||
# ports: # 生产环境建议不要暴露
|
||||
# - 5432:5432
|
||||
networks:
|
||||
- fastgpt
|
||||
environment:
|
||||
# 这里的配置只有首次运行生效。修改后,重启镜像是不会生效的。需要把持久化数据删除再重启,才有效果
|
||||
- GS_USER=username
|
||||
- GS_PASSWORD=password
|
||||
- GS_DB=postgres
|
||||
volumes:
|
||||
- ./opengauss/data:/var/lib/opengauss/data
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'netstat -lntp | grep tcp6 > /dev/null 2>&1']
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
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 $$!
|
||||
|
||||
redis:
|
||||
image: redis:7.2-alpine
|
||||
container_name: redis
|
||||
# ports:
|
||||
# - 6379:6379
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
command: |
|
||||
redis-server --requirepass mypassword --loglevel warning --maxclients 10000 --appendonly yes --save 60 10 --maxmemory 4gb --maxmemory-policy noeviction
|
||||
healthcheck:
|
||||
test: ['CMD', 'redis-cli', '-a', 'mypassword', 'ping']
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
volumes:
|
||||
- ./redis/data:/data
|
||||
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.7-fix2 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.7-fix2 # 阿里云
|
||||
ports:
|
||||
- 3005:3000
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.7-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.7-fix2 # 阿里云
|
||||
# image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/labring/fastgpt:v4.8.4-linuxarm64 # openGauss在arm架构上性能更好
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
- fastgpt
|
||||
depends_on:
|
||||
- mongo
|
||||
- gs
|
||||
- sandbox
|
||||
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
|
||||
# 数据库最大连接数
|
||||
- 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
|
||||
# openGauss 连接参数
|
||||
- OPENGAUSS_URL=opengauss://gaussdb:Huawei12%23%24@gs:9999/test
|
||||
# Redis 连接参数
|
||||
- REDIS_URL=redis://default:mypassword@redis:6379
|
||||
# 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
|
||||
# 对话文件过期天数
|
||||
- CHAT_FILE_EXPIRE_TIME=7
|
||||
volumes:
|
||||
- ./config.json:/app/data/config.json
|
||||
|
||||
# AI Proxy
|
||||
aiproxy:
|
||||
image: ghcr.io/labring/aiproxy:v0.1.7
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/labring/aiproxy:v0.1.7 # 阿里云
|
||||
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:
|
||||
@@ -96,15 +96,15 @@ services:
|
||||
# fastgpt
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
|
||||
ports:
|
||||
- 3005:3000
|
||||
networks:
|
||||
@@ -114,8 +114,8 @@ services:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -72,15 +72,15 @@ services:
|
||||
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.9.10-fix2 # 阿里云
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.9.10-fix2 # 阿里云
|
||||
ports:
|
||||
- 3005:3000
|
||||
networks:
|
||||
@@ -90,8 +90,8 @@ services:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.9.10 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10 # 阿里云
|
||||
image: ghcr.io/labring/fastgpt:v4.9.10-fix2 # git
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.9.10-fix2 # 阿里云
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
||||
@@ -645,7 +645,7 @@ data 为集合的 ID。
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
### 创建一个外部文件库集合(商业版)
|
||||
### 创建一个外部文件库集合(弃用)
|
||||
|
||||
{{< tabs tabTotal="3" >}}
|
||||
{{< tab tabName="请求示例" >}}
|
||||
|
||||
@@ -15,8 +15,8 @@ weight: 790
|
||||
|
||||
### 2. 更新镜像 tag
|
||||
|
||||
- 更新 FastGPT 镜像 tag: v4.9.10
|
||||
- 更新 FastGPT 商业版镜像 tag: v4.9.10
|
||||
- 更新 FastGPT 镜像 tag: v4.9.10-fix2
|
||||
- 更新 FastGPT 商业版镜像 tag: v4.9.10-fix2
|
||||
- mcp_server 无需更新
|
||||
- Sandbox 无需更新
|
||||
- AIProxy 无需更新
|
||||
|
||||
@@ -10,12 +10,16 @@ weight: 789
|
||||
|
||||
## 🚀 新增内容
|
||||
|
||||
1. 工作流中,子流程版本控制,可选择“保持最新版本”,无需手动更新。
|
||||
1. 工作流中增加节点搜索功能。
|
||||
2. 工作流中,子流程版本控制,可选择“保持最新版本”,无需手动更新。
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
|
||||
1. 原文缓存改用 gridfs 存储,提高上限。
|
||||
|
||||
## 🐛 修复
|
||||
|
||||
1. 工作流中,管理员声明的全局系统工具,无法进行版本管理。
|
||||
2. 工具调用节点前,有交互节点时,上下文异常。
|
||||
3. 修复备份导入,小于 1000 字时,无法分块问题。
|
||||
4. 自定义 PDF 解析,无法保存 base64 图片。
|
||||
1
env.d.ts
vendored
@@ -15,7 +15,6 @@ declare global {
|
||||
MONGODB_LOG_URI?: string;
|
||||
PG_URL: string;
|
||||
OCEANBASE_URL: string;
|
||||
OPENGAUSS_URL: string;
|
||||
MILVUS_ADDRESS: string;
|
||||
MILVUS_TOKEN: string;
|
||||
SANDBOX_URL: string;
|
||||
|
||||
@@ -4,6 +4,9 @@ import { type ErrType } from '../errorCode';
|
||||
/* dataset: 507000 */
|
||||
const startCode = 507000;
|
||||
export enum CommonErrEnum {
|
||||
methodNotAllowed = 'methodNotAllowed',
|
||||
systemError = 'systemError',
|
||||
unauthorized = 'unauthorized',
|
||||
invalidParams = 'invalidParams',
|
||||
invalidResource = 'invalidResource',
|
||||
fileNotFound = 'fileNotFound',
|
||||
@@ -35,6 +38,22 @@ const datasetErr = [
|
||||
{
|
||||
statusText: CommonErrEnum.inheritPermissionError,
|
||||
message: 'error.inheritPermissionError'
|
||||
},
|
||||
{
|
||||
statusText: CommonErrEnum.methodNotAllowed,
|
||||
message: i18nT('common:code_error.error_message.405')
|
||||
},
|
||||
{
|
||||
statusText: CommonErrEnum.systemError,
|
||||
message: i18nT('common:code_error.error_message.500')
|
||||
},
|
||||
{
|
||||
statusText: CommonErrEnum.unauthorized,
|
||||
message: i18nT('common:code_error.error_message.403')
|
||||
},
|
||||
{
|
||||
statusText: CommonErrEnum.invalidParams,
|
||||
message: i18nT('common:code_error.error_message.422')
|
||||
}
|
||||
];
|
||||
export default datasetErr.reduce((acc, cur, index) => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from './type';
|
||||
|
||||
export enum AppTypeEnum {
|
||||
gate = 'gate',
|
||||
folder = 'folder',
|
||||
simple = 'simple',
|
||||
workflow = 'advanced',
|
||||
|
||||
24
packages/global/core/app/tags.d.ts
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import { TeamMemberStatusEnum } from 'support/user/team/constant';
|
||||
import type { SourceMemberType } from 'support/user/type';
|
||||
|
||||
export type TagSchemaType = {
|
||||
_id: string;
|
||||
teamId: string;
|
||||
name: string;
|
||||
color: string;
|
||||
createTime: Date;
|
||||
};
|
||||
|
||||
export type TagWithCountType = TagSchemaType & {
|
||||
count: number;
|
||||
};
|
||||
|
||||
export type TagListItemType = {
|
||||
_id: string;
|
||||
teamId: string;
|
||||
name: string;
|
||||
color: string;
|
||||
createTime: Date;
|
||||
count?: number;
|
||||
sourceMember?: SourceMemberType;
|
||||
};
|
||||
1
packages/global/core/app/type.d.ts
vendored
@@ -65,6 +65,7 @@ export type AppListItemType = {
|
||||
inheritPermission?: boolean;
|
||||
private?: boolean;
|
||||
sourceMember: SourceMemberType;
|
||||
tags?: string[];
|
||||
};
|
||||
|
||||
export type AppDetailType = AppSchema & {
|
||||
|
||||
@@ -46,7 +46,7 @@ export const appWorkflow2Form = ({
|
||||
chatConfig
|
||||
}: {
|
||||
nodes: StoreNodeItemType[];
|
||||
chatConfig: AppChatConfigType;
|
||||
chatConfig?: AppChatConfigType;
|
||||
}) => {
|
||||
const defaultAppForm = getDefaultAppForm();
|
||||
const findInputValueByKey = (inputs: FlowNodeInputItemType[], key: string) => {
|
||||
@@ -172,6 +172,10 @@ export const appWorkflow2Form = ({
|
||||
}
|
||||
});
|
||||
|
||||
if (chatConfig) {
|
||||
defaultAppForm.chatConfig = chatConfig;
|
||||
}
|
||||
|
||||
return defaultAppForm;
|
||||
};
|
||||
|
||||
|
||||
7
packages/global/core/dataset/api.d.ts
vendored
@@ -124,13 +124,6 @@ export type PgSearchRawType = {
|
||||
collection_id: string;
|
||||
score: number;
|
||||
};
|
||||
|
||||
export type GsSearchRawType = {
|
||||
id: string;
|
||||
collection_id: string;
|
||||
score: number;
|
||||
};
|
||||
|
||||
export type PushDatasetDataChunkProps = {
|
||||
q: string; // embedding content
|
||||
a?: string; // bonus content
|
||||
|
||||
@@ -40,5 +40,6 @@ export function getSourceNameIcon({
|
||||
export const predictDataLimitLength = (mode: TrainingModeEnum, data: any[]) => {
|
||||
if (mode === TrainingModeEnum.qa) return data.length * 20;
|
||||
if (mode === TrainingModeEnum.auto) return data.length * 5;
|
||||
if (mode === TrainingModeEnum.image) return data.length * 2;
|
||||
return data.length;
|
||||
};
|
||||
|
||||
1
packages/global/core/workflow/type/node.d.ts
vendored
@@ -125,6 +125,7 @@ export type FlowNodeItemType = FlowNodeTemplateType & {
|
||||
nodeId: string;
|
||||
parentNodeId?: string;
|
||||
isError?: boolean;
|
||||
searchedText?: string;
|
||||
debugResult?: {
|
||||
status: 'running' | 'success' | 'skipped' | 'failed';
|
||||
message?: string;
|
||||
|
||||
@@ -2,7 +2,18 @@ import { NullPermission, PermissionKeyEnum, PermissionList } from '../constant';
|
||||
import { type PermissionListType } from '../type';
|
||||
import { i18nT } from '../../../../web/i18n/utils';
|
||||
export enum AppPermissionKeyEnum {}
|
||||
export const AppPermissionList: PermissionListType = {
|
||||
|
||||
export enum AppPermissionKeyEnum {
|
||||
log = 'log',
|
||||
quickGate = 'quickGate',
|
||||
featuredGate = 'featuredGate'
|
||||
}
|
||||
|
||||
export const AppLogPermission = 0b100000;
|
||||
export const GateQuickAppPermission = 0b001100;
|
||||
export const GateFeaturedAppPermission = 0b010100;
|
||||
|
||||
export const AppPermissionList: PermissionListType<AppPermissionKeyEnum> = {
|
||||
[PermissionKeyEnum.read]: {
|
||||
...PermissionList[PermissionKeyEnum.read],
|
||||
description: i18nT('app:permission.des.read')
|
||||
@@ -13,8 +24,28 @@ export const AppPermissionList: PermissionListType = {
|
||||
},
|
||||
[PermissionKeyEnum.manage]: {
|
||||
...PermissionList[PermissionKeyEnum.manage],
|
||||
value: 0b111111,
|
||||
description: i18nT('app:permission.des.manage')
|
||||
},
|
||||
[AppPermissionKeyEnum.log]: {
|
||||
name: i18nT('app:permission.name.log'),
|
||||
value: AppLogPermission,
|
||||
checkBoxType: 'multiple',
|
||||
description: i18nT('app:permission.des.log')
|
||||
},
|
||||
[AppPermissionKeyEnum.quickGate]: {
|
||||
name: '门户快捷应用权限',
|
||||
description: '',
|
||||
value: GateQuickAppPermission,
|
||||
checkBoxType: 'hiden'
|
||||
},
|
||||
[AppPermissionKeyEnum.featuredGate]: {
|
||||
name: '门户推荐应用权限',
|
||||
description: '',
|
||||
value: GateFeaturedAppPermission,
|
||||
checkBoxType: 'hiden'
|
||||
}
|
||||
};
|
||||
|
||||
export const AppDefaultPermissionVal = NullPermission;
|
||||
export const AppLogPermissionVal = AppPermissionList[AppPermissionKeyEnum.log].value;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { type PerConstructPros, Permission } from '../controller';
|
||||
import { AppDefaultPermissionVal } from './constant';
|
||||
import { AppDefaultPermissionVal, AppPermissionList } from './constant';
|
||||
|
||||
export class AppPermission extends Permission {
|
||||
hasLogPer: boolean = false;
|
||||
constructor(props?: PerConstructPros) {
|
||||
if (!props) {
|
||||
props = {
|
||||
@@ -10,6 +11,13 @@ export class AppPermission extends Permission {
|
||||
} else if (!props?.per) {
|
||||
props.per = AppDefaultPermissionVal;
|
||||
}
|
||||
props.permissionList = AppPermissionList;
|
||||
super(props);
|
||||
this.setUpdatePermissionCallback(() => {
|
||||
this.hasReadPer = this.checkPer(AppPermissionList.read.value);
|
||||
this.hasWritePer = this.checkPer(AppPermissionList.write.value);
|
||||
this.hasManagePer = this.checkPer(AppPermissionList.manage.value);
|
||||
this.hasLogPer = this.checkPer(AppPermissionList.log.value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { type PermissionListType, type PermissionValueType } from './type';
|
||||
import { PermissionList, NullPermission, OwnerPermissionVal } from './constant';
|
||||
import {
|
||||
PermissionList,
|
||||
NullPermission,
|
||||
OwnerPermissionVal,
|
||||
ManagePermissionVal
|
||||
} from './constant';
|
||||
|
||||
export type PerConstructPros = {
|
||||
per?: PermissionValueType;
|
||||
@@ -63,6 +68,7 @@ export class Permission {
|
||||
if (perm === OwnerPermissionVal) {
|
||||
return this.value === OwnerPermissionVal;
|
||||
}
|
||||
|
||||
return (this.value & perm) === perm;
|
||||
}
|
||||
|
||||
|
||||
2
packages/global/support/permission/type.d.ts
vendored
@@ -18,7 +18,7 @@ export type PermissionListType<T = {}> = Record<
|
||||
name: string;
|
||||
description: string;
|
||||
value: PermissionValueType;
|
||||
checkBoxType: 'single' | 'multiple';
|
||||
checkBoxType: 'single' | 'multiple' | 'hiden';
|
||||
}
|
||||
>;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export const TeamPermissionList: PermissionListType<TeamPermissionKeyEnum> = {
|
||||
},
|
||||
[PermissionKeyEnum.manage]: {
|
||||
...PermissionList[PermissionKeyEnum.manage],
|
||||
value: 0b000001
|
||||
value: 0b000101
|
||||
},
|
||||
[TeamPermissionKeyEnum.appCreate]: {
|
||||
checkBoxType: 'multiple',
|
||||
|
||||
31
packages/global/support/user/team/gate/api.d.ts
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
export type putUpdateGateConfigData = {
|
||||
status?: boolean;
|
||||
tools?: GateTool[];
|
||||
slogan?: string;
|
||||
placeholderText?: string;
|
||||
};
|
||||
|
||||
export type putUpdateGateConfigResponse = {
|
||||
status?: boolean;
|
||||
tools?: string[];
|
||||
slogan?: string;
|
||||
placeholderText?: string;
|
||||
};
|
||||
|
||||
export type putUpdateGateConfigCopyRightData = {
|
||||
name?: string;
|
||||
logo?: string;
|
||||
banner?: string;
|
||||
};
|
||||
|
||||
export type putUpdateGateConfigCopyRightResponse = {
|
||||
name: string;
|
||||
logo: string;
|
||||
banner: string;
|
||||
};
|
||||
|
||||
export type getGateConfigCopyRightResponse = {
|
||||
name: string;
|
||||
logo: string;
|
||||
banner: string;
|
||||
};
|
||||
12
packages/global/support/user/team/gate/type.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export type GateSchemaType = {
|
||||
teamId: string;
|
||||
status: boolean;
|
||||
tools: string[];
|
||||
featuredApps: string[];
|
||||
quickApps: string[];
|
||||
slogan: string;
|
||||
placeholderText: string;
|
||||
name: string;
|
||||
logo: string;
|
||||
banner: string;
|
||||
};
|
||||
@@ -13,6 +13,7 @@ const staticPluginList = [
|
||||
'WeWorkWebhook',
|
||||
'google',
|
||||
'bing',
|
||||
'bocha',
|
||||
'delay'
|
||||
];
|
||||
// Run in worker thread (Have npm packages)
|
||||
|
||||
604
packages/plugins/src/bocha/template.json
Normal file
@@ -0,0 +1,604 @@
|
||||
{
|
||||
"author": "",
|
||||
"name": "网络搜索",
|
||||
"avatar": "common/searchLight",
|
||||
"intro": "使用博查AI搜索引擎进行网络搜索。",
|
||||
"showStatus": true,
|
||||
"weight": 10,
|
||||
"courseUrl": "",
|
||||
"isTool": true,
|
||||
"templateType": "search",
|
||||
"workflow": {
|
||||
"nodes": [
|
||||
{
|
||||
"nodeId": "pluginInput",
|
||||
"name": "workflow:template.plugin_start",
|
||||
"intro": "workflow:intro_plugin_input",
|
||||
"avatar": "core/workflow/template/workflowStart",
|
||||
"flowNodeType": "pluginInput",
|
||||
"showStatus": false,
|
||||
"position": {
|
||||
"x": 636.3048409085379,
|
||||
"y": -238.61714728578016
|
||||
},
|
||||
"version": "481",
|
||||
"inputs": [
|
||||
{
|
||||
"renderTypeList": ["input"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
"key": "apiKey",
|
||||
"label": "apiKey",
|
||||
"description": "博查API密钥",
|
||||
"defaultValue": "",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"renderTypeList": ["input", "reference"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
"key": "query",
|
||||
"label": "query",
|
||||
"description": "搜索查询词",
|
||||
"defaultValue": "",
|
||||
"required": true,
|
||||
"toolDescription": "搜索查询词"
|
||||
},
|
||||
{
|
||||
"renderTypeList": ["input", "reference"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
"key": "freshness",
|
||||
"label": "freshness",
|
||||
"description": "搜索指定时间范围内的网页。可填值:oneDay(一天内)、oneWeek(一周内)、oneMonth(一个月内)、oneYear(一年内)、noLimit(不限,默认)、YYYY-MM-DD..YYYY-MM-DD(日期范围)、YYYY-MM-DD(指定日期)",
|
||||
"defaultValue": "noLimit",
|
||||
"required": false,
|
||||
"toolDescription": "搜索时间范围"
|
||||
},
|
||||
{
|
||||
"renderTypeList": ["input", "reference"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "boolean",
|
||||
"canEdit": true,
|
||||
"key": "summary",
|
||||
"label": "summary",
|
||||
"description": "是否显示文本摘要。true显示,false不显示(默认)",
|
||||
"defaultValue": false,
|
||||
"required": false,
|
||||
"toolDescription": "是否显示文本摘要"
|
||||
},
|
||||
{
|
||||
"renderTypeList": ["input", "reference"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
"key": "include",
|
||||
"label": "include",
|
||||
"description": "指定搜索的site范围。多个域名使用|或,分隔,最多20个。例如:qq.com|m.163.com",
|
||||
"defaultValue": "",
|
||||
"required": false,
|
||||
"toolDescription": "指定搜索的site范围"
|
||||
},
|
||||
{
|
||||
"renderTypeList": ["input", "reference"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
"key": "exclude",
|
||||
"label": "exclude",
|
||||
"description": "排除搜索的网站范围。多个域名使用|或,分隔,最多20个。例如:qq.com|m.163.com",
|
||||
"defaultValue": "",
|
||||
"required": false,
|
||||
"toolDescription": "排除搜索的网站范围"
|
||||
},
|
||||
{
|
||||
"renderTypeList": ["input", "reference"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "number",
|
||||
"canEdit": true,
|
||||
"key": "count",
|
||||
"label": "count",
|
||||
"description": "返回结果的条数。可填范围:1-50,默认为10",
|
||||
"defaultValue": 10,
|
||||
"required": false,
|
||||
"min": 1,
|
||||
"max": 50,
|
||||
"toolDescription": "返回结果条数"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "apiKey",
|
||||
"valueType": "string",
|
||||
"key": "apiKey",
|
||||
"label": "apiKey",
|
||||
"type": "hidden"
|
||||
},
|
||||
{
|
||||
"id": "query",
|
||||
"valueType": "string",
|
||||
"key": "query",
|
||||
"label": "query",
|
||||
"type": "hidden"
|
||||
},
|
||||
{
|
||||
"id": "freshness",
|
||||
"valueType": "string",
|
||||
"key": "freshness",
|
||||
"label": "freshness",
|
||||
"type": "hidden"
|
||||
},
|
||||
{
|
||||
"id": "summary",
|
||||
"valueType": "boolean",
|
||||
"key": "summary",
|
||||
"label": "summary",
|
||||
"type": "hidden"
|
||||
},
|
||||
{
|
||||
"id": "include",
|
||||
"valueType": "string",
|
||||
"key": "include",
|
||||
"label": "include",
|
||||
"type": "hidden"
|
||||
},
|
||||
{
|
||||
"id": "exclude",
|
||||
"valueType": "string",
|
||||
"key": "exclude",
|
||||
"label": "exclude",
|
||||
"type": "hidden"
|
||||
},
|
||||
{
|
||||
"id": "count",
|
||||
"valueType": "number",
|
||||
"key": "count",
|
||||
"label": "count",
|
||||
"type": "hidden"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeId": "pluginOutput",
|
||||
"name": "common:core.module.template.self_output",
|
||||
"intro": "workflow:intro_custom_plugin_output",
|
||||
"avatar": "core/workflow/template/pluginOutput",
|
||||
"flowNodeType": "pluginOutput",
|
||||
"showStatus": false,
|
||||
"position": {
|
||||
"x": 2764.1105686698083,
|
||||
"y": -30.617147285780163
|
||||
},
|
||||
"version": "481",
|
||||
"inputs": [
|
||||
{
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "object",
|
||||
"canEdit": true,
|
||||
"key": "result",
|
||||
"label": "result",
|
||||
"isToolOutput": true,
|
||||
"description": "",
|
||||
"value": ["nyA6oA8mF1iW", "httpRawResponse"]
|
||||
}
|
||||
],
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"nodeId": "pluginConfig",
|
||||
"name": "common:core.module.template.system_config",
|
||||
"intro": "",
|
||||
"avatar": "core/workflow/template/systemConfig",
|
||||
"flowNodeType": "pluginConfig",
|
||||
"position": {
|
||||
"x": 184.66337662472682,
|
||||
"y": -216.05298493910115
|
||||
},
|
||||
"version": "4811",
|
||||
"inputs": [],
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"nodeId": "nyA6oA8mF1iW",
|
||||
"name": "HTTP 请求",
|
||||
"intro": "调用博查搜索API",
|
||||
"avatar": "core/workflow/template/httpRequest",
|
||||
"flowNodeType": "httpRequest468",
|
||||
"showStatus": true,
|
||||
"position": {
|
||||
"x": 1335.0647252518884,
|
||||
"y": -455.9043948565971
|
||||
},
|
||||
"version": "481",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "system_addInputParam",
|
||||
"renderTypeList": ["addInputParam"],
|
||||
"valueType": "dynamic",
|
||||
"label": "",
|
||||
"required": false,
|
||||
"description": "common:core.module.input.description.HTTP Dynamic Input",
|
||||
"customInputConfig": {
|
||||
"selectValueTypeList": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"object",
|
||||
"arrayString",
|
||||
"arrayNumber",
|
||||
"arrayBoolean",
|
||||
"arrayObject",
|
||||
"arrayAny",
|
||||
"any",
|
||||
"chatHistory",
|
||||
"datasetQuote",
|
||||
"dynamic",
|
||||
"selectDataset",
|
||||
"selectApp"
|
||||
],
|
||||
"showDescription": false,
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpMethod",
|
||||
"renderTypeList": ["custom"],
|
||||
"valueType": "string",
|
||||
"label": "",
|
||||
"value": "POST",
|
||||
"required": true,
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpTimeout",
|
||||
"renderTypeList": ["custom"],
|
||||
"valueType": "number",
|
||||
"label": "",
|
||||
"value": 30,
|
||||
"min": 5,
|
||||
"max": 600,
|
||||
"required": true,
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpReqUrl",
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "string",
|
||||
"label": "",
|
||||
"description": "common:core.module.input.description.Http Request Url",
|
||||
"placeholder": "https://api.ai.com/getInventory",
|
||||
"required": false,
|
||||
"value": "https://api.bochaai.com/v1/web-search",
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpHeader",
|
||||
"renderTypeList": ["custom"],
|
||||
"valueType": "any",
|
||||
"value": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"type": "string",
|
||||
"value": "Bearer {{$pluginInput.apiKey$}}"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"type": "string",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"label": "",
|
||||
"description": "common:core.module.input.description.Http Request Header",
|
||||
"placeholder": "common:core.module.input.description.Http Request Header",
|
||||
"required": false,
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpParams",
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "any",
|
||||
"value": [],
|
||||
"label": "",
|
||||
"required": false,
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpJsonBody",
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "any",
|
||||
"value": "{\n \"query\": \"{{query}}\",\n \"freshness\": \"{{freshness}}\",\n \"summary\": {{summary}},\n \"include\": \"{{include}}\",\n \"exclude\": \"{{exclude}}\",\n \"count\": {{count}}\n}",
|
||||
"label": "",
|
||||
"required": false,
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpFormBody",
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "any",
|
||||
"value": [],
|
||||
"label": "",
|
||||
"required": false,
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"key": "system_httpContentType",
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "string",
|
||||
"value": "json",
|
||||
"label": "",
|
||||
"required": false,
|
||||
"debugLabel": "",
|
||||
"toolDescription": ""
|
||||
},
|
||||
{
|
||||
"valueType": "string",
|
||||
"renderTypeList": ["reference"],
|
||||
"key": "query",
|
||||
"label": "query",
|
||||
"toolDescription": "博查搜索检索词",
|
||||
"required": true,
|
||||
"canEdit": true,
|
||||
"editField": {
|
||||
"key": true,
|
||||
"description": true
|
||||
},
|
||||
"customInputConfig": {
|
||||
"selectValueTypeList": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"object",
|
||||
"arrayString",
|
||||
"arrayNumber",
|
||||
"arrayBoolean",
|
||||
"arrayObject",
|
||||
"arrayAny",
|
||||
"any",
|
||||
"chatHistory",
|
||||
"datasetQuote",
|
||||
"dynamic",
|
||||
"selectApp",
|
||||
"selectDataset"
|
||||
],
|
||||
"showDescription": false,
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"value": ["pluginInput", "query"]
|
||||
},
|
||||
{
|
||||
"valueType": "string",
|
||||
"renderTypeList": ["reference"],
|
||||
"key": "freshness",
|
||||
"label": "freshness",
|
||||
"toolDescription": "搜索时间范围",
|
||||
"required": false,
|
||||
"canEdit": true,
|
||||
"editField": {
|
||||
"key": true,
|
||||
"description": true
|
||||
},
|
||||
"customInputConfig": {
|
||||
"selectValueTypeList": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"object",
|
||||
"arrayString",
|
||||
"arrayNumber",
|
||||
"arrayBoolean",
|
||||
"arrayObject",
|
||||
"arrayAny",
|
||||
"any",
|
||||
"chatHistory",
|
||||
"datasetQuote",
|
||||
"dynamic",
|
||||
"selectApp",
|
||||
"selectDataset"
|
||||
],
|
||||
"showDescription": false,
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"value": ["pluginInput", "freshness"]
|
||||
},
|
||||
{
|
||||
"valueType": "boolean",
|
||||
"renderTypeList": ["reference"],
|
||||
"key": "summary",
|
||||
"label": "summary",
|
||||
"toolDescription": "是否显示文本摘要",
|
||||
"required": false,
|
||||
"canEdit": true,
|
||||
"editField": {
|
||||
"key": true,
|
||||
"description": true
|
||||
},
|
||||
"customInputConfig": {
|
||||
"selectValueTypeList": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"object",
|
||||
"arrayString",
|
||||
"arrayNumber",
|
||||
"arrayBoolean",
|
||||
"arrayObject",
|
||||
"arrayAny",
|
||||
"any",
|
||||
"chatHistory",
|
||||
"datasetQuote",
|
||||
"dynamic",
|
||||
"selectApp",
|
||||
"selectDataset"
|
||||
],
|
||||
"showDescription": false,
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"value": ["pluginInput", "summary"]
|
||||
},
|
||||
{
|
||||
"valueType": "string",
|
||||
"renderTypeList": ["reference"],
|
||||
"key": "include",
|
||||
"label": "include",
|
||||
"toolDescription": "指定搜索的site范围",
|
||||
"required": false,
|
||||
"canEdit": true,
|
||||
"editField": {
|
||||
"key": true,
|
||||
"description": true
|
||||
},
|
||||
"customInputConfig": {
|
||||
"selectValueTypeList": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"object",
|
||||
"arrayString",
|
||||
"arrayNumber",
|
||||
"arrayBoolean",
|
||||
"arrayObject",
|
||||
"arrayAny",
|
||||
"any",
|
||||
"chatHistory",
|
||||
"datasetQuote",
|
||||
"dynamic",
|
||||
"selectApp",
|
||||
"selectDataset"
|
||||
],
|
||||
"showDescription": false,
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"value": ["pluginInput", "include"]
|
||||
},
|
||||
{
|
||||
"valueType": "string",
|
||||
"renderTypeList": ["reference"],
|
||||
"key": "exclude",
|
||||
"label": "exclude",
|
||||
"toolDescription": "排除搜索的网站范围",
|
||||
"required": false,
|
||||
"canEdit": true,
|
||||
"editField": {
|
||||
"key": true,
|
||||
"description": true
|
||||
},
|
||||
"customInputConfig": {
|
||||
"selectValueTypeList": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"object",
|
||||
"arrayString",
|
||||
"arrayNumber",
|
||||
"arrayBoolean",
|
||||
"arrayObject",
|
||||
"arrayAny",
|
||||
"any",
|
||||
"chatHistory",
|
||||
"datasetQuote",
|
||||
"dynamic",
|
||||
"selectApp",
|
||||
"selectDataset"
|
||||
],
|
||||
"showDescription": false,
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"value": ["pluginInput", "exclude"]
|
||||
},
|
||||
{
|
||||
"valueType": "number",
|
||||
"renderTypeList": ["reference"],
|
||||
"key": "count",
|
||||
"label": "count",
|
||||
"toolDescription": "返回结果条数",
|
||||
"required": false,
|
||||
"canEdit": true,
|
||||
"editField": {
|
||||
"key": true,
|
||||
"description": true
|
||||
},
|
||||
"customInputConfig": {
|
||||
"selectValueTypeList": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"object",
|
||||
"arrayString",
|
||||
"arrayNumber",
|
||||
"arrayBoolean",
|
||||
"arrayObject",
|
||||
"arrayAny",
|
||||
"any",
|
||||
"chatHistory",
|
||||
"datasetQuote",
|
||||
"dynamic",
|
||||
"selectApp",
|
||||
"selectDataset"
|
||||
],
|
||||
"showDescription": false,
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"value": ["pluginInput", "count"]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "error",
|
||||
"key": "error",
|
||||
"label": "workflow:request_error",
|
||||
"description": "HTTP请求错误信息,成功时返回空",
|
||||
"valueType": "object",
|
||||
"type": "static"
|
||||
},
|
||||
{
|
||||
"id": "httpRawResponse",
|
||||
"key": "httpRawResponse",
|
||||
"required": true,
|
||||
"label": "workflow:raw_response",
|
||||
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
||||
"valueType": "any",
|
||||
"type": "static"
|
||||
},
|
||||
{
|
||||
"id": "system_addOutputParam",
|
||||
"key": "system_addOutputParam",
|
||||
"type": "dynamic",
|
||||
"valueType": "dynamic",
|
||||
"label": "",
|
||||
"editField": {
|
||||
"key": true,
|
||||
"valueType": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "pluginInput",
|
||||
"target": "nyA6oA8mF1iW",
|
||||
"sourceHandle": "pluginInput-source-right",
|
||||
"targetHandle": "nyA6oA8mF1iW-target-left"
|
||||
},
|
||||
{
|
||||
"source": "nyA6oA8mF1iW",
|
||||
"target": "pluginOutput",
|
||||
"sourceHandle": "nyA6oA8mF1iW-source-right",
|
||||
"targetHandle": "pluginOutput-target-left"
|
||||
}
|
||||
]
|
||||
},
|
||||
"chatConfig": {}
|
||||
}
|
||||
178
packages/service/common/buffer/rawText/controller.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
import { retryFn } from '@fastgpt/global/common/system/utils';
|
||||
import { connectionMongo } from '../../mongo';
|
||||
import { MongoRawTextBufferSchema, bucketName } from './schema';
|
||||
import { addLog } from '../../system/log';
|
||||
import { setCron } from '../../system/cron';
|
||||
import { checkTimerLock } from '../../system/timerLock/utils';
|
||||
import { TimerIdEnum } from '../../system/timerLock/constants';
|
||||
|
||||
const getGridBucket = () => {
|
||||
return new connectionMongo.mongo.GridFSBucket(connectionMongo.connection.db!, {
|
||||
bucketName: bucketName
|
||||
});
|
||||
};
|
||||
|
||||
export const addRawTextBuffer = async ({
|
||||
sourceId,
|
||||
sourceName,
|
||||
text,
|
||||
expiredTime
|
||||
}: {
|
||||
sourceId: string;
|
||||
sourceName: string;
|
||||
text: string;
|
||||
expiredTime: Date;
|
||||
}) => {
|
||||
const gridBucket = getGridBucket();
|
||||
const metadata = {
|
||||
sourceId,
|
||||
sourceName,
|
||||
expiredTime
|
||||
};
|
||||
|
||||
const buffer = Buffer.from(text);
|
||||
|
||||
const fileSize = buffer.length;
|
||||
// 单块大小:尽可能大,但不超过 14MB,不小于128KB
|
||||
const chunkSizeBytes = (() => {
|
||||
// 计算理想块大小:文件大小 ÷ 目标块数(10)。 并且每个块需要小于 14MB
|
||||
const idealChunkSize = Math.min(Math.ceil(fileSize / 10), 14 * 1024 * 1024);
|
||||
|
||||
// 确保块大小至少为128KB
|
||||
const minChunkSize = 128 * 1024; // 128KB
|
||||
|
||||
// 取理想块大小和最小块大小中的较大值
|
||||
let chunkSize = Math.max(idealChunkSize, minChunkSize);
|
||||
|
||||
// 将块大小向上取整到最接近的64KB的倍数,使其更整齐
|
||||
chunkSize = Math.ceil(chunkSize / (64 * 1024)) * (64 * 1024);
|
||||
|
||||
return chunkSize;
|
||||
})();
|
||||
|
||||
const uploadStream = gridBucket.openUploadStream(sourceId, {
|
||||
metadata,
|
||||
chunkSizeBytes
|
||||
});
|
||||
|
||||
return retryFn(async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
uploadStream.end(buffer);
|
||||
uploadStream.on('finish', () => {
|
||||
resolve(uploadStream.id);
|
||||
});
|
||||
uploadStream.on('error', (error) => {
|
||||
addLog.error('addRawTextBuffer error', error);
|
||||
resolve('');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const getRawTextBuffer = async (sourceId: string) => {
|
||||
const gridBucket = getGridBucket();
|
||||
|
||||
return retryFn(async () => {
|
||||
const bufferData = await MongoRawTextBufferSchema.findOne(
|
||||
{
|
||||
'metadata.sourceId': sourceId
|
||||
},
|
||||
'_id metadata'
|
||||
).lean();
|
||||
if (!bufferData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Read file content
|
||||
const downloadStream = gridBucket.openDownloadStream(bufferData._id);
|
||||
const chunks: Buffer[] = [];
|
||||
|
||||
return new Promise<{
|
||||
text: string;
|
||||
sourceName: string;
|
||||
} | null>((resolve, reject) => {
|
||||
downloadStream.on('data', (chunk) => {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
downloadStream.on('end', () => {
|
||||
const buffer = Buffer.concat(chunks);
|
||||
const text = buffer.toString('utf8');
|
||||
resolve({
|
||||
text,
|
||||
sourceName: bufferData.metadata?.sourceName || ''
|
||||
});
|
||||
});
|
||||
|
||||
downloadStream.on('error', (error) => {
|
||||
addLog.error('getRawTextBuffer error', error);
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteRawTextBuffer = async (sourceId: string): Promise<boolean> => {
|
||||
const gridBucket = getGridBucket();
|
||||
|
||||
return retryFn(async () => {
|
||||
const buffer = await MongoRawTextBufferSchema.findOne({ 'metadata.sourceId': sourceId });
|
||||
if (!buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await gridBucket.delete(buffer._id);
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
export const updateRawTextBufferExpiredTime = async ({
|
||||
sourceId,
|
||||
expiredTime
|
||||
}: {
|
||||
sourceId: string;
|
||||
expiredTime: Date;
|
||||
}) => {
|
||||
return retryFn(async () => {
|
||||
return MongoRawTextBufferSchema.updateOne(
|
||||
{ 'metadata.sourceId': sourceId },
|
||||
{ $set: { 'metadata.expiredTime': expiredTime } }
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export const clearExpiredRawTextBufferCron = async () => {
|
||||
const clearExpiredRawTextBuffer = async () => {
|
||||
addLog.debug('Clear expired raw text buffer start');
|
||||
const gridBucket = getGridBucket();
|
||||
|
||||
return retryFn(async () => {
|
||||
const data = await MongoRawTextBufferSchema.find(
|
||||
{
|
||||
'metadata.expiredTime': { $lt: new Date() }
|
||||
},
|
||||
'_id'
|
||||
).lean();
|
||||
|
||||
for (const item of data) {
|
||||
await gridBucket.delete(item._id);
|
||||
}
|
||||
addLog.debug('Clear expired raw text buffer end');
|
||||
});
|
||||
};
|
||||
|
||||
setCron('*/10 * * * *', async () => {
|
||||
if (
|
||||
await checkTimerLock({
|
||||
timerId: TimerIdEnum.clearExpiredRawTextBuffer,
|
||||
lockMinuted: 9
|
||||
})
|
||||
) {
|
||||
try {
|
||||
await clearExpiredRawTextBuffer();
|
||||
} catch (error) {
|
||||
addLog.error('clearExpiredRawTextBufferCron error', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,33 +1,22 @@
|
||||
import { getMongoModel, Schema } from '../../mongo';
|
||||
import { type RawTextBufferSchemaType } from './type';
|
||||
import { getMongoModel, type Types, Schema } from '../../mongo';
|
||||
|
||||
export const collectionName = 'buffer_rawtexts';
|
||||
export const bucketName = 'buffer_rawtext';
|
||||
|
||||
const RawTextBufferSchema = new Schema({
|
||||
sourceId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
rawText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
createTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
},
|
||||
metadata: Object
|
||||
metadata: {
|
||||
sourceId: { type: String, required: true },
|
||||
sourceName: { type: String, required: true },
|
||||
expiredTime: { type: Date, required: true }
|
||||
}
|
||||
});
|
||||
RawTextBufferSchema.index({ 'metadata.sourceId': 'hashed' });
|
||||
RawTextBufferSchema.index({ 'metadata.expiredTime': -1 });
|
||||
|
||||
try {
|
||||
RawTextBufferSchema.index({ sourceId: 1 });
|
||||
// 20 minutes
|
||||
RawTextBufferSchema.index({ createTime: 1 }, { expireAfterSeconds: 20 * 60 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
export const MongoRawTextBuffer = getMongoModel<RawTextBufferSchemaType>(
|
||||
collectionName,
|
||||
RawTextBufferSchema
|
||||
);
|
||||
export const MongoRawTextBufferSchema = getMongoModel<{
|
||||
_id: Types.ObjectId;
|
||||
metadata: {
|
||||
sourceId: string;
|
||||
sourceName: string;
|
||||
expiredTime: Date;
|
||||
};
|
||||
}>(`${bucketName}.files`, RawTextBufferSchema);
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
export type RawTextBufferSchemaType = {
|
||||
sourceId: string;
|
||||
rawText: string;
|
||||
createTime: Date;
|
||||
metadata?: {
|
||||
filename: string;
|
||||
};
|
||||
};
|
||||
@@ -6,13 +6,13 @@ import { type DatasetFileSchema } from '@fastgpt/global/core/dataset/type';
|
||||
import { MongoChatFileSchema, MongoDatasetFileSchema } from './schema';
|
||||
import { detectFileEncoding, detectFileEncodingByPath } from '@fastgpt/global/common/file/tools';
|
||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { MongoRawTextBuffer } from '../../buffer/rawText/schema';
|
||||
import { readRawContentByFileBuffer } from '../read/utils';
|
||||
import { gridFsStream2Buffer, stream2Encoding } from './utils';
|
||||
import { addLog } from '../../system/log';
|
||||
import { readFromSecondary } from '../../mongo/utils';
|
||||
import { parseFileExtensionFromUrl } from '@fastgpt/global/common/string/tools';
|
||||
import { Readable } from 'stream';
|
||||
import { addRawTextBuffer, getRawTextBuffer } from '../../buffer/rawText/controller';
|
||||
import { addMinutes } from 'date-fns';
|
||||
|
||||
export function getGFSCollection(bucket: `${BucketNameEnum}`) {
|
||||
MongoDatasetFileSchema;
|
||||
@@ -223,15 +223,13 @@ export const readFileContentFromMongo = async ({
|
||||
rawText: string;
|
||||
filename: string;
|
||||
}> => {
|
||||
const bufferId = `${fileId}-${customPdfParse}`;
|
||||
const bufferId = `${String(fileId)}-${customPdfParse}`;
|
||||
// read buffer
|
||||
const fileBuffer = await MongoRawTextBuffer.findOne({ sourceId: bufferId }, undefined, {
|
||||
...readFromSecondary
|
||||
}).lean();
|
||||
const fileBuffer = await getRawTextBuffer(bufferId);
|
||||
if (fileBuffer) {
|
||||
return {
|
||||
rawText: fileBuffer.rawText,
|
||||
filename: fileBuffer.metadata?.filename || ''
|
||||
rawText: fileBuffer.text,
|
||||
filename: fileBuffer?.sourceName
|
||||
};
|
||||
}
|
||||
|
||||
@@ -265,16 +263,13 @@ export const readFileContentFromMongo = async ({
|
||||
}
|
||||
});
|
||||
|
||||
// < 14M
|
||||
if (fileBuffers.length < 14 * 1024 * 1024 && rawText.trim()) {
|
||||
MongoRawTextBuffer.create({
|
||||
sourceId: bufferId,
|
||||
rawText,
|
||||
metadata: {
|
||||
filename: file.filename
|
||||
}
|
||||
});
|
||||
}
|
||||
// Add buffer
|
||||
addRawTextBuffer({
|
||||
sourceId: bufferId,
|
||||
sourceName: file.filename,
|
||||
text: rawText,
|
||||
expiredTime: addMinutes(new Date(), 20)
|
||||
});
|
||||
|
||||
return {
|
||||
rawText,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { Schema, getMongoModel } from '../../mongo';
|
||||
|
||||
const DatasetFileSchema = new Schema({});
|
||||
const ChatFileSchema = new Schema({});
|
||||
const DatasetFileSchema = new Schema({
|
||||
metadata: Object
|
||||
});
|
||||
const ChatFileSchema = new Schema({
|
||||
metadata: Object
|
||||
});
|
||||
|
||||
try {
|
||||
DatasetFileSchema.index({ uploadDate: -1 });
|
||||
DatasetFileSchema.index({ uploadDate: -1 });
|
||||
|
||||
ChatFileSchema.index({ uploadDate: -1 });
|
||||
ChatFileSchema.index({ 'metadata.chatId': 1 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
ChatFileSchema.index({ uploadDate: -1 });
|
||||
ChatFileSchema.index({ 'metadata.chatId': 1 });
|
||||
|
||||
export const MongoDatasetFileSchema = getMongoModel('dataset.files', DatasetFileSchema);
|
||||
export const MongoChatFileSchema = getMongoModel('chat.files', ChatFileSchema);
|
||||
|
||||
@@ -1,5 +1,57 @@
|
||||
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
||||
import { PassThrough } from 'stream';
|
||||
import { getGridBucket } from './controller';
|
||||
import { type BucketNameEnum } from '@fastgpt/global/common/file/constants';
|
||||
import { retryFn } from '@fastgpt/global/common/system/utils';
|
||||
|
||||
export const createFileFromText = async ({
|
||||
bucket,
|
||||
filename,
|
||||
text,
|
||||
metadata
|
||||
}: {
|
||||
bucket: `${BucketNameEnum}`;
|
||||
filename: string;
|
||||
text: string;
|
||||
metadata: Record<string, any>;
|
||||
}) => {
|
||||
const gridBucket = getGridBucket(bucket);
|
||||
|
||||
const buffer = Buffer.from(text);
|
||||
|
||||
const fileSize = buffer.length;
|
||||
// 单块大小:尽可能大,但不超过 14MB,不小于128KB
|
||||
const chunkSizeBytes = (() => {
|
||||
// 计算理想块大小:文件大小 ÷ 目标块数(10)。 并且每个块需要小于 14MB
|
||||
const idealChunkSize = Math.min(Math.ceil(fileSize / 10), 14 * 1024 * 1024);
|
||||
|
||||
// 确保块大小至少为128KB
|
||||
const minChunkSize = 128 * 1024; // 128KB
|
||||
|
||||
// 取理想块大小和最小块大小中的较大值
|
||||
let chunkSize = Math.max(idealChunkSize, minChunkSize);
|
||||
|
||||
// 将块大小向上取整到最接近的64KB的倍数,使其更整齐
|
||||
chunkSize = Math.ceil(chunkSize / (64 * 1024)) * (64 * 1024);
|
||||
|
||||
return chunkSize;
|
||||
})();
|
||||
|
||||
const uploadStream = gridBucket.openUploadStream(filename, {
|
||||
metadata,
|
||||
chunkSizeBytes
|
||||
});
|
||||
|
||||
return retryFn(async () => {
|
||||
return new Promise<{ fileId: string }>((resolve, reject) => {
|
||||
uploadStream.end(buffer);
|
||||
uploadStream.on('finish', () => {
|
||||
resolve({ fileId: String(uploadStream.id) });
|
||||
});
|
||||
uploadStream.on('error', reject);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const gridFsStream2Buffer = (stream: NodeJS.ReadableStream) => {
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
|
||||
@@ -110,7 +110,7 @@ export const readRawContentByFileBuffer = async ({
|
||||
|
||||
return {
|
||||
rawText: text,
|
||||
formatText: rawText,
|
||||
formatText: text,
|
||||
imageList
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,7 +5,8 @@ export enum TimerIdEnum {
|
||||
clearExpiredSubPlan = 'clearExpiredSubPlan',
|
||||
updateStandardPlan = 'updateStandardPlan',
|
||||
scheduleTriggerApp = 'scheduleTriggerApp',
|
||||
notification = 'notification'
|
||||
notification = 'notification',
|
||||
clearExpiredRawTextBuffer = 'clearExpiredRawTextBuffer'
|
||||
}
|
||||
|
||||
export enum LockNotificationEnum {
|
||||
|
||||
@@ -3,6 +3,5 @@ export const DatasetVectorTableName = 'modeldata';
|
||||
|
||||
export const PG_ADDRESS = process.env.PG_URL;
|
||||
export const OCEANBASE_ADDRESS = process.env.OCEANBASE_URL;
|
||||
export const OPENGAUSS_ADDRESS = process.env.OPENGAUSS_URL;
|
||||
export const MILVUS_ADDRESS = process.env.MILVUS_ADDRESS;
|
||||
export const MILVUS_TOKEN = process.env.MILVUS_TOKEN;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/* vector crud */
|
||||
import { PgVectorCtrl } from './pg';
|
||||
import { ObVectorCtrl } from './oceanbase';
|
||||
import { GsVectorCtrl } from './opengauss';
|
||||
import { getVectorsByText } from '../../core/ai/embedding';
|
||||
import { type DelDatasetVectorCtrlProps, type InsertVectorProps } from './controller.d';
|
||||
import { type EmbeddingModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||
import { MILVUS_ADDRESS, PG_ADDRESS, OCEANBASE_ADDRESS, OPENGAUSS_ADDRESS } from './constants';
|
||||
import { MILVUS_ADDRESS, PG_ADDRESS, OCEANBASE_ADDRESS } from './constants';
|
||||
import { MilvusCtrl } from './milvus';
|
||||
import { setRedisCache, getRedisCache, delRedisCache, CacheKeyEnum } from '../redis/cache';
|
||||
import { throttle } from 'lodash';
|
||||
@@ -15,7 +14,6 @@ const getVectorObj = () => {
|
||||
if (PG_ADDRESS) return new PgVectorCtrl();
|
||||
if (OCEANBASE_ADDRESS) return new ObVectorCtrl();
|
||||
if (MILVUS_ADDRESS) return new MilvusCtrl();
|
||||
if (OPENGAUSS_ADDRESS) return new GsVectorCtrl();
|
||||
|
||||
return new PgVectorCtrl();
|
||||
};
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
import { delay } from '@fastgpt/global/common/system/utils';
|
||||
import { addLog } from '../../system/log';
|
||||
import { Pool } from 'pg';
|
||||
import type { QueryResultRow } from 'pg';
|
||||
import { OPENGAUSS_ADDRESS } from '../constants';
|
||||
|
||||
export const connectGs = async (): Promise<Pool> => {
|
||||
if (global.gsClient) {
|
||||
return global.gsClient;
|
||||
}
|
||||
|
||||
global.gsClient = new Pool({
|
||||
connectionString: OPENGAUSS_ADDRESS,
|
||||
max: Number(process.env.DB_MAX_LINK || 20),
|
||||
min: 10,
|
||||
keepAlive: true,
|
||||
idleTimeoutMillis: 600000,
|
||||
connectionTimeoutMillis: 20000,
|
||||
query_timeout: 30000,
|
||||
statement_timeout: 40000,
|
||||
idle_in_transaction_session_timeout: 60000
|
||||
});
|
||||
|
||||
global.gsClient.on('error', async (err) => {
|
||||
addLog.error(`openGauss error`, err);
|
||||
global.gsClient?.end();
|
||||
global.gsClient = null;
|
||||
|
||||
await delay(1000);
|
||||
addLog.info(`Retry connect openGauss`);
|
||||
connectGs();
|
||||
});
|
||||
|
||||
try {
|
||||
await global.gsClient.connect();
|
||||
console.log('openGauss connected');
|
||||
return global.gsClient;
|
||||
} catch (error) {
|
||||
addLog.error(`openGauss connect error`, error);
|
||||
global.gsClient?.end();
|
||||
global.gsClient = null;
|
||||
|
||||
await delay(1000);
|
||||
addLog.info(`Retry connect openGauss`);
|
||||
|
||||
return connectGs();
|
||||
}
|
||||
};
|
||||
|
||||
type WhereProps = (string | [string, string | number])[];
|
||||
type GetProps = {
|
||||
fields?: string[];
|
||||
where?: WhereProps;
|
||||
order?: { field: string; mode: 'DESC' | 'ASC' | string }[];
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
};
|
||||
|
||||
type DeleteProps = {
|
||||
where: WhereProps;
|
||||
};
|
||||
|
||||
type ValuesProps = { key: string; value?: string | number }[];
|
||||
type UpdateProps = {
|
||||
values: ValuesProps;
|
||||
where: WhereProps;
|
||||
};
|
||||
type InsertProps = {
|
||||
values: ValuesProps[];
|
||||
};
|
||||
|
||||
class GsClass {
|
||||
private getWhereStr(where?: WhereProps) {
|
||||
return where
|
||||
? `WHERE ${where
|
||||
.map((item) => {
|
||||
if (typeof item === 'string') {
|
||||
return item;
|
||||
}
|
||||
const val = typeof item[1] === 'number' ? item[1] : `'${String(item[1])}'`;
|
||||
return `${item[0]}=${val}`;
|
||||
})
|
||||
.join(' ')}`
|
||||
: '';
|
||||
}
|
||||
private getUpdateValStr(values: ValuesProps) {
|
||||
return values
|
||||
.map((item) => {
|
||||
const val =
|
||||
typeof item.value === 'number'
|
||||
? item.value
|
||||
: `'${String(item.value).replace(/\'/g, '"')}'`;
|
||||
|
||||
return `${item.key}=${val}`;
|
||||
})
|
||||
.join(',');
|
||||
}
|
||||
private getInsertValStr(values: ValuesProps[]) {
|
||||
return values
|
||||
.map(
|
||||
(items) =>
|
||||
`(${items
|
||||
.map((item) =>
|
||||
typeof item.value === 'number'
|
||||
? item.value
|
||||
: `'${String(item.value).replace(/\'/g, '"')}'`
|
||||
)
|
||||
.join(',')})`
|
||||
)
|
||||
.join(',');
|
||||
}
|
||||
async select<T extends QueryResultRow = any>(table: string, props: GetProps) {
|
||||
const sql = `SELECT ${
|
||||
!props.fields || props.fields?.length === 0 ? '*' : props.fields?.join(',')
|
||||
}
|
||||
FROM ${table}
|
||||
${this.getWhereStr(props.where)}
|
||||
${
|
||||
props.order
|
||||
? `ORDER BY ${props.order.map((item) => `${item.field} ${item.mode}`).join(',')}`
|
||||
: ''
|
||||
}
|
||||
LIMIT ${props.limit || 10} OFFSET ${props.offset || 0}
|
||||
`;
|
||||
|
||||
const gs = await connectGs();
|
||||
return gs.query<T>(sql);
|
||||
}
|
||||
async count(table: string, props: GetProps) {
|
||||
const sql = `SELECT COUNT(${props?.fields?.[0] || '*'})
|
||||
FROM ${table}
|
||||
${this.getWhereStr(props.where)}
|
||||
`;
|
||||
|
||||
const gs = await connectGs();
|
||||
return gs.query(sql).then((res) => Number(res.rows[0]?.count || 0));
|
||||
}
|
||||
async delete(table: string, props: DeleteProps) {
|
||||
const sql = `DELETE FROM ${table} ${this.getWhereStr(props.where)}`;
|
||||
const gs = await connectGs();
|
||||
return gs.query(sql);
|
||||
}
|
||||
async update(table: string, props: UpdateProps) {
|
||||
if (props.values.length === 0) {
|
||||
return {
|
||||
rowCount: 0
|
||||
};
|
||||
}
|
||||
|
||||
const sql = `UPDATE ${table} SET ${this.getUpdateValStr(props.values)} ${this.getWhereStr(
|
||||
props.where
|
||||
)}`;
|
||||
const gs = await connectGs();
|
||||
return gs.query(sql);
|
||||
}
|
||||
async insert(table: string, props: InsertProps) {
|
||||
if (props.values.length === 0) {
|
||||
return {
|
||||
rowCount: 0,
|
||||
rows: []
|
||||
};
|
||||
}
|
||||
|
||||
const fields = props.values[0].map((item) => item.key).join(',');
|
||||
const sql = `INSERT INTO ${table} (${fields}) VALUES ${this.getInsertValStr(
|
||||
props.values
|
||||
)} RETURNING id`;
|
||||
|
||||
const gs = await connectGs();
|
||||
return gs.query<{ id: string }>(sql);
|
||||
}
|
||||
async query<T extends QueryResultRow = any>(sql: string) {
|
||||
const gs = await connectGs();
|
||||
const start = Date.now();
|
||||
return gs.query<T>(sql).then((res) => {
|
||||
const time = Date.now() - start;
|
||||
|
||||
if (time > 300) {
|
||||
addLog.warn(`gs query time: ${time}ms, sql: ${sql}`);
|
||||
}
|
||||
|
||||
return res;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const GsClient = new GsClass();
|
||||
export const Gs = global.gsClient;
|
||||
@@ -1,253 +0,0 @@
|
||||
/* pg vector crud */
|
||||
import { DatasetVectorTableName } from '../constants';
|
||||
import { delay } from '@fastgpt/global/common/system/utils';
|
||||
import { GsClient, connectGs } from './controller';
|
||||
import { GsSearchRawType } from '@fastgpt/global/core/dataset/api';
|
||||
import type {
|
||||
DelDatasetVectorCtrlProps,
|
||||
EmbeddingRecallCtrlProps,
|
||||
EmbeddingRecallResponse,
|
||||
InsertVectorControllerProps
|
||||
} from '../controller.d';
|
||||
import dayjs from 'dayjs';
|
||||
import { addLog } from '../../system/log';
|
||||
|
||||
export class GsVectorCtrl {
|
||||
constructor() {}
|
||||
init = async () => {
|
||||
try {
|
||||
await connectGs();
|
||||
await GsClient.query(`
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
CREATE TABLE IF NOT EXISTS ${DatasetVectorTableName} (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
vector VECTOR(1536) NOT NULL,
|
||||
team_id VARCHAR(50) NOT NULL,
|
||||
dataset_id VARCHAR(50) NOT NULL,
|
||||
collection_id VARCHAR(50) NOT NULL,
|
||||
createtime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`);
|
||||
|
||||
await GsClient.query(
|
||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS vector_index ON ${DatasetVectorTableName} USING hnsw (vector vector_ip_ops) WITH (m = 32, ef_construction = 128);`
|
||||
);
|
||||
await GsClient.query(
|
||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS team_dataset_collection_index ON ${DatasetVectorTableName} USING btree(team_id, dataset_id, collection_id);`
|
||||
);
|
||||
await GsClient.query(
|
||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS create_time_index ON ${DatasetVectorTableName} USING btree(createtime);`
|
||||
);
|
||||
|
||||
addLog.info('init pg successful');
|
||||
} catch (error) {
|
||||
addLog.error('init pg error', error);
|
||||
}
|
||||
};
|
||||
insert = async (props: InsertVectorControllerProps): Promise<{ insertId: string }> => {
|
||||
const { teamId, datasetId, collectionId, vector, retry = 3 } = props;
|
||||
|
||||
try {
|
||||
const { rowCount, rows } = await GsClient.insert(DatasetVectorTableName, {
|
||||
values: [
|
||||
[
|
||||
{ key: 'vector', value: `[${vector}]` },
|
||||
{ key: 'team_id', value: String(teamId) },
|
||||
{ key: 'dataset_id', value: String(datasetId) },
|
||||
{ key: 'collection_id', value: String(collectionId) }
|
||||
]
|
||||
]
|
||||
});
|
||||
|
||||
if (rowCount === 0) {
|
||||
return Promise.reject('insertDatasetData: no insert');
|
||||
}
|
||||
|
||||
return {
|
||||
insertId: rows[0].id
|
||||
};
|
||||
} catch (error) {
|
||||
if (retry <= 0) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
await delay(500);
|
||||
return this.insert({
|
||||
...props,
|
||||
retry: retry - 1
|
||||
});
|
||||
}
|
||||
};
|
||||
delete = async (props: DelDatasetVectorCtrlProps): Promise<any> => {
|
||||
const { teamId, retry = 2 } = props;
|
||||
|
||||
const teamIdWhere = `team_id='${String(teamId)}' AND`;
|
||||
|
||||
const where = await (() => {
|
||||
if ('id' in props && props.id) return `${teamIdWhere} id=${props.id}`;
|
||||
|
||||
if ('datasetIds' in props && props.datasetIds) {
|
||||
const datasetIdWhere = `dataset_id IN (${props.datasetIds
|
||||
.map((id) => `'${String(id)}'`)
|
||||
.join(',')})`;
|
||||
|
||||
if ('collectionIds' in props && props.collectionIds) {
|
||||
return `${teamIdWhere} ${datasetIdWhere} AND collection_id IN (${props.collectionIds
|
||||
.map((id) => `'${String(id)}'`)
|
||||
.join(',')})`;
|
||||
}
|
||||
|
||||
return `${teamIdWhere} ${datasetIdWhere}`;
|
||||
}
|
||||
|
||||
if ('idList' in props && Array.isArray(props.idList)) {
|
||||
if (props.idList.length === 0) return;
|
||||
return `${teamIdWhere} id IN (${props.idList.map((id) => String(id)).join(',')})`;
|
||||
}
|
||||
return Promise.reject('deleteDatasetData: no where');
|
||||
})();
|
||||
|
||||
if (!where) return;
|
||||
|
||||
try {
|
||||
await GsClient.delete(DatasetVectorTableName, {
|
||||
where: [where]
|
||||
});
|
||||
} catch (error) {
|
||||
if (retry <= 0) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
await delay(500);
|
||||
return this.delete({
|
||||
...props,
|
||||
retry: retry - 1
|
||||
});
|
||||
}
|
||||
};
|
||||
embRecall = async (props: EmbeddingRecallCtrlProps): Promise<EmbeddingRecallResponse> => {
|
||||
const {
|
||||
teamId,
|
||||
datasetIds,
|
||||
vector,
|
||||
limit,
|
||||
forbidCollectionIdList,
|
||||
filterCollectionIdList,
|
||||
retry = 2
|
||||
} = props;
|
||||
|
||||
// Get forbid collection
|
||||
const formatForbidCollectionIdList = (() => {
|
||||
if (!filterCollectionIdList) return forbidCollectionIdList;
|
||||
const list = forbidCollectionIdList
|
||||
.map((id) => String(id))
|
||||
.filter((id) => !filterCollectionIdList.includes(id));
|
||||
return list;
|
||||
})();
|
||||
const forbidCollectionSql =
|
||||
formatForbidCollectionIdList.length > 0
|
||||
? `AND collection_id NOT IN (${formatForbidCollectionIdList.map((id) => `'${id}'`).join(',')})`
|
||||
: '';
|
||||
|
||||
// Filter by collectionId
|
||||
const formatFilterCollectionId = (() => {
|
||||
if (!filterCollectionIdList) return;
|
||||
|
||||
return filterCollectionIdList
|
||||
.map((id) => String(id))
|
||||
.filter((id) => !forbidCollectionIdList.includes(id));
|
||||
})();
|
||||
const filterCollectionIdSql = formatFilterCollectionId
|
||||
? `AND collection_id IN (${formatFilterCollectionId.map((id) => `'${id}'`).join(',')})`
|
||||
: '';
|
||||
// Empty data
|
||||
if (formatFilterCollectionId && formatFilterCollectionId.length === 0) {
|
||||
return { results: [] };
|
||||
}
|
||||
|
||||
try {
|
||||
const results: any = await GsClient.query(
|
||||
`BEGIN;
|
||||
SET ob_hnsw_ef_search = ${global.systemEnv?.hnswEfSearch || 100};
|
||||
SELECT id, collection_id, inner_product(vector, [${vector}]) AS score
|
||||
FROM ${DatasetVectorTableName}
|
||||
WHERE team_id='${teamId}'
|
||||
AND dataset_id IN (${datasetIds.map((id) => `'${String(id)}'`).join(',')})
|
||||
${filterCollectionIdSql}
|
||||
${forbidCollectionSql}
|
||||
ORDER BY score desc APPROXIMATE LIMIT ${limit};
|
||||
COMMIT;`
|
||||
);
|
||||
const rows = results?.[3]?.rows as GsSearchRawType[];
|
||||
|
||||
if (!Array.isArray(rows)) {
|
||||
return {
|
||||
results: []
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
results: rows.map((item) => ({
|
||||
id: String(item.id),
|
||||
collectionId: item.collection_id,
|
||||
score: item.score * -1
|
||||
}))
|
||||
};
|
||||
} catch (error) {
|
||||
if (retry <= 0) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
return this.embRecall({
|
||||
...props,
|
||||
retry: retry - 1
|
||||
});
|
||||
}
|
||||
};
|
||||
getVectorDataByTime = async (start: Date, end: Date) => {
|
||||
const { rows } = await GsClient.query<{
|
||||
id: string;
|
||||
team_id: string;
|
||||
dataset_id: string;
|
||||
}>(`SELECT id, team_id, dataset_id
|
||||
FROM ${DatasetVectorTableName}
|
||||
WHERE createtime BETWEEN '${dayjs(start).format('YYYY-MM-DD HH:mm:ss')}' AND '${dayjs(
|
||||
end
|
||||
).format('YYYY-MM-DD HH:mm:ss')}';
|
||||
`);
|
||||
|
||||
return rows.map((item) => ({
|
||||
id: String(item.id),
|
||||
teamId: item.team_id,
|
||||
datasetId: item.dataset_id
|
||||
}));
|
||||
};
|
||||
getVectorCountByTeamId = async (teamId: string) => {
|
||||
const total = await GsClient.count(DatasetVectorTableName, {
|
||||
where: [['team_id', String(teamId)]]
|
||||
});
|
||||
|
||||
return total;
|
||||
};
|
||||
getVectorCountByDatasetId = async (teamId: string, datasetId: string) => {
|
||||
const total = await GsClient.count(DatasetVectorTableName, {
|
||||
where: [['team_id', String(teamId)], 'and', ['dataset_id', String(datasetId)]]
|
||||
});
|
||||
|
||||
return total;
|
||||
};
|
||||
getVectorCountByCollectionId = async (
|
||||
teamId: string,
|
||||
datasetId: string,
|
||||
collectionId: string
|
||||
) => {
|
||||
const total = await GsClient.count(DatasetVectorTableName, {
|
||||
where: [
|
||||
['team_id', String(teamId)],
|
||||
'and',
|
||||
['dataset_id', String(datasetId)],
|
||||
'and',
|
||||
['collection_id', String(collectionId)]
|
||||
]
|
||||
});
|
||||
|
||||
return total;
|
||||
};
|
||||
}
|
||||
1
packages/service/common/vectorDB/type.d.ts
vendored
@@ -6,7 +6,6 @@ declare global {
|
||||
var pgClient: Pool | null;
|
||||
var obClient: MysqlPool | null;
|
||||
var milvusClient: MilvusClient | null;
|
||||
var gsClient: Pool | null;
|
||||
}
|
||||
|
||||
export type EmbeddingRecallItemType = {
|
||||
|
||||
@@ -64,7 +64,12 @@ const AppSchema = new Schema({
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
},
|
||||
|
||||
tags: [
|
||||
{
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'app_tags'
|
||||
}
|
||||
],
|
||||
// role and auth
|
||||
teamTags: {
|
||||
type: [String]
|
||||
|
||||
242
packages/service/core/app/tags/controller.ts
Normal file
@@ -0,0 +1,242 @@
|
||||
import { MongoTag } from './schema';
|
||||
import { MongoApp } from '../schema';
|
||||
import { Types } from '../../../common/mongo';
|
||||
|
||||
/**
|
||||
* 创建新标签
|
||||
*/
|
||||
export const createTag = async ({
|
||||
teamId,
|
||||
name,
|
||||
color
|
||||
}: {
|
||||
teamId: string;
|
||||
name: string;
|
||||
color?: string;
|
||||
}) => {
|
||||
const tag = await MongoTag.create({
|
||||
teamId,
|
||||
name,
|
||||
color
|
||||
});
|
||||
|
||||
return tag.toObject();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取团队所有标签
|
||||
*/
|
||||
export const getTeamTags = async (teamId: string) => {
|
||||
const tags = await MongoTag.find({ teamId }).lean();
|
||||
return tags;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取标签使用统计
|
||||
*/
|
||||
export const getTagsWithCount = async (teamId: string) => {
|
||||
return MongoTag.aggregate([
|
||||
{ $match: { teamId: new Types.ObjectId(teamId) } },
|
||||
{
|
||||
$lookup: {
|
||||
from: 'apps',
|
||||
localField: '_id',
|
||||
foreignField: 'tags',
|
||||
as: 'apps'
|
||||
}
|
||||
},
|
||||
{
|
||||
$addFields: {
|
||||
count: { $size: '$apps' }
|
||||
}
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
apps: 0
|
||||
}
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新标签
|
||||
*/
|
||||
export const updateTag = async ({
|
||||
tagId,
|
||||
teamId,
|
||||
name,
|
||||
color
|
||||
}: {
|
||||
tagId: string;
|
||||
teamId: string;
|
||||
name?: string;
|
||||
color?: string;
|
||||
}) => {
|
||||
const updateData: Record<string, any> = {};
|
||||
if (name !== undefined) updateData.name = name;
|
||||
if (color !== undefined) updateData.color = color;
|
||||
|
||||
await MongoTag.updateOne({ _id: tagId, teamId }, { $set: updateData });
|
||||
|
||||
return MongoTag.findById(tagId).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除标签
|
||||
*/
|
||||
export const deleteTag = async ({ tagId, teamId }: { tagId: string; teamId: string }) => {
|
||||
// 先从所有 app 中移除该标签
|
||||
await MongoApp.updateMany({ teamId, tags: tagId }, { $pull: { tags: tagId } });
|
||||
|
||||
// 然后删除标签
|
||||
await MongoTag.deleteOne({ _id: tagId, teamId });
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 为 app 添加标签
|
||||
*/
|
||||
export const addTagToApp = async ({
|
||||
appId,
|
||||
tagId,
|
||||
teamId
|
||||
}: {
|
||||
appId: string;
|
||||
tagId: string;
|
||||
teamId: string;
|
||||
}) => {
|
||||
// 确认标签存在且属于该团队
|
||||
const tag = await MongoTag.findOne({ _id: tagId, teamId });
|
||||
if (!tag) {
|
||||
throw new Error('Tag not found or not authorized');
|
||||
}
|
||||
|
||||
await MongoApp.updateOne({ _id: appId, teamId }, { $addToSet: { tags: tagId } });
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 从 app 移除标签
|
||||
*/
|
||||
export const removeTagFromApp = async ({
|
||||
appId,
|
||||
tagId,
|
||||
teamId
|
||||
}: {
|
||||
appId: string;
|
||||
tagId: string;
|
||||
teamId: string;
|
||||
}) => {
|
||||
await MongoApp.updateOne({ _id: appId, teamId }, { $pull: { tags: tagId } });
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量删除标签
|
||||
*/
|
||||
export const batchDeleteTags = async ({ tagIds, teamId }: { tagIds: string[]; teamId: string }) => {
|
||||
if (!tagIds || tagIds.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 先从所有 app 中移除这些标签
|
||||
await MongoApp.updateMany(
|
||||
{ teamId, tags: { $in: tagIds } },
|
||||
{ $pull: { tags: { $in: tagIds } } }
|
||||
);
|
||||
|
||||
// 然后删除标签
|
||||
const result = await MongoTag.deleteMany({ _id: { $in: tagIds }, teamId });
|
||||
|
||||
return { deletedCount: result.deletedCount };
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量为 app 添加标签
|
||||
*/
|
||||
export const batchAddTagsToApp = async ({
|
||||
appId,
|
||||
tagIds,
|
||||
teamId
|
||||
}: {
|
||||
appId: string;
|
||||
tagIds: string[];
|
||||
teamId: string;
|
||||
}) => {
|
||||
if (!tagIds || tagIds.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 确认标签存在且属于该团队
|
||||
const tags = await MongoTag.find({ _id: { $in: tagIds }, teamId });
|
||||
if (tags.length !== tagIds.length) {
|
||||
throw new Error('Some tags not found or not authorized');
|
||||
}
|
||||
|
||||
await MongoApp.updateOne({ _id: appId, teamId }, { $addToSet: { tags: { $each: tagIds } } });
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量从 app 移除标签
|
||||
*/
|
||||
export const batchRemoveTagsFromApp = async ({
|
||||
appId,
|
||||
tagIds,
|
||||
teamId
|
||||
}: {
|
||||
appId: string;
|
||||
tagIds: string[];
|
||||
teamId: string;
|
||||
}) => {
|
||||
if (!tagIds || tagIds.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
await MongoApp.updateOne({ _id: appId, teamId }, { $pull: { tags: { $in: tagIds } } });
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量为某一标签添加 app(全量更新)
|
||||
*/
|
||||
export const batchAddAppsToTag = async ({
|
||||
tagId,
|
||||
appIds,
|
||||
teamId
|
||||
}: {
|
||||
tagId: string;
|
||||
appIds: string[];
|
||||
teamId: string;
|
||||
}) => {
|
||||
// 确认标签存在且属于该团队
|
||||
const tag = await MongoTag.findOne({ _id: tagId, teamId });
|
||||
if (!tag) {
|
||||
throw new Error('Tag not found or not authorized');
|
||||
}
|
||||
|
||||
// 如果 appIds 为空数组,则移除该标签的所有应用
|
||||
if (!appIds || appIds.length === 0) {
|
||||
await MongoApp.updateMany({ teamId, tags: tagId }, { $pull: { tags: tagId } });
|
||||
return true;
|
||||
}
|
||||
|
||||
// 确认所有 app 都存在且属于该团队
|
||||
const apps = await MongoApp.find({ _id: { $in: appIds }, teamId });
|
||||
if (apps.length !== appIds.length) {
|
||||
throw new Error('Some apps not found or not authorized');
|
||||
}
|
||||
|
||||
// 先从所有应用中移除该标签
|
||||
await MongoApp.updateMany({ teamId, tags: tagId }, { $pull: { tags: tagId } });
|
||||
|
||||
// 然后为指定的应用添加该标签
|
||||
await MongoApp.updateMany({ _id: { $in: appIds }, teamId }, { $addToSet: { tags: tagId } });
|
||||
|
||||
return true;
|
||||
};
|
||||
37
packages/service/core/app/tags/schema.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
|
||||
import { getMongoModel, Schema } from '../../../common/mongo';
|
||||
|
||||
export const TagCollectionName = 'app_tags';
|
||||
|
||||
export type TagSchemaType = {
|
||||
_id: string;
|
||||
teamId: string;
|
||||
name: string;
|
||||
color: string;
|
||||
createTime: Date;
|
||||
};
|
||||
|
||||
const TagSchema = new Schema({
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName,
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#3370ff'
|
||||
},
|
||||
createTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
}
|
||||
});
|
||||
|
||||
// 创建复合索引:按团队和名称确保唯一性
|
||||
TagSchema.index({ teamId: 1, name: 1 }, { unique: true });
|
||||
|
||||
export const MongoTag = getMongoModel<TagSchemaType>(TagCollectionName, TagSchema);
|
||||
@@ -77,7 +77,10 @@ export const createCollectionAndInsertData = async ({
|
||||
const chunkSplitter = computeChunkSplitter(createCollectionParams);
|
||||
const paragraphChunkDeep = computeParagraphChunkDeep(createCollectionParams);
|
||||
|
||||
if (trainingType === DatasetCollectionDataProcessModeEnum.qa) {
|
||||
if (
|
||||
trainingType === DatasetCollectionDataProcessModeEnum.qa ||
|
||||
trainingType === DatasetCollectionDataProcessModeEnum.backup
|
||||
) {
|
||||
delete createCollectionParams.chunkTriggerType;
|
||||
delete createCollectionParams.chunkTriggerMinSize;
|
||||
delete createCollectionParams.dataEnhanceCollectionName;
|
||||
|
||||
@@ -218,6 +218,10 @@ export const rawText2Chunks = ({
|
||||
};
|
||||
};
|
||||
|
||||
if (backupParse) {
|
||||
return parseDatasetBackup2Chunks(rawText).chunks;
|
||||
}
|
||||
|
||||
// Chunk condition
|
||||
// 1. 选择最大值条件,只有超过了最大值(默认为模型的最大值*0.7),才会触发分块
|
||||
if (chunkTriggerType === ChunkTriggerConfigTypeEnum.maxSize) {
|
||||
@@ -240,10 +244,6 @@ export const rawText2Chunks = ({
|
||||
}
|
||||
}
|
||||
|
||||
if (backupParse) {
|
||||
return parseDatasetBackup2Chunks(rawText).chunks;
|
||||
}
|
||||
|
||||
const { chunks } = splitText2Chunks({
|
||||
text: rawText,
|
||||
chunkSize,
|
||||
|
||||
@@ -86,7 +86,6 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
||||
});
|
||||
|
||||
// Check interactive entry
|
||||
const interactiveResponse = lastInteractive;
|
||||
props.node.isEntry = false;
|
||||
const hasReadFilesTool = toolNodes.some(
|
||||
(item) => item.flowNodeType === FlowNodeTypeEnum.readFiles
|
||||
@@ -143,7 +142,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
||||
})
|
||||
}
|
||||
];
|
||||
if (interactiveResponse) {
|
||||
if (lastInteractive && isEntry) {
|
||||
return value.slice(0, -2);
|
||||
}
|
||||
return value;
|
||||
@@ -183,7 +182,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
||||
toolModel,
|
||||
maxRunToolTimes: 30,
|
||||
messages: adaptMessages,
|
||||
interactiveEntryToolParams: interactiveResponse?.toolParams
|
||||
interactiveEntryToolParams: lastInteractive?.toolParams
|
||||
});
|
||||
}
|
||||
if (toolModel.functionCall) {
|
||||
@@ -194,7 +193,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
||||
toolNodes,
|
||||
toolModel,
|
||||
messages: adaptMessages,
|
||||
interactiveEntryToolParams: interactiveResponse?.toolParams
|
||||
interactiveEntryToolParams: lastInteractive?.toolParams
|
||||
});
|
||||
}
|
||||
|
||||
@@ -224,7 +223,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
||||
toolNodes,
|
||||
toolModel,
|
||||
messages: adaptMessages,
|
||||
interactiveEntryToolParams: interactiveResponse?.toolParams
|
||||
interactiveEntryToolParams: lastInteractive?.toolParams
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import type {
|
||||
SystemVariablesType
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import type { FlowNodeOutputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import type {
|
||||
AIChatItemValueItemType,
|
||||
ChatHistoryItemResType,
|
||||
|
||||
@@ -17,6 +17,7 @@ import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||
import { getPluginRunUserQuery } from '@fastgpt/global/core/workflow/utils';
|
||||
import { getPluginInputsFromStoreNodes } from '@fastgpt/global/core/app/plugin/utils';
|
||||
import type { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { getUserChatInfoAndAuthTeamPoints } from '../../../../support/permission/auth/team';
|
||||
|
||||
type RunPluginProps = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.forbidStream]?: boolean;
|
||||
@@ -73,9 +74,11 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
||||
};
|
||||
});
|
||||
|
||||
const { externalProvider } = await getUserChatInfoAndAuthTeamPoints(runningAppInfo.tmbId);
|
||||
const runtimeVariables = {
|
||||
...filterSystemVariables(props.variables),
|
||||
appId: String(plugin.id)
|
||||
appId: String(plugin.id),
|
||||
...(externalProvider ? externalProvider.externalWorkflowVariables : {})
|
||||
};
|
||||
const { flowResponses, flowUsages, assistantResponses, runTimes } = await dispatchWorkFlow({
|
||||
...props,
|
||||
|
||||
@@ -20,6 +20,7 @@ import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { getAppVersionById } from '../../../app/version/controller';
|
||||
import { parseUrlToFileType } from '@fastgpt/global/common/file/tools';
|
||||
import { type ChildrenInteractive } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||
import { getUserChatInfoAndAuthTeamPoints } from '../../../../support/permission/auth/team';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.userChatInput]: string;
|
||||
@@ -97,11 +98,13 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
|
||||
|
||||
// Rewrite children app variables
|
||||
const systemVariables = filterSystemVariables(variables);
|
||||
const { externalProvider } = await getUserChatInfoAndAuthTeamPoints(appData.tmbId);
|
||||
const childrenRunVariables = {
|
||||
...systemVariables,
|
||||
...childrenAppVariables,
|
||||
histories: chatHistories,
|
||||
appId: String(appData._id)
|
||||
appId: String(appData._id),
|
||||
...(externalProvider ? externalProvider.externalWorkflowVariables : {})
|
||||
};
|
||||
|
||||
const childrenInteractive =
|
||||
|
||||
@@ -5,8 +5,6 @@ import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { type DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import axios from 'axios';
|
||||
import { serverRequestBaseUrl } from '../../../../common/api/serverRequest';
|
||||
import { MongoRawTextBuffer } from '../../../../common/buffer/rawText/schema';
|
||||
import { readFromSecondary } from '../../../../common/mongo/utils';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { detectFileEncoding, parseUrlToFileType } from '@fastgpt/global/common/file/tools';
|
||||
import { readRawContentByFileBuffer } from '../../../../common/file/read/utils';
|
||||
@@ -14,6 +12,8 @@ import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { type ChatItemType, type UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { parseFileExtensionFromUrl } from '@fastgpt/global/common/string/tools';
|
||||
import { addLog } from '../../../../common/system/log';
|
||||
import { addRawTextBuffer, getRawTextBuffer } from '../../../../common/buffer/rawText/controller';
|
||||
import { addMinutes } from 'date-fns';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.fileUrlList]: string[];
|
||||
@@ -158,14 +158,12 @@ export const getFileContentFromLinks = async ({
|
||||
parseUrlList
|
||||
.map(async (url) => {
|
||||
// Get from buffer
|
||||
const fileBuffer = await MongoRawTextBuffer.findOne({ sourceId: url }, undefined, {
|
||||
...readFromSecondary
|
||||
}).lean();
|
||||
const fileBuffer = await getRawTextBuffer(url);
|
||||
if (fileBuffer) {
|
||||
return formatResponseObject({
|
||||
filename: fileBuffer.metadata?.filename || url,
|
||||
filename: fileBuffer.sourceName || url,
|
||||
url,
|
||||
content: fileBuffer.rawText
|
||||
content: fileBuffer.text
|
||||
});
|
||||
}
|
||||
|
||||
@@ -220,17 +218,12 @@ export const getFileContentFromLinks = async ({
|
||||
});
|
||||
|
||||
// Add to buffer
|
||||
try {
|
||||
if (buffer.length < 14 * 1024 * 1024 && rawText.trim()) {
|
||||
MongoRawTextBuffer.create({
|
||||
sourceId: url,
|
||||
rawText,
|
||||
metadata: {
|
||||
filename: filename
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {}
|
||||
addRawTextBuffer({
|
||||
sourceId: url,
|
||||
sourceName: filename,
|
||||
text: rawText,
|
||||
expiredTime: addMinutes(new Date(), 20)
|
||||
});
|
||||
|
||||
return formatResponseObject({ filename, url, content: rawText });
|
||||
} catch (error) {
|
||||
|
||||
@@ -137,7 +137,7 @@ export const authApp = async ({
|
||||
appId: ParentIdType;
|
||||
per: PermissionValueType;
|
||||
}): Promise<
|
||||
AuthResponseType & {
|
||||
AuthResponseType<AppPermission> & {
|
||||
app: AppDetailType;
|
||||
}
|
||||
> => {
|
||||
|
||||
568
packages/service/support/user/team/gate/controller.ts
Normal file
@@ -0,0 +1,568 @@
|
||||
import { MongoTeamGate } from './schema';
|
||||
import { Types } from '../../../../common/mongo';
|
||||
import type { ClientSession } from '../../../../common/mongo';
|
||||
import { mongoSessionRun } from '../../../../common/mongo/sessionRun';
|
||||
import {
|
||||
GateFeaturedAppPermission,
|
||||
GateQuickAppPermission
|
||||
} from '@fastgpt/global/support/permission/app/constant';
|
||||
import { PerResourceTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||
import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant';
|
||||
import { MongoMemberGroupModel } from '../../../permission/memberGroup/memberGroupSchema';
|
||||
import { MongoResourcePermission } from '../../../permission/schema';
|
||||
|
||||
export const addGatePermission = async ({
|
||||
teamId,
|
||||
appId,
|
||||
per,
|
||||
session
|
||||
}: {
|
||||
teamId: string;
|
||||
appId: string;
|
||||
per: number;
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
// 1. 先找全员组
|
||||
const teamGroup = await MongoMemberGroupModel.findOne({
|
||||
teamId,
|
||||
name: DefaultGroupName
|
||||
});
|
||||
if (!teamGroup) {
|
||||
return Promise.reject('找不到全员组');
|
||||
}
|
||||
|
||||
// 2. 加权限
|
||||
await MongoResourcePermission.updateOne(
|
||||
{
|
||||
teamId,
|
||||
groupId: teamGroup?._id,
|
||||
resourceType: PerResourceTypeEnum.app,
|
||||
resourceId: appId
|
||||
},
|
||||
{
|
||||
permission: per
|
||||
},
|
||||
{
|
||||
session,
|
||||
upsert: true
|
||||
}
|
||||
);
|
||||
};
|
||||
export const removeGatePermission = async ({
|
||||
teamId,
|
||||
appId,
|
||||
per,
|
||||
session
|
||||
}: {
|
||||
teamId: string;
|
||||
appId: string;
|
||||
per: number;
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
// 1. 先找全员组
|
||||
const teamGroup = await MongoMemberGroupModel.findOne({
|
||||
teamId,
|
||||
name: DefaultGroupName
|
||||
});
|
||||
if (!teamGroup) {
|
||||
return Promise.reject('找不到全员组');
|
||||
}
|
||||
|
||||
await MongoResourcePermission.deleteOne(
|
||||
{
|
||||
teamId,
|
||||
groupId: teamGroup?._id,
|
||||
resourceType: PerResourceTypeEnum.app,
|
||||
resourceId: appId,
|
||||
permission: per
|
||||
},
|
||||
{
|
||||
session
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建团队门户配置
|
||||
*/
|
||||
export const createGateConfig = async ({ teamId }: { teamId: string }) => {
|
||||
const gate = await MongoTeamGate.create({
|
||||
teamId
|
||||
});
|
||||
|
||||
return gate.toObject();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取团队门户配置
|
||||
*/
|
||||
export const getGateConfig = async (teamId: string) => {
|
||||
const gate = await MongoTeamGate.findOne({ teamId }).lean();
|
||||
return gate;
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新团队门户配置
|
||||
*/
|
||||
export const updateGateConfig = async ({
|
||||
teamId,
|
||||
status,
|
||||
name,
|
||||
banner,
|
||||
logo,
|
||||
tools,
|
||||
placeholderText
|
||||
}: {
|
||||
teamId: string;
|
||||
status?: boolean;
|
||||
name?: string;
|
||||
banner?: string;
|
||||
logo?: string;
|
||||
tools?: string[];
|
||||
placeholderText?: string;
|
||||
}) => {
|
||||
const updateData: Record<string, any> = {};
|
||||
if (status !== undefined) updateData.status = status;
|
||||
if (name !== undefined) updateData.name = name;
|
||||
if (banner !== undefined) updateData.banner = banner;
|
||||
if (logo !== undefined) updateData.logo = logo;
|
||||
if (tools !== undefined) updateData.tools = tools;
|
||||
if (placeholderText !== undefined) updateData.placeholderText = placeholderText;
|
||||
|
||||
// 使用 upsert 选项,如果不存在则创建
|
||||
await MongoTeamGate.updateOne({ teamId }, { $set: updateData }, { upsert: true });
|
||||
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除团队门户配置
|
||||
*/
|
||||
export const deleteGateConfig = async (teamId: string) => {
|
||||
await MongoTeamGate.deleteOne({ teamId });
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 启用或禁用团队门户
|
||||
*/
|
||||
export const toggleGateStatus = async ({ teamId, status }: { teamId: string; status: boolean }) => {
|
||||
await MongoTeamGate.updateOne({ teamId }, { $set: { status } }, { upsert: true });
|
||||
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新门户工具配置
|
||||
*/
|
||||
export const updateGateTools = async ({ teamId, tools }: { teamId: string; tools: string[] }) => {
|
||||
await MongoTeamGate.updateOne({ teamId }, { $set: { tools } }, { upsert: true });
|
||||
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 添加门户工具
|
||||
*/
|
||||
export const addGateTool = async ({ teamId, tool }: { teamId: string; tool: string }) => {
|
||||
await MongoTeamGate.updateOne({ teamId }, { $addToSet: { tools: tool } }, { upsert: true });
|
||||
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 移除门户工具
|
||||
*/
|
||||
export const removeGateTool = async ({ teamId, tool }: { teamId: string; tool: string }) => {
|
||||
await MongoTeamGate.updateOne({ teamId }, { $pull: { tools: tool } });
|
||||
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新特色应用列表
|
||||
*/
|
||||
export const updateFeaturedApps = async ({
|
||||
teamId,
|
||||
featuredApps
|
||||
}: {
|
||||
teamId: string;
|
||||
featuredApps: string[];
|
||||
}) => {
|
||||
// 将字符串数组转换为 ObjectId 数组
|
||||
const objectIdArray = featuredApps.map((id) => new Types.ObjectId(id));
|
||||
await MongoTeamGate.updateOne(
|
||||
{ teamId },
|
||||
{ $set: { featuredApps: objectIdArray } },
|
||||
{ upsert: true }
|
||||
);
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 添加特色应用
|
||||
*/
|
||||
export const addFeaturedApp = async ({ teamId, appId }: { teamId: string; appId: string }) => {
|
||||
await MongoTeamGate.updateOne(
|
||||
{ teamId },
|
||||
{ $addToSet: { featuredApps: new Types.ObjectId(appId) } },
|
||||
{ upsert: true }
|
||||
);
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除特色应用
|
||||
*/
|
||||
export const removeFeaturedApp = async ({
|
||||
teamId,
|
||||
appId,
|
||||
session
|
||||
}: {
|
||||
teamId: string;
|
||||
appId: string;
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
await MongoTeamGate.updateOne(
|
||||
{ teamId },
|
||||
{ $pull: { featuredApps: new Types.ObjectId(appId) } },
|
||||
{ session }
|
||||
);
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 移动特色应用位置(原子操作)
|
||||
* @param teamId 团队ID
|
||||
* @param appId 要移动的应用ID
|
||||
* @param toIndex 目标位置索引
|
||||
*/
|
||||
export const moveFeatureAppToPosition = async ({
|
||||
teamId,
|
||||
appId,
|
||||
toIndex
|
||||
}: {
|
||||
teamId: string;
|
||||
appId: string;
|
||||
toIndex: number;
|
||||
}) => {
|
||||
const objectId = new Types.ObjectId(appId);
|
||||
|
||||
// 获取当前配置
|
||||
const config = await MongoTeamGate.findOne({ teamId }).lean();
|
||||
if (!config || !config.featuredApps) {
|
||||
throw new Error('团队配置不存在');
|
||||
}
|
||||
|
||||
const apps = [...config.featuredApps];
|
||||
const currentIndex = apps.findIndex((id) => id.toString() === appId);
|
||||
|
||||
if (currentIndex === -1) {
|
||||
throw new Error('应用不在特色应用列表中');
|
||||
}
|
||||
|
||||
// 移动数组元素
|
||||
const [movedApp] = apps.splice(currentIndex, 1);
|
||||
apps.splice(toIndex, 0, movedApp);
|
||||
|
||||
// 一次性更新
|
||||
await MongoTeamGate.updateOne({ teamId }, { $set: { featuredApps: apps } });
|
||||
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新工具排序
|
||||
* @param teamId 团队ID
|
||||
* @param orderedTools 按新顺序排列的工具数组
|
||||
*/
|
||||
export const reorderTools = async ({
|
||||
teamId,
|
||||
orderedTools
|
||||
}: {
|
||||
teamId: string;
|
||||
orderedTools: string[];
|
||||
}) => {
|
||||
await MongoTeamGate.updateOne({ teamId }, { $set: { tools: orderedTools } });
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量更新门户配置
|
||||
*/
|
||||
export const batchUpdateGateConfigs = async (
|
||||
configs: {
|
||||
teamId: string;
|
||||
status?: boolean;
|
||||
banner?: string;
|
||||
logo?: string;
|
||||
tools?: string[];
|
||||
placeholderText?: string;
|
||||
}[]
|
||||
) => {
|
||||
const operations = configs.map((config) => {
|
||||
const { teamId, ...updateData } = config;
|
||||
return {
|
||||
updateOne: {
|
||||
filter: { teamId },
|
||||
update: { $set: updateData },
|
||||
upsert: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
if (operations.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
await MongoTeamGate.bulkWrite(operations);
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量更新特色应用
|
||||
*/
|
||||
export const batchUpdateFeaturedApps = async (
|
||||
updates: {
|
||||
teamId: string;
|
||||
featuredApps: string[];
|
||||
}[]
|
||||
) => {
|
||||
const operations = updates.map((update) => {
|
||||
const { teamId, featuredApps } = update;
|
||||
// 将字符串数组转换为 ObjectId 数组
|
||||
const objectIdArray = featuredApps.map((id) => new Types.ObjectId(id));
|
||||
return {
|
||||
updateOne: {
|
||||
filter: { teamId },
|
||||
update: { $set: { featuredApps: objectIdArray } },
|
||||
upsert: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
if (operations.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const teamId = updates[0]?.teamId;
|
||||
|
||||
const gateConfig = await MongoTeamGate.findOne({ teamId });
|
||||
if (!gateConfig) return Promise.reject('无 gate 配置');
|
||||
|
||||
const updatedAppId = updates[0].featuredApps;
|
||||
const deleteAppId = gateConfig.featuredApps.filter((id) => !updatedAppId.includes(id));
|
||||
|
||||
await mongoSessionRun(async (session) => {
|
||||
await MongoTeamGate.bulkWrite(operations, { session });
|
||||
|
||||
for (const id of deleteAppId) {
|
||||
await removeGatePermission({
|
||||
teamId,
|
||||
appId: id,
|
||||
per: GateFeaturedAppPermission,
|
||||
session
|
||||
});
|
||||
}
|
||||
for (const id of updatedAppId) {
|
||||
await addGatePermission({
|
||||
teamId,
|
||||
appId: id,
|
||||
per: GateFeaturedAppPermission,
|
||||
session
|
||||
});
|
||||
}
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量更新工具排序
|
||||
*/
|
||||
export const batchUpdateToolsOrder = async (
|
||||
updates: {
|
||||
teamId: string;
|
||||
tools: string[];
|
||||
}[]
|
||||
) => {
|
||||
const operations = updates.map((update) => {
|
||||
const { teamId, tools } = update;
|
||||
return {
|
||||
updateOne: {
|
||||
filter: { teamId },
|
||||
update: { $set: { tools } },
|
||||
upsert: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
if (operations.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
await MongoTeamGate.bulkWrite(operations);
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量删除特色应用
|
||||
* @param teamId 团队ID
|
||||
* @param appIds 要删除的应用ID数组
|
||||
*/
|
||||
export const batchDeleteFeaturedApps = async ({
|
||||
teamId,
|
||||
appIds,
|
||||
session
|
||||
}: {
|
||||
teamId: string;
|
||||
appIds: string[];
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
if (!appIds || appIds.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await MongoTeamGate.updateOne(
|
||||
{ teamId },
|
||||
{ $pull: { featuredApps: { $in: appIds.map((id) => new Types.ObjectId(id)) } } },
|
||||
{
|
||||
session
|
||||
}
|
||||
);
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新快速应用列表
|
||||
*/
|
||||
export const updateQuickApps = async ({
|
||||
teamId,
|
||||
quickApps
|
||||
}: {
|
||||
teamId: string;
|
||||
quickApps: string[];
|
||||
}) => {
|
||||
await MongoTeamGate.updateOne({ teamId }, { $set: { quickApps } }, { upsert: true });
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 添加快速应用
|
||||
*/
|
||||
export const addQuickApp = async ({ teamId, appId }: { teamId: string; appId: string }) => {
|
||||
await MongoTeamGate.updateOne(
|
||||
{ teamId },
|
||||
{ $addToSet: { quickApps: new Types.ObjectId(appId) } },
|
||||
{ upsert: true }
|
||||
);
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除快速应用
|
||||
*/
|
||||
export const removeQuickApp = async ({ teamId, appId }: { teamId: string; appId: string }) => {
|
||||
await MongoTeamGate.updateOne({ teamId }, { $pull: { quickApps: new Types.ObjectId(appId) } });
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 移动快速应用位置(原子操作)
|
||||
* @param teamId 团队ID
|
||||
* @param appId 要移动的应用ID
|
||||
* @param toIndex 目标位置索引
|
||||
*/
|
||||
export const moveQuickAppToPosition = async ({
|
||||
teamId,
|
||||
appId,
|
||||
toIndex
|
||||
}: {
|
||||
teamId: string;
|
||||
appId: string;
|
||||
toIndex: number;
|
||||
}) => {
|
||||
const objectId = new Types.ObjectId(appId);
|
||||
|
||||
// 获取当前配置
|
||||
const config = await MongoTeamGate.findOne({ teamId }).lean();
|
||||
if (!config || !config.quickApps) {
|
||||
throw new Error('团队配置不存在');
|
||||
}
|
||||
|
||||
const apps = [...config.quickApps];
|
||||
const currentIndex = apps.findIndex((id) => id.toString() === appId);
|
||||
|
||||
if (currentIndex === -1) {
|
||||
throw new Error('应用不在快速应用列表中');
|
||||
}
|
||||
|
||||
// 移动数组元素
|
||||
const [movedApp] = apps.splice(currentIndex, 1);
|
||||
apps.splice(toIndex, 0, movedApp);
|
||||
|
||||
// 一次性更新
|
||||
await MongoTeamGate.updateOne({ teamId }, { $set: { quickApps: apps } });
|
||||
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量更新快速应用
|
||||
*/
|
||||
export const batchUpdateQuickApps = async (teamId: string, quickApps: string[]) => {
|
||||
const gateConfig = await MongoTeamGate.findOne({ teamId });
|
||||
if (!gateConfig) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 计算删除的appId
|
||||
const deleteAppIds = gateConfig.quickApps.filter((id) => !quickApps.includes(id.toString()));
|
||||
|
||||
return mongoSessionRun(async (session) => {
|
||||
// 1. 删除权限
|
||||
for (const id of deleteAppIds) {
|
||||
await removeGatePermission({
|
||||
teamId,
|
||||
appId: id,
|
||||
per: GateQuickAppPermission,
|
||||
session
|
||||
});
|
||||
}
|
||||
// 加权限
|
||||
for (const id of quickApps) {
|
||||
await addGatePermission({
|
||||
teamId,
|
||||
appId: id,
|
||||
per: GateQuickAppPermission,
|
||||
session
|
||||
});
|
||||
}
|
||||
|
||||
gateConfig.quickApps = quickApps;
|
||||
await gateConfig.save({ session });
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量删除快速应用
|
||||
* @param teamId 团队ID
|
||||
* @param appIds 要删除的应用ID数组
|
||||
*/
|
||||
export const batchDeleteQuickApps = async ({
|
||||
teamId,
|
||||
appIds
|
||||
}: {
|
||||
teamId: string;
|
||||
appIds: string[];
|
||||
}) => {
|
||||
if (!appIds || appIds.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await MongoTeamGate.updateOne(
|
||||
{ teamId },
|
||||
{ $pull: { quickApps: { $in: appIds.map((id) => new Types.ObjectId(id)) } } }
|
||||
);
|
||||
return true;
|
||||
};
|
||||
45
packages/service/support/user/team/gate/schema.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
|
||||
import { Schema, getMongoModel } from '../../../../common/mongo';
|
||||
import type { GateSchemaType } from '@fastgpt/global/support/user/team/gate/type';
|
||||
|
||||
export const gateCollectionName = 'team_gate_config';
|
||||
|
||||
const GateConfigSchema = new Schema({
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName
|
||||
},
|
||||
status: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
name: {
|
||||
type: String
|
||||
},
|
||||
banner: {
|
||||
type: String
|
||||
},
|
||||
logo: {
|
||||
type: String
|
||||
},
|
||||
tools: {
|
||||
type: [String]
|
||||
},
|
||||
placeholderText: {
|
||||
type: String
|
||||
},
|
||||
featuredApps: [
|
||||
{
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'apps'
|
||||
}
|
||||
],
|
||||
quickApps: [
|
||||
{
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'apps'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
export const MongoTeamGate = getMongoModel<GateSchemaType>(gateCollectionName, GateConfigSchema);
|
||||
@@ -17,6 +17,11 @@ const TeamSchema = new Schema({
|
||||
type: String,
|
||||
default: '/icon/logo.svg'
|
||||
},
|
||||
// todo :banner
|
||||
banner: {
|
||||
type: String,
|
||||
default: '/icon/banner.svg'
|
||||
},
|
||||
createTime: {
|
||||
type: Date,
|
||||
default: () => Date.now()
|
||||
|
||||
@@ -287,6 +287,7 @@ export const iconPaths = {
|
||||
'core/workflow/template/aiChat': () => import('./icons/core/workflow/template/aiChat.svg'),
|
||||
'core/workflow/template/baseChart': () => import('./icons/core/workflow/template/baseChart.svg'),
|
||||
'core/workflow/template/bing': () => import('./icons/core/workflow/template/bing.svg'),
|
||||
'core/workflow/template/bocha': () => import('./icons/core/workflow/template/bocha.svg'),
|
||||
'core/workflow/template/codeRun': () => import('./icons/core/workflow/template/codeRun.svg'),
|
||||
'core/workflow/template/customFeedback': () =>
|
||||
import('./icons/core/workflow/template/customFeedback.svg'),
|
||||
@@ -473,6 +474,31 @@ export const iconPaths = {
|
||||
'support/user/userLightSmall': () => import('./icons/support/user/userLightSmall.svg'),
|
||||
'support/user/usersFill': () => import('./icons/support/user/usersFill.svg'),
|
||||
'support/user/usersLight': () => import('./icons/support/user/usersLight.svg'),
|
||||
'support/gate/gateLight': () => import('./icons/support/gate/gateLight.svg'),
|
||||
'support/gate/chat/sidebar/chatGray': () =>
|
||||
import('./icons/support/gate/chat/sidebar/chatGray.svg'),
|
||||
'support/gate/chat/historySlider/new_chat': () =>
|
||||
import('./icons/support/gate/chat/historySlider/new_chat.svg'),
|
||||
'support/gate/chat/historySlider/clear-all': () =>
|
||||
import('./icons/support/gate/chat/historySlider/clear-all.svg'),
|
||||
'support/gate/chat/historySlider/chevron-right2': () =>
|
||||
import('./icons/support/gate/chat/historySlider/chevron-right2.svg'),
|
||||
'support/gate/chat/toolkitLine': () => import('./icons/support/gate/chat/toolkitLine.svg'),
|
||||
'support/gate/chat/historySlider/chevron-left2': () =>
|
||||
import('./icons/support/gate/chat/historySlider/chevron-left2.svg'),
|
||||
'support/gate/chat/sidebar/appGray': () =>
|
||||
import('./icons/support/gate/chat/sidebar/appGray.svg'),
|
||||
'support/gate/chat/voiceGray': () => import('./icons/support/gate/chat/voiceGray.svg'),
|
||||
'support/gate/chat/fileGray': () => import('./icons/support/gate/chat/fileGray.svg'),
|
||||
'support/gate/chat/paperclip': () => import('./icons/support/gate/chat/paperclip.svg'),
|
||||
'support/gate/chat/imageGray': () => import('./icons/support/gate/chat/imageGray.svg'),
|
||||
'support/gate/chat/sidebar/CollapseButton': () =>
|
||||
import('./icons/support/gate/chat/sidebar/CollapseButton.svg'),
|
||||
'support/gate/home/savePrimary': () => import('./icons/support/gate/home/savePrimary.svg'),
|
||||
'support/gate/home/shareLight': () => import('./icons/support/gate/home/shareLight.svg'),
|
||||
'support/gate/home/sharePrimary': () => import('./icons/support/gate/home/sharePrimary.svg'),
|
||||
'support/gate/home/upload': () => import('./icons/support/gate/home/upload.svg'),
|
||||
'support/gate/home/add': () => import('./icons/support/gate/home/add.svg'),
|
||||
text: () => import('./icons/text.svg'),
|
||||
union: () => import('./icons/union.svg'),
|
||||
user: () => import('./icons/user.svg'),
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="113" height="97" viewBox="0 0 113 97" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 31.7259C1.80046 29.9255 3.82784 28.3872 5.96621 27.1988C8.10469 26.0103 10.3126 25.1947 12.4634 24.7992C14.6143 24.4037 16.6664 24.4361 18.5022 24.8938C20.2678 25.334 21.7994 26.1604 23.0183 27.3272L23.021 27.3245L47.189 51.4924L33.4778 65.2037L0 31.7259Z" fill="#C4DEFE"/>
|
||||
<path d="M9.15662 11.5625C11.3617 10.2893 13.7181 9.32825 16.0912 8.73374C18.4645 8.13923 20.8082 7.92284 22.9882 8.09751C25.1681 8.27217 27.1419 8.83457 28.7966 9.75182C30.3881 10.6341 31.6537 11.8287 32.529 13.2712L32.5316 13.2697L32.6082 13.4025C32.6162 13.4162 32.6251 13.4297 32.633 13.4435L49.886 43.3286L33.0941 53.0234L9.15662 11.5625Z" fill="#A6CBFF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.1377 0C33.6839 4.40811e-05 36.2052 0.345872 38.5576 1.01758C40.9099 1.68929 43.0472 2.67394 44.8477 3.91504C46.6482 5.15627 48.0773 6.63021 49.0518 8.25195C49.9888 9.81168 50.4867 11.4792 50.5234 13.166H50.5273V21.4072C56.6623 17.6586 63.874 15.498 71.5898 15.498C93.9304 15.4984 112.042 33.6087 112.042 55.9492C112.042 78.29 93.9305 96.401 71.5898 96.4014C49.3907 96.4014 31.3704 78.5193 31.1426 56.374H31.1377V0ZM71.9473 35.0439C60.1187 35.0441 50.5295 44.6334 50.5293 56.4619C50.5293 63.5338 53.9569 69.8057 59.2412 73.7061C66.4989 79.0625 76.5515 75.3841 85.3955 77.1592C92.613 78.608 97.2369 82.6827 98.3652 83.7686C97.3562 82.731 93.791 78.7138 92.2715 72.3291C89.8011 61.9479 94.8744 49.6043 87.5771 41.8184C83.6695 37.6493 78.1122 35.0441 71.9473 35.0439Z" fill="#006EFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.6665 3.0263C10.5079 3.01307 10.2763 3.01095 9.84294 3.01095H7.16646C6.45348 3.01095 5.96581 3.01152 5.58819 3.04048C5.21887 3.06881 5.02616 3.12054 4.89105 3.18516C4.57275 3.3374 4.32387 3.57549 4.17134 3.85649C4.11194 3.96593 4.05991 4.12789 4.03072 4.4633C4.00053 4.81012 3.9998 5.26058 3.9998 5.93236V14.0677C3.9998 14.7394 4.00053 15.1899 4.03072 15.5367C4.05991 15.8721 4.11194 16.0341 4.17134 16.1435C4.32387 16.4245 4.57275 16.6626 4.89105 16.8149C5.02616 16.8795 5.21887 16.9312 5.58819 16.9595C5.96581 16.9885 6.45348 16.9891 7.16646 16.9891H12.4998C13.2128 16.9891 13.7005 16.9885 14.0781 16.9595C14.4474 16.9312 14.6401 16.8795 14.7752 16.8149C15.0935 16.6626 15.3424 16.4245 15.4949 16.1435C15.5543 16.0341 15.6063 15.8721 15.6355 15.5367C15.6657 15.1899 15.6665 14.7394 15.6665 14.0677V8.42632C15.6665 8.04949 15.6642 7.84193 15.654 7.70438L12.8076 7.70439C12.5963 7.70441 12.3934 7.70443 12.2221 7.69129C12.0356 7.67698 11.8167 7.64346 11.5952 7.53756C11.2863 7.38982 11.0253 7.14923 10.8582 6.84149C10.736 6.61626 10.6972 6.39184 10.681 6.2055C10.6664 6.03826 10.6664 5.84201 10.6665 5.64647C10.6665 5.63747 10.6665 5.62847 10.6665 5.61947V3.0263ZM11.8068 1.61342C11.6211 1.53551 11.4284 1.47397 11.2311 1.42951C10.8511 1.34388 10.4571 1.34404 9.92517 1.34426C9.89812 1.34427 9.87072 1.34428 9.84294 1.34428L7.13385 1.34428C6.4615 1.34427 5.90966 1.34427 5.46075 1.37869C4.99631 1.41431 4.57159 1.49047 4.17193 1.68162C3.54942 1.97936 3.03339 2.45928 2.70655 3.0614C2.49347 3.45396 2.40926 3.87156 2.37033 4.31878C2.33311 4.74646 2.33312 5.26987 2.33313 5.89642V14.1036C2.33312 14.7301 2.33311 15.2536 2.37033 15.6812C2.40926 16.1285 2.49347 16.5461 2.70655 16.9386C3.03339 17.5407 3.54942 18.0207 4.17193 18.3184C4.57159 18.5096 4.99631 18.5857 5.46075 18.6213C5.90965 18.6558 6.46147 18.6557 7.13382 18.6557H12.5324C13.2048 18.6557 13.7566 18.6558 14.2055 18.6213C14.67 18.5857 15.0947 18.5096 15.4943 18.3184C16.1168 18.0207 16.6329 17.5407 16.9597 16.9386C17.1728 16.5461 17.257 16.1285 17.2959 15.6812C17.3332 15.2536 17.3331 14.7301 17.3331 14.1036V8.42632C17.3331 8.39763 17.3331 8.3693 17.3332 8.3413C17.3335 7.85013 17.3337 7.46273 17.2381 7.08878C17.1885 6.89509 17.1202 6.70705 17.0344 6.52696C17.0287 6.51433 17.0227 6.50187 17.0163 6.4896C16.9608 6.37678 16.8983 6.26719 16.8292 6.16139C16.6188 5.83909 16.3328 5.57093 15.9611 5.22237C15.9405 5.20307 15.9197 5.18353 15.8986 5.16372L13.2417 2.66977C13.2216 2.65089 13.2018 2.63225 13.1822 2.61385C12.8076 2.26189 12.5241 1.99554 12.186 1.80108C12.0761 1.73786 11.9628 1.68091 11.8466 1.63043C11.8335 1.62442 11.8202 1.61875 11.8068 1.61342ZM12.3331 4.10281V5.61947C12.3331 5.82534 12.3337 5.94445 12.339 6.02864C12.3423 6.02893 12.3458 6.02922 12.3495 6.0295C12.4492 6.03715 12.5869 6.03772 12.8331 6.03772H14.3944L12.3331 4.10281Z" fill="#707070"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,7 @@
|
||||
<svg width="16" height="20" viewBox="0 0 16 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="icon/solid/chevron-right2">
|
||||
<path id="Rectangle 3101"
|
||||
d="M11.0474 14.2501C11.0474 15.735 9.25219 16.4786 8.20225 15.4286L3.95213 11.1785C3.30126 10.5276 3.30126 9.47236 3.95213 8.82149L8.20225 4.57138C9.25219 3.52143 11.0474 4.26505 11.0474 5.74989L11.0474 14.2501Z"
|
||||
fill="currentColor" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 444 B |
@@ -0,0 +1,7 @@
|
||||
<svg width="16" height="20" viewBox="0 0 16 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="icon/solid/chevron-right2">
|
||||
<path id="Rectangle 3101"
|
||||
d="M4.95255 5.74989C4.95255 4.26505 6.74778 3.52143 7.79772 4.57138L12.0478 8.82149C12.6987 9.47236 12.6987 10.5276 12.0478 11.1785L7.79772 15.4286C6.74778 16.4786 4.95255 15.735 4.95255 14.2501V5.74989Z"
|
||||
fill="currentColor" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 436 B |
@@ -0,0 +1,7 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="icon/line/clear-all">
|
||||
<path id="Union" fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M7.33331 2.63809C7.33331 2.49081 7.4527 2.37142 7.59997 2.37142H8.39997C8.54725 2.37142 8.66664 2.49081 8.66664 2.63809V4.2C8.66664 4.9732 9.29344 5.6 10.0666 5.6L12.861 5.6C13.0083 5.6 13.1277 5.71939 13.1277 5.86666V6.66666C13.1277 6.81394 13.0083 6.93333 12.861 6.93333L3.13891 6.93333C2.99164 6.93333 2.87224 6.81394 2.87224 6.66666V5.86666C2.87224 5.71939 2.99164 5.6 3.13891 5.6L5.93331 5.6C6.70651 5.6 7.33331 4.97319 7.33331 4.2V2.63809ZM7.59997 1.03809C6.71632 1.03809 5.99997 1.75443 5.99997 2.63809V4.2C5.99997 4.23681 5.97012 4.26666 5.93331 4.26666L3.13891 4.26666C2.25526 4.26666 1.53891 4.98301 1.53891 5.86666V6.66666C1.53891 7.41125 2.04753 8.03705 2.73629 8.21558L1.47841 12.628C1.18709 13.6499 1.9545 14.6667 3.01711 14.6667H13.0318C14.0831 14.6667 14.8487 13.6701 14.5778 12.6543L13.384 8.17923C14.0109 7.96253 14.461 7.36717 14.461 6.66666V5.86666C14.461 4.98301 13.7447 4.26666 12.861 4.26666L10.0666 4.26666C10.0298 4.26666 9.99997 4.23681 9.99997 4.2V2.63809C9.99997 1.75443 9.28363 1.03809 8.39997 1.03809H7.59997ZM4.30936 8.26696H11.8226C11.9434 8.26696 12.0491 8.34817 12.0803 8.46489L13.2895 12.9979C13.3347 13.1672 13.207 13.3333 13.0318 13.3333H10.6269C10.627 13.3291 10.6271 13.3249 10.6271 13.3206L10.6409 11.4144C10.6436 11.0462 10.3472 10.7456 9.97907 10.7429C9.61089 10.7403 9.31026 11.0366 9.30759 11.4047L9.2938 13.311C9.29374 13.3184 9.29381 13.3259 9.294 13.3333H6.87303L6.87324 13.3206L6.88704 11.4144C6.88971 11.0462 6.5934 10.7456 6.22522 10.7429C5.85704 10.7403 5.55641 11.0366 5.55374 11.4047L5.53995 13.311C5.53989 13.3184 5.53996 13.3259 5.54015 13.3333H3.01711C2.84 13.3333 2.71211 13.1639 2.76066 12.9936L4.05291 8.46052C4.08557 8.34596 4.19024 8.26696 4.30936 8.26696Z"
|
||||
fill="currentColor" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,8 @@
|
||||
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M11.3834 2.86546C11.3834 3.27967 11.0476 3.61546 10.6334 3.61546H6.05212C4.39495 3.61546 3.05139 4.95892 3.05139 6.61546V10.3215C3.05158 11.5943 3.84602 12.6857 4.9696 13.1201L5.19885 13.1977L5.54646 13.3005C5.76638 13.3656 5.94445 13.5277 6.02982 13.7406L6.16492 14.0774C6.29685 14.4057 6.68973 14.54 6.99503 14.3611L8.59462 13.4243C8.70956 13.357 8.84034 13.3215 8.97353 13.3215H12.8014C14.4065 13.3215 15.7178 12.0607 15.7985 10.4761L15.8021 10.3215V7.97703C15.8021 7.56281 16.1379 7.22703 16.5521 7.22703C16.9663 7.22703 17.3021 7.56281 17.3021 7.97703V10.3215C17.3019 12.8066 15.2865 14.8215 12.8014 14.8215H9.38096C9.24764 14.8215 9.11674 14.857 9.00172 14.9245L6.57434 16.3471C6.10009 16.625 5.48906 16.4168 5.28381 15.907L4.90857 14.9729C4.82314 14.7602 4.64369 14.6019 4.42992 14.5193C2.74626 13.8685 1.55158 12.2347 1.55139 10.3215V6.61546C1.55139 4.13017 3.56684 2.11546 6.05212 2.11546H10.6334C11.0476 2.11546 11.3834 2.45124 11.3834 2.86546Z"
|
||||
fill="#3370FF" />
|
||||
<path
|
||||
d="M14.9027 1.52901C15.2541 1.52912 15.5392 1.81403 15.5392 2.16549V3.43844H16.8121C17.1636 3.43851 17.4486 3.72344 17.4486 4.07491C17.4485 4.42632 17.1635 4.71132 16.8121 4.71139H15.5392V5.98434C15.5391 6.33571 15.2541 6.62071 14.9027 6.62081C14.5513 6.62081 14.2663 6.33577 14.2662 5.98434V4.71139H12.9933C12.6418 4.71139 12.3569 4.42637 12.3568 4.07491C12.3568 3.7234 12.6418 3.43844 12.9933 3.43844H14.2662V2.16549C14.2662 1.81397 14.5512 1.52901 14.9027 1.52901Z"
|
||||
fill="#3370FF" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.61372 6.52442C6.30407 6.52442 6.86372 5.96478 6.86372 5.27442C6.86372 4.58407 6.30407 4.02442 5.61372 4.02442C4.92336 4.02442 4.36371 4.58407 4.36371 5.27442C4.36371 5.96478 4.92336 6.52442 5.61372 6.52442Z" fill="#707070"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.666656 5.31489C0.666656 3.63474 0.666656 2.79466 0.993637 2.15292C1.28126 1.58843 1.7402 1.12949 2.30468 0.841873C2.94642 0.514893 3.7865 0.514893 5.46666 0.514893H12.5333C14.2135 0.514893 15.0536 0.514893 15.6953 0.841873C16.2598 1.12949 16.7187 1.58843 17.0063 2.15292C17.3333 2.79466 17.3333 3.63473 17.3333 5.31489V10.6852C17.3333 12.3654 17.3333 13.2054 17.0063 13.8472C16.7187 14.4117 16.2598 14.8706 15.6953 15.1582C15.0536 15.4852 14.2135 15.4852 12.5333 15.4852H5.46666C3.7865 15.4852 2.94642 15.4852 2.30468 15.1582C1.7402 14.8706 1.28126 14.4117 0.993637 13.8472C0.666656 13.2054 0.666656 12.3654 0.666656 10.6852V5.31489ZM5.46666 2.18156H12.5333C13.4009 2.18156 13.9514 2.18286 14.368 2.2169C14.7652 2.24935 14.8919 2.30306 14.9386 2.32688C15.1895 2.45472 15.3935 2.65869 15.5213 2.90957C15.5452 2.95633 15.5989 3.08303 15.6313 3.48022C15.6654 3.89686 15.6667 4.44731 15.6667 5.31489V10.6852C15.6667 10.6952 15.6667 10.7052 15.6667 10.7152L11.6244 6.67291C11.2989 6.34747 10.7713 6.34747 10.4459 6.67291L3.36552 13.7533C3.17216 13.7239 3.09546 13.6906 3.06134 13.6732C2.81045 13.5454 2.60648 13.3414 2.47865 13.0905C2.45483 13.0438 2.40111 12.9171 2.36866 12.5199C2.33462 12.1032 2.33332 11.5528 2.33332 10.6852V5.31489C2.33332 4.44731 2.33462 3.89686 2.36866 3.48022C2.40111 3.08303 2.45483 2.95633 2.47865 2.90957C2.60648 2.65869 2.81045 2.45472 3.06134 2.32688C3.10809 2.30306 3.23479 2.24935 3.63198 2.2169C4.04863 2.18286 4.59908 2.18156 5.46666 2.18156ZM11.0351 8.44068L5.65725 13.8185H12.5333C13.4009 13.8185 13.9514 13.8172 14.368 13.7832C14.7652 13.7508 14.8919 13.697 14.9386 13.6732C15.1895 13.5454 15.3935 13.3414 15.5213 13.0905C15.5316 13.0704 15.5474 13.0354 15.5647 12.9703L11.0351 8.44068Z" fill="#707070"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,7 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="icon/line/paperclip">
|
||||
<path id="Icon (Stroke)" fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M13.001 3.12035C12.4123 3.12035 11.8477 3.3542 11.4315 3.77046L4.63705 10.5649C3.94333 11.2586 3.55361 12.1995 3.55361 13.1805C3.55361 14.1616 3.94333 15.1025 4.63705 15.7962C5.33077 16.4899 6.27165 16.8796 7.25271 16.8796C8.23377 16.8796 9.17465 16.4899 9.86837 15.7962L16.6628 9.00179C16.9515 8.71306 17.4196 8.71306 17.7084 9.00179C17.9971 9.29051 17.9971 9.75863 17.7084 10.0474L10.9139 16.8418C9.94292 17.8128 8.62594 18.3583 7.25271 18.3583C5.87948 18.3583 4.5625 17.8128 3.59148 16.8418C2.62046 15.8708 2.07495 14.5538 2.07495 13.1805C2.07495 11.8073 2.62046 10.4903 3.59148 9.51931L10.3859 2.72489C11.0795 2.03133 12.0201 1.64169 13.001 1.64169C13.9818 1.64169 14.9225 2.03133 15.6161 2.72489C16.3096 3.41846 16.6993 4.35913 16.6993 5.33997C16.6993 6.32082 16.3096 7.26149 15.6161 7.95506L8.81425 14.7495C8.39814 15.1656 7.83378 15.3993 7.24532 15.3993C6.65685 15.3993 6.09249 15.1656 5.67638 14.7495C5.26028 14.3334 5.02651 13.769 5.02651 13.1805C5.02651 12.5921 5.26028 12.0277 5.67638 11.6116L11.9536 5.34181C12.2425 5.05325 12.7106 5.05353 12.9991 5.34242C13.2877 5.63132 13.2874 6.09943 12.9985 6.38799L6.72195 12.6572C6.58334 12.796 6.50517 12.9844 6.50517 13.1805C6.50517 13.3768 6.58315 13.5651 6.72195 13.7039C6.86076 13.8427 7.04902 13.9207 7.24532 13.9207C7.44162 13.9207 7.62988 13.8427 7.76868 13.7039L14.5705 6.90949C14.9866 6.49326 15.2206 5.92852 15.2206 5.33997C15.2206 4.75129 14.9868 4.18672 14.5705 3.77046C14.1542 3.3542 13.5897 3.12035 13.001 3.12035Z"
|
||||
fill="currentColor" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,8 @@
|
||||
<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M9.91227 5.23185C10.2356 4.95244 10.724 4.98763 11.0036 5.31079C11.2829 5.63414 11.2479 6.12338 10.9246 6.40291L9.16113 7.92797L10.8774 9.51977C11.192 9.81221 11.2103 10.305 10.9181 10.62C10.6259 10.9347 10.1339 10.9531 9.81868 10.6615L7.54085 8.54972C7.37406 8.39504 7.29205 8.18359 7.29346 7.97273C7.2559 7.71942 7.34339 7.45278 7.55143 7.27286L9.91227 5.23185Z"
|
||||
fill="currentcolor" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M13.0072 0.108149C15.6489 0.242083 17.7498 2.42669 17.75 5.10164V10.8984L17.7435 11.1555C17.614 13.7122 15.5638 15.7622 13.0072 15.8918L12.75 15.8984H5.25L4.99284 15.8918C2.43607 15.7623 0.385993 13.7123 0.25651 11.1555L0.25 10.8984V5.10164C0.250186 2.42663 2.35104 0.24199 4.99284 0.108149L5.25 0.101639H12.75L13.0072 0.108149ZM5.92546 14.2317H12.75C14.5909 14.2316 16.0833 12.7392 16.0833 10.8984V5.10164C16.0831 3.26092 14.5907 1.76842 12.75 1.76831H5.92546V14.2317ZM4.39225 1.8798C3.02015 2.24419 1.99539 3.4618 1.92074 4.92993L1.91667 5.10164V10.8984C1.91667 12.4427 2.96708 13.7408 4.39225 14.1194V1.8798Z"
|
||||
fill="currentcolor" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,14 @@
|
||||
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M0.10022 1.2C0.10022 0.537258 0.637478 0 1.30022 0H6.90022C7.56296 0 8.10022 0.537258 8.10022 1.2V6.8C8.10022 7.46274 7.56296 8 6.90022 8H1.30022C0.637478 8 0.10022 7.46274 0.10022 6.8V1.2ZM2.10022 6V2H6.10022V6H2.10022Z"
|
||||
fill="#8A95A7" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M10.1002 1.2C10.1002 0.537258 10.6375 0 11.3002 0H16.9002C17.563 0 18.1002 0.537258 18.1002 1.2V6.8C18.1002 7.46274 17.563 8 16.9002 8H11.3002C10.6375 8 10.1002 7.46274 10.1002 6.8V1.2ZM12.1002 6V2H16.1002V6H12.1002Z"
|
||||
fill="#8A95A7" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M11.3002 10C10.6375 10 10.1002 10.5373 10.1002 11.2V16.8C10.1002 17.4627 10.6375 18 11.3002 18H16.9002C17.563 18 18.1002 17.4627 18.1002 16.8V11.2C18.1002 10.5373 17.563 10 16.9002 10H11.3002ZM12.1002 12V16H16.1002V12H12.1002Z"
|
||||
fill="#8A95A7" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M0.10022 11.2C0.10022 10.5373 0.637478 10 1.30022 10H6.90022C7.56296 10 8.10022 10.5373 8.10022 11.2V16.8C8.10022 17.4627 7.56296 18 6.90022 18H1.30022C0.637478 18 0.10022 17.4627 0.10022 16.8V11.2ZM2.10022 16V12H6.10022V16H2.10022Z"
|
||||
fill="#8A95A7" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,18 @@
|
||||
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="icon/line/chat">
|
||||
<g id="Union">
|
||||
<path
|
||||
d="M6.18697 8.52243C6.77251 8.52244 7.24715 8.99732 7.24735 9.58281C7.24735 10.1685 6.77263 10.6432 6.18697 10.6432C5.60129 10.6432 5.12659 10.1685 5.12659 9.58281C5.12679 8.99731 5.60142 8.52243 6.18697 8.52243Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M10.0004 8.52243C10.586 8.52244 11.0606 8.99732 11.0608 9.58281C11.0608 10.1685 10.5861 10.6432 10.0004 10.6432C9.41477 10.6432 8.94006 10.1685 8.94006 9.58281C8.94027 8.99731 9.4149 8.52243 10.0004 8.52243Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M13.8139 8.52243C14.3994 8.52249 14.8741 8.99735 14.8743 9.58281C14.8743 10.1684 14.3995 10.6431 13.8139 10.6432C13.2282 10.6432 12.7535 10.1685 12.7535 9.58281C12.7537 8.99731 13.2284 8.52243 13.8139 8.52243Z"
|
||||
fill="currentColor" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M13.7504 2.5247C16.5117 2.52492 18.7504 4.76342 18.7504 7.5247V11.6425C18.7502 14.4037 16.5109 16.6425 13.7496 16.6425H9.94918C9.80105 16.6425 9.65542 16.6824 9.52763 16.7573L6.83069 18.3377C6.30374 18.6465 5.62482 18.4151 5.39677 17.8486L4.9801 16.811C4.88518 16.5747 4.6854 16.3983 4.44788 16.3064C2.57725 15.5833 1.24985 13.7682 1.24963 11.6425V7.5247C1.24963 4.76328 3.48902 2.5247 6.25045 2.5247H13.7504ZM6.25045 4.19137C4.40914 4.19137 2.9163 5.68411 2.9163 7.5247V11.6425C2.91651 13.0567 3.79923 14.2694 5.04765 14.7521L5.30237 14.8383L5.68892 14.9523C5.93318 15.0246 6.1312 15.2049 6.22603 15.4414L6.37577 15.8157C6.52236 16.1805 6.9586 16.3293 7.29781 16.1307L9.07515 15.0898C9.20286 15.015 9.34872 14.9759 9.4967 14.9759H13.7496C15.5331 14.9759 16.9901 13.5749 17.0797 11.8143L17.0838 11.6425V7.5247C17.0838 5.74165 15.6833 4.28501 13.9222 4.19544L13.7504 4.19137H6.25045Z"
|
||||
fill="currentColor" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M12.81 4.4538H12.8072C14.1971 4.45385 14.8993 4.45754 15.4374 4.73173C15.9173 4.97621 16.3074 5.36631 16.5518 5.84612C16.8298 6.3916 16.8298 7.10566 16.8298 8.5338V12.42C16.8298 13.8481 16.8298 14.5622 16.5518 15.1077C16.3074 15.5875 15.9173 15.9776 15.4374 16.2221C14.892 16.5 14.1779 16.5 12.7498 16.5H5.24992C3.82179 16.5 3.10772 16.5 2.56225 16.2221C2.08243 15.9776 1.69233 15.5875 1.44786 15.1077C1.16992 14.5622 1.16992 13.8481 1.16992 12.42V8.5338C1.16992 7.10566 1.16992 6.3916 1.44786 5.84612C1.69233 5.36631 2.08243 4.97621 2.56225 4.73173C3.10772 4.4538 3.82179 4.4538 5.24992 4.4538H5.36574V4.19994C5.36574 2.70877 6.57457 1.49994 8.06574 1.49994H10.11C11.6012 1.49994 12.81 2.70877 12.81 4.19994V4.4538ZM8.06574 2.99994H10.11C10.7727 2.99994 11.31 3.5372 11.31 4.19994V4.4538H6.86574V4.19994C6.86574 3.5372 7.403 2.99994 8.06574 2.99994ZM12.7498 5.9538H5.24992C4.5111 5.9538 4.0472 5.95496 3.69724 5.98356C3.36478 6.01072 3.26927 6.05497 3.24323 6.06824C3.04566 6.16891 2.88503 6.32954 2.78437 6.52711C2.7711 6.55314 2.72684 6.64865 2.69968 6.98111C2.68387 7.17461 2.67645 7.40293 2.67297 7.6933H15.3267C15.3232 7.40293 15.3158 7.17461 15.3 6.98111C15.2728 6.64865 15.2286 6.55314 15.2153 6.52711C15.1147 6.32954 14.954 6.16891 14.7565 6.06824C14.7304 6.05497 14.6349 6.01072 14.3025 5.98356C13.9525 5.95496 13.4886 5.9538 12.7498 5.9538ZM15.3298 9.0433H10.9765V11.392C10.9765 11.6405 10.775 11.842 10.5265 11.842H7.47313C7.2246 11.842 7.02313 11.6405 7.02313 11.392V9.0433H2.66992V12.42C2.66992 13.1588 2.67109 13.6227 2.69968 13.9727C2.72684 14.3052 2.7711 14.4007 2.78437 14.4267C2.88503 14.6243 3.04566 14.7849 3.24323 14.8856C3.26927 14.8988 3.36478 14.9431 3.69723 14.9702C4.0472 14.9988 4.5111 15 5.24992 15H12.7498C13.4886 15 13.9525 14.9988 14.3025 14.9702C14.6349 14.9431 14.7304 14.8988 14.7565 14.8856C14.954 14.7849 15.1147 14.6243 15.2153 14.4267C15.2286 14.4007 15.2728 14.3052 15.3 13.9727C15.3286 13.6227 15.3298 13.1588 15.3298 12.42V9.0433ZM9.62651 9.0433H8.37313V10.492H9.62651V9.0433Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M7.91635 2.02287C8.46897 1.47025 9.21848 1.15979 10 1.15979C10.7815 1.15979 11.531 1.47025 12.0837 2.02287C12.6363 2.57549 12.9467 3.325 12.9467 4.10652V9.99999C12.9467 10.7815 12.6363 11.531 12.0837 12.0836C11.531 12.6363 10.7815 12.9467 10 12.9467C9.21848 12.9467 8.46897 12.6363 7.91635 12.0836C7.36373 11.531 7.05327 10.7815 7.05327 9.99999V4.10652C7.05327 3.325 7.36373 2.57549 7.91635 2.02287ZM10 2.63316C9.60924 2.63316 9.23448 2.78839 8.95817 3.06469C8.68186 3.341 8.52663 3.71576 8.52663 4.10652V9.99999C8.52663 10.3907 8.68186 10.7655 8.95817 11.0418C9.23448 11.3181 9.60924 11.4734 10 11.4734C10.3908 11.4734 10.7655 11.3181 11.0418 11.0418C11.3181 10.7655 11.4734 10.3907 11.4734 9.99999V4.10652C11.4734 3.71576 11.3181 3.341 11.0418 3.06469C10.7655 2.78839 10.3908 2.63316 10 2.63316ZM4.84322 7.78994C5.25008 7.78994 5.5799 8.11976 5.5799 8.52662V9.99999C5.5799 11.1723 6.04559 12.2965 6.87452 13.1255C7.70345 13.9544 8.82772 14.4201 10 14.4201C11.1723 14.4201 12.2966 13.9544 13.1255 13.1255C13.9544 12.2965 14.4201 11.1723 14.4201 9.99999V8.52662C14.4201 8.11976 14.7499 7.78994 15.1568 7.78994C15.5636 7.78994 15.8935 8.11976 15.8935 8.52662V9.99999C15.8935 11.563 15.2725 13.0621 14.1673 14.1673C13.2372 15.0974 12.0281 15.6846 10.7367 15.8472V17.3668H12.9467C13.3536 17.3668 13.6834 17.6966 13.6834 18.1035C13.6834 18.5104 13.3536 18.8402 12.9467 18.8402H7.05327C6.64641 18.8402 6.31659 18.5104 6.31659 18.1035C6.31659 17.6966 6.64641 17.3668 7.05327 17.3668H9.26332V15.8472C7.97191 15.6846 6.76285 15.0974 5.83269 14.1673C4.72745 13.0621 4.10654 11.563 4.10654 9.99999V8.52662C4.10654 8.11976 4.43636 7.78994 4.84322 7.78994Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<!-- 保持原路径不变 -->
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M9.57021 1.39896C9.85172 1.32274 10.1484 1.32274 10.4299 1.39896C10.757 1.48751 11.0321 1.70357 11.2481 1.87322C11.2689 1.88955 11.2891 1.90544 11.3088 1.92075L16.8123 6.20128C16.8337 6.21793 16.855 6.23443 16.8761 6.25081C17.1809 6.48733 17.4525 6.6981 17.655 6.97191C17.8327 7.21212 17.9651 7.48272 18.0456 7.77043C18.1374 8.09838 18.137 8.4422 18.1366 8.82801C18.1365 8.85472 18.1365 8.88163 18.1365 8.90875V14.8115C18.1365 15.2387 18.1365 15.6085 18.1116 15.9134C18.0853 16.2355 18.0271 16.5578 17.8688 16.8684C17.6333 17.3306 17.2575 17.7064 16.7954 17.9418C16.4847 18.1001 16.1625 18.1584 15.8403 18.1847C15.5354 18.2096 15.1656 18.2096 14.7385 18.2096H5.26167C4.8345 18.2096 4.4647 18.2096 4.15985 18.1847C3.83769 18.1584 3.51541 18.1001 3.20478 17.9418C2.7426 17.7064 2.36685 17.3306 2.13136 16.8684C1.97308 16.5578 1.91484 16.2355 1.88852 15.9134C1.86362 15.6085 1.86363 15.2387 1.86364 14.8115L1.86364 8.90875C1.86364 8.88163 1.86361 8.85472 1.86358 8.82801C1.86315 8.4422 1.86276 8.09838 1.95456 7.77043C2.03509 7.48272 2.16744 7.21211 2.3451 6.97191C2.54761 6.6981 2.81925 6.48733 3.12405 6.25081C3.14515 6.23443 3.16642 6.21793 3.18782 6.20128L8.69136 1.92075C8.71105 1.90544 8.73129 1.88954 8.75208 1.87322C8.96808 1.70357 9.24317 1.48751 9.57021 1.39896ZM8.39904 16.5429H11.6011V11.3715C11.6011 11.1371 11.6005 11.0071 11.5934 10.9141C11.5005 10.9071 11.3705 10.9065 11.1361 10.9065H8.86404C8.62967 10.9065 8.49969 10.9071 8.40672 10.9141C8.39966 11.0071 8.39904 11.1371 8.39904 11.3715V16.5429ZM13.2678 16.5429L13.2678 11.3451C13.2678 11.1407 13.2678 10.9405 13.2539 10.7706C13.2387 10.5838 13.2026 10.3617 13.0885 10.1379C12.9308 9.82839 12.6792 9.57677 12.3697 9.41907C12.1459 9.30502 11.9238 9.26889 11.7369 9.25362C11.5671 9.23975 11.3668 9.23977 11.1624 9.2398H8.83772C8.63333 9.23977 8.43305 9.23975 8.26321 9.25362C8.07637 9.26889 7.85429 9.30502 7.63045 9.41907C7.32096 9.57676 7.06934 9.82839 6.91165 10.1379C6.79759 10.3617 6.76146 10.5838 6.7462 10.7706C6.73232 10.9405 6.73235 11.1407 6.73237 11.3451L6.73237 16.5429H5.29363C4.82543 16.5429 4.52439 16.5422 4.29557 16.5236C4.07648 16.5057 3.99795 16.4754 3.96143 16.4568C3.81286 16.3811 3.69207 16.2603 3.61637 16.1118C3.59776 16.0753 3.56756 15.9967 3.54965 15.7776C3.53096 15.5488 3.53031 15.2478 3.53031 14.7796V8.90875C3.53031 8.39549 3.53755 8.29823 3.55954 8.21968C3.58542 8.12719 3.62797 8.0402 3.68508 7.96299C3.73358 7.89741 3.80592 7.83198 4.21106 7.51687L9.71459 3.23634C9.86132 3.12222 9.94061 3.06115 10.0001 3.02088C10.0595 3.06115 10.1388 3.12222 10.2856 3.23634L15.7891 7.51687C16.1942 7.83198 16.2666 7.89741 16.3151 7.96299C16.3722 8.0402 16.4147 8.12719 16.4406 8.21968C16.4626 8.29823 16.4698 8.39549 16.4698 8.90875V14.7796C16.4698 15.2478 16.4692 15.5488 16.4505 15.7776C16.4326 15.9967 16.4024 16.0753 16.3838 16.1118C16.3081 16.2603 16.1873 16.3811 16.0387 16.4568C16.0022 16.4754 15.9237 16.5057 15.7046 16.5236C15.4758 16.5422 15.1747 16.5429 14.7065 16.5429H13.2678Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5 3.33301C10.9603 3.33301 11.3334 3.7061 11.3334 4.16634V9.16634H16.3334C16.7936 9.16634 17.1667 9.53944 17.1667 9.99967C17.1667 10.4599 16.7936 10.833 16.3334 10.833H11.3334V15.833C11.3334 16.2932 10.9603 16.6663 10.5 16.6663C10.0398 16.6663 9.66671 16.2932 9.66671 15.833V10.833H4.66671C4.20647 10.833 3.83337 10.4599 3.83337 9.99967C3.83337 9.53944 4.20647 9.16634 4.66671 9.16634H9.66671V4.16634C9.66671 3.7061 10.0398 3.33301 10.5 3.33301Z" fill="#3370FF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 619 B |
@@ -0,0 +1,12 @@
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_19520_1493)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M6.99991 2.05339C4.26775 2.05339 2.0529 4.26824 2.0529 7.0004C2.0529 9.73256 4.26775 11.9474 6.99991 11.9474C9.73207 11.9474 11.9469 9.73256 11.9469 7.0004C11.9469 4.26824 9.73207 2.05339 6.99991 2.05339ZM0.88623 7.0004C0.88623 3.62391 3.62342 0.886719 6.99991 0.886719C10.3764 0.886719 13.1136 3.62391 13.1136 7.0004C13.1136 10.3769 10.3764 13.1141 6.99991 13.1141C3.62342 13.1141 0.88623 10.3769 0.88623 7.0004ZM6.41657 4.78826C6.41657 4.46609 6.67774 4.20493 6.99991 4.20493H7.00544C7.3276 4.20493 7.58877 4.46609 7.58877 4.78826C7.58877 5.11042 7.3276 5.37159 7.00544 5.37159H6.99991C6.67774 5.37159 6.41657 5.11042 6.41657 4.78826ZM6.99991 6.41706C7.32207 6.41706 7.58324 6.67823 7.58324 7.0004V9.21253C7.58324 9.5347 7.32207 9.79587 6.99991 9.79587C6.67774 9.79587 6.41657 9.5347 6.41657 9.21253V7.0004C6.41657 6.67823 6.67774 6.41706 6.99991 6.41706Z"
|
||||
fill="#3370FF" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_19520_1493">
|
||||
<rect width="14" height="14" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M11.5538 3.5208C11.4875 3.5049 11.4085 3.50008 11.0059 3.50008H6V5.30008C6 5.52247 6.00058 5.64416 6.00773 5.7316C6.00801 5.73508 6.0083 5.73838 6.00859 5.74149C6.0117 5.74178 6.01499 5.74206 6.01848 5.74235C6.10592 5.74949 6.22761 5.75008 6.45 5.75008H11.55C11.7724 5.75008 11.8941 5.74949 11.9815 5.74235C11.985 5.74206 11.9883 5.74178 11.9914 5.74149C11.9917 5.73838 11.992 5.73508 11.9923 5.7316C11.9994 5.64416 12 5.52247 12 5.30008V3.81211C11.8588 3.67386 11.8143 3.63743 11.7706 3.6106C11.7035 3.56947 11.6303 3.53917 11.5538 3.5208ZM13.2802 2.96965L13.2333 2.92269C13.2184 2.90784 13.2037 2.8931 13.1891 2.87848C12.9735 2.66249 12.7835 2.47206 12.5543 2.33164C12.353 2.20827 12.1335 2.11736 11.9039 2.06224C11.6426 1.9995 11.3735 1.99975 11.0684 2.00004C11.0477 2.00006 11.0269 2.00008 11.0059 2.00008L5.81903 2.00008C5.63224 2.00007 5.45554 2.00007 5.28855 2.00105C5.27578 2.0004 5.26293 2.00008 5.25 2.00008C5.23345 2.00008 5.21702 2.00061 5.20074 2.00167C4.86462 2.00446 4.5692 2.01214 4.31113 2.03322C3.88956 2.06767 3.50203 2.14159 3.13803 2.32706C2.57354 2.61468 2.1146 3.07362 1.82698 3.6381C1.64151 4.00211 1.56759 4.38963 1.53315 4.81121C1.49998 5.2171 1.49999 5.71537 1.5 6.3191V12.681C1.49999 13.2848 1.49998 13.783 1.53315 14.1889C1.56759 14.6105 1.64151 14.998 1.82698 15.362C2.1146 15.9265 2.57354 16.3855 3.13803 16.6731C3.50203 16.8586 3.88956 16.9325 4.31113 16.9669C4.5692 16.988 4.86462 16.9957 5.20074 16.9985C5.21702 16.9995 5.23345 17.0001 5.25 17.0001C5.26293 17.0001 5.27578 16.9997 5.28855 16.9991C5.45553 17.0001 5.63222 17.0001 5.81901 17.0001H12.181C12.3678 17.0001 12.5445 17.0001 12.7115 16.9991C12.7242 16.9997 12.7371 17.0001 12.75 17.0001C12.7666 17.0001 12.783 16.9995 12.7993 16.9985C13.1354 16.9957 13.4308 16.988 13.6889 16.9669C14.1104 16.9325 14.498 16.8586 14.862 16.6731C15.4265 16.3855 15.8854 15.9265 16.173 15.362C16.3585 14.998 16.4324 14.6105 16.4669 14.1889C16.5 13.7831 16.5 13.2848 16.5 12.6811V7.49419C16.5 7.47319 16.5 7.45236 16.5 7.4317C16.5003 7.12653 16.5006 6.85748 16.4378 6.59614C16.3827 6.36656 16.2918 6.14709 16.1684 5.94577C16.028 5.71662 15.8376 5.52655 15.6216 5.31096C15.607 5.29637 15.5922 5.28165 15.5774 5.2668L13.2802 2.96965C13.2803 2.96971 13.2802 2.96958 13.2802 2.96965ZM13.5 5.31074V5.32399C13.5 5.51328 13.5 5.69763 13.4873 5.85375C13.4733 6.02519 13.4402 6.22749 13.3365 6.43106C13.1927 6.71331 12.9632 6.94278 12.681 7.08659C12.4774 7.19031 12.2751 7.22336 12.1037 7.23737C11.9476 7.25012 11.7632 7.2501 11.5739 7.25008L6.45 7.25008C6.44202 7.25008 6.43404 7.25008 6.42608 7.25008C6.23679 7.2501 6.05245 7.25012 5.89633 7.23737C5.72488 7.22336 5.52258 7.19031 5.31902 7.08659C5.03677 6.94278 4.8073 6.7133 4.66349 6.43106C4.55977 6.22749 4.52672 6.02519 4.51271 5.85375C4.49995 5.69763 4.49998 5.51329 4.5 5.324C4.5 5.31603 4.5 5.30806 4.5 5.30008V3.52322C4.47733 3.52479 4.4551 3.52646 4.43328 3.52824C4.10447 3.5551 3.93631 3.6038 3.81902 3.66357C3.53677 3.80738 3.3073 4.03685 3.16349 4.31909C3.10372 4.43639 3.05503 4.60454 3.02816 4.93335C3.00058 5.27092 3 5.70764 3 6.35008V12.6501C3 13.2925 3.00058 13.7292 3.02816 14.0668C3.05503 14.3956 3.10372 14.5638 3.16349 14.6811C3.3073 14.9633 3.53677 15.1928 3.81902 15.3366C3.93631 15.3964 4.10447 15.445 4.43328 15.4719C4.4551 15.4737 4.47733 15.4754 4.5 15.4769L4.5 11.4262C4.49998 11.2369 4.49995 11.0525 4.51271 10.8964C4.52672 10.725 4.55977 10.5227 4.66349 10.3191C4.8073 10.0368 5.03677 9.80738 5.31902 9.66357C5.52258 9.55984 5.72488 9.52679 5.89633 9.51278C6.05245 9.50003 6.2368 9.50005 6.42609 9.50007H11.5739C11.7632 9.50005 11.9475 9.50003 12.1037 9.51278C12.2751 9.52679 12.4774 9.55984 12.681 9.66357C12.9632 9.80738 13.1927 10.0368 13.3365 10.3191C13.4402 10.5227 13.4733 10.725 13.4873 10.8964C13.5 11.0525 13.5 11.2369 13.5 11.4262L13.5 15.4769C13.5227 15.4754 13.5449 15.4737 13.5667 15.4719C13.8955 15.445 14.0637 15.3964 14.181 15.3366C14.4632 15.1928 14.6927 14.9633 14.8365 14.6811C14.8963 14.5638 14.945 14.3956 14.9718 14.0668C14.9994 13.7292 15 13.2925 15 12.6501V7.49419C15 7.0916 14.9952 7.01255 14.9793 6.94631C14.9609 6.86979 14.9306 6.79663 14.8895 6.72952C14.8539 6.67144 14.8014 6.61213 14.5167 6.32746L13.5 5.31074ZM12 15.5001V11.4501C12 11.2277 11.9994 11.106 11.9923 11.0186C11.992 11.0151 11.9917 11.0118 11.9914 11.0087C11.9883 11.0084 11.985 11.0081 11.9815 11.0078C11.8941 11.0007 11.7724 11.0001 11.55 11.0001H6.45C6.22761 11.0001 6.10592 11.0007 6.01848 11.0078C6.01499 11.0081 6.0117 11.0084 6.00859 11.0087C6.0083 11.0118 6.00801 11.0151 6.00773 11.0186C6.00058 11.106 6 11.2277 6 11.4501V15.5001H12Z"
|
||||
fill="#3370FF" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M6.72916 1.85097L6.69716 1.85085C5.98981 1.84827 5.41301 1.84617 4.94539 1.88309C4.46228 1.92122 4.0275 2.00464 3.62407 2.21292C3.01781 2.52591 2.5263 3.01564 2.21111 3.62075C2.00154 4.02311 1.91644 4.45656 1.8765 4.93842C1.83788 5.40451 1.83788 5.97916 1.83789 6.68347V11.3274C1.83788 12.0263 1.83788 12.5969 1.87635 13.0602C1.91616 13.5396 2.001 13.9708 2.20943 14.3721C2.52252 14.9748 3.01395 15.4662 3.61667 15.7793C4.01791 15.9877 4.44916 16.0726 4.92851 16.1124C5.39183 16.1509 5.96247 16.1508 6.66137 16.1508H11.3384C12.0373 16.1508 12.6079 16.1509 13.0712 16.1124C13.5506 16.0726 13.9818 15.9877 14.3831 15.7793C14.9858 15.4662 15.4772 14.9748 15.7903 14.3721C15.9987 13.9708 16.0836 13.5396 16.1234 13.0602C16.1619 12.5969 16.1619 12.0263 16.1619 11.3274V9.50554C16.1619 9.09133 15.8261 8.75554 15.4119 8.75554C14.9976 8.75554 14.6619 9.09133 14.6619 9.50554V11.2954C14.6619 12.0341 14.6613 12.5422 14.6285 12.9361C14.5966 13.321 14.5379 13.5291 14.4592 13.6806C14.2884 14.0094 14.0204 14.2774 13.6916 14.4482C13.5402 14.5269 13.332 14.5856 12.9471 14.6175C12.5532 14.6502 12.045 14.6508 11.3064 14.6508H6.69339C5.9547 14.6508 5.44655 14.6502 5.05265 14.6175C4.66773 14.5856 4.45958 14.5269 4.30814 14.4482C3.97938 14.2774 3.71132 14.0094 3.54055 13.6806C3.46188 13.5292 3.40317 13.321 3.37121 12.9361C3.33849 12.5422 3.33789 12.034 3.33789 11.2953V6.71554C3.33789 5.97142 3.33849 5.45912 3.37138 5.06231C3.40354 4.67419 3.46264 4.46502 3.54147 4.31369C3.7137 3.98302 3.98088 3.71681 4.31217 3.54578C4.46347 3.46767 4.67333 3.40923 5.06343 3.37843C5.46198 3.34697 5.97664 3.34825 6.72372 3.35096C7.34592 3.35322 7.97166 3.35468 8.54751 3.35468C8.96173 3.35468 9.29751 3.0189 9.29751 2.60468C9.29751 2.19047 8.96173 1.85468 8.54751 1.85468C7.97404 1.85468 7.35021 1.85322 6.72916 1.85097ZM8.26254 8.66553C7.96964 8.95843 7.96964 9.4333 8.26254 9.7262C8.55543 10.0191 9.0303 10.0191 9.3232 9.72619L14.6619 4.38754V6.5054C14.6619 6.91962 14.9976 7.2554 15.4119 7.2554C15.8261 7.2554 16.1619 6.91962 16.1619 6.5054V2.6698C16.1622 2.66102 16.1623 2.6522 16.1623 2.64334C16.1623 2.22913 15.8265 1.89334 15.4123 1.89334C15.4122 1.89334 15.4124 1.89334 15.4123 1.89334H11.5503C11.136 1.89334 10.8003 2.22913 10.8003 2.64334C10.8003 3.05756 11.136 3.39334 11.5503 3.39334H13.5347L8.26254 8.66553Z"
|
||||
fill="white" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M5.47674 0.0561965L5.44118 0.0560671C4.65524 0.053204 4.01435 0.0508692 3.49477 0.0918841C2.95798 0.134258 2.47489 0.226947 2.02664 0.458364C1.35301 0.806127 0.806891 1.35027 0.456684 2.02263C0.223824 2.46969 0.129267 2.9513 0.0848958 3.48669C0.0419755 4.00458 0.0419831 4.64308 0.0419925 5.42564V10.5855C0.041983 11.3621 0.0419753 11.9961 0.0847264 12.5109C0.128958 13.0435 0.223226 13.5227 0.454811 13.9685C0.802688 14.6382 1.34873 15.1842 2.01842 15.5321C2.46424 15.7637 2.9434 15.858 3.47601 15.9022C3.99081 15.945 4.62486 15.945 5.40142 15.9449H10.5981C11.3746 15.945 12.0087 15.945 12.5235 15.9022C13.0561 15.858 13.5353 15.7637 13.9811 15.5321C14.6508 15.1842 15.1968 14.6382 15.5447 13.9685C15.7763 13.5227 15.8705 13.0435 15.9148 12.5109C15.9575 11.9962 15.9575 11.3621 15.9575 10.5856V8.56128C15.9575 8.10104 15.5844 7.72795 15.1242 7.72795C14.6639 7.72795 14.2908 8.10104 14.2908 8.56128V10.55C14.2908 11.3708 14.2902 11.9354 14.2538 12.373C14.2183 12.8007 14.1531 13.032 14.0657 13.2002C13.8759 13.5655 13.5781 13.8634 13.2128 14.0531C13.0445 14.1405 12.8132 14.2057 12.3856 14.2413C11.9479 14.2776 11.3833 14.2783 10.5625 14.2783H5.43699C4.61622 14.2783 4.05161 14.2776 3.61395 14.2413C3.18626 14.2057 2.95498 14.1405 2.78671 14.0531C2.42142 13.8634 2.12358 13.5655 1.93383 13.2002C1.84642 13.032 1.78119 12.8007 1.74568 12.373C1.70933 11.9353 1.70866 11.3707 1.70866 10.5499V5.46128C1.70866 4.63448 1.70933 4.06526 1.74587 3.62435C1.78161 3.19311 1.84727 2.9607 1.93485 2.79256C2.12623 2.42514 2.42309 2.12936 2.79119 1.93932C2.95931 1.85253 3.19248 1.7876 3.62592 1.75338C4.06876 1.71843 4.6406 1.71984 5.47069 1.72285C6.16203 1.72536 6.85729 1.72699 7.49713 1.72699C7.95737 1.72699 8.33046 1.3539 8.33046 0.893659C8.33046 0.433422 7.95737 0.0603261 7.49713 0.0603261C6.85993 0.0603261 6.1668 0.0587019 5.47674 0.0561965ZM7.18049 7.62794C6.85505 7.95338 6.85505 8.48101 7.18049 8.80645C7.50592 9.13189 8.03356 9.13189 8.359 8.80645L14.2908 2.87461V5.22779C14.2908 5.68803 14.6639 6.06113 15.1242 6.06113C15.5844 6.06113 15.9575 5.68803 15.9575 5.22779V0.966006C15.9578 0.95625 15.958 0.946452 15.958 0.936614C15.958 0.476377 15.5849 0.103281 15.1247 0.103281C15.1246 0.103281 15.1248 0.103281 15.1247 0.103281H10.8335C10.3733 0.103281 10.0002 0.476377 10.0002 0.936614C10.0002 1.39685 10.3733 1.76995 10.8335 1.76995H13.0385L7.18049 7.62794Z"
|
||||
fill="#3370FF" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,7 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="icon/line/export">
|
||||
<path id="Icon (Stroke)" fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M11.2928 2.58684C11.6834 2.19631 12.3165 2.19631 12.707 2.58684L16.707 6.58684C17.0976 6.97736 17.0976 7.61053 16.707 8.00105C16.3165 8.39158 15.6834 8.39158 15.2928 8.00105L12.9999 5.70816V15.2939C12.9999 15.8462 12.5522 16.2939 11.9999 16.2939C11.4477 16.2939 10.9999 15.8462 10.9999 15.2939V5.70816L8.70705 8.00105C8.31652 8.39158 7.68336 8.39158 7.29283 8.00105C6.90231 7.61053 6.90231 6.97736 7.29283 6.58684L11.2928 2.58684ZM2.99994 11.2939C3.55222 11.2939 3.99994 11.7417 3.99994 12.2939V16.4939C3.99994 17.3505 4.00072 17.9328 4.03749 18.3829C4.07331 18.8213 4.13824 19.0455 4.21793 19.2019C4.40967 19.5783 4.71564 19.8842 5.09196 20.076C5.24836 20.1556 5.47256 20.2206 5.91098 20.2564C6.36107 20.2932 6.94336 20.2939 7.79994 20.2939H16.1999C17.0565 20.2939 17.6388 20.2932 18.0889 20.2564C18.5273 20.2206 18.7515 20.1556 18.9079 20.076C19.2842 19.8842 19.5902 19.5783 19.782 19.2019C19.8616 19.0455 19.9266 18.8213 19.9624 18.3829C19.9992 17.9328 19.9999 17.3505 19.9999 16.4939V12.2939C19.9999 11.7417 20.4477 11.2939 20.9999 11.2939C21.5522 11.2939 21.9999 11.7417 21.9999 12.2939V16.5353C22 17.3402 22 18.0046 21.9557 18.5458C21.9098 19.1079 21.8113 19.6246 21.564 20.1099C21.1805 20.8626 20.5686 21.4745 19.8159 21.858C19.3306 22.1053 18.8139 22.2038 18.2518 22.2498C17.7106 22.294 17.0462 22.294 16.2413 22.2939H7.75862C6.95366 22.294 6.2893 22.294 5.74811 22.2498C5.18602 22.2038 4.66931 22.1053 4.18398 21.858C3.43133 21.4745 2.81941 20.8626 2.43591 20.1099C2.18862 19.6246 2.09006 19.1079 2.04413 18.5458C1.99992 18.0046 1.99993 17.3402 1.99994 16.5352L1.99994 12.2939C1.99994 11.7417 2.44766 11.2939 2.99994 11.2939Z"
|
||||
fill="#3370FF" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
289
packages/web/components/common/MySelect/GateSelect.tsx
Normal file
@@ -0,0 +1,289 @@
|
||||
import type { ForwardedRef } from 'react';
|
||||
import React, {
|
||||
useRef,
|
||||
forwardRef,
|
||||
useMemo,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useState
|
||||
} from 'react';
|
||||
import {
|
||||
Menu,
|
||||
MenuList,
|
||||
MenuItem,
|
||||
Button,
|
||||
useDisclosure,
|
||||
MenuButton,
|
||||
Box,
|
||||
Flex,
|
||||
Input,
|
||||
Tag,
|
||||
HStack
|
||||
} from '@chakra-ui/react';
|
||||
import type { ButtonProps, MenuItemProps } from '@chakra-ui/react';
|
||||
import MyIcon from '../Icon';
|
||||
import { useRequest2 } from '../../../hooks/useRequest';
|
||||
import MyDivider from '../MyDivider';
|
||||
import type { useScrollPagination } from '../../../hooks/useScrollPagination';
|
||||
import Avatar from '../Avatar';
|
||||
|
||||
/** 选择组件 Props 类型
|
||||
* value: 选中的值
|
||||
* placeholder: 占位符
|
||||
* list: 列表数据
|
||||
* isLoading: 是否加载中
|
||||
* ScrollData: 分页滚动数据控制器 [useScrollPagination] 的返回值
|
||||
* */
|
||||
export type GateSelectProps<T = any> = Omit<ButtonProps, 'onChange'> & {
|
||||
value?: T;
|
||||
placeholder?: string;
|
||||
isSearch?: boolean;
|
||||
list: {
|
||||
alias?: string;
|
||||
icon?: string;
|
||||
iconSize?: string;
|
||||
label: string | React.ReactNode;
|
||||
description?: string;
|
||||
value: T;
|
||||
showBorder?: boolean;
|
||||
tagColor?: string;
|
||||
tagText?: string;
|
||||
}[];
|
||||
isLoading?: boolean;
|
||||
onChange?: (val: T) => any | Promise<any>;
|
||||
ScrollData?: ReturnType<typeof useScrollPagination>['ScrollData'];
|
||||
};
|
||||
|
||||
const GateSelect = <T = any,>(
|
||||
{
|
||||
placeholder,
|
||||
value,
|
||||
isSearch = false,
|
||||
width = '100%',
|
||||
list = [],
|
||||
onChange,
|
||||
isLoading = false,
|
||||
ScrollData,
|
||||
...props
|
||||
}: GateSelectProps<T>,
|
||||
ref: ForwardedRef<{
|
||||
focus: () => void;
|
||||
}>
|
||||
) => {
|
||||
const ButtonRef = useRef<HTMLButtonElement>(null);
|
||||
const MenuListRef = useRef<HTMLDivElement>(null);
|
||||
const SelectedItemRef = useRef<HTMLDivElement>(null);
|
||||
const SearchInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const menuItemStyles: MenuItemProps = {
|
||||
borderRadius: 'sm',
|
||||
py: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
_hover: {
|
||||
backgroundColor: 'myGray.100'
|
||||
},
|
||||
_notLast: {
|
||||
mb: 1
|
||||
}
|
||||
};
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const selectItem = useMemo(() => list.find((item) => item.value === value), [list, value]);
|
||||
|
||||
const [search, setSearch] = useState('');
|
||||
const filterList = useMemo(() => {
|
||||
if (!isSearch || !search) {
|
||||
return list;
|
||||
}
|
||||
return list.filter((item) => {
|
||||
const text = `${item.label?.toString()}${item.alias}${item.value}`;
|
||||
const regx = new RegExp(search, 'gi');
|
||||
return regx.test(text);
|
||||
});
|
||||
}, [list, search, isSearch]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
focus() {
|
||||
onOpen();
|
||||
}
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen && MenuListRef.current && SelectedItemRef.current) {
|
||||
const menu = MenuListRef.current;
|
||||
const selectedItem = SelectedItemRef.current;
|
||||
menu.scrollTop = selectedItem.offsetTop - menu.offsetTop - 100;
|
||||
|
||||
if (isSearch) {
|
||||
setSearch('');
|
||||
}
|
||||
}
|
||||
}, [isSearch, isOpen]);
|
||||
|
||||
const { runAsync: onclickChange, loading } = useRequest2((val: T) => onChange?.(val));
|
||||
|
||||
const ListRender = useMemo(() => {
|
||||
return (
|
||||
<>
|
||||
{filterList.map((item, i) => (
|
||||
<Box key={i}>
|
||||
<MenuItem
|
||||
{...menuItemStyles}
|
||||
{...(value === item.value
|
||||
? {
|
||||
ref: SelectedItemRef,
|
||||
color: 'primary.700',
|
||||
bg: 'myGray.100',
|
||||
fontWeight: '600'
|
||||
}
|
||||
: {
|
||||
color: 'myGray.900'
|
||||
})}
|
||||
onClick={() => {
|
||||
if (value !== item.value) {
|
||||
onclickChange(item.value);
|
||||
}
|
||||
}}
|
||||
whiteSpace={'pre-wrap'}
|
||||
fontSize={'sm'}
|
||||
display={'block'}
|
||||
mb={0.5}
|
||||
>
|
||||
<Flex alignItems={'center'} justifyContent="space-between" width="100%">
|
||||
<Flex alignItems={'center'}>
|
||||
{item.icon && (
|
||||
<Avatar mr={2} src={item.icon as any} w={item.iconSize ?? '1rem'} />
|
||||
)}
|
||||
{item.label}
|
||||
</Flex>
|
||||
{item.tagText && (
|
||||
<Tag size="sm" colorScheme={item.tagColor || 'gray'} ml={2}>
|
||||
{item.tagText}
|
||||
</Tag>
|
||||
)}
|
||||
</Flex>
|
||||
{item.description && (
|
||||
<Box color={'myGray.500'} fontSize={'xs'}>
|
||||
{item.description}
|
||||
</Box>
|
||||
)}
|
||||
</MenuItem>
|
||||
{item.showBorder && <MyDivider my={2} />}
|
||||
</Box>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}, [filterList, value]);
|
||||
|
||||
const isSelecting = loading || isLoading;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Menu
|
||||
autoSelect={false}
|
||||
isOpen={isOpen && !isSelecting}
|
||||
onOpen={onOpen}
|
||||
onClose={onClose}
|
||||
strategy={'fixed'}
|
||||
>
|
||||
<MenuButton
|
||||
as={Button}
|
||||
ref={ButtonRef}
|
||||
width={width}
|
||||
px={3}
|
||||
rightIcon={<MyIcon name={'core/chat/chevronDown'} w={4} color={'myGray.500'} />}
|
||||
variant={'whitePrimaryOutline'}
|
||||
size={'md'}
|
||||
fontSize={'sm'}
|
||||
textAlign={'left'}
|
||||
h={'auto'}
|
||||
whiteSpace={'pre-wrap'}
|
||||
wordBreak={'break-word'}
|
||||
_active={{
|
||||
transform: 'none'
|
||||
}}
|
||||
_hover={{
|
||||
borderRadius: '10px',
|
||||
border: '0.5px solid var(--Gray-Iron-250, #E0E0E0)',
|
||||
background: 'var(--Gray-Iron-150, #F3F3F3)'
|
||||
}}
|
||||
{...(isOpen
|
||||
? {
|
||||
borderColor: 'primary.600',
|
||||
color: 'primary.700'
|
||||
}
|
||||
: {})}
|
||||
{...props}
|
||||
>
|
||||
<Flex alignItems={'center'} justifyContent="space-between" width="100%">
|
||||
<Flex alignItems={'center'}>
|
||||
{isSelecting && <MyIcon mr={2} name={'common/loading'} w={'1rem'} />}
|
||||
{isSearch && isOpen ? (
|
||||
<Input
|
||||
ref={SearchInputRef}
|
||||
autoFocus
|
||||
variant={'unstyled'}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder={
|
||||
selectItem?.alias ||
|
||||
(typeof selectItem?.label === 'string' ? selectItem?.label : placeholder)
|
||||
}
|
||||
size={'sm'}
|
||||
w={'100%'}
|
||||
color={'myGray.700'}
|
||||
onBlur={() => {
|
||||
setTimeout(() => {
|
||||
SearchInputRef?.current?.focus();
|
||||
}, 0);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Flex alignItems="center">
|
||||
{selectItem?.icon && (
|
||||
<Avatar mr={2} src={selectItem.icon as any} w={selectItem.iconSize ?? '1rem'} />
|
||||
)}
|
||||
{selectItem?.alias || selectItem?.label || placeholder}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
{selectItem?.tagText && (
|
||||
<Tag size="sm" colorScheme={selectItem.tagColor || 'gray'} ml={2}>
|
||||
{selectItem.tagText}
|
||||
</Tag>
|
||||
)}
|
||||
</Flex>
|
||||
</MenuButton>
|
||||
|
||||
<MenuList
|
||||
ref={MenuListRef}
|
||||
className={props.className}
|
||||
w={(() => {
|
||||
const w = ButtonRef.current?.clientWidth;
|
||||
if (w) {
|
||||
return `${w}px !important`;
|
||||
}
|
||||
return Array.isArray(width)
|
||||
? width.map((item) => `${item} !important`)
|
||||
: `${width} !important`;
|
||||
})()}
|
||||
px={'6px'}
|
||||
py={'6px'}
|
||||
border={'1px solid #fff'}
|
||||
boxShadow={
|
||||
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
|
||||
}
|
||||
zIndex={99}
|
||||
maxH={'40vh'}
|
||||
overflowY={'auto'}
|
||||
>
|
||||
{ScrollData ? <ScrollData>{ListRender}</ScrollData> : ListRender}
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default forwardRef(GateSelect) as <T>(
|
||||
props: GateSelectProps<T> & { ref?: React.Ref<HTMLSelectElement> }
|
||||
) => JSX.Element;
|
||||
@@ -50,6 +50,7 @@ export type SelectProps<T = any> = Omit<ButtonProps, 'onChange'> & {
|
||||
showBorder?: boolean;
|
||||
}[];
|
||||
isLoading?: boolean;
|
||||
showAvatar?: boolean;
|
||||
onChange?: (val: T) => any | Promise<any>;
|
||||
ScrollData?: ReturnType<typeof useScrollPagination>['ScrollData'];
|
||||
customOnOpen?: () => void;
|
||||
@@ -79,6 +80,7 @@ const MySelect = <T = any,>(
|
||||
list = [],
|
||||
onChange,
|
||||
isLoading = false,
|
||||
showAvatar = true,
|
||||
ScrollData,
|
||||
customOnOpen,
|
||||
customOnClose,
|
||||
@@ -255,7 +257,7 @@ const MySelect = <T = any,>(
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{selectItem?.icon && (
|
||||
{selectItem?.icon && showAvatar && (
|
||||
<Avatar
|
||||
mr={2}
|
||||
src={selectItem.icon as any}
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
const HighlightText = ({
|
||||
rawText,
|
||||
matchText,
|
||||
color = 'primary.600'
|
||||
color = 'primary.600',
|
||||
mode = 'text'
|
||||
}: {
|
||||
rawText: string;
|
||||
matchText: string;
|
||||
color?: string;
|
||||
mode?: 'text' | 'bg';
|
||||
}) => {
|
||||
const regex = new RegExp(`(${matchText})`, 'gi');
|
||||
const parts = rawText.split(regex);
|
||||
const { parts } = useMemo(() => {
|
||||
const regx = new RegExp(`(${matchText})`, 'gi');
|
||||
const parts = rawText.split(regx);
|
||||
|
||||
return {
|
||||
regx,
|
||||
parts
|
||||
};
|
||||
}, [rawText, matchText]);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
@@ -28,7 +37,17 @@ const HighlightText = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Box as="span" key={index} color={highLight ? color : 'inherit'}>
|
||||
<Box
|
||||
as="span"
|
||||
key={index}
|
||||
{...(mode === 'bg'
|
||||
? {
|
||||
bg: highLight ? color : 'transparent'
|
||||
}
|
||||
: {
|
||||
color: highLight ? color : 'inherit'
|
||||
})}
|
||||
>
|
||||
{part}
|
||||
</Box>
|
||||
);
|
||||
@@ -37,4 +56,4 @@ const HighlightText = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default HighlightText;
|
||||
export default React.memo(HighlightText);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { forwardRef } from 'react';
|
||||
import React, { forwardRef, useRef, useState, useEffect } from 'react';
|
||||
import { Flex, Box, type BoxProps, HStack } from '@chakra-ui/react';
|
||||
import MyIcon from '../Icon';
|
||||
|
||||
@@ -26,8 +26,41 @@ const FillRowTabs = ({
|
||||
iconGap = 2,
|
||||
...props
|
||||
}: Props) => {
|
||||
const tabsRef = useRef<HTMLDivElement>(null);
|
||||
const itemsRef = useRef<Map<any, HTMLDivElement>>(new Map());
|
||||
const [sliderStyle, setSliderStyle] = useState({
|
||||
width: 0,
|
||||
left: 0,
|
||||
opacity: 0
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const updateSlider = () => {
|
||||
const activeItem = itemsRef.current.get(value);
|
||||
if (activeItem && tabsRef.current) {
|
||||
const tabsRect = tabsRef.current.getBoundingClientRect();
|
||||
const itemRect = activeItem.getBoundingClientRect();
|
||||
|
||||
setSliderStyle({
|
||||
width: itemRect.width,
|
||||
left: itemRect.left - tabsRect.left,
|
||||
opacity: 1
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
updateSlider();
|
||||
window.addEventListener('resize', updateSlider);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', updateSlider);
|
||||
};
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
ref={tabsRef}
|
||||
position="relative"
|
||||
display={'inline-flex'}
|
||||
px={'3px'}
|
||||
py={'3px'}
|
||||
@@ -40,9 +73,29 @@ const FillRowTabs = ({
|
||||
fontWeight={'medium'}
|
||||
{...props}
|
||||
>
|
||||
{/* 滑动背景元素 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
height="calc(100% - 6px)"
|
||||
top="3px"
|
||||
borderRadius={'xs'}
|
||||
bg="white"
|
||||
boxShadow="1.5"
|
||||
transition="all 0.14s ease-in-out"
|
||||
pointerEvents="none"
|
||||
style={{
|
||||
width: `${sliderStyle.width}px`,
|
||||
left: `${sliderStyle.left}px`,
|
||||
opacity: sliderStyle.opacity
|
||||
}}
|
||||
/>
|
||||
|
||||
{list.map((item) => (
|
||||
<HStack
|
||||
key={item.value}
|
||||
ref={(el) => {
|
||||
if (el) itemsRef.current.set(item.value, el);
|
||||
}}
|
||||
flex={'1 0 0'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
@@ -53,19 +106,14 @@ const FillRowTabs = ({
|
||||
userSelect={'none'}
|
||||
whiteSpace={'noWrap'}
|
||||
gap={iconGap}
|
||||
{...(value === item.value
|
||||
? {
|
||||
bg: 'white',
|
||||
boxShadow: '1.5',
|
||||
color: 'primary.600'
|
||||
}
|
||||
: {
|
||||
color: 'myGray.500',
|
||||
_hover: {
|
||||
color: 'primary.600'
|
||||
},
|
||||
onClick: () => onChange(item.value)
|
||||
})}
|
||||
zIndex={1}
|
||||
position="relative"
|
||||
transition="color 0.25s ease"
|
||||
onClick={() => onChange(item.value)}
|
||||
color={value === item.value ? 'primary.600' : 'myGray.500'}
|
||||
_hover={{
|
||||
color: 'primary.600'
|
||||
}}
|
||||
>
|
||||
{item.icon && <MyIcon name={item.icon as any} w={iconSize} />}
|
||||
<Box fontSize={labelSize}>{item.label}</Box>
|
||||
|
||||
@@ -3,6 +3,8 @@ import { useContextSelector } from 'use-context-selector';
|
||||
|
||||
export const useSystem = () => {
|
||||
const isPc = useContextSelector(useSystemStoreContext, (state) => state.isPc);
|
||||
const isMac =
|
||||
typeof window !== 'undefined' && window.navigator.userAgent.toLocaleLowerCase().includes('mac');
|
||||
|
||||
return { isPc };
|
||||
return { isPc, isMac };
|
||||
};
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
"api_key": "API key",
|
||||
"bills_and_invoices": "Bills",
|
||||
"channel": "Channel",
|
||||
"config_app": "Featured Applications",
|
||||
"config_copyright": "Application configuration",
|
||||
"config_home": "Home page configuration",
|
||||
"config_model": "Model configuration",
|
||||
"confirm_logout": "Confirm to log out?",
|
||||
"create_channel": "Add new channel",
|
||||
@@ -11,7 +14,12 @@
|
||||
"custom_model": "custom model",
|
||||
"default_model": "Default model",
|
||||
"default_model_config": "Default model configuration",
|
||||
"gateway.cname_tip": "Please go to your domain name service provider, such as adding the domain name, and parsing the CNAME to Ixjgiwggswmb.sealoshzh.site. After the resolution takes effect, you can bind the custom domain name.",
|
||||
"gateway.save_config": "save",
|
||||
"gateway.share": "share",
|
||||
"gateways": "Gate Management",
|
||||
"logout": "Sign out",
|
||||
"logs": "Homepage log",
|
||||
"model.active": "Active",
|
||||
"model.alias": "Alias",
|
||||
"model.alias_tip": "The name of the model displayed in the system is convenient for users to understand.",
|
||||
|
||||
31
packages/web/i18n/en/account_gate.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"Gate": "Gate",
|
||||
"Gate List": "Gate List",
|
||||
"Gate app avatar updated": "Gate app icon update",
|
||||
"Gate app created successfully": "The gate application was created successfully",
|
||||
"No Gates Available": "No Gates Available",
|
||||
"Operation failed": "Operation failed",
|
||||
"available_tools": "Available tools",
|
||||
"confirm_delete_gate": "Confirm deletion of the gate",
|
||||
"deep_thinking": "Deep thinking",
|
||||
"delete_gate": "Delete the gate",
|
||||
"dialog_prompt_text": "Dialog prompt text",
|
||||
"disabled": "closure",
|
||||
"enabled": "Enable",
|
||||
"example": "Schematic diagram",
|
||||
"file_upload": "File upload",
|
||||
"gate_list": "Portal list",
|
||||
"gate_logo": "LOGO preview",
|
||||
"image_upload": "Image upload",
|
||||
"no_gate_available": "No portal available",
|
||||
"no_gate_to_delete": "There is no gate to delete",
|
||||
"quick_app": "Quick Application",
|
||||
"slogan": "slogan",
|
||||
"status": "state",
|
||||
"suggestion_ratio_1_1": "Suggested ratio 1:1",
|
||||
"suggestion_ratio_4_1": "Suggested ratio 4:1",
|
||||
"team_name": "Team name",
|
||||
"upload": "Upload",
|
||||
"voice_input": "Voice input",
|
||||
"web_search": "Search online"
|
||||
}
|
||||
@@ -48,6 +48,7 @@
|
||||
"create_by_template": "By template",
|
||||
"create_copy_success": "Duplicate Created Successfully",
|
||||
"create_empty_app": "Create Default App",
|
||||
"create_empty_gate": "Create a blank gate",
|
||||
"create_empty_plugin": "Create Default Plugin",
|
||||
"create_empty_workflow": "Create Default Workflow",
|
||||
"cron.every_day": "Run Daily",
|
||||
@@ -123,6 +124,8 @@
|
||||
"permission.des.manage": "Based on write permissions, you can configure publishing channels, view conversation logs, and assign permissions to the application.",
|
||||
"permission.des.read": "Use the app to have conversations",
|
||||
"permission.des.write": "Can view and edit apps",
|
||||
"permission.des.log": "Can view conversation logs",
|
||||
"permission.name.log": "View logs",
|
||||
"plugin.Instructions": "Instructions",
|
||||
"plugin_cost_by_token": "Charged based on token usage",
|
||||
"plugin_cost_per_times": "{{cost}} points/time",
|
||||
@@ -148,6 +151,7 @@
|
||||
"team_tags_set": "Team tags",
|
||||
"temperature": "Temperature",
|
||||
"temperature_tip": "Range 0~10. \nThe larger the value, the more divergent the model’s answer is; the smaller the value, the more rigorous the answer.",
|
||||
"template.gate": "Gate",
|
||||
"template.hard_strict": "Strict Q&A template",
|
||||
"template.hard_strict_des": "Based on the question and answer template, stricter requirements are imposed on the model's answers.",
|
||||
"template.qa_template": "Q&A template",
|
||||
@@ -181,6 +185,8 @@
|
||||
"tts_browser": "Browser's own (free)",
|
||||
"tts_close": "Close",
|
||||
"type.All": "All",
|
||||
"type.Create gate": "Create a gate",
|
||||
"type.Create gate tip": "The gate should not be created here",
|
||||
"type.Create http plugin tip": "Batch create plugins through OpenAPI Schema, compatible with GPTs format.",
|
||||
"type.Create mcp tools tip": "Automatically parse and batch create callable MCP tools by entering the MCP address",
|
||||
"type.Create one plugin tip": "Customizable input and output workflows, usually used to encapsulate reusable workflows.",
|
||||
@@ -189,6 +195,7 @@
|
||||
"type.Create simple bot tip": "Create a simple AI app by filling out a form, suitable for beginners.",
|
||||
"type.Create workflow bot": "Create Workflow",
|
||||
"type.Create workflow tip": "Build complex multi-turn dialogue AI applications through low-code methods, recommended for advanced users.",
|
||||
"type.Gate": "Gate",
|
||||
"type.Http plugin": "HTTP Plugin",
|
||||
"type.Import from json": "Import JSON",
|
||||
"type.Import from json tip": "Create applications directly through JSON configuration files",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"chat.quote.No Data": "The file cannot be found",
|
||||
"chat.quote.deleted": "This data has been deleted ~",
|
||||
"chat.waiting_for_response": "Please wait for the conversation to complete",
|
||||
"chat_gate_app": "Portal homepage",
|
||||
"chat_history": "Conversation History",
|
||||
"chat_input_guide_lexicon_is_empty": "Lexicon not configured yet",
|
||||
"chat_test_app": "Debug-{{name}}",
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
"Confirm": "Confirm",
|
||||
"Continue_Adding": "Continue adding",
|
||||
"Copy": "Copy",
|
||||
"Create Success": "Created successfully",
|
||||
"Creating": "Creating",
|
||||
"Delete": "Delete",
|
||||
"Delete Success": "Delete successfully",
|
||||
"Detail": "Detail",
|
||||
"Documents": "Documents",
|
||||
"Done": "Done",
|
||||
@@ -44,12 +46,14 @@
|
||||
"Folder": "Folder",
|
||||
"FullScreen": "FullScreen",
|
||||
"FullScreenLight": "FullScreenLight",
|
||||
"Gate.service.is.unavailable": "The Gate is not available",
|
||||
"Import": "Import",
|
||||
"Input": "Input",
|
||||
"Instructions": "Instruction",
|
||||
"Intro": "Introduction",
|
||||
"Loading": "Loading...",
|
||||
"Login": "Login",
|
||||
"Manage tags": "Management Tags",
|
||||
"More": "More",
|
||||
"Move": "Move",
|
||||
"Name": "Name",
|
||||
@@ -74,22 +78,29 @@
|
||||
"Run": "Run",
|
||||
"Running": "Running",
|
||||
"Save": "Save",
|
||||
"Save Failed": "Saving failed",
|
||||
"Save Success": "Save successfully",
|
||||
"Save_and_exit": "Save and Exit",
|
||||
"Search": "Search",
|
||||
"Select tags": "Select a tag",
|
||||
"Select_all": "Select all",
|
||||
"Setting": "Setting",
|
||||
"Status": "Status",
|
||||
"Submit": "Submit",
|
||||
"Success": "Success",
|
||||
"Tag already added": "The tag has been added",
|
||||
"Tags": "Label",
|
||||
"Team": "Team",
|
||||
"UnKnow": "Unknown",
|
||||
"Unlimited": "Unlimited",
|
||||
"Update": "Update",
|
||||
"Update Success": "Update successfully",
|
||||
"Username": "Username",
|
||||
"Waiting": "Waiting",
|
||||
"Warning": "Warning",
|
||||
"Website": "Website",
|
||||
"action_confirm": "Confirm",
|
||||
"add_app": "Added apps",
|
||||
"add_new": "add_new",
|
||||
"add_new_param": "Add new param",
|
||||
"add_success": "Added Successfully",
|
||||
@@ -135,10 +146,14 @@
|
||||
"code_error.error_code.504": "Gateway Timeout",
|
||||
"code_error.error_code[429]": "Requests are too frequent",
|
||||
"code_error.error_message.403": "Credential Error",
|
||||
"code_error.error_message.405": "methodNotAllowed",
|
||||
"code_error.error_message.510": "Insufficient Account Balance",
|
||||
"code_error.error_message.511": "Unauthorized to Operate This Model",
|
||||
"code_error.error_message.513": "Unauthorized to Read This File",
|
||||
"code_error.error_message.514": "Invalid API Key",
|
||||
"code_error.error_message[405]": "Method not allowed",
|
||||
"code_error.error_message[422]": "Params illegal",
|
||||
"code_error.error_message[500]": "System Error",
|
||||
"code_error.openapi_error.api_key_not_exist": "API Key Does Not Exist",
|
||||
"code_error.openapi_error.exceed_limit": "Up to 10 API Keys",
|
||||
"code_error.openapi_error.un_auth": "Unauthorized to Operate This API Key",
|
||||
@@ -829,10 +844,12 @@
|
||||
"folder.open_dataset": "Open Dataset",
|
||||
"folder_description": "Folder Description",
|
||||
"free": "Free",
|
||||
"gate.placeholder": "You can ask me any questions",
|
||||
"get_QR_failed": "Failed to Get QR Code",
|
||||
"get_app_failed": "Failed to Retrieve App",
|
||||
"get_laf_failed": "Failed to Retrieve Laf Function List",
|
||||
"has_verification": "Verified, Click to Unbind",
|
||||
"have_a_try": "Give it a try",
|
||||
"have_done": "Completed",
|
||||
"import_failed": "Import Failed",
|
||||
"import_success": "Imported Successfully",
|
||||
@@ -911,11 +928,14 @@
|
||||
"next_step": "Next",
|
||||
"no": "No",
|
||||
"no_child_folder": "No Subdirectories, Place Here",
|
||||
"no_data_available": "No valid data",
|
||||
"no_intro": "No Introduction Available",
|
||||
"no_laf_env": "System Not Configured with Laf Environment",
|
||||
"no_matching_apps_found": "No matching app found",
|
||||
"no_more_data": "No More Data",
|
||||
"no_pay_way": "There is no suitable payment channel in the system",
|
||||
"no_select_data": "No Data Available",
|
||||
"no_selected_apps": "No choice of applications yet",
|
||||
"not_model_config": "No related model configured",
|
||||
"not_open": "Not Open",
|
||||
"not_permission": "The current subscription package does not support team operation logs",
|
||||
@@ -996,6 +1016,7 @@
|
||||
"read_quote": "View citations",
|
||||
"redo_tip": "Redo ctrl shift z",
|
||||
"redo_tip_mac": "Redo ⌘ shift z",
|
||||
"reorder_failed": "Sorting failed",
|
||||
"request_end": "All Loaded",
|
||||
"request_error": "request_error",
|
||||
"request_more": "Click to Load More",
|
||||
@@ -1004,11 +1025,13 @@
|
||||
"resume_failed": "Resume Failed",
|
||||
"root_folder": "Root Folder",
|
||||
"save_failed": "save_failed",
|
||||
"save_success": "Saved Successfully",
|
||||
"save_success": "Save successfully",
|
||||
"scan_code": "Scan the QR code to pay",
|
||||
"select_file_failed": "File Selection Failed",
|
||||
"select_reference_variable": "Select Reference Variable",
|
||||
"select_tag": "Filter tags",
|
||||
"select_template": "Select Template",
|
||||
"selected": "Selected",
|
||||
"set_avatar": "Click to set_avatar",
|
||||
"share_link": "Share Link",
|
||||
"speech_error_tip": "Speech to Text Failed",
|
||||
@@ -1199,7 +1222,9 @@
|
||||
"system.Help Document": "Help Document",
|
||||
"system_help_chatbot": "Help Chatbot",
|
||||
"tag_list": "Tag List",
|
||||
"tag_manage": "Tag management",
|
||||
"team_tag": "Team Tag",
|
||||
"team_tags_set": "Team Tags",
|
||||
"templateTags.Image_generation": "Image generation",
|
||||
"templateTags.Office_services": "Office Services",
|
||||
"templateTags.Roleplay": "role play",
|
||||
@@ -1207,8 +1232,7 @@
|
||||
"templateTags.Writing": "Writing",
|
||||
"template_market": "Template Market",
|
||||
"textarea_variable_picker_tip": "Enter \"/\" to select a variable",
|
||||
"ui.textarea.Magnifying": "Magnifying",
|
||||
"un_used": "Unused",
|
||||
"ui.textarea.Magnifying": "enlarge",
|
||||
"unauth_token": "The certificate has expired, please log in again",
|
||||
"undo_tip": "Undo ctrl z",
|
||||
"undo_tip_mac": "Undo ⌘ z ",
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
"field_required": "Required",
|
||||
"field_used_as_tool_input": "Used as Tool Call Parameter",
|
||||
"filter_description": "Currently supports filtering by tags and creation time. Fill in the format as follows:\n{\n \"tags\": {\n \"$and\": [\"Tag 1\",\"Tag 2\"],\n \"$or\": [\"When there are $and tags, and is effective, or is not effective\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm format, collection creation time greater than this time\",\n \"$lte\": \"YYYY-MM-DD HH:mm format, collection creation time less than this time, can be used with $gte\"\n }\n}",
|
||||
"find_tip": "Find node ctrl f",
|
||||
"find_tip_mac": "Find node ⌘ f",
|
||||
"foldAll": "Collapse all",
|
||||
"form_input_result": "User complete input result",
|
||||
"form_input_result_tip": "an object containing the complete result",
|
||||
@@ -123,18 +125,23 @@
|
||||
"max_tokens": "Maximum Tokens",
|
||||
"mouse_priority": "Mouse first\n- Press the left button to drag the canvas\n- Hold down shift and left click to select batches",
|
||||
"new_context": "New Context",
|
||||
"next": "Next",
|
||||
"no_match_node": "No results",
|
||||
"no_node_found": "No node was not found",
|
||||
"not_contains": "Does Not Contain",
|
||||
"only_the_reference_type_is_supported": "Only reference type is supported",
|
||||
"optional_value_type": "Optional Value Type",
|
||||
"optional_value_type_tip": "You can specify one or more data types. When dynamically adding fields, users can only select the configured types.",
|
||||
"pan_priority": "Touchpad first\n- Click to batch select\n- Move the canvas with two fingers",
|
||||
"pass_returned_object_as_output_to_next_nodes": "Pass the object returned in the code as output to the next nodes. The variable name needs to correspond to the return key.",
|
||||
"please_enter_node_name": "Enter the node name",
|
||||
"plugin.Instruction_Tip": "You can configure an instruction to explain the purpose of the plugin. This instruction will be displayed each time the plugin is used. Supports standard Markdown syntax.",
|
||||
"plugin.Instructions": "Instructions",
|
||||
"plugin.global_file_input": "File links (deprecated)",
|
||||
"plugin_file_abandon_tip": "Plugin global file upload has been deprecated, please adjust it as soon as possible. \nRelated functions can be achieved through plug-in input and adding image type input.",
|
||||
"plugin_input": "Plugin Input",
|
||||
"plugin_output_tool": "When the plug-in is executed as a tool, whether this field responds as a result of the tool",
|
||||
"previous": "Previous",
|
||||
"question_classification": "Classify",
|
||||
"question_optimization": "Query extension",
|
||||
"quote_content_placeholder": "The structure of the reference content can be customized to better suit different scenarios. \nSome variables can be used for template configuration\n\n{{q}} - main content\n\n{{a}} - auxiliary data\n\n{{source}} - source name\n\n{{sourceId}} - source ID\n\n{{index}} - nth reference",
|
||||
@@ -177,9 +184,9 @@
|
||||
"text_content_extraction": "Text Extract",
|
||||
"text_to_extract": "Text to Extract",
|
||||
"these_variables_will_be_input_parameters_for_code_execution": "These variables will be input parameters for code execution",
|
||||
"tool.tool_result": "Tool operation results",
|
||||
"to_add_node": "to add",
|
||||
"to_connect_node": "to connect",
|
||||
"tool.tool_result": "Tool operation results",
|
||||
"tool_call_termination": "Stop ToolCall",
|
||||
"tool_custom_field": "Custom Tool",
|
||||
"tool_field": " Tool Field Parameter Configuration",
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
"api_key": "API 密钥",
|
||||
"bills_and_invoices": "账单与发票",
|
||||
"channel": "模型渠道",
|
||||
"config_app": "精选应用",
|
||||
"config_copyright": "版权信息",
|
||||
"config_home": "门户配置",
|
||||
"config_model": "模型配置",
|
||||
"confirm_logout": "确认退出登录?",
|
||||
"create_channel": "新增渠道",
|
||||
@@ -11,7 +14,12 @@
|
||||
"custom_model": "自定义模型",
|
||||
"default_model": "预设模型",
|
||||
"default_model_config": "默认模型配置",
|
||||
"gateway.cname_tip": "请到您的域名服务商处,比如添加该域名的、CNAME 解析到 Ixjgiwggswmb.sealoshzh.site,解析生效后即可绑定自定义域名。",
|
||||
"gateway.save_config": "保存",
|
||||
"gateway.share": "分享",
|
||||
"gateways": "门户管理",
|
||||
"logout": "登出",
|
||||
"logs": "首页日志",
|
||||
"model.active": "启用",
|
||||
"model.alias": "别名",
|
||||
"model.alias_tip": "模型在系统中展示的名字,方便用户理解",
|
||||
|
||||
32
packages/web/i18n/zh-CN/account_gate.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"Gate": "门户",
|
||||
"Gate List": "门户列表",
|
||||
"Gate app avatar updated": "门户应用图标更新",
|
||||
"Gate app created successfully": "门户应用创建成功",
|
||||
"No Gates Available": "暂无可用门户",
|
||||
"Operation failed": "操作失败",
|
||||
"available_tools": "可用工具",
|
||||
"confirm_delete_gate": "确认删除门户",
|
||||
"deep_thinking": "深度思考",
|
||||
"delete_gate": "删除门户",
|
||||
"dialog_prompt_text": "对话框提示文字",
|
||||
"disabled": "关闭",
|
||||
"enabled": "启用",
|
||||
"example": "示意图",
|
||||
"file_upload": "文件上传",
|
||||
"gate_list": "门户列表",
|
||||
"gate_logo": "LOGO预览",
|
||||
"gate_name": "门户名称",
|
||||
"image_upload": "图片上传",
|
||||
"no_gate_available": "没有可用门户",
|
||||
"no_gate_to_delete": "没有可以删除的门户了",
|
||||
"quick_app": "快捷应用",
|
||||
"slogan": "标语",
|
||||
"status": "状态",
|
||||
"suggestion_ratio_1_1": "建议比例 1:1",
|
||||
"suggestion_ratio_4_1": "建议比例 4:1",
|
||||
"team_name": "团队名",
|
||||
"upload": "上传",
|
||||
"voice_input": "语音输入",
|
||||
"web_search": "联网搜索"
|
||||
}
|
||||
@@ -48,6 +48,7 @@
|
||||
"create_by_template": "从模板创建",
|
||||
"create_copy_success": "创建副本成功",
|
||||
"create_empty_app": "创建空白应用",
|
||||
"create_empty_gate": "创建空白门户",
|
||||
"create_empty_plugin": "创建空白插件",
|
||||
"create_empty_workflow": "创建空白工作流",
|
||||
"cron.every_day": "每天执行",
|
||||
@@ -123,6 +124,8 @@
|
||||
"permission.des.manage": "写权限基础上,可配置发布渠道、查看对话日志、分配该应用权限",
|
||||
"permission.des.read": "可使用该应用进行对话",
|
||||
"permission.des.write": "可查看和编辑应用",
|
||||
"permission.des.log": "可查看对话日志",
|
||||
"permission.name.log": "查看日志",
|
||||
"plugin.Instructions": "使用说明",
|
||||
"plugin_cost_by_token": "依据 token 消耗计费",
|
||||
"plugin_cost_per_times": "{{cost}} 积分/次",
|
||||
@@ -148,6 +151,7 @@
|
||||
"team_tags_set": "团队标签",
|
||||
"temperature": "温度",
|
||||
"temperature_tip": "范围 0~10。值越大,代表模型回答越发散;值越小,代表回答越严谨。",
|
||||
"template.gate": "门户",
|
||||
"template.hard_strict": "严格问答模板",
|
||||
"template.hard_strict_des": "在问答模板基础上,对模型的回答做更严格的要求。",
|
||||
"template.qa_template": "问答模板",
|
||||
@@ -181,6 +185,8 @@
|
||||
"tts_browser": "浏览器自带(免费)",
|
||||
"tts_close": "关闭",
|
||||
"type.All": "全部",
|
||||
"type.Create gate": "创建门户",
|
||||
"type.Create gate tip": "门户不该在这里被创建",
|
||||
"type.Create http plugin tip": "通过 OpenAPI Schema 批量创建插件,兼容 GPTs 格式",
|
||||
"type.Create mcp tools tip": "通过输入 MCP 地址,自动解析并批量创建可调用的 MCP 工具",
|
||||
"type.Create one plugin tip": "可以自定义输入和输出的工作流,通常用于封装重复使用的工作流",
|
||||
@@ -189,6 +195,7 @@
|
||||
"type.Create simple bot tip": "通过填表单形式,创建简单的 AI 应用,适合新手",
|
||||
"type.Create workflow bot": "创建工作流",
|
||||
"type.Create workflow tip": "通过低代码的方式,构建逻辑复杂的多轮对话 AI 应用,推荐高级玩家使用",
|
||||
"type.Gate": "门户",
|
||||
"type.Http plugin": "HTTP 插件",
|
||||
"type.Import from json": "导入 JSON 配置",
|
||||
"type.Import from json tip": "通过 JSON 配置文件,直接创建应用",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"chat.quote.No Data": "找不到该文件",
|
||||
"chat.quote.deleted": "该数据已被删除~",
|
||||
"chat.waiting_for_response": "请等待对话完成",
|
||||
"chat_gate_app": "门户首页",
|
||||
"chat_history": "聊天记录",
|
||||
"chat_input_guide_lexicon_is_empty": "还没有配置词库",
|
||||
"chat_test_app": "调试-{{name}}",
|
||||
|
||||
@@ -13,8 +13,11 @@
|
||||
"Confirm": "确认",
|
||||
"Continue_Adding": "继续添加",
|
||||
"Copy": "复制",
|
||||
"Create Success": "创建成功",
|
||||
"Creating": "创建中",
|
||||
"Delete": "删除",
|
||||
"Delete Failed": "删除失败",
|
||||
"Delete Success": "删除成功",
|
||||
"Detail": "详情",
|
||||
"Documents": "文档",
|
||||
"Done": "完成",
|
||||
@@ -44,12 +47,14 @@
|
||||
"Folder": "文件夹",
|
||||
"FullScreen": "全屏",
|
||||
"FullScreenLight": "全屏预览",
|
||||
"Gate.service.is.unavailable": "门户不可用",
|
||||
"Import": "导入",
|
||||
"Input": "输入",
|
||||
"Instructions": "使用说明",
|
||||
"Intro": "介绍",
|
||||
"Loading": "加载中...",
|
||||
"Login": "登录",
|
||||
"Manage tags": "管理标签",
|
||||
"More": "更多",
|
||||
"Move": "移动",
|
||||
"Name": "名称",
|
||||
@@ -74,22 +79,29 @@
|
||||
"Run": "运行",
|
||||
"Running": "运行中",
|
||||
"Save": "保存",
|
||||
"Save Failed": "保存失败",
|
||||
"Save Success": "保存成功",
|
||||
"Save_and_exit": "保存并退出",
|
||||
"Search": "搜索",
|
||||
"Select tags": "选择标签",
|
||||
"Select_all": "全选",
|
||||
"Setting": "设置",
|
||||
"Status": "状态",
|
||||
"Submit": "提交",
|
||||
"Success": "成功",
|
||||
"Tag already added": "标签已经添加过了",
|
||||
"Tags": "标签",
|
||||
"Team": "团队",
|
||||
"UnKnow": "未知",
|
||||
"Unlimited": "无限制",
|
||||
"Update": "更新",
|
||||
"Update Success": "更新成功",
|
||||
"Username": "用户名",
|
||||
"Waiting": "等待中",
|
||||
"Warning": "警告",
|
||||
"Website": "网站",
|
||||
"action_confirm": "操作确认",
|
||||
"add_app": "新增应用",
|
||||
"add_new": "新增",
|
||||
"add_new_param": "新增参数",
|
||||
"add_success": "添加成功",
|
||||
@@ -135,6 +147,9 @@
|
||||
"code_error.error_code.503": "服务器暂时过载或正在维护",
|
||||
"code_error.error_code.504": "网关超时",
|
||||
"code_error.error_message.403": "凭证错误",
|
||||
"code_error.error_message.405": "方式不允许",
|
||||
"code_error.error_message.422": "Params非法",
|
||||
"code_error.error_message.500": "系统错误",
|
||||
"code_error.error_message.510": "账户余额不足",
|
||||
"code_error.error_message.511": "没有权限操作此模型",
|
||||
"code_error.error_message.513": "没有权限读取该文件",
|
||||
@@ -829,10 +844,12 @@
|
||||
"folder.open_dataset": "打开知识库",
|
||||
"folder_description": "文件夹描述",
|
||||
"free": "免费",
|
||||
"gate.placeholder": "你可以问我任何问题",
|
||||
"get_QR_failed": "获取二维码失败",
|
||||
"get_app_failed": "获取应用失败",
|
||||
"get_laf_failed": "获取Laf函数列表失败",
|
||||
"has_verification": "已验证,点击取消绑定",
|
||||
"have_a_try": "试一试",
|
||||
"have_done": "已完成",
|
||||
"import_failed": "导入失败",
|
||||
"import_success": "导入成功",
|
||||
@@ -911,11 +928,14 @@
|
||||
"next_step": "下一步",
|
||||
"no": "否",
|
||||
"no_child_folder": "没有子目录了,就放这里吧",
|
||||
"no_data_available": "无有效数据",
|
||||
"no_intro": "暂无介绍",
|
||||
"no_laf_env": "系统未配置Laf环境",
|
||||
"no_matching_apps_found": "没有找到匹配的应用",
|
||||
"no_more_data": "没有更多了~",
|
||||
"no_pay_way": "系统无合适的支付渠道",
|
||||
"no_select_data": "没有可选值",
|
||||
"no_selected_apps": "暂无选择的应用",
|
||||
"not_model_config": "未配置相关模型",
|
||||
"not_open": "未开启",
|
||||
"not_permission": "当前订阅套餐不支持团队操作日志",
|
||||
@@ -996,6 +1016,7 @@
|
||||
"read_quote": "查看引用",
|
||||
"redo_tip": "恢复 ctrl shift z",
|
||||
"redo_tip_mac": "恢复 ⌘ shift z",
|
||||
"reorder_failed": "排序失败",
|
||||
"request_end": "已加载全部",
|
||||
"request_error": "请求异常",
|
||||
"request_more": "点击加载更多",
|
||||
@@ -1008,7 +1029,9 @@
|
||||
"scan_code": "扫码支付",
|
||||
"select_file_failed": "选择文件异常",
|
||||
"select_reference_variable": "选择引用变量",
|
||||
"select_tag": "筛选标签",
|
||||
"select_template": "选择模板",
|
||||
"selected": "已选择",
|
||||
"set_avatar": "点击设置头像",
|
||||
"share_link": "分享链接",
|
||||
"speech_error_tip": "语音转文字失败",
|
||||
@@ -1199,7 +1222,9 @@
|
||||
"system.Help Document": "帮助文档",
|
||||
"system_help_chatbot": "机器人助手",
|
||||
"tag_list": "标签列表",
|
||||
"tag_manage": "标签管理",
|
||||
"team_tag": "团队标签",
|
||||
"team_tags_set": "团队标签",
|
||||
"templateTags.Image_generation": "图片生成",
|
||||
"templateTags.Office_services": "办公服务",
|
||||
"templateTags.Roleplay": "角色扮演",
|
||||
@@ -1207,6 +1232,7 @@
|
||||
"templateTags.Writing": "文本创作",
|
||||
"template_market": "模板市场",
|
||||
"textarea_variable_picker_tip": "输入\"/\"可选择变量",
|
||||
"tool_select": "工具选择",
|
||||
"ui.textarea.Magnifying": "放大",
|
||||
"un_used": "未使用",
|
||||
"unauth_token": "凭证已过期,请重新登录",
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
"field_required": "必填",
|
||||
"field_used_as_tool_input": "作为工具调用参数",
|
||||
"filter_description": "目前支持标签和创建时间过滤,需按照以下格式填写:\n{\n \"tags\": {\n \"$and\": [\"标签 1\",\"标签 2\"],\n \"$or\": [\"有 $and 标签时,and 生效,or 不生效\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm 格式即可,集合的创建时间大于该时间\",\n \"$lte\": \"YYYY-MM-DD HH:mm 格式即可,集合的创建时间小于该时间,可和 $gte 共同使用\"\n }\n}",
|
||||
"find_tip": "查找节点 ctrl f",
|
||||
"find_tip_mac": "查找节点 ⌘ f",
|
||||
"foldAll": "全部折叠",
|
||||
"form_input_result": "用户完整输入结果",
|
||||
"form_input_result_tip": "一个包含完整结果的对象",
|
||||
@@ -123,18 +125,23 @@
|
||||
"max_tokens": "最大 Tokens",
|
||||
"mouse_priority": "鼠标优先\n- 左键按下后可拖动画布\n- 按住 shift 后左键可批量选择",
|
||||
"new_context": "新的上下文",
|
||||
"next": "下一个",
|
||||
"no_match_node": "无结果",
|
||||
"no_node_found": "未搜索到节点",
|
||||
"not_contains": "不包含",
|
||||
"only_the_reference_type_is_supported": "仅支持引用类型",
|
||||
"optional_value_type": "可选的数据类型",
|
||||
"optional_value_type_tip": "可以指定 1 个或多个数据类型,用户在动态添加字段时,仅可选择配置的类型",
|
||||
"pan_priority": "触摸板优先\n- 单击批量选择\n- 双指移动画布",
|
||||
"pass_returned_object_as_output_to_next_nodes": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key",
|
||||
"please_enter_node_name": "请输入节点名称",
|
||||
"plugin.Instruction_Tip": "可以配置一段说明,以解释该插件的用途。每次使用插件前,会显示该段说明。支持标准 Markdown 语法。",
|
||||
"plugin.Instructions": "使用说明",
|
||||
"plugin.global_file_input": "文件链接(弃用)",
|
||||
"plugin_file_abandon_tip": "插件全局文件上传已弃用,请尽快调整。可以通过插件输入,添加图片类型输入来实现相关功能。",
|
||||
"plugin_input": "插件输入",
|
||||
"plugin_output_tool": "插件作为工具执行时,该字段是否作为工具响应结果",
|
||||
"previous": "上一个",
|
||||
"question_classification": "问题分类",
|
||||
"question_optimization": "问题优化",
|
||||
"quote_content_placeholder": "可以自定义引用内容的结构,以更好的适配不同场景。可以使用一些变量来进行模板配置\n{{q}} - 主要内容\n{{a}} - 辅助数据\n{{source}} - 来源名\n{{sourceId}} - 来源ID\n{{index}} - 第 n 个引用",
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
"api_key": "API 金鑰",
|
||||
"bills_and_invoices": "帳單與發票",
|
||||
"channel": "模型管道",
|
||||
"config_app": "精選應用",
|
||||
"config_copyright": "應用配置",
|
||||
"config_home": "首頁配置",
|
||||
"config_model": "模型設定",
|
||||
"confirm_logout": "確認登出登入?",
|
||||
"create_channel": "新增頻道",
|
||||
@@ -11,7 +14,12 @@
|
||||
"custom_model": "自訂模型",
|
||||
"default_model": "預設模型",
|
||||
"default_model_config": "預設模型設定",
|
||||
"gateway.cname_tip": "請到您的域名服務商處,比如添加該域名的、CNAME 解析到 Ixjgiwggswmb.sealoshzh.site,解析生效後即可綁定自定義域名。",
|
||||
"gateway.save_config": "保存",
|
||||
"gateway.share": "分享",
|
||||
"gateways": "門戶管理",
|
||||
"logout": "登出",
|
||||
"logs": "首頁日誌",
|
||||
"model.active": "啟用",
|
||||
"model.alias": "別名",
|
||||
"model.alias_tip": "模型在系統中展示的名字,方便使用者理解",
|
||||
|
||||
30
packages/web/i18n/zh-Hant/account_gate.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Gate": "門戶",
|
||||
"Gate List": "門戶列表",
|
||||
"Gate app avatar updated": "門戶應用圖標更新",
|
||||
"Gate app created successfully": "門戶應用創建成功",
|
||||
"No Gates Available": "暫無可用門戶",
|
||||
"Operation failed": "操作失敗",
|
||||
"available_tools": "可用工具",
|
||||
"confirm_delete_gate": "確認刪除門戶",
|
||||
"deep_thinking": "深度思考",
|
||||
"delete_gate": "刪除門戶",
|
||||
"dialog_prompt_text": "對話框提示文字",
|
||||
"disabled": "關閉",
|
||||
"enabled": "啟用",
|
||||
"example": "示意圖",
|
||||
"file_upload": "文件上傳",
|
||||
"gate_list": "門戶列表",
|
||||
"gate_logo": "LOGO預覽",
|
||||
"image_upload": "圖片上傳",
|
||||
"no_gate_available": "沒有可用門戶",
|
||||
"no_gate_to_delete": "沒有可以刪除的門戶了",
|
||||
"quick_app": "快捷應用",
|
||||
"slogan": "標語",
|
||||
"status": "狀態",
|
||||
"suggestion_ratio_1_1": "建議比例 1:1",
|
||||
"suggestion_ratio_4_1": "建議比例 4:1",
|
||||
"team_name": "團隊名",
|
||||
"voice_input": "語音輸入",
|
||||
"web_search": "聯網搜索"
|
||||
}
|
||||
@@ -48,6 +48,7 @@
|
||||
"create_by_template": "從範本建立",
|
||||
"create_copy_success": "建立副本成功",
|
||||
"create_empty_app": "建立空白應用程式",
|
||||
"create_empty_gate": "創建空白門戶",
|
||||
"create_empty_plugin": "建立空白外掛",
|
||||
"create_empty_workflow": "建立空白工作流程",
|
||||
"cron.every_day": "每天執行",
|
||||
@@ -123,6 +124,8 @@
|
||||
"permission.des.manage": "在寫入權限基礎上,可以設定發布通道、檢視對話紀錄、分配這個應用程式的權限",
|
||||
"permission.des.read": "可以使用這個應用程式進行對話",
|
||||
"permission.des.write": "可以檢視和編輯應用程式",
|
||||
"permission.des.log": "可查看對話日誌",
|
||||
"permission.name.log": "查看日誌",
|
||||
"plugin.Instructions": "使用說明",
|
||||
"plugin_cost_by_token": "根據 token 消耗計費",
|
||||
"plugin_cost_per_times": "{{cost}} 積分/次",
|
||||
@@ -148,6 +151,7 @@
|
||||
"team_tags_set": "團隊標籤",
|
||||
"temperature": "溫度",
|
||||
"temperature_tip": "範圍 0~10。\n值越大,代表模型回答越發散;值越小,代表回答越嚴謹。",
|
||||
"template.gate": "門戶",
|
||||
"template.hard_strict": "嚴格問答範本",
|
||||
"template.hard_strict_des": "在問答範本基礎上,對模型的回答做出更嚴格的要求。",
|
||||
"template.qa_template": "問答範本",
|
||||
@@ -181,6 +185,8 @@
|
||||
"tts_browser": "瀏覽器自帶 (免費)",
|
||||
"tts_close": "關閉",
|
||||
"type.All": "全部",
|
||||
"type.Create gate": "創建門戶",
|
||||
"type.Create gate tip": "門戶不該在這裡被創建",
|
||||
"type.Create http plugin tip": "透過 OpenAPI Schema 批次建立外掛,相容 GPTs 格式",
|
||||
"type.Create mcp tools tip": "通過輸入 MCP 地址,自動解析並批量創建可調用的 MCP 工具",
|
||||
"type.Create one plugin tip": "可以自訂輸入和輸出的工作流程,通常用於封裝重複使用的工作流程",
|
||||
@@ -189,6 +195,7 @@
|
||||
"type.Create simple bot tip": "透過填寫表單的方式,建立簡單的 AI 應用程式,適合新手",
|
||||
"type.Create workflow bot": "建立工作流程",
|
||||
"type.Create workflow tip": "透過低程式碼的方式,建立邏輯複雜的多輪對話 AI 應用程式,建議進階使用者使用",
|
||||
"type.Gate": "門戶",
|
||||
"type.Http plugin": "HTTP 外掛",
|
||||
"type.Import from json": "匯入 JSON 設定",
|
||||
"type.Import from json tip": "透過 JSON 設定文件,直接建立應用",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"chat.quote.No Data": "找不到該文件",
|
||||
"chat.quote.deleted": "該資料已被刪除~",
|
||||
"chat.waiting_for_response": "請等待對話完成",
|
||||
"chat_gate_app": "門戶首頁",
|
||||
"chat_history": "對話紀錄",
|
||||
"chat_input_guide_lexicon_is_empty": "尚未設定詞彙庫",
|
||||
"chat_test_app": "除錯-{{name}}",
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
"Confirm": "確認",
|
||||
"Continue_Adding": "繼續新增",
|
||||
"Copy": "複製",
|
||||
"Create Success": "創建成功",
|
||||
"Creating": "建立中",
|
||||
"Delete": "刪除",
|
||||
"Delete Success": "刪除成功",
|
||||
"Detail": "詳細資料",
|
||||
"Documents": "文件",
|
||||
"Done": "完成",
|
||||
@@ -44,12 +46,14 @@
|
||||
"Folder": "資料夾",
|
||||
"FullScreen": "全屏",
|
||||
"FullScreenLight": "全屏預覽",
|
||||
"Gate.service.is.unavailable": "門戶不可用",
|
||||
"Import": "匯入",
|
||||
"Input": "輸入",
|
||||
"Instructions": "使用說明",
|
||||
"Intro": "介紹",
|
||||
"Loading": "載入中...",
|
||||
"Login": "登入",
|
||||
"Manage tags": "管理標籤",
|
||||
"More": "更多",
|
||||
"Move": "移動",
|
||||
"Name": "名稱",
|
||||
@@ -74,22 +78,28 @@
|
||||
"Run": "執行",
|
||||
"Running": "執行中",
|
||||
"Save": "儲存",
|
||||
"Save Failed": "保存失敗",
|
||||
"Save Success": "保存成功",
|
||||
"Save_and_exit": "儲存並離開",
|
||||
"Search": "搜尋",
|
||||
"Select tags": "選擇標籤",
|
||||
"Select_all": "全選",
|
||||
"Setting": "設定",
|
||||
"Status": "狀態",
|
||||
"Submit": "送出",
|
||||
"Success": "成功",
|
||||
"Tag already added": "標籤已經添加過了",
|
||||
"Team": "團隊",
|
||||
"UnKnow": "未知",
|
||||
"Unlimited": "無限制",
|
||||
"Update": "更新",
|
||||
"Update Success": "更新成功",
|
||||
"Username": "使用者名稱",
|
||||
"Waiting": "等待中",
|
||||
"Warning": "警告",
|
||||
"Website": "網站",
|
||||
"action_confirm": "確認",
|
||||
"add_app": "新增應用",
|
||||
"add_new": "新增",
|
||||
"add_new_param": "新增參數",
|
||||
"add_success": "新增成功",
|
||||
@@ -139,6 +149,9 @@
|
||||
"code_error.error_message.511": "無權操作此模型",
|
||||
"code_error.error_message.513": "無權讀取此檔案",
|
||||
"code_error.error_message.514": "API 金鑰無效",
|
||||
"code_error.error_message[405]": "方式不允許",
|
||||
"code_error.error_message[422]": "Params非法",
|
||||
"code_error.error_message[500]": "系統錯誤",
|
||||
"code_error.openapi_error.api_key_not_exist": "API 金鑰不存在",
|
||||
"code_error.openapi_error.exceed_limit": "最多 10 組 API 金鑰",
|
||||
"code_error.openapi_error.un_auth": "無權操作此 API 金鑰",
|
||||
@@ -829,10 +842,12 @@
|
||||
"folder.open_dataset": "開啟知識庫",
|
||||
"folder_description": "資料夾描述",
|
||||
"free": "免費",
|
||||
"gate.placeholder": "你可以問我任何問題",
|
||||
"get_QR_failed": "取得 QR Code 失敗",
|
||||
"get_app_failed": "取得應用程式失敗",
|
||||
"get_laf_failed": "取得 LAF 函式清單失敗",
|
||||
"has_verification": "已驗證,點選解除綁定",
|
||||
"have_a_try": "試一試",
|
||||
"have_done": "已完成",
|
||||
"import_failed": "匯入失敗",
|
||||
"import_success": "匯入成功",
|
||||
@@ -911,11 +926,14 @@
|
||||
"next_step": "下一步",
|
||||
"no": "否",
|
||||
"no_child_folder": "無子目錄,放置在此",
|
||||
"no_data_available": "無有效數據",
|
||||
"no_intro": "暫無介紹",
|
||||
"no_laf_env": "系統未設定 LAF 環境",
|
||||
"no_matching_apps_found": "沒有找到匹配的應用",
|
||||
"no_more_data": "沒有更多資料了",
|
||||
"no_pay_way": "系統無合適的支付渠道",
|
||||
"no_select_data": "沒有可選擇的資料",
|
||||
"no_selected_apps": "暫無選擇的應用",
|
||||
"not_model_config": "未設定相關模型",
|
||||
"not_open": "未開啟",
|
||||
"not_permission": "當前訂閱套餐不支持團隊操作日誌",
|
||||
@@ -1004,11 +1022,13 @@
|
||||
"resume_failed": "恢復失敗",
|
||||
"root_folder": "根目錄",
|
||||
"save_failed": "儲存失敗",
|
||||
"save_success": "儲存成功",
|
||||
"save_success": "保存成功",
|
||||
"scan_code": "掃碼支付",
|
||||
"select_file_failed": "選擇檔案失敗",
|
||||
"select_reference_variable": "選擇引用變數",
|
||||
"select_tag": "篩選標籤",
|
||||
"select_template": "選擇範本",
|
||||
"selected": "已選擇",
|
||||
"set_avatar": "點選設定頭像",
|
||||
"share_link": "分享連結",
|
||||
"speech_error_tip": "語音轉文字失敗",
|
||||
@@ -1199,7 +1219,9 @@
|
||||
"system.Help Document": "說明文件",
|
||||
"system_help_chatbot": "機器人助手",
|
||||
"tag_list": "標籤列表",
|
||||
"tag_manage": "標籤管理",
|
||||
"team_tag": "團隊標籤",
|
||||
"team_tags_set": "團隊標籤",
|
||||
"templateTags.Image_generation": "圖片生成",
|
||||
"templateTags.Office_services": "辦公服務",
|
||||
"templateTags.Roleplay": "角色扮演",
|
||||
@@ -1208,7 +1230,6 @@
|
||||
"template_market": "模板市場",
|
||||
"textarea_variable_picker_tip": "輸入「/」以選擇變數",
|
||||
"ui.textarea.Magnifying": "放大",
|
||||
"un_used": "未使用",
|
||||
"unauth_token": "憑證已過期,請重新登入",
|
||||
"undo_tip": "復原 ctrl z",
|
||||
"undo_tip_mac": "復原 ⌘ z ",
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
"field_required": "必填",
|
||||
"field_used_as_tool_input": "作為工具呼叫參數",
|
||||
"filter_description": "目前支援標籤和建立時間篩選,需按照以下格式填寫:\n{\n \"tags\": {\n \"$and\": [\"標籤 1\",\"標籤 2\"],\n \"$or\": [\"當有 $and 標籤時,$and 才會生效,$or 不會生效\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm 格式,資料集的建立時間大於這個時間\",\n \"$lte\": \"YYYY-MM-DD HH:mm 格式,資料集的建立時間小於這個時間,可以和 $gte 一起使用\"\n }\n}",
|
||||
"find_tip": "查找節點 ctrl f",
|
||||
"find_tip_mac": "查找節點 ⌘ f",
|
||||
"foldAll": "全部折疊",
|
||||
"form_input_result": "使用者完整輸入結果",
|
||||
"form_input_result_tip": "一個包含完整結果的物件",
|
||||
@@ -123,18 +125,23 @@
|
||||
"max_tokens": "最大 Token 數",
|
||||
"mouse_priority": "滑鼠優先\n- 按下左鍵拖曳畫布\n- 按住 Shift 鍵並點選左鍵可批次選取",
|
||||
"new_context": "新的脈絡",
|
||||
"next": "下一個",
|
||||
"no_match_node": "無結果",
|
||||
"no_node_found": "未搜索到節點",
|
||||
"not_contains": "不包含",
|
||||
"only_the_reference_type_is_supported": "僅支援引用類型",
|
||||
"optional_value_type": "可選的資料類型",
|
||||
"optional_value_type_tip": "可以指定一或多個資料類型,使用者在動態新增欄位時,只能選擇已設定的類型",
|
||||
"pan_priority": "觸控板優先\n- 點選可批次選取\n- 使用兩指移動畫布",
|
||||
"pass_returned_object_as_output_to_next_nodes": "將程式碼中 return 的物件作為輸出,傳遞給後續的節點。變數名稱需要對應 return 的鍵值",
|
||||
"please_enter_node_name": "請輸入節點名稱",
|
||||
"plugin.Instruction_Tip": "您可以設定一段說明來解釋這個外掛程式的用途。每次使用外掛程式前,都會顯示這段說明。支援標準 Markdown 語法。",
|
||||
"plugin.Instructions": "使用說明",
|
||||
"plugin.global_file_input": "檔案連結(已淘汰)",
|
||||
"plugin_file_abandon_tip": "外掛程式全域檔案上傳功能已淘汰,請儘速調整。您可以透過外掛程式輸入,新增圖片類型輸入來達成相關功能。",
|
||||
"plugin_input": "外掛程式輸入",
|
||||
"plugin_output_tool": "外掛程式作為工具執行時,這個欄位是否作為工具的回應結果",
|
||||
"previous": "上一個",
|
||||
"question_classification": "問題分類",
|
||||
"question_optimization": "問題最佳化",
|
||||
"quote_content_placeholder": "可以自訂引用內容的結構,以便更好地適應不同場景。可以使用一些變數來設定範本\n{{q}} - 主要內容\n{{a}} - 輔助資料\n{{source}} - 來源名稱\n{{sourceId}} - 來源 ID\n{{index}} - 第 n 個引用",
|
||||
@@ -177,9 +184,9 @@
|
||||
"text_content_extraction": "文字內容擷取",
|
||||
"text_to_extract": "要擷取的文字",
|
||||
"these_variables_will_be_input_parameters_for_code_execution": "這些變數會作為程式碼執行的輸入參數",
|
||||
"tool.tool_result": "工具運行結果",
|
||||
"to_add_node": "添加節點",
|
||||
"to_connect_node": "連接節點",
|
||||
"tool.tool_result": "工具運行結果",
|
||||
"tool_call_termination": "工具呼叫終止",
|
||||
"tool_custom_field": "自訂工具變數",
|
||||
"tool_field": "工具參數設定",
|
||||
|
||||
2
packages/web/types/i18next.d.ts
vendored
@@ -34,6 +34,7 @@ export interface I18nNamespaces {
|
||||
account_info: typeof account_info;
|
||||
account_usage: typeof account_usage;
|
||||
account_bill: typeof account_bill;
|
||||
account_gate: typeof account_gate;
|
||||
account_apikey: typeof account_apikey;
|
||||
account_setting: typeof account_setting;
|
||||
account_inform: typeof account_inform;
|
||||
@@ -71,6 +72,7 @@ declare module 'i18next' {
|
||||
'account_info',
|
||||
'account_usage',
|
||||
'account_bill',
|
||||
'account_gate',
|
||||
'account_apikey',
|
||||
'account_setting',
|
||||
'account_inform',
|
||||
|
||||
@@ -29,8 +29,6 @@ MONGODB_LOG_URI=mongodb://username:password@0.0.0.0:27017/fastgpt?authSource=adm
|
||||
PG_URL=postgresql://username:password@host:port/postgres
|
||||
# OceanBase 向量库连接参数
|
||||
OCEANBASE_URL=
|
||||
# openGauss 向量库连接参数
|
||||
OPENGAUSS_URL=
|
||||
# milvus 向量库连接参数
|
||||
MILVUS_ADDRESS=
|
||||
MILVUS_TOKEN=
|
||||
|
||||