mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-19 10:07:24 +00:00
feat: prompt call tool support reason;perf: ai proxy doc (#3982)
* update schema * perf: ai proxy doc * feat: prompt call tool support reason
This commit is contained in:
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -27,7 +27,5 @@
|
|||||||
},
|
},
|
||||||
"markdown.copyFiles.destination": {
|
"markdown.copyFiles.destination": {
|
||||||
"/docSite/content/**/*": "${documentWorkspaceFolder}/docSite/assets/imgs/"
|
"/docSite/content/**/*": "${documentWorkspaceFolder}/docSite/assets/imgs/"
|
||||||
},
|
}
|
||||||
"markdown.copyFiles.overwriteBehavior": "nameIncrementally",
|
|
||||||
"markdown.copyFiles.transformPath": "const filename = uri.path.split('/').pop(); return `/imgs/${filename}`;"
|
|
||||||
}
|
}
|
24
README.md
24
README.md
@@ -115,16 +115,6 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b
|
|||||||
<img src="https://img.shields.io/badge/-返回顶部-7d09f1.svg" alt="#" align="right">
|
<img src="https://img.shields.io/badge/-返回顶部-7d09f1.svg" alt="#" align="right">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
## 🏘️ 社区交流群
|
|
||||||
|
|
||||||
扫码加入飞书话题群:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
<a href="#readme">
|
|
||||||
<img src="https://img.shields.io/badge/-返回顶部-7d09f1.svg" alt="#" align="right">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
## 🏘️ 加入我们
|
## 🏘️ 加入我们
|
||||||
|
|
||||||
我们正在寻找志同道合的小伙伴,加速 FastGPT 的发展。你可以通过 [FastGPT 2025 招聘](https://fael3z0zfze.feishu.cn/wiki/P7FOwEmPziVcaYkvVaacnVX1nvg)了解 FastGPT 的招聘信息。
|
我们正在寻找志同道合的小伙伴,加速 FastGPT 的发展。你可以通过 [FastGPT 2025 招聘](https://fael3z0zfze.feishu.cn/wiki/P7FOwEmPziVcaYkvVaacnVX1nvg)了解 FastGPT 的招聘信息。
|
||||||
@@ -135,17 +125,25 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b
|
|||||||
- [Sealos:快速部署集群应用](https://github.com/labring/sealos)
|
- [Sealos:快速部署集群应用](https://github.com/labring/sealos)
|
||||||
- [AI Proxy API调用地址](https://sealos.run/aiproxy/?k=fastgpt-github/)
|
- [AI Proxy API调用地址](https://sealos.run/aiproxy/?k=fastgpt-github/)
|
||||||
- [One API:多模型管理,支持 Azure、文心一言等](https://github.com/songquanpeng/one-api)
|
- [One API:多模型管理,支持 Azure、文心一言等](https://github.com/songquanpeng/one-api)
|
||||||
- [TuShan:5 分钟搭建后台管理系统](https://github.com/msgbyte/tushan)
|
|
||||||
|
|
||||||
<a href="#readme">
|
<a href="#readme">
|
||||||
<img src="https://img.shields.io/badge/-返回顶部-7d09f1.svg" alt="#" align="right">
|
<img src="https://img.shields.io/badge/-返回顶部-7d09f1.svg" alt="#" align="right">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
## 🌿 第三方生态
|
## 🌿 第三方生态
|
||||||
|
|
||||||
- [COW 个人微信/企微机器人](https://doc.tryfastgpt.ai/docs/use-cases/external-integration/onwechat/)
|
|
||||||
- [SiliconCloud (硅基流动) —— 开源模型在线体验平台](https://cloud.siliconflow.cn/i/TR9Ym0c4)
|
- [SiliconCloud (硅基流动) —— 开源模型在线体验平台](https://cloud.siliconflow.cn/i/TR9Ym0c4)
|
||||||
|
- [COW 个人微信/企微机器人](https://doc.tryfastgpt.ai/docs/use-cases/external-integration/onwechat/)
|
||||||
|
|
||||||
|
<a href="#readme">
|
||||||
|
<img src="https://img.shields.io/badge/-返回顶部-7d09f1.svg" alt="#" align="right">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## 🏘️ 社区交流群
|
||||||
|
|
||||||
|
扫码加入飞书话题群:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
<a href="#readme">
|
<a href="#readme">
|
||||||
<img src="https://img.shields.io/badge/-返回顶部-7d09f1.svg" alt="#" align="right">
|
<img src="https://img.shields.io/badge/-返回顶部-7d09f1.svg" alt="#" align="right">
|
||||||
|
@@ -141,10 +141,9 @@ services:
|
|||||||
- AIPROXY_API_ENDPOINT=http://aiproxy:3000
|
- AIPROXY_API_ENDPOINT=http://aiproxy:3000
|
||||||
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
|
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
|
||||||
- AIPROXY_API_TOKEN=aiproxy
|
- AIPROXY_API_TOKEN=aiproxy
|
||||||
# AI模型的API地址哦。务必加 /v1。这里默认填写了OneApi的访问地址。
|
# 模型中转地址(如果用了 AI Proxy,下面 2 个就不需要了,旧版 OneAPI 用户,使用下面的变量)
|
||||||
- OPENAI_BASE_URL=http://oneapi:3000/v1
|
# - OPENAI_BASE_URL=http://oneapi:3000/v1
|
||||||
# AI模型的API Key。(这里默认填写了OneAPI的快速默认key,测试通后,务必及时修改)
|
# - CHAT_API_KEY=sk-fastgpt
|
||||||
- CHAT_API_KEY=sk-fastgpt
|
|
||||||
# 数据库最大连接数
|
# 数据库最大连接数
|
||||||
- DB_MAX_LINK=30
|
- DB_MAX_LINK=30
|
||||||
# 登录凭证密钥
|
# 登录凭证密钥
|
||||||
@@ -180,32 +179,37 @@ services:
|
|||||||
container_name: aiproxy
|
container_name: aiproxy
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
pgsql:
|
aiproxy_pg:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
- '3002:3000/tcp'
|
- '3002:3000'
|
||||||
networks:
|
networks:
|
||||||
- fastgpt
|
- fastgpt
|
||||||
environment:
|
environment:
|
||||||
- ADMIN_KEY=aiproxy # 对应 fastgpt 里的AIPROXY_API_TOKEN
|
# 对应 fastgpt 里的AIPROXY_API_TOKEN
|
||||||
- LOG_DETAIL_STORAGE_HOURS=1 # 日志详情保存时间(小时)
|
- ADMIN_KEY=aiproxy
|
||||||
- TZ=Asia/Shanghai
|
# 错误日志详情保存时间(小时)
|
||||||
- SQL_DSN=postgres://postgres:aiproxy@pgsql:5432/aiproxy
|
- LOG_DETAIL_STORAGE_HOURS=1
|
||||||
|
# 数据库连接地址
|
||||||
|
- SQL_DSN=postgres://postgres:aiproxy@aiproxy_pg:5432/aiproxy
|
||||||
|
# 最大重试次数
|
||||||
|
- RetryTimes=3
|
||||||
|
# 不需要计费
|
||||||
|
- BILLING_ENABLED=false
|
||||||
|
# 不需要严格检测模型
|
||||||
- DISABLE_MODEL_CONFIG=true
|
- DISABLE_MODEL_CONFIG=true
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ['CMD', 'curl', '-f', 'http://localhost:3000/api/status']
|
test: ['CMD', 'curl', '-f', 'http://localhost:3000/api/status']
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 10
|
retries: 10
|
||||||
|
aiproxy_pg:
|
||||||
# AI Proxy
|
# image: pgvector/pgvector:0.8.0-pg15 # docker hub
|
||||||
pgsql:
|
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.8.0-pg15 # 阿里云
|
||||||
# image: "postgres:latest"
|
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.7.0 # 阿里云
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
container_name: pgsql
|
container_name: aiproxy_pg
|
||||||
volumes:
|
volumes:
|
||||||
- ./pgsql:/var/lib/postgresql/data
|
- ./aiproxy_pg:/var/lib/postgresql/data
|
||||||
networks:
|
networks:
|
||||||
- fastgpt
|
- fastgpt
|
||||||
environment:
|
environment:
|
||||||
|
@@ -11,8 +11,8 @@ services:
|
|||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.8.0-pg15 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.8.0-pg15 # 阿里云
|
||||||
container_name: pg
|
container_name: pg
|
||||||
restart: always
|
restart: always
|
||||||
ports: # 生产环境建议不要暴露
|
# ports: # 生产环境建议不要暴露
|
||||||
- 5432:5432
|
# - 5432:5432
|
||||||
networks:
|
networks:
|
||||||
- fastgpt
|
- fastgpt
|
||||||
environment:
|
environment:
|
||||||
@@ -99,10 +99,9 @@ services:
|
|||||||
- AIPROXY_API_ENDPOINT=http://aiproxy:3000
|
- AIPROXY_API_ENDPOINT=http://aiproxy:3000
|
||||||
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
|
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
|
||||||
- AIPROXY_API_TOKEN=aiproxy
|
- AIPROXY_API_TOKEN=aiproxy
|
||||||
# AI模型的API地址哦。务必加 /v1。这里默认填写了OneApi的访问地址。
|
# 模型中转地址(如果用了 AI Proxy,下面 2 个就不需要了,旧版 OneAPI 用户,使用下面的变量)
|
||||||
- OPENAI_BASE_URL=http://oneapi:3000/v1
|
# - OPENAI_BASE_URL=http://oneapi:3000/v1
|
||||||
# AI模型的API Key。(这里默认填写了OneAPI的快速默认key,测试通后,务必及时修改)
|
# - CHAT_API_KEY=sk-fastgpt
|
||||||
- CHAT_API_KEY=sk-fastgpt
|
|
||||||
# 数据库最大连接数
|
# 数据库最大连接数
|
||||||
- DB_MAX_LINK=30
|
- DB_MAX_LINK=30
|
||||||
# 登录凭证密钥
|
# 登录凭证密钥
|
||||||
@@ -137,32 +136,37 @@ services:
|
|||||||
container_name: aiproxy
|
container_name: aiproxy
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
pgsql:
|
aiproxy_pg:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
- '3002:3000/tcp'
|
- '3002:3000'
|
||||||
networks:
|
networks:
|
||||||
- fastgpt
|
- fastgpt
|
||||||
environment:
|
environment:
|
||||||
- ADMIN_KEY=aiproxy # 对应 fastgpt 里的AIPROXY_API_TOKEN
|
# 对应 fastgpt 里的AIPROXY_API_TOKEN
|
||||||
- LOG_DETAIL_STORAGE_HOURS=1 # 日志详情保存时间(小时)
|
- ADMIN_KEY=aiproxy
|
||||||
- TZ=Asia/Shanghai
|
# 错误日志详情保存时间(小时)
|
||||||
- SQL_DSN=postgres://postgres:aiproxy@pgsql:5432/aiproxy
|
- LOG_DETAIL_STORAGE_HOURS=1
|
||||||
|
# 数据库连接地址
|
||||||
|
- SQL_DSN=postgres://postgres:aiproxy@aiproxy_pg:5432/aiproxy
|
||||||
|
# 最大重试次数
|
||||||
|
- RetryTimes=3
|
||||||
|
# 不需要计费
|
||||||
|
- BILLING_ENABLED=false
|
||||||
|
# 不需要严格检测模型
|
||||||
- DISABLE_MODEL_CONFIG=true
|
- DISABLE_MODEL_CONFIG=true
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ['CMD', 'curl', '-f', 'http://localhost:3000/api/status']
|
test: ['CMD', 'curl', '-f', 'http://localhost:3000/api/status']
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 10
|
retries: 10
|
||||||
|
aiproxy_pg:
|
||||||
# AI Proxy
|
# image: pgvector/pgvector:0.8.0-pg15 # docker hub
|
||||||
pgsql:
|
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.8.0-pg15 # 阿里云
|
||||||
# image: "postgres:latest"
|
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.7.0 # 阿里云
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
container_name: pgsql
|
container_name: aiproxy_pg
|
||||||
volumes:
|
volumes:
|
||||||
- ./pgsql:/var/lib/postgresql/data
|
- ./aiproxy_pg:/var/lib/postgresql/data
|
||||||
networks:
|
networks:
|
||||||
- fastgpt
|
- fastgpt
|
||||||
environment:
|
environment:
|
||||||
|
@@ -79,10 +79,9 @@ services:
|
|||||||
- AIPROXY_API_ENDPOINT=http://aiproxy:3000
|
- AIPROXY_API_ENDPOINT=http://aiproxy:3000
|
||||||
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
|
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
|
||||||
- AIPROXY_API_TOKEN=aiproxy
|
- AIPROXY_API_TOKEN=aiproxy
|
||||||
# AI模型的API地址哦。务必加 /v1。这里默认填写了OneApi的访问地址。
|
# 模型中转地址(如果用了 AI Proxy,下面 2 个就不需要了,旧版 OneAPI 用户,使用下面的变量)
|
||||||
- OPENAI_BASE_URL=http://oneapi:3000/v1
|
# - OPENAI_BASE_URL=http://oneapi:3000/v1
|
||||||
# AI模型的API Key。(这里默认填写了OneAPI的快速默认key,测试通后,务必及时修改)
|
# - CHAT_API_KEY=sk-fastgpt
|
||||||
- CHAT_API_KEY=sk-fastgpt
|
|
||||||
# 数据库最大连接数
|
# 数据库最大连接数
|
||||||
- DB_MAX_LINK=30
|
- DB_MAX_LINK=30
|
||||||
# 登录凭证密钥
|
# 登录凭证密钥
|
||||||
@@ -118,32 +117,37 @@ services:
|
|||||||
container_name: aiproxy
|
container_name: aiproxy
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
pgsql:
|
aiproxy_pg:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
- '3002:3000/tcp'
|
- '3002:3000'
|
||||||
networks:
|
networks:
|
||||||
- fastgpt
|
- fastgpt
|
||||||
environment:
|
environment:
|
||||||
- ADMIN_KEY=aiproxy # 对应 fastgpt 里的AIPROXY_API_TOKEN
|
# 对应 fastgpt 里的AIPROXY_API_TOKEN
|
||||||
- LOG_DETAIL_STORAGE_HOURS=1 # 日志详情保存时间(小时)
|
- ADMIN_KEY=aiproxy
|
||||||
- TZ=Asia/Shanghai
|
# 错误日志详情保存时间(小时)
|
||||||
- SQL_DSN=postgres://postgres:aiproxy@pgsql:5432/aiproxy
|
- LOG_DETAIL_STORAGE_HOURS=1
|
||||||
|
# 数据库连接地址
|
||||||
|
- SQL_DSN=postgres://postgres:aiproxy@aiproxy_pg:5432/aiproxy
|
||||||
|
# 最大重试次数
|
||||||
|
- RetryTimes=3
|
||||||
|
# 不需要计费
|
||||||
|
- BILLING_ENABLED=false
|
||||||
|
# 不需要严格检测模型
|
||||||
- DISABLE_MODEL_CONFIG=true
|
- DISABLE_MODEL_CONFIG=true
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ['CMD', 'curl', '-f', 'http://localhost:3000/api/status']
|
test: ['CMD', 'curl', '-f', 'http://localhost:3000/api/status']
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 10
|
retries: 10
|
||||||
|
aiproxy_pg:
|
||||||
# AI Proxy
|
# image: pgvector/pgvector:0.8.0-pg15 # docker hub
|
||||||
pgsql:
|
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.8.0-pg15 # 阿里云
|
||||||
# image: "postgres:latest"
|
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.7.0 # 阿里云
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
container_name: pgsql
|
container_name: aiproxy_pg
|
||||||
volumes:
|
volumes:
|
||||||
- ./pgsql:/var/lib/postgresql/data
|
- ./aiproxy_pg:/var/lib/postgresql/data
|
||||||
networks:
|
networks:
|
||||||
- fastgpt
|
- fastgpt
|
||||||
environment:
|
environment:
|
||||||
|
BIN
docSite/assets/imgs/aiproxy1.png
Normal file
BIN
docSite/assets/imgs/aiproxy1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 135 KiB |
@@ -30,7 +30,7 @@ weight: 707
|
|||||||
|
|
||||||
### PgVector版本
|
### PgVector版本
|
||||||
|
|
||||||
非常轻量,适合数据量在 5000 万以下。
|
非常轻量,适合知识库索引量在 5000 万以下。
|
||||||
|
|
||||||
{{< table "table-hover table-striped-columns" >}}
|
{{< table "table-hover table-striped-columns" >}}
|
||||||
| 环境 | 最低配置(单节点) | 推荐配置 |
|
| 环境 | 最低配置(单节点) | 推荐配置 |
|
||||||
@@ -149,18 +149,14 @@ curl -o docker-compose.yml https://raw.githubusercontent.com/labring/FastGPT/mai
|
|||||||
{{< tab tabName="PgVector版本" >}}
|
{{< tab tabName="PgVector版本" >}}
|
||||||
{{< markdownify >}}
|
{{< markdownify >}}
|
||||||
|
|
||||||
```
|
无需操作
|
||||||
FE_DOMAIN=你的前端你访问地址,例如 http://192.168.0.1:3000;https://cloud.fastgpt.cn
|
|
||||||
```
|
|
||||||
|
|
||||||
{{< /markdownify >}}
|
{{< /markdownify >}}
|
||||||
{{< /tab >}}
|
{{< /tab >}}
|
||||||
{{< tab tabName="Milvus版本" >}}
|
{{< tab tabName="Milvus版本" >}}
|
||||||
{{< markdownify >}}
|
{{< markdownify >}}
|
||||||
|
|
||||||
```
|
无需操作
|
||||||
FE_DOMAIN=你的前端你访问地址,例如 http://192.168.0.1:3000;https://cloud.fastgpt.cn
|
|
||||||
```
|
|
||||||
|
|
||||||
{{< /markdownify >}}
|
{{< /markdownify >}}
|
||||||
{{< /tab >}}
|
{{< /tab >}}
|
||||||
@@ -174,7 +170,6 @@ FE_DOMAIN=你的前端你访问地址,例如 http://192.168.0.1:3000;https://clo
|
|||||||
{{% alert icon="🤖" context="success" %}}
|
{{% alert icon="🤖" context="success" %}}
|
||||||
|
|
||||||
1. 修改`MILVUS_ADDRESS`和`MILVUS_TOKEN`链接参数,分别对应 `zilliz` 的 `Public Endpoint` 和 `Api key`,记得把自己ip加入白名单。
|
1. 修改`MILVUS_ADDRESS`和`MILVUS_TOKEN`链接参数,分别对应 `zilliz` 的 `Public Endpoint` 和 `Api key`,记得把自己ip加入白名单。
|
||||||
2. 修改FE_DOMAIN=你的前端你访问地址,例如 http://192.168.0.1:3000;https://cloud.fastgpt.cn
|
|
||||||
|
|
||||||
{{% /alert %}}
|
{{% /alert %}}
|
||||||
|
|
||||||
@@ -189,30 +184,28 @@ FE_DOMAIN=你的前端你访问地址,例如 http://192.168.0.1:3000;https://clo
|
|||||||
```bash
|
```bash
|
||||||
# 启动容器
|
# 启动容器
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
# 等待10s,OneAPI第一次总是要重启几次才能连上Mysql
|
|
||||||
sleep 10
|
|
||||||
# 重启一次oneapi(由于OneAPI的默认Key有点问题,不重启的话会提示找不到渠道,临时手动重启一次解决,等待作者修复)
|
|
||||||
docker restart oneapi
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. 访问 FastGPT
|
### 4. 访问 FastGPT
|
||||||
|
|
||||||
目前可以通过 `ip:3000` 直接访问(注意防火墙)。登录用户名为 `root`,密码为`docker-compose.yml`环境变量里设置的 `DEFAULT_ROOT_PSW`。
|
目前可以通过 `ip:3000` 直接访问(注意开放防火墙)。登录用户名为 `root`,密码为`docker-compose.yml`环境变量里设置的 `DEFAULT_ROOT_PSW`。
|
||||||
|
|
||||||
如果需要域名访问,请自行安装并配置 Nginx。
|
如果需要域名访问,请自行安装并配置 Nginx。
|
||||||
|
|
||||||
首次运行,会自动初始化 root 用户,密码为 `1234`(与环境变量中的`DEFAULT_ROOT_PSW`一致),日志里会提示一次`MongoServerError: Unable to read from a snapshot due to pending collection catalog changes;`可忽略。
|
首次运行,会自动初始化 root 用户,密码为 `1234`(与环境变量中的`DEFAULT_ROOT_PSW`一致),日志可能会提示一次`MongoServerError: Unable to read from a snapshot due to pending collection catalog changes;`可忽略。
|
||||||
|
|
||||||
### 5. 配置模型
|
### 5. 配置模型
|
||||||
|
|
||||||
登录FastGPT后,进入“模型提供商”页面,首先配置模型渠道,[点击查看相关教程](/docs/development/modelconfig/ai-proxy)
|
- 首次登录FastGPT后,系统会提示未配置`语言模型`和`索引模型`,并自动跳转模型配置页面。系统必须至少有这两类模型才能正常使用。
|
||||||
|
- 如果系统未正常跳转,可以在`账号-模型提供商`页面,进行模型配置。[点击查看相关教程](/docs/development/modelconfig/ai-proxy)
|
||||||
然后配置具体模型,务必先配置至少一个语言模型和一个向量模型,否则系统无法正常使用。
|
- 目前已知可能问题:首次进入系统后,整个浏览器 tab 无法响应。此时需要删除该tab,重新打开一次即可。
|
||||||
|
|
||||||
[点击查看模型配置教程](/docs/development/modelConfig/intro/)
|
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
|
### 登录系统后,浏览器无法响应
|
||||||
|
|
||||||
|
无法点击任何内容,刷新也无效。此时需要删除该tab,重新打开一次即可。
|
||||||
|
|
||||||
### Mongo 副本集自动初始化失败
|
### Mongo 副本集自动初始化失败
|
||||||
|
|
||||||
最新的 docker-compose 示例优化 Mongo 副本集初始化,实现了全自动。目前在 unbuntu20,22 centos7, wsl2, mac, window 均通过测试。仍无法正常启动,大部分是因为 cpu 不支持 AVX 指令集,可以切换 Mongo4.x 版本。
|
最新的 docker-compose 示例优化 Mongo 副本集初始化,实现了全自动。目前在 unbuntu20,22 centos7, wsl2, mac, window 均通过测试。仍无法正常启动,大部分是因为 cpu 不支持 AVX 指令集,可以切换 Mongo4.x 版本。
|
||||||
|
@@ -7,7 +7,7 @@ toc: true
|
|||||||
weight: 744
|
weight: 744
|
||||||
---
|
---
|
||||||
|
|
||||||
从 FastGPT 4.8.23 版本开始,引入 AI Proxy 来进一步方便模型的配置。
|
从 `FastGPT 4.8.23` 版本开始,引入 AI Proxy 来进一步方便模型的配置。
|
||||||
|
|
||||||
AI Proxy 与 One API 类似,也是作为一个 OpenAI 接口管理 & 分发系统,可以通过标准的 OpenAI API 格式访问所有的大模型,开箱即用。
|
AI Proxy 与 One API 类似,也是作为一个 OpenAI 接口管理 & 分发系统,可以通过标准的 OpenAI API 格式访问所有的大模型,开箱即用。
|
||||||
|
|
||||||
@@ -15,13 +15,29 @@ AI Proxy 与 One API 类似,也是作为一个 OpenAI 接口管理 & 分发系
|
|||||||
|
|
||||||
### Docker 版本
|
### Docker 版本
|
||||||
|
|
||||||
`docker-compose.yml` 文件已加入了 AI Proxy 配置,可直接使用。
|
`docker-compose.yml` 文件已加入了 AI Proxy 配置,可直接使用。[点击查看最新的 yml 配置](https://raw.githubusercontent.com/labring/FastGPT/main/deploy/docker/docker-compose-pgvector.yml)
|
||||||
|
|
||||||
## 基础使用
|
从旧版升级的用户,可以复制 yml 里,ai proxy 的配置,加入到旧的 yml 文件中。
|
||||||
|
|
||||||
|
## 运行原理
|
||||||
|
|
||||||
|
AI proxy 核心模块:
|
||||||
|
|
||||||
|
1. 渠道管理:管理各家模型提供商的 API Key 和可用模型列表。
|
||||||
|
2. 模型调用:根据请求的模型,选中对应的渠道;根据渠道的 API 格式,构造请求体,发送请求;格式化响应体成标准格式返回。
|
||||||
|
3. 调用日志:详细记录模型调用的日志,并在错误时候可以记录其入参和报错信息,方便排查。
|
||||||
|
|
||||||
|
运行流程:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 在 FastGPT 中使用
|
||||||
|
|
||||||
|
AI proxy 相关功能,可以在`账号-模型提供商`页面找到。
|
||||||
|
|
||||||
### 1. 创建渠道
|
### 1. 创建渠道
|
||||||
|
|
||||||
如果 FastGPT 的环境变量中,设置了 AIPROXY_API_ENDPOINT 的值,那么在“模型提供商”的配置页面,会多出两个 tab,可以直接在 FastGPT 平台上配置模型渠道,以及查看模型实际调用日志。
|
在`模型提供商`的配置页面,点击`模型渠道`,进入渠道配置页面
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -36,9 +52,18 @@ AI Proxy 与 One API 类似,也是作为一个 OpenAI 接口管理 & 分发系
|
|||||||
1. 渠道名:展示在外部的渠道名称,仅作标识;
|
1. 渠道名:展示在外部的渠道名称,仅作标识;
|
||||||
2. 厂商:模型对应的厂商,不同厂商对应不同的默认地址和 API 密钥格式;
|
2. 厂商:模型对应的厂商,不同厂商对应不同的默认地址和 API 密钥格式;
|
||||||
3. 模型:当前渠道具体可以使用的模型,系统内置了主流的一些模型,如果下拉框中没有想要的选项,可以点击“新增模型”,[增加自定义模型](/docs/development/modelconfig/intro/#新增自定义模型);
|
3. 模型:当前渠道具体可以使用的模型,系统内置了主流的一些模型,如果下拉框中没有想要的选项,可以点击“新增模型”,[增加自定义模型](/docs/development/modelconfig/intro/#新增自定义模型);
|
||||||
4. 模型映射:将 FastGPT 请求的模型,映射到具体提供的模型上;
|
4. 模型映射:将 FastGPT 请求的模型,映射到具体提供的模型上。例如:
|
||||||
5. 代理地址:具体请求的地址,系统给每个主流渠道配置了默认的地址,如果无需改动则不用填
|
|
||||||
6. API 密钥:从模型厂商处获取的 API 凭证
|
```json
|
||||||
|
{
|
||||||
|
"gpt-4o-test": "gpt-4o",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
FatGPT 中的模型为 `gpt-4o-test`,向 AI Proxy 发起请求时也是 `gpt-4o-test`。AI proxy 在向上游发送请求时,实际的`model`为 `gpt-4o`。
|
||||||
|
|
||||||
|
5. 代理地址:具体请求的地址,系统给每个主流渠道配置了默认的地址,如果无需改动则不用填。
|
||||||
|
6. API 密钥:从模型厂商处获取的 API 凭证。注意部分厂商需要提供多个密钥组合,可以根据提示进行输入。
|
||||||
|
|
||||||
最后点击“新增”,就能在“模型渠道”下看到刚刚配置的渠道
|
最后点击“新增”,就能在“模型渠道”下看到刚刚配置的渠道
|
||||||
|
|
||||||
@@ -60,16 +85,15 @@ AI Proxy 与 One API 类似,也是作为一个 OpenAI 接口管理 & 分发系
|
|||||||
|
|
||||||
### 3. 启用模型
|
### 3. 启用模型
|
||||||
|
|
||||||
最后在“模型配置”中,可以选择启用对应的模型,这样就能在平台中使用了
|
最后在`模型配置`中,可以选择启用对应的模型,这样就能在平台中使用了,更多模型配置可以参考[模型配置](/docs/development/modelconfig/intro)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## 其他功能介绍
|
||||||
## 渠道设置
|
|
||||||
|
|
||||||
### 优先级
|
### 优先级
|
||||||
|
|
||||||
在 FastGPT 中,可以给渠道设置优先级,对于同样的模型,优先级越高的渠道会越优先请求
|
范围1~100。数值越大,越容易被优先选中。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -81,13 +105,15 @@ AI Proxy 与 One API 类似,也是作为一个 OpenAI 接口管理 & 分发系
|
|||||||
|
|
||||||
### 调用日志
|
### 调用日志
|
||||||
|
|
||||||
在 “调用日志” 页面,会展示发送到模型处的请求记录,包括具体的输入输出 tokens、请求时间、请求耗时、请求地址等等
|
在 `调用日志` 页面,会展示发送到模型处的请求记录,包括具体的输入输出 tokens、请求时间、请求耗时、请求地址等等。错误的请求,则会详细的入参和错误信息,方便排查,但仅会保留 1 小时(环境变量里可配置)。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 如何从 OneAPI 迁移到 AI Proxy
|
## 从 OneAPI 迁移到 AI Proxy
|
||||||
|
|
||||||
可以从任意终端,发起 1 个 HTTP 请求。其中 {{host}} 替换成 AI Proxy 地址,{{admin_key}} 替换成 AI Proxy 中 ADMIN_KEY 的值,参数 dsn 为 OneAPI 的 mysql 连接串
|
可以从任意终端,发起 1 个 HTTP 请求。其中 `{{host}}` 替换成 AI Proxy 地址,`{{admin_key}}` 替换成 AI Proxy 中 `ADMIN_KEY` 的值。
|
||||||
|
|
||||||
|
Body 参数 `dsn` 为 OneAPI 的 mysql 连接串。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --location --request POST '{{host}}/api/channels/import/oneapi' \
|
curl --location --request POST '{{host}}/api/channels/import/oneapi' \
|
||||||
@@ -100,4 +126,4 @@ curl --location --request POST '{{host}}/api/channels/import/oneapi' \
|
|||||||
|
|
||||||
执行成功的情况下会返回 "success": true
|
执行成功的情况下会返回 "success": true
|
||||||
|
|
||||||
脚本目前不是完全准,可能会有部分渠道遗漏,还需要手动再检查下
|
脚本目前不是完全准,仅是简单的做数据映射,主要是迁移`代理地址`、`模型`和`API 密钥`,建议迁移后再进行手动检查。
|
@@ -46,6 +46,7 @@ curl --location --request POST 'https://{{host}}/api/admin/initv490' \
|
|||||||
|
|
||||||
1. 知识库数据不再限制索引数量,可无限自定义。同时可自动更新输入文本的索引,不影响自定义索引。
|
1. 知识库数据不再限制索引数量,可无限自定义。同时可自动更新输入文本的索引,不影响自定义索引。
|
||||||
2. Markdown 解析,增加链接后中文标点符号检测,增加空格。
|
2. Markdown 解析,增加链接后中文标点符号检测,增加空格。
|
||||||
|
3. Prompt 模式工具调用,支持思考模型。同时优化其格式检测,减少空输出的概率。
|
||||||
|
|
||||||
## 🐛 修复
|
## 🐛 修复
|
||||||
|
|
||||||
|
@@ -1,8 +1,11 @@
|
|||||||
import type {
|
import type {
|
||||||
|
AIChatItemValueItemType,
|
||||||
ChatItemType,
|
ChatItemType,
|
||||||
ChatItemValueItemType,
|
ChatItemValueItemType,
|
||||||
RuntimeUserPromptType,
|
RuntimeUserPromptType,
|
||||||
UserChatItemType
|
SystemChatItemValueItemType,
|
||||||
|
UserChatItemType,
|
||||||
|
UserChatItemValueItemType
|
||||||
} from '../../core/chat/type.d';
|
} from '../../core/chat/type.d';
|
||||||
import { ChatFileTypeEnum, ChatItemValueTypeEnum, ChatRoleEnum } from '../../core/chat/constants';
|
import { ChatFileTypeEnum, ChatItemValueTypeEnum, ChatRoleEnum } from '../../core/chat/constants';
|
||||||
import type {
|
import type {
|
||||||
@@ -174,137 +177,24 @@ export const GPTMessages2Chats = (
|
|||||||
): ChatItemType[] => {
|
): ChatItemType[] => {
|
||||||
const chatMessages = messages
|
const chatMessages = messages
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
const value: ChatItemType['value'] = [];
|
|
||||||
const obj = GPT2Chat[item.role];
|
const obj = GPT2Chat[item.role];
|
||||||
|
|
||||||
if (
|
const value = (() => {
|
||||||
obj === ChatRoleEnum.System &&
|
if (
|
||||||
item.role === ChatCompletionRequestMessageRoleEnum.System
|
obj === ChatRoleEnum.System &&
|
||||||
) {
|
item.role === ChatCompletionRequestMessageRoleEnum.System
|
||||||
if (Array.isArray(item.content)) {
|
) {
|
||||||
item.content.forEach((item) => [
|
const value: SystemChatItemValueItemType[] = [];
|
||||||
value.push({
|
|
||||||
type: ChatItemValueTypeEnum.text,
|
if (Array.isArray(item.content)) {
|
||||||
text: {
|
item.content.forEach((item) => [
|
||||||
content: item.text
|
|
||||||
}
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
value.push({
|
|
||||||
type: ChatItemValueTypeEnum.text,
|
|
||||||
text: {
|
|
||||||
content: item.content
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
obj === ChatRoleEnum.Human &&
|
|
||||||
item.role === ChatCompletionRequestMessageRoleEnum.User
|
|
||||||
) {
|
|
||||||
if (typeof item.content === 'string') {
|
|
||||||
value.push({
|
|
||||||
type: ChatItemValueTypeEnum.text,
|
|
||||||
text: {
|
|
||||||
content: item.content
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (Array.isArray(item.content)) {
|
|
||||||
item.content.forEach((item) => {
|
|
||||||
if (item.type === 'text') {
|
|
||||||
value.push({
|
value.push({
|
||||||
type: ChatItemValueTypeEnum.text,
|
type: ChatItemValueTypeEnum.text,
|
||||||
text: {
|
text: {
|
||||||
content: item.text
|
content: item.text
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
} else if (item.type === 'image_url') {
|
]);
|
||||||
value.push({
|
|
||||||
//@ts-ignore
|
|
||||||
type: ChatItemValueTypeEnum.file,
|
|
||||||
file: {
|
|
||||||
type: ChatFileTypeEnum.image,
|
|
||||||
name: '',
|
|
||||||
url: item.image_url.url
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (item.type === 'file_url') {
|
|
||||||
value.push({
|
|
||||||
// @ts-ignore
|
|
||||||
type: ChatItemValueTypeEnum.file,
|
|
||||||
file: {
|
|
||||||
type: ChatFileTypeEnum.file,
|
|
||||||
name: item.name,
|
|
||||||
url: item.url
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
obj === ChatRoleEnum.AI &&
|
|
||||||
item.role === ChatCompletionRequestMessageRoleEnum.Assistant
|
|
||||||
) {
|
|
||||||
if (item.tool_calls && reserveTool) {
|
|
||||||
// save tool calls
|
|
||||||
const toolCalls = item.tool_calls as ChatCompletionMessageToolCall[];
|
|
||||||
value.push({
|
|
||||||
//@ts-ignore
|
|
||||||
type: ChatItemValueTypeEnum.tool,
|
|
||||||
tools: toolCalls.map((tool) => {
|
|
||||||
let toolResponse =
|
|
||||||
messages.find(
|
|
||||||
(msg) =>
|
|
||||||
msg.role === ChatCompletionRequestMessageRoleEnum.Tool &&
|
|
||||||
msg.tool_call_id === tool.id
|
|
||||||
)?.content || '';
|
|
||||||
toolResponse =
|
|
||||||
typeof toolResponse === 'string' ? toolResponse : JSON.stringify(toolResponse);
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: tool.id,
|
|
||||||
toolName: tool.toolName || '',
|
|
||||||
toolAvatar: tool.toolAvatar || '',
|
|
||||||
functionName: tool.function.name,
|
|
||||||
params: tool.function.arguments,
|
|
||||||
response: toolResponse as string
|
|
||||||
};
|
|
||||||
})
|
|
||||||
});
|
|
||||||
} else if (item.function_call && reserveTool) {
|
|
||||||
const functionCall = item.function_call as ChatCompletionMessageFunctionCall;
|
|
||||||
const functionResponse = messages.find(
|
|
||||||
(msg) =>
|
|
||||||
msg.role === ChatCompletionRequestMessageRoleEnum.Function &&
|
|
||||||
msg.name === item.function_call?.name
|
|
||||||
) as ChatCompletionFunctionMessageParam;
|
|
||||||
|
|
||||||
if (functionResponse) {
|
|
||||||
value.push({
|
|
||||||
//@ts-ignore
|
|
||||||
type: ChatItemValueTypeEnum.tool,
|
|
||||||
tools: [
|
|
||||||
{
|
|
||||||
id: functionCall.id || '',
|
|
||||||
toolName: functionCall.toolName || '',
|
|
||||||
toolAvatar: functionCall.toolAvatar || '',
|
|
||||||
functionName: functionCall.name,
|
|
||||||
params: functionCall.arguments,
|
|
||||||
response: functionResponse.content || ''
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (item.interactive) {
|
|
||||||
value.push({
|
|
||||||
//@ts-ignore
|
|
||||||
type: ChatItemValueTypeEnum.interactive,
|
|
||||||
interactive: item.interactive
|
|
||||||
});
|
|
||||||
} else if (typeof item.content === 'string') {
|
|
||||||
const lastValue = value[value.length - 1];
|
|
||||||
if (lastValue && lastValue.type === ChatItemValueTypeEnum.text && lastValue.text) {
|
|
||||||
lastValue.text.content += item.content;
|
|
||||||
} else {
|
} else {
|
||||||
value.push({
|
value.push({
|
||||||
type: ChatItemValueTypeEnum.text,
|
type: ChatItemValueTypeEnum.text,
|
||||||
@@ -313,8 +203,145 @@ export const GPTMessages2Chats = (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
|
} else if (
|
||||||
|
obj === ChatRoleEnum.Human &&
|
||||||
|
item.role === ChatCompletionRequestMessageRoleEnum.User
|
||||||
|
) {
|
||||||
|
const value: UserChatItemValueItemType[] = [];
|
||||||
|
|
||||||
|
if (typeof item.content === 'string') {
|
||||||
|
value.push({
|
||||||
|
type: ChatItemValueTypeEnum.text,
|
||||||
|
text: {
|
||||||
|
content: item.content
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (Array.isArray(item.content)) {
|
||||||
|
item.content.forEach((item) => {
|
||||||
|
if (item.type === 'text') {
|
||||||
|
value.push({
|
||||||
|
type: ChatItemValueTypeEnum.text,
|
||||||
|
text: {
|
||||||
|
content: item.text
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (item.type === 'image_url') {
|
||||||
|
value.push({
|
||||||
|
//@ts-ignore
|
||||||
|
type: ChatItemValueTypeEnum.file,
|
||||||
|
file: {
|
||||||
|
type: ChatFileTypeEnum.image,
|
||||||
|
name: '',
|
||||||
|
url: item.image_url.url
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (item.type === 'file_url') {
|
||||||
|
value.push({
|
||||||
|
// @ts-ignore
|
||||||
|
type: ChatItemValueTypeEnum.file,
|
||||||
|
file: {
|
||||||
|
type: ChatFileTypeEnum.file,
|
||||||
|
name: item.name,
|
||||||
|
url: item.url
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
} else if (
|
||||||
|
obj === ChatRoleEnum.AI &&
|
||||||
|
item.role === ChatCompletionRequestMessageRoleEnum.Assistant
|
||||||
|
) {
|
||||||
|
const value: AIChatItemValueItemType[] = [];
|
||||||
|
|
||||||
|
if (typeof item.reasoning_text === 'string') {
|
||||||
|
value.push({
|
||||||
|
type: ChatItemValueTypeEnum.reasoning,
|
||||||
|
reasoning: {
|
||||||
|
content: item.reasoning_text
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (item.tool_calls && reserveTool) {
|
||||||
|
// save tool calls
|
||||||
|
const toolCalls = item.tool_calls as ChatCompletionMessageToolCall[];
|
||||||
|
value.push({
|
||||||
|
//@ts-ignore
|
||||||
|
type: ChatItemValueTypeEnum.tool,
|
||||||
|
tools: toolCalls.map((tool) => {
|
||||||
|
let toolResponse =
|
||||||
|
messages.find(
|
||||||
|
(msg) =>
|
||||||
|
msg.role === ChatCompletionRequestMessageRoleEnum.Tool &&
|
||||||
|
msg.tool_call_id === tool.id
|
||||||
|
)?.content || '';
|
||||||
|
toolResponse =
|
||||||
|
typeof toolResponse === 'string' ? toolResponse : JSON.stringify(toolResponse);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: tool.id,
|
||||||
|
toolName: tool.toolName || '',
|
||||||
|
toolAvatar: tool.toolAvatar || '',
|
||||||
|
functionName: tool.function.name,
|
||||||
|
params: tool.function.arguments,
|
||||||
|
response: toolResponse as string
|
||||||
|
};
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (item.function_call && reserveTool) {
|
||||||
|
const functionCall = item.function_call as ChatCompletionMessageFunctionCall;
|
||||||
|
const functionResponse = messages.find(
|
||||||
|
(msg) =>
|
||||||
|
msg.role === ChatCompletionRequestMessageRoleEnum.Function &&
|
||||||
|
msg.name === item.function_call?.name
|
||||||
|
) as ChatCompletionFunctionMessageParam;
|
||||||
|
|
||||||
|
if (functionResponse) {
|
||||||
|
value.push({
|
||||||
|
//@ts-ignore
|
||||||
|
type: ChatItemValueTypeEnum.tool,
|
||||||
|
tools: [
|
||||||
|
{
|
||||||
|
id: functionCall.id || '',
|
||||||
|
toolName: functionCall.toolName || '',
|
||||||
|
toolAvatar: functionCall.toolAvatar || '',
|
||||||
|
functionName: functionCall.name,
|
||||||
|
params: functionCall.arguments,
|
||||||
|
response: functionResponse.content || ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.interactive) {
|
||||||
|
value.push({
|
||||||
|
//@ts-ignore
|
||||||
|
type: ChatItemValueTypeEnum.interactive,
|
||||||
|
interactive: item.interactive
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (typeof item.content === 'string') {
|
||||||
|
const lastValue = value[value.length - 1];
|
||||||
|
if (lastValue && lastValue.type === ChatItemValueTypeEnum.text && lastValue.text) {
|
||||||
|
lastValue.text.content += item.content;
|
||||||
|
} else {
|
||||||
|
value.push({
|
||||||
|
type: ChatItemValueTypeEnum.text,
|
||||||
|
text: {
|
||||||
|
content: item.content
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return [];
|
||||||
|
})();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dataId: item.dataId,
|
dataId: item.dataId,
|
||||||
|
1
packages/global/core/chat/type.d.ts
vendored
1
packages/global/core/chat/type.d.ts
vendored
@@ -77,6 +77,7 @@ export type AIChatItemValueItemType = {
|
|||||||
| ChatItemValueTypeEnum.reasoning
|
| ChatItemValueTypeEnum.reasoning
|
||||||
| ChatItemValueTypeEnum.tool
|
| ChatItemValueTypeEnum.tool
|
||||||
| ChatItemValueTypeEnum.interactive;
|
| ChatItemValueTypeEnum.interactive;
|
||||||
|
|
||||||
text?: {
|
text?: {
|
||||||
content: string;
|
content: string;
|
||||||
};
|
};
|
||||||
|
@@ -55,7 +55,7 @@ export const AiChatModule: FlowNodeTemplateType = {
|
|||||||
showStatus: true,
|
showStatus: true,
|
||||||
isTool: true,
|
isTool: true,
|
||||||
courseUrl: '/docs/guide/workbench/workflow/ai_chat/',
|
courseUrl: '/docs/guide/workbench/workflow/ai_chat/',
|
||||||
version: '4813',
|
version: '490',
|
||||||
inputs: [
|
inputs: [
|
||||||
Input_Template_SettingAiModel,
|
Input_Template_SettingAiModel,
|
||||||
// --- settings modal
|
// --- settings modal
|
||||||
|
@@ -58,6 +58,13 @@ export const ToolModule: FlowNodeTemplateType = {
|
|||||||
valueType: WorkflowIOValueTypeEnum.boolean,
|
valueType: WorkflowIOValueTypeEnum.boolean,
|
||||||
value: true
|
value: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: NodeInputKeyEnum.aiChatReasoning,
|
||||||
|
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||||
|
label: '',
|
||||||
|
valueType: WorkflowIOValueTypeEnum.boolean,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.aiChatTopP,
|
key: NodeInputKeyEnum.aiChatTopP,
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||||
|
@@ -245,7 +245,7 @@ export const readRawContentByFileBuffer = async ({
|
|||||||
if (result_data.data.status === 'success') {
|
if (result_data.data.status === 'success') {
|
||||||
const result = result_data.data.result.pages
|
const result = result_data.data.result.pages
|
||||||
.map((page) => page.md)
|
.map((page) => page.md)
|
||||||
.join('\n')
|
.join('')
|
||||||
// Do some post-processing
|
// Do some post-processing
|
||||||
.replace(/\\[\(\)]/g, '$')
|
.replace(/\\[\(\)]/g, '$')
|
||||||
.replace(/\\[\[\]]/g, '$$')
|
.replace(/\\[\[\]]/g, '$$')
|
||||||
|
@@ -75,6 +75,81 @@
|
|||||||
"showTopP": true,
|
"showTopP": true,
|
||||||
"showStopSign": true,
|
"showStopSign": true,
|
||||||
"responseFormatList": ["text", "json_object"]
|
"responseFormatList": ["text", "json_object"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "moonshot-v1-8k-vision-preview",
|
||||||
|
"name": "moonshot-v1-8k-vision-preview",
|
||||||
|
"maxContext": 8000,
|
||||||
|
"maxResponse": 4000,
|
||||||
|
"quoteMaxToken": 6000,
|
||||||
|
"maxTemperature": 1,
|
||||||
|
"vision": true,
|
||||||
|
"toolChoice": true,
|
||||||
|
"functionCall": false,
|
||||||
|
"defaultSystemChatPrompt": "",
|
||||||
|
"datasetProcess": true,
|
||||||
|
"usedInClassify": true,
|
||||||
|
"customCQPrompt": "",
|
||||||
|
"usedInExtractFields": true,
|
||||||
|
"usedInQueryExtension": true,
|
||||||
|
"customExtractPrompt": "",
|
||||||
|
"usedInToolCall": true,
|
||||||
|
"defaultConfig": {},
|
||||||
|
"fieldMap": {},
|
||||||
|
"type": "llm",
|
||||||
|
"showTopP": true,
|
||||||
|
"showStopSign": true,
|
||||||
|
"responseFormatList": ["text", "json_object"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "moonshot-v1-32k-vision-preview",
|
||||||
|
"name": "moonshot-v1-32k-vision-preview",
|
||||||
|
"maxContext": 32000,
|
||||||
|
"maxResponse": 4000,
|
||||||
|
"quoteMaxToken": 32000,
|
||||||
|
"maxTemperature": 1,
|
||||||
|
"vision": true,
|
||||||
|
"toolChoice": true,
|
||||||
|
"functionCall": false,
|
||||||
|
"defaultSystemChatPrompt": "",
|
||||||
|
"datasetProcess": true,
|
||||||
|
"usedInClassify": true,
|
||||||
|
"customCQPrompt": "",
|
||||||
|
"usedInExtractFields": true,
|
||||||
|
"usedInQueryExtension": true,
|
||||||
|
"customExtractPrompt": "",
|
||||||
|
"usedInToolCall": true,
|
||||||
|
"defaultConfig": {},
|
||||||
|
"fieldMap": {},
|
||||||
|
"type": "llm",
|
||||||
|
"showTopP": true,
|
||||||
|
"showStopSign": true,
|
||||||
|
"responseFormatList": ["text", "json_object"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "moonshot-v1-128k-vision-preview",
|
||||||
|
"name": "moonshot-v1-128k-vision-preview",
|
||||||
|
"maxContext": 128000,
|
||||||
|
"maxResponse": 4000,
|
||||||
|
"quoteMaxToken": 60000,
|
||||||
|
"maxTemperature": 1,
|
||||||
|
"vision": true,
|
||||||
|
"toolChoice": true,
|
||||||
|
"functionCall": false,
|
||||||
|
"defaultSystemChatPrompt": "",
|
||||||
|
"datasetProcess": true,
|
||||||
|
"usedInClassify": true,
|
||||||
|
"customCQPrompt": "",
|
||||||
|
"usedInExtractFields": true,
|
||||||
|
"usedInQueryExtension": true,
|
||||||
|
"customExtractPrompt": "",
|
||||||
|
"usedInToolCall": true,
|
||||||
|
"defaultConfig": {},
|
||||||
|
"fieldMap": {},
|
||||||
|
"type": "llm",
|
||||||
|
"showTopP": true,
|
||||||
|
"showStopSign": true,
|
||||||
|
"responseFormatList": ["text", "json_object"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -9,41 +9,23 @@ const AppTemplateSchema = new Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
name: {
|
name: String,
|
||||||
type: String
|
intro: String,
|
||||||
},
|
avatar: String,
|
||||||
intro: {
|
author: String,
|
||||||
type: String
|
|
||||||
},
|
|
||||||
avatar: {
|
|
||||||
type: String
|
|
||||||
},
|
|
||||||
author: {
|
|
||||||
type: String
|
|
||||||
},
|
|
||||||
tags: {
|
tags: {
|
||||||
type: [String],
|
type: [String],
|
||||||
default: undefined
|
default: undefined
|
||||||
},
|
},
|
||||||
type: {
|
type: String,
|
||||||
type: String
|
isActive: Boolean,
|
||||||
},
|
userGuide: Object,
|
||||||
isActive: {
|
isQuickTemplate: Boolean,
|
||||||
type: Boolean
|
|
||||||
},
|
|
||||||
userGuide: {
|
|
||||||
type: Object
|
|
||||||
},
|
|
||||||
isQuickTemplate: {
|
|
||||||
type: Boolean
|
|
||||||
},
|
|
||||||
order: {
|
order: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: -1
|
default: -1
|
||||||
},
|
},
|
||||||
workflow: {
|
workflow: Object
|
||||||
type: Object
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AppTemplateSchema.index({ templateId: 1 });
|
AppTemplateSchema.index({ templateId: 1 });
|
||||||
|
@@ -55,7 +55,8 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
userChatInput,
|
userChatInput,
|
||||||
history = 6,
|
history = 6,
|
||||||
fileUrlList: fileLinks,
|
fileUrlList: fileLinks,
|
||||||
aiChatVision
|
aiChatVision,
|
||||||
|
aiChatReasoning
|
||||||
}
|
}
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
@@ -63,6 +64,9 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
const useVision = aiChatVision && toolModel.vision;
|
const useVision = aiChatVision && toolModel.vision;
|
||||||
const chatHistories = getHistories(history, histories);
|
const chatHistories = getHistories(history, histories);
|
||||||
|
|
||||||
|
props.params.aiChatVision = aiChatVision && toolModel.vision;
|
||||||
|
props.params.aiChatReasoning = aiChatReasoning && toolModel.reasoning;
|
||||||
|
|
||||||
const toolNodeIds = filterToolNodeIdByEdges({ nodeId, edges: runtimeEdges });
|
const toolNodeIds = filterToolNodeIdByEdges({ nodeId, edges: runtimeEdges });
|
||||||
|
|
||||||
// Gets the module to which the tool is connected
|
// Gets the module to which the tool is connected
|
||||||
|
@@ -24,7 +24,12 @@ import {
|
|||||||
import { AIChatItemType } from '@fastgpt/global/core/chat/type';
|
import { AIChatItemType } from '@fastgpt/global/core/chat/type';
|
||||||
import { GPTMessages2Chats } from '@fastgpt/global/core/chat/adapt';
|
import { GPTMessages2Chats } from '@fastgpt/global/core/chat/adapt';
|
||||||
import { formatToolResponse, initToolCallEdges, initToolNodes } from './utils';
|
import { formatToolResponse, initToolCallEdges, initToolNodes } from './utils';
|
||||||
import { computedMaxToken, llmCompletionsBodyFormat } from '../../../../ai/utils';
|
import {
|
||||||
|
computedMaxToken,
|
||||||
|
llmCompletionsBodyFormat,
|
||||||
|
parseReasoningContent,
|
||||||
|
parseReasoningStreamContent
|
||||||
|
} from '../../../../ai/utils';
|
||||||
import { WorkflowResponseType } from '../../type';
|
import { WorkflowResponseType } from '../../type';
|
||||||
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
|
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
import { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||||
@@ -58,6 +63,7 @@ export const runToolWithPromptCall = async (
|
|||||||
temperature,
|
temperature,
|
||||||
maxToken,
|
maxToken,
|
||||||
aiChatVision,
|
aiChatVision,
|
||||||
|
aiChatReasoning,
|
||||||
aiChatTopP,
|
aiChatTopP,
|
||||||
aiChatStopSign,
|
aiChatStopSign,
|
||||||
aiChatResponseFormat,
|
aiChatResponseFormat,
|
||||||
@@ -216,7 +222,7 @@ export const runToolWithPromptCall = async (
|
|||||||
const [requestMessages] = await Promise.all([
|
const [requestMessages] = await Promise.all([
|
||||||
loadRequestMessages({
|
loadRequestMessages({
|
||||||
messages: filterMessages,
|
messages: filterMessages,
|
||||||
useVision: toolModel.vision && aiChatVision,
|
useVision: aiChatVision,
|
||||||
origin: requestOrigin
|
origin: requestOrigin
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
@@ -251,22 +257,46 @@ export const runToolWithPromptCall = async (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const answer = await (async () => {
|
const { answer, reasoning } = await (async () => {
|
||||||
if (res && isStreamResponse) {
|
if (res && isStreamResponse) {
|
||||||
const { answer } = await streamResponse({
|
const { answer, reasoning } = await streamResponse({
|
||||||
res,
|
res,
|
||||||
toolNodes,
|
toolNodes,
|
||||||
stream: aiResponse,
|
stream: aiResponse,
|
||||||
workflowStreamResponse
|
workflowStreamResponse,
|
||||||
|
aiChatReasoning
|
||||||
});
|
});
|
||||||
|
|
||||||
return answer;
|
return { answer, reasoning };
|
||||||
} else {
|
} else {
|
||||||
const result = aiResponse as ChatCompletion;
|
const content = aiResponse.choices?.[0]?.message?.content || '';
|
||||||
|
const reasoningContent: string = aiResponse.choices?.[0]?.message?.reasoning_content || '';
|
||||||
|
|
||||||
return result.choices?.[0]?.message?.content || '';
|
// API already parse reasoning content
|
||||||
|
if (reasoningContent || !aiChatReasoning) {
|
||||||
|
return {
|
||||||
|
answer: content,
|
||||||
|
reasoning: reasoningContent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const [think, answer] = parseReasoningContent(content);
|
||||||
|
return {
|
||||||
|
answer,
|
||||||
|
reasoning: think
|
||||||
|
};
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
if (stream && !isStreamResponse && aiChatReasoning && reasoning) {
|
||||||
|
workflowStreamResponse?.({
|
||||||
|
event: SseResponseEventEnum.fastAnswer,
|
||||||
|
data: textAdaptGptResponse({
|
||||||
|
reasoning_content: reasoning
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const { answer: replaceAnswer, toolJson } = parseAnswer(answer);
|
const { answer: replaceAnswer, toolJson } = parseAnswer(answer);
|
||||||
if (!answer && !toolJson) {
|
if (!answer && !toolJson) {
|
||||||
return Promise.reject(getEmptyResponseTip());
|
return Promise.reject(getEmptyResponseTip());
|
||||||
@@ -294,11 +324,16 @@ export const runToolWithPromptCall = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No tool is invoked, indicating that the process is over
|
// No tool is invoked, indicating that the process is over
|
||||||
const gptAssistantResponse: ChatCompletionAssistantMessageParam = {
|
const gptAssistantResponse: ChatCompletionMessageParam = {
|
||||||
role: ChatCompletionRequestMessageRoleEnum.Assistant,
|
role: ChatCompletionRequestMessageRoleEnum.Assistant,
|
||||||
content: replaceAnswer
|
content: replaceAnswer,
|
||||||
|
reasoning_text: reasoning
|
||||||
};
|
};
|
||||||
const completeMessages = filterMessages.concat(gptAssistantResponse);
|
const completeMessages = filterMessages.concat({
|
||||||
|
...gptAssistantResponse,
|
||||||
|
reasoning_text: undefined
|
||||||
|
});
|
||||||
|
|
||||||
const inputTokens = await countGptMessagesTokens(requestMessages);
|
const inputTokens = await countGptMessagesTokens(requestMessages);
|
||||||
const outputTokens = await countGptMessagesTokens([gptAssistantResponse]);
|
const outputTokens = await countGptMessagesTokens([gptAssistantResponse]);
|
||||||
|
|
||||||
@@ -379,9 +414,10 @@ export const runToolWithPromptCall = async (
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
// 合并工具调用的结果,使用 functionCall 格式存储。
|
// 合并工具调用的结果,使用 functionCall 格式存储。
|
||||||
const assistantToolMsgParams: ChatCompletionAssistantMessageParam = {
|
const assistantToolMsgParams: ChatCompletionMessageParam = {
|
||||||
role: ChatCompletionRequestMessageRoleEnum.Assistant,
|
role: ChatCompletionRequestMessageRoleEnum.Assistant,
|
||||||
function_call: toolJson
|
function_call: toolJson,
|
||||||
|
reasoning_text: reasoning
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only toolCall tokens are counted here, Tool response tokens count towards the next reply
|
// Only toolCall tokens are counted here, Tool response tokens count towards the next reply
|
||||||
@@ -502,12 +538,14 @@ ANSWER: `;
|
|||||||
async function streamResponse({
|
async function streamResponse({
|
||||||
res,
|
res,
|
||||||
stream,
|
stream,
|
||||||
workflowStreamResponse
|
workflowStreamResponse,
|
||||||
|
aiChatReasoning
|
||||||
}: {
|
}: {
|
||||||
res: NextApiResponse;
|
res: NextApiResponse;
|
||||||
toolNodes: ToolNodeItemType[];
|
toolNodes: ToolNodeItemType[];
|
||||||
stream: StreamChatType;
|
stream: StreamChatType;
|
||||||
workflowStreamResponse?: WorkflowResponseType;
|
workflowStreamResponse?: WorkflowResponseType;
|
||||||
|
aiChatReasoning?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const write = responseWriteController({
|
const write = responseWriteController({
|
||||||
res,
|
res,
|
||||||
@@ -515,7 +553,9 @@ async function streamResponse({
|
|||||||
});
|
});
|
||||||
|
|
||||||
let startResponseWrite = false;
|
let startResponseWrite = false;
|
||||||
let textAnswer = '';
|
let answer = '';
|
||||||
|
let reasoning = '';
|
||||||
|
const { parsePart, getStartTagBuffer } = parseReasoningStreamContent();
|
||||||
|
|
||||||
for await (const part of stream) {
|
for await (const part of stream) {
|
||||||
if (res.closed) {
|
if (res.closed) {
|
||||||
@@ -523,13 +563,21 @@ async function streamResponse({
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const responseChoice = part.choices?.[0]?.delta;
|
const [reasoningContent, content] = parsePart(part, aiChatReasoning);
|
||||||
// console.log(responseChoice, '---===');
|
answer += content;
|
||||||
|
reasoning += reasoningContent;
|
||||||
|
|
||||||
if (responseChoice?.content) {
|
if (aiChatReasoning && reasoningContent) {
|
||||||
const content = responseChoice?.content || '';
|
workflowStreamResponse?.({
|
||||||
textAnswer += content;
|
write,
|
||||||
|
event: SseResponseEventEnum.answer,
|
||||||
|
data: textAdaptGptResponse({
|
||||||
|
reasoning_content: reasoningContent
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content) {
|
||||||
if (startResponseWrite) {
|
if (startResponseWrite) {
|
||||||
workflowStreamResponse?.({
|
workflowStreamResponse?.({
|
||||||
write,
|
write,
|
||||||
@@ -538,18 +586,20 @@ async function streamResponse({
|
|||||||
text: content
|
text: content
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
} else if (textAnswer.length >= 3) {
|
} else if (answer.length >= 3) {
|
||||||
textAnswer = textAnswer.trim();
|
answer = answer.trimStart();
|
||||||
if (textAnswer.startsWith('0')) {
|
if (/0(:|:)/.test(answer)) {
|
||||||
startResponseWrite = true;
|
startResponseWrite = true;
|
||||||
|
|
||||||
// find first : index
|
// find first : index
|
||||||
const firstIndex = textAnswer.indexOf(':');
|
const firstIndex =
|
||||||
textAnswer = textAnswer.substring(firstIndex + 1).trim();
|
answer.indexOf('0:') !== -1 ? answer.indexOf('0:') : answer.indexOf('0:');
|
||||||
|
answer = answer.substring(firstIndex + 2).trim();
|
||||||
workflowStreamResponse?.({
|
workflowStreamResponse?.({
|
||||||
write,
|
write,
|
||||||
event: SseResponseEventEnum.answer,
|
event: SseResponseEventEnum.answer,
|
||||||
data: textAdaptGptResponse({
|
data: textAdaptGptResponse({
|
||||||
text: textAnswer
|
text: answer
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -557,7 +607,23 @@ async function streamResponse({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { answer: textAnswer.trim() };
|
if (answer === '') {
|
||||||
|
answer = getStartTagBuffer();
|
||||||
|
if (/0(:|:)/.test(answer)) {
|
||||||
|
// find first : index
|
||||||
|
const firstIndex = answer.indexOf('0:') !== -1 ? answer.indexOf('0:') : answer.indexOf('0:');
|
||||||
|
answer = answer.substring(firstIndex + 2).trim();
|
||||||
|
workflowStreamResponse?.({
|
||||||
|
write,
|
||||||
|
event: SseResponseEventEnum.answer,
|
||||||
|
data: textAdaptGptResponse({
|
||||||
|
text: answer
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { answer, reasoning };
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseAnswer = (
|
const parseAnswer = (
|
||||||
@@ -568,8 +634,7 @@ const parseAnswer = (
|
|||||||
} => {
|
} => {
|
||||||
str = str.trim();
|
str = str.trim();
|
||||||
// 首先,使用正则表达式提取TOOL_ID和TOOL_ARGUMENTS
|
// 首先,使用正则表达式提取TOOL_ID和TOOL_ARGUMENTS
|
||||||
const prefixReg = /^1(:|:)/;
|
const prefixReg = /1(:|:)/;
|
||||||
const answerPrefixReg = /^0(:|:)/;
|
|
||||||
|
|
||||||
if (prefixReg.test(str)) {
|
if (prefixReg.test(str)) {
|
||||||
const toolString = sliceJsonStr(str);
|
const toolString = sliceJsonStr(str);
|
||||||
@@ -585,13 +650,21 @@ const parseAnswer = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
if (/^1(:|:)/.test(str)) {
|
||||||
answer: ERROR_TEXT
|
return {
|
||||||
};
|
answer: ERROR_TEXT
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
answer: str
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const firstIndex = str.indexOf('0:') !== -1 ? str.indexOf('0:') : str.indexOf('0:');
|
||||||
|
const answer = str.substring(firstIndex + 2).trim();
|
||||||
return {
|
return {
|
||||||
answer: str.replace(answerPrefixReg, '')
|
answer
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -22,6 +22,7 @@ export type DispatchToolModuleProps = ModuleDispatchProps<{
|
|||||||
[NodeInputKeyEnum.aiChatTemperature]: number;
|
[NodeInputKeyEnum.aiChatTemperature]: number;
|
||||||
[NodeInputKeyEnum.aiChatMaxToken]: number;
|
[NodeInputKeyEnum.aiChatMaxToken]: number;
|
||||||
[NodeInputKeyEnum.aiChatVision]?: boolean;
|
[NodeInputKeyEnum.aiChatVision]?: boolean;
|
||||||
|
[NodeInputKeyEnum.aiChatReasoning]?: boolean;
|
||||||
[NodeInputKeyEnum.aiChatTopP]?: number;
|
[NodeInputKeyEnum.aiChatTopP]?: number;
|
||||||
[NodeInputKeyEnum.aiChatStopSign]?: string;
|
[NodeInputKeyEnum.aiChatStopSign]?: string;
|
||||||
[NodeInputKeyEnum.aiChatResponseFormat]?: string;
|
[NodeInputKeyEnum.aiChatResponseFormat]?: string;
|
||||||
|
@@ -563,6 +563,15 @@ async function streamResponse({
|
|||||||
// if answer is empty, try to get value from startTagBuffer. (Cause: The response content is too short to exceed the minimum parse length)
|
// if answer is empty, try to get value from startTagBuffer. (Cause: The response content is too short to exceed the minimum parse length)
|
||||||
if (answer === '') {
|
if (answer === '') {
|
||||||
answer = getStartTagBuffer();
|
answer = getStartTagBuffer();
|
||||||
|
if (isResponseAnswerText && answer) {
|
||||||
|
workflowStreamResponse?.({
|
||||||
|
write,
|
||||||
|
event: SseResponseEventEnum.answer,
|
||||||
|
data: textAdaptGptResponse({
|
||||||
|
text: answer
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { answer, reasoning };
|
return { answer, reasoning };
|
||||||
|
@@ -27,7 +27,9 @@ parentPort?.on('message', async (props: ReadRawTextProps<Uint8Array>) => {
|
|||||||
case 'csv':
|
case 'csv':
|
||||||
return readCsvRawText(params);
|
return readCsvRawText(params);
|
||||||
default:
|
default:
|
||||||
return Promise.reject('Only support .txt, .md, .html, .pdf, .docx, pptx, .csv, .xlsx');
|
return Promise.reject(
|
||||||
|
`Only support .txt, .md, .html, .pdf, .docx, pptx, .csv, .xlsx. "${params.extension}" is not supported.`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -139,14 +139,14 @@ const ChannelTable = ({ Tab }: { Tab: React.ReactNode }) => {
|
|||||||
</Td>
|
</Td>
|
||||||
<Td>
|
<Td>
|
||||||
<MyNumberInput
|
<MyNumberInput
|
||||||
defaultValue={item.priority || 0}
|
defaultValue={item.priority || 1}
|
||||||
min={0}
|
min={1}
|
||||||
max={100}
|
max={100}
|
||||||
h={'32px'}
|
h={'32px'}
|
||||||
w={'80px'}
|
w={'80px'}
|
||||||
onBlur={(e) => {
|
onBlur={(e) => {
|
||||||
const val = (() => {
|
const val = (() => {
|
||||||
if (!e) return 0;
|
if (!e) return 1;
|
||||||
return e;
|
return e;
|
||||||
})();
|
})();
|
||||||
updateChannel({
|
updateChannel({
|
||||||
|
@@ -130,7 +130,8 @@ export const postCreateChannel = (data: CreateChannelProps) =>
|
|||||||
base_url: data.base_url,
|
base_url: data.base_url,
|
||||||
models: data.models,
|
models: data.models,
|
||||||
model_mapping: data.model_mapping,
|
model_mapping: data.model_mapping,
|
||||||
key: data.key
|
key: data.key,
|
||||||
|
priority: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
export const putChannelStatus = (id: number, status: ChannelStatusEnum) =>
|
export const putChannelStatus = (id: number, status: ChannelStatusEnum) =>
|
||||||
@@ -146,7 +147,7 @@ export const putChannel = (data: ChannelInfoType) =>
|
|||||||
model_mapping: data.model_mapping,
|
model_mapping: data.model_mapping,
|
||||||
key: data.key,
|
key: data.key,
|
||||||
status: data.status,
|
status: data.status,
|
||||||
priority: data.priority
|
priority: data.priority ? Math.max(data.priority, 1) : undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
export const deleteChannel = (id: number) => DELETE(`/channel/${id}`);
|
export const deleteChannel = (id: number) => DELETE(`/channel/${id}`);
|
||||||
|
Reference in New Issue
Block a user