diff --git a/Dockerfile b/Dockerfile index c73840ba4..9e85ad3f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,14 +9,12 @@ ARG name # copy packages and one project COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ COPY ./packages ./packages -COPY ./projects/$name ./projects/$name +COPY ./projects/$name/package.json ./projects/$name/package.json RUN \ [ -f pnpm-lock.yaml ] && pnpm install || \ (echo "Lockfile not found." && exit 1) -RUN pnpm prune - # Rebuild the source code only when needed FROM node:current-alpine AS builder WORKDIR /app @@ -24,9 +22,11 @@ WORKDIR /app ARG name # copy common node_modules and one project node_modules +COPY package.json pnpm-workspace.yaml ./ COPY --from=deps /app/node_modules ./node_modules COPY --from=deps /app/packages ./packages -COPY --from=deps /app/projects/$name ./projects/$name +COPY ./projects/$name ./projects/$name +COPY --from=deps /app/projects/$name/node_modules ./projects/$name/node_modules # Uncomment the following line in case you want to disable telemetry during the build. ENV NEXT_TELEMETRY_DISABLED 1 diff --git a/docSite/assets/imgs/v45-1.png b/docSite/assets/imgs/v45-1.png new file mode 100644 index 000000000..a5590a29e Binary files /dev/null and b/docSite/assets/imgs/v45-1.png differ diff --git a/docSite/assets/imgs/v45-2.png b/docSite/assets/imgs/v45-2.png new file mode 100644 index 000000000..10e032525 Binary files /dev/null and b/docSite/assets/imgs/v45-2.png differ diff --git a/docSite/assets/imgs/v45-3.png b/docSite/assets/imgs/v45-3.png new file mode 100644 index 000000000..f8738ac73 Binary files /dev/null and b/docSite/assets/imgs/v45-3.png differ diff --git a/docSite/assets/imgs/v45-4.png b/docSite/assets/imgs/v45-4.png new file mode 100644 index 000000000..5dac603f9 Binary files /dev/null and b/docSite/assets/imgs/v45-4.png differ diff --git a/docSite/content/docs/custom-models/chatglm2-m3e.md b/docSite/content/docs/custom-models/chatglm2-m3e.md index a6c2f0533..daa328f50 100644 --- a/docSite/content/docs/custom-models/chatglm2-m3e.md +++ b/docSite/content/docs/custom-models/chatglm2-m3e.md @@ -63,15 +63,15 @@ Authorization 为 sk-aaabbbcccdddeeefffggghhhiiijjjkkk。model 为刚刚在 One ```json "ChatModels": [ - //已有模型 + //其他对话模型 { "model": "chatglm2", "name": "chatglm2", - "contextMaxToken": 8000, + "maxToken": 8000, + "price": 0, "quoteMaxToken": 4000, "maxTemperature": 1.2, - "price": 0, - "defaultSystem": "" + "defaultSystemChatPrompt": "" } ], "VectorModels": [ diff --git a/docSite/content/docs/custom-models/chatglm2.md b/docSite/content/docs/custom-models/chatglm2.md index 0d8d57474..384a66f9a 100644 --- a/docSite/content/docs/custom-models/chatglm2.md +++ b/docSite/content/docs/custom-models/chatglm2.md @@ -107,11 +107,11 @@ Authorization 为 sk-aaabbbcccdddeeefffggghhhiiijjjkkk。model 为刚刚在 One { "model": "chatglm2", "name": "chatglm2", - "contextMaxToken": 8000, + "maxToken": 8000, + "price": 0, "quoteMaxToken": 4000, "maxTemperature": 1.2, - "price": 0, - "defaultSystem": "" + "defaultSystemChatPrompt": "" } ] ``` diff --git a/docSite/content/docs/development/configuration.md b/docSite/content/docs/development/configuration.md index b45a76e0f..4e0407fbb 100644 --- a/docSite/content/docs/development/configuration.md +++ b/docSite/content/docs/development/configuration.md @@ -27,31 +27,75 @@ weight: 520 }, "ChatModels": [ { - "model": "gpt-3.5-turbo", - "name": "GPT35-4k", - "contextMaxToken": 4000, // 最大token,均按 gpt35 计算 + "model": "gpt-3.5-turbo", // 实际调用的模型 + "name": "GPT35-4k", // 展示的名字 + "maxToken": 4000, // 最大token,均按 gpt35 计算 "quoteMaxToken": 2000, // 引用内容最大 token "maxTemperature": 1.2, // 最大温度 "price": 0, - "defaultSystem": "" + "defaultSystemChatPrompt": "" }, { "model": "gpt-3.5-turbo-16k", "name": "GPT35-16k", - "contextMaxToken": 16000, + "maxToken": 16000, "quoteMaxToken": 8000, "maxTemperature": 1.2, "price": 0, - "defaultSystem": "" + "defaultSystemChatPrompt": "" }, { "model": "gpt-4", "name": "GPT4-8k", - "contextMaxToken": 8000, + "maxToken": 8000, "quoteMaxToken": 4000, "maxTemperature": 1.2, "price": 0, - "defaultSystem": "" + "defaultSystemChatPrompt": "" + } + ], + "QAModel": [ // QA 拆分模型 + { + "model": "gpt-3.5-turbo-16k", + "name": "GPT35-16k", + "maxToken": 16000, + "price": 0 + } + ], + "ExtractModels": [ // 内容提取模型 + { + "model": "gpt-3.5-turbo-16k", + "name": "GPT35-16k", + "maxToken": 16000, + "price": 0, + "functionCall": true, // 是否支持 function call + "functionPrompt": "" // 自定义非 function call 提示词 + } + ], + "CQModels": [ // Classify Question: 问题分类模型 + { + "model": "gpt-3.5-turbo-16k", + "name": "GPT35-16k", + "maxToken": 16000, + "price": 0, + "functionCall": true, + "functionPrompt": "" + }, + { + "model": "gpt-4", + "name": "GPT4-8k", + "maxToken": 8000, + "price": 0, + "functionCall": true, + "functionPrompt": "" + } + ], + "QGModels": [ // Question Generation: 生成下一步指引模型 + { + "model": "gpt-3.5-turbo", + "name": "GPT35-4k", + "maxToken": 4000, + "price": 0 } ], "VectorModels": [ @@ -62,36 +106,6 @@ weight: 520 "defaultToken": 500, "maxToken": 3000 } - ], - "QAModel": { // QA 拆分模型 - "model": "gpt-3.5-turbo-16k", - "name": "GPT35-16k", - "maxToken": 16000, - "price": 0 - }, - "ExtractModel": { // 内容提取模型 - "model": "gpt-3.5-turbo-16k", - "functionCall": true, // 是否使用 functionCall - "name": "GPT35-16k", - "maxToken": 16000, - "price": 0, - "prompt": "" - }, - "CQModel": { // Classify Question: 问题分类模型 - "model": "gpt-3.5-turbo-16k", - "functionCall": true, - "name": "GPT35-16k", - "maxToken": 16000, - "price": 0, - "prompt": "" - }, - "QGModel": { // Question Generation: 生成下一步指引模型 - "model": "gpt-3.5-turbo", - "name": "GPT35-4k", - "maxToken": 4000, - "price": 0, - "prompt": "", - "functionCall": false - } + ] } ``` diff --git a/docSite/content/docs/installation/docker.md b/docSite/content/docs/installation/docker.md index 608d55a34..f7d45bdfb 100644 --- a/docSite/content/docs/installation/docker.md +++ b/docSite/content/docs/installation/docker.md @@ -139,6 +139,21 @@ docker-compose 端口定义为:`映射端口:运行端口`。 (自行补习 docker 基本知识) +### relation "modeldata" does not exist + +PG 数据库没有连接上/初始化失败,可以查看日志。FastGPT 会在每次连接上 PG 时进行表初始化,如果报错会有对应日志。 + +1. 检查数据库容器是否正常启动 +2. 非 docker 部署的,需要手动安装 pg vector 插件 +3. 查看 fastgpt 日志,有没有相关报错 + +### Operation `auth_codes.findOne()` buffering timed out after 10000ms + +mongo连接失败,检查 +1. mongo 服务有没有起来(有些 cpu 不支持 AVX,无法用 mongo5,需要换成 mongo4.x,可以dockerhub找个最新的4.x,修改镜像版本,重新运行) +2. 环境变量(账号密码,注意host和port) + + ### 错误排查方式 遇到问题先按下面方式排查。 diff --git a/docSite/content/docs/installation/one-api.md b/docSite/content/docs/installation/one-api.md index 07233a4f5..7513b65a0 100644 --- a/docSite/content/docs/installation/one-api.md +++ b/docSite/content/docs/installation/one-api.md @@ -99,12 +99,12 @@ CHAT_API_KEY=sk-xxxxxx { "model": "ERNIE-Bot", // 这里的模型需要对应 One API 的模型 "name": "文心一言", // 对外展示的名称 - "contextMaxToken": 4000, // 最大长下文 token,无论什么模型都按 GPT35 的计算。GPT 外的模型需要自行大致计算下这个值。可以调用官方接口去比对 Token 的倍率,然后在这里粗略计算。 + "maxToken": 4000, // 最大长下文 token,无论什么模型都按 GPT35 的计算。GPT 外的模型需要自行大致计算下这个值。可以调用官方接口去比对 Token 的倍率,然后在这里粗略计算。 // 例如:文心一言的中英文 token 基本是 1:1,而 GPT 的中文 Token 是 2:1,如果文心一言官方最大 Token 是 4000,那么这里就可以填 8000,保险点就填 7000. + "price": 0, // 1个token 价格 => 1.5 / 100000 * 1000 = 0.015元/1k token "quoteMaxToken": 2000, // 引用知识库的最大 Token "maxTemperature": 1, // 最大温度 - "price": 0, // 1个token 价格 => 1.5 / 100000 * 1000 = 0.015元/1k token - "defaultSystem": "" // 默认的系统提示词 + "defaultSystemChatPrompt": "" // 默认的系统提示词 } ... ], diff --git a/docSite/content/docs/installation/upgrading/45.md b/docSite/content/docs/installation/upgrading/45.md new file mode 100644 index 000000000..427cab2ef --- /dev/null +++ b/docSite/content/docs/installation/upgrading/45.md @@ -0,0 +1,84 @@ +--- +title: 'V4.5(需进行较为复杂更新)' +description: 'FastGPT V4.5 更新' +icon: 'upgrade' +draft: false +toc: true +weight: 839 +--- + +FastGPT V4.5 引入 PgVector0.5 版本的 HNSW 索引,极大的提高了知识库检索的速度,比起`IVFFlat`索引大致有3~10倍的性能提升,可轻松实现百万数据毫秒级搜索。缺点在于构建索引的速度非常慢,4c16g 500w 组数据使用`并行构建`大约花了 48 小时。具体参数配置可参考 [PgVector官方](https://github.com/pgvector/pgvector) + +下面需要对数据库进行一些操作升级: + +## PgVector升级:Sealos 部署方案 + +1. 点击[Sealos桌面](https://cloud.sealos.io)的数据库应用。 +2. 点击【pg】数据库的详情。 +3. 点击右上角的重启,等待重启完成。 +4. 点击左侧的一键链接,等待打开 Terminal。 +5. 依次输入下方 sql 命令 + +```sql +-- 升级插件名 +ALTER EXTENSION vector UPDATE; +-- 插件是否升级成功,成功的话,vector插件版本为 0.5.0,旧版的为 0.4.1 +\dx + +-- 下面两个语句会设置 pg 在构建索引时可用的内存大小,需根据自身的数据库规格来动态配置,可配置为 1/4 的内存大小 +alter system set maintenance_work_mem = '2400MB'; +select pg_reload_conf(); + +-- 开始构建索引,该索引构建时间非常久,直接点击右上角的叉,退出 Terminal 即可 +CREATE INDEX CONCURRENTLY vector_index ON modeldata USING hnsw (vector vector_ip_ops) WITH (m = 16, ef_construction = 64); +-- 可以再次点击一键链接,进入 Terminal,输入下方命令,如果看到 "vector_index" hnsw (vector vector_ip_ops) WITH (m='16', ef_construction='64') 则代表构建完成(注意,后面没有 INVALID) +\d modeldata +``` + +| | | +| --------------------- | --------------------- | +| ![](/imgs/v45-1.png) | ![](/imgs/v45-2.png) | +| ![](/imgs/v45-3.png) | ![](/imgs/v45-4.png) | + + + +## PgVector升级:Docker-compose.yml 部署方案 + +下面的命令是基于给的 docker-compose 模板,如果数据库账号密码更换了,请自行调整。 + +1. 修改 `docker-compose.yml` 中pg的镜像版本,改成 `ankane/pgvector:v0.5.0` 或 `registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.5.0` +2. 重启 pg 容器(docker-compose pull && docker-compose up -d),等待重启完成。 +3. 进入容器: `docker exec -it pg bash` +4. 连接数据库: `psql 'postgresql://username:password@localhost:5432/postgres'` +5. 执行下面 sql 命令 + +```sql +-- 升级插件名 +ALTER EXTENSION vector UPDATE; +-- 插件是否升级成功,成功的话,vector插件版本为 0.5.0,旧版的为 0.4.2 +\dx + +-- 下面两个语句会设置 pg 在构建索引时可用的内存大小,需根据自身的数据库规格来动态配置,可配置为 1/4 的内存大小 +alter system set maintenance_work_mem = '2400MB'; +select pg_reload_conf(); + +-- 开始构建索引,该索引构建时间非常久,直接关掉终端即可,不要使用 ctrl+c 关闭 +CREATE INDEX CONCURRENTLY vector_index ON modeldata USING hnsw (vector vector_ip_ops) WITH (m = 16, ef_construction = 64); +-- 可以再次连接数据库,输入下方命令。如果看到 "vector_index" hnsw (vector vector_ip_ops) WITH (m='16', ef_construction='64') 则代表构建完成(注意,后面没有 INVALID) +\d modeldata +``` + +## 版本新功能介绍 + +### Fast GPT V4.5 + +1. 新增 - 升级 PgVector 插件,引入 HNSW 索引,极大加快的知识库搜索速度。 +2. 新增 - AI对话模块,增加【返回AI内容】选项,可控制 AI 的内容不直接返回浏览器。 +3. 新增 - 支持问题分类选择模型 +4. 优化 - TextSplitter,采用递归拆解法。 +5. 优化 - 高级编排 UX 性能 +6. 修复 - 分享链接鉴权问题 + +## 该版本需要修改 `config.json` 文件 + +最新配置可参考: [V45版本最新 config.json](/docs/development/configuration) \ No newline at end of file diff --git a/docSite/content/docs/use-cases/ai_settings.md b/docSite/content/docs/use-cases/ai_settings.md new file mode 100644 index 000000000..e93039d10 --- /dev/null +++ b/docSite/content/docs/use-cases/ai_settings.md @@ -0,0 +1,94 @@ +--- +title: "AI 高级配置说明" +description: "FastGPT AI 高级配置说明" +icon: "sign_language" +draft: false +toc: true +weight: 310 +--- + +在 FastGPT 的 AI 对话模块中,有一个 AI 高级配置,里面包含了 AI 模型的参数配置,本文详细介绍这些配置的含义。 + +# 返回AI内容 + +这是一个开关,打开的时候,当 AI 对话模块运行时,会将其输出的内容返回到浏览器(API响应);如果关闭,AI 输出的内容不会返回到浏览器,但是生成的内容仍可以通过【AI回复】进行输出。你可以将【AI回复】连接到其他模块中。 + +# 温度 + +可选范围0-10,约大代表生成的内容约自由扩散,越小代表约严谨。调节能力有限,知识库问答场景通常设置为0。 + +# 回复上限 + +控制 AI 回复的最大 Tokens,较小的值可以一定程度上减少 AI 的废话,但也可能导致 AI 回复不完整。 + +# 引用模板 & 引用提示词 + +这两个参数与知识库问答场景相关,可以控制知识库相关的提示词。 + +## AI 对话消息组成 + +想使用明白这两个变量,首先要了解传递传递给 AI 模型的消息格式。它是一个数组,FastGPT 中这个数组的组成形式为: + +```json +[ + 内置提示词(config.json 配置,一般为空) + 系统提示词 (用户输入的提示词) + 历史记录 + 问题(由引用提示词、引用模板和用户问题组成) +] +``` + +{{% alert icon="🍅" context="success" %}} +Tips: 可以通过点击上下文按键查看完整的 +{{% /alert %}} + +## 引用模板和提示词设计 + +引用模板和引用提示词通常是成对出现,引用提示词依赖引用模板。 + +FastGPT 知识库采用 QA 对(不一定都是问答格式,仅代表两个变量)的格式存储,在转义成字符串时候会根据**引用模板**来进行格式化。知识库包含 3 个变量: q, a, file_id, index, source,可以通过 {{q}} {{a}} {{file_id}} {{index}} {{source}} 按需引入。下面一个模板例子: + +**引用模板** + +``` +{instruction:"{{q}}",output:"{{a}}",source:"{{source}}"} +``` + +搜索到的知识库,会自动将 q,a,source 替换成对应的内容。每条搜索到的内容,会通过 `\n` 隔开。例如: +``` +{instruction:"电影《铃芽之旅》的导演是谁?",output:"电影《铃芽之旅》的导演是新海诚。",source:"手动输入"} +{instruction:"本作的主人公是谁?",output:"本作的主人公是名叫铃芽的少女。",source:""} +{instruction:"电影《铃芽之旅》男主角是谁?",output:"电影《铃芽之旅》男主角是宗像草太,由松村北斗配音。",source:""} +{instruction:"电影《铃芽之旅》的编剧是谁?22",output:"新海诚是本片的编剧。",source:"手动输入"} +``` + +**引用提示词** + +引用模板需要和引用提示词一起使用,提示词中可以写引用模板的格式说明以及对话的要求等。可以使用 {{quote}} 来使用 **引用模板**,使用 {{question}} 来引入问题。例如: + +``` +你的背景知识: +""" +{{quote}} +""" +对话要求: +1. 背景知识是最新的,其中 instruction 是相关介绍,output 是预期回答或补充。 +2. 使用背景知识回答问题。 +3. 背景知识无法回答问题时,你可以礼貌的的回答用户问题。 +我的问题是:"{{question}}" +``` + +转义后则为: +``` +你的背景知识: +""" +{instruction:"电影《铃芽之旅》的导演是谁?",output:"电影《铃芽之旅》的导演是新海诚。",source:"手动输入"} +{instruction:"本作的主人公是谁?",output:"本作的主人公是名叫铃芽的少女。",source:""} +{instruction:"电影《铃芽之旅》男主角是谁?",output:"电影《铃芽之旅》男主角是宗像草太,由松村北斗配音} +""" +对话要求: +1. 背景知识是最新的,其中 instruction 是相关介绍,output 是预期回答或补充。 +2. 使用背景知识回答问题。 +3. 背景知识无法回答问题时,你可以礼貌的的回答用户问题。 +我的问题是:"{{question}}" +``` \ No newline at end of file diff --git a/docSite/content/docs/use-cases/prompt.md b/docSite/content/docs/use-cases/prompt.md deleted file mode 100644 index f99959713..000000000 --- a/docSite/content/docs/use-cases/prompt.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: "提示词 & 引用提示词" -description: "FastGPT 提示词 & 引用提示词说明" -icon: "sign_language" -draft: false -toc: true -weight: 310 ---- - -限定词从 V4.4.3 版本后去除,被“引用提示词”和“引用模板”替代。 - -# AI 对话消息组成 - -传递给 AI 模型的消息是一个数组,FastGPT 中这个数组的组成形式为: - -```json -[ - 内置提示词(config.json 配置,一般为空) - 提示词 (用户输入的提示词) - 历史记录 - 问题(会由输入的问题、引用提示词和引用模板来决定) -] -``` - -{{% alert icon="🍅" context="success" %}} -Tips: 可以通过点击上下文按键查看完整的 -{{% /alert %}} - -# 引用模板和提示词设计 - -知识库采用 QA 对的格式存储,在转义成字符串时候会根据**引用模板**来进行格式化。知识库包含 3 个变量: q,a 和 source,可以通过 {{q}} {{a}} {{source}} 按需引入。下面一个模板例子: - -**引用模板** - -``` -{instruction:"{{q}}",output:"{{a}}",source:"{{source}}"} -``` - -搜索到的知识库,会自动将 q,a,source 替换成对应的内容。每条搜索到的内容,会通过 `\n` 隔开。例如: -``` -{instruction:"电影《铃芽之旅》的导演是谁?",output:"电影《铃芽之旅》的导演是新海诚。",source:"手动输入"} -{instruction:"本作的主人公是谁?",output:"本作的主人公是名叫铃芽的少女。",source:""} -{instruction:"电影《铃芽之旅》男主角是谁?",output:"电影《铃芽之旅》男主角是宗像草太,由松村北斗配音。",source:""} -{instruction:"电影《铃芽之旅》的编剧是谁?22",output:"新海诚是本片的编剧。",source:"手动输入"} -``` - -**引用提示词** - -引用模板需要和引用提示词一起使用,提示词中可以写引用模板的格式说明以及对话的要求等。可以使用 {{quote}} 来使用 **引用模板**,使用 {{question}} 来引入问题。例如: - -``` -你的背景知识: -""" -{{quote}} -""" -对话要求: -1. 背景知识是最新的,其中 instruction 是相关介绍,output 是预期回答或补充。 -2. 使用背景知识回答问题。 -3. 背景知识无法回答问题时,你可以礼貌的的回答用户问题。 -我的问题是:"{{question}}" -``` - - -# 提示词案例 - -## 仅回复知识库里的内容 - -**引用提示词**里添加: -``` -你的背景知识: -""" -{{quote}} -""" -对话要求: -1. 回答前,请先判断背景知识是否足够回答问题,如果无法回答,请直接回复:“对不起,我无法回答你的问题~”。 -2. 背景知识是最新的,其中 instruction 是相关介绍,output 是预期回答或补充。 -3. 使用背景知识回答问题。 -我的问题是:"{{question}}" -``` - -## 说明引用来源 - -**引用模板:** - -``` -{instruction:"{{q}}",output:"{{a}}",source:"{{source}}"} -``` - -**引用提示词:** - -``` -你的背景知识: -""" -{{quote}} -""" -对话要求: -1. 背景知识是最新的,其中 instruction 是相关介绍,output 是预期回答或补充,source是背景来源。 -2. 使用背景知识回答问题。 -3. 在回答问题后,你需要给出本次回答对应的背景来源,来源展示格式如下: - -“ -这是AI作答。本次知识来源: -1. source1 -2. source2 -...... -” - -我的问题是:"{{question}}" -``` diff --git a/docSite/content/docs/workflow/examples/fixingEvidence.md b/docSite/content/docs/workflow/examples/fixingEvidence.md index a81627837..ec84afa8e 100644 --- a/docSite/content/docs/workflow/examples/fixingEvidence.md +++ b/docSite/content/docs/workflow/examples/fixingEvidence.md @@ -232,7 +232,7 @@ weight: 142 "outputs": [ { "key": "answerText", - "label": "模型回复", + "label": "AI回复", "description": "将在 stream 回复完毕后触发", "valueType": "string", "type": "source", diff --git a/docSite/content/docs/workflow/examples/google_search.md b/docSite/content/docs/workflow/examples/google_search.md index d5d603b14..af896b595 100644 --- a/docSite/content/docs/workflow/examples/google_search.md +++ b/docSite/content/docs/workflow/examples/google_search.md @@ -432,7 +432,7 @@ export default async function (ctx: FunctionContext) { "outputs": [ { "key": "answerText", - "label": "模型回复", + "label": "AI回复", "description": "直接响应,无需配置", "type": "hidden", "targets": [] diff --git a/docSite/content/docs/workflow/examples/lab_appointment.md b/docSite/content/docs/workflow/examples/lab_appointment.md index cc5730c68..7e5b7fb4f 100644 --- a/docSite/content/docs/workflow/examples/lab_appointment.md +++ b/docSite/content/docs/workflow/examples/lab_appointment.md @@ -751,7 +751,7 @@ HTTP 模块允许你调用任意 POST 类型的 HTTP 接口,从而实验一些 "outputs": [ { "key": "answerText", - "label": "模型回复", + "label": "模型AI回复回复", "description": "将在 stream 回复完毕后触发", "valueType": "string", "type": "source", diff --git a/docSite/content/docs/workflow/examples/op_question.md b/docSite/content/docs/workflow/examples/op_question.md index c4a8e9ccd..7920b6000 100644 --- a/docSite/content/docs/workflow/examples/op_question.md +++ b/docSite/content/docs/workflow/examples/op_question.md @@ -313,7 +313,7 @@ weight: 144 "outputs": [ { "key": "answerText", - "label": "模型回复", + "label": "AI回复", "description": "将在 stream 回复完毕后触发", "valueType": "string", "type": "source", diff --git a/docSite/content/docs/workflow/examples/versatile_assistant.md b/docSite/content/docs/workflow/examples/versatile_assistant.md index 4d3643595..89a237465 100644 --- a/docSite/content/docs/workflow/examples/versatile_assistant.md +++ b/docSite/content/docs/workflow/examples/versatile_assistant.md @@ -745,7 +745,7 @@ PS2:配置中的问题分类还包含着“联网搜索”,这个是另一 "outputs": [ { "key": "answerText", - "label": "模型回复", + "label": "AI回复", "description": "将在 stream 回复完毕后触发", "valueType": "string", "type": "source", @@ -903,7 +903,7 @@ PS2:配置中的问题分类还包含着“联网搜索”,这个是另一 "outputs": [ { "key": "answerText", - "label": "模型回复", + "label": "AI回复", "description": "将在 stream 回复完毕后触发", "valueType": "string", "type": "source", @@ -1117,7 +1117,7 @@ PS2:配置中的问题分类还包含着“联网搜索”,这个是另一 "outputs": [ { "key": "answerText", - "label": "模型回复", + "label": "AI回复", "description": "将在 stream 回复完毕后触发", "valueType": "string", "type": "source", @@ -1484,7 +1484,7 @@ PS2:配置中的问题分类还包含着“联网搜索”,这个是另一 "outputs": [ { "key": "answerText", - "label": "模型回复", + "label": "AI回复", "description": "将在 stream 回复完毕后触发", "valueType": "string", "type": "source", diff --git a/packages/common/mongo/init.ts b/packages/common/mongo/init.ts index dcb9bb4cd..de2b7ed98 100644 --- a/packages/common/mongo/init.ts +++ b/packages/common/mongo/init.ts @@ -29,7 +29,9 @@ export async function connectMongo({ bufferCommands: true, maxConnecting: Number(process.env.DB_MAX_LINK || 5), maxPoolSize: Number(process.env.DB_MAX_LINK || 5), - minPoolSize: 2 + minPoolSize: 2, + connectTimeoutMS: 20000, + waitQueueTimeoutMS: 20000 }); console.log('mongo connected'); diff --git a/packages/common/package.json b/packages/common/package.json index 6af26a944..33b1bf030 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -5,7 +5,9 @@ "mongoose": "^7.0.2", "winston": "^3.10.0", "winston-mongodb": "^5.1.1", - "axios": "^1.5.1" + "axios": "^1.5.1", + "nextjs-cors": "^2.1.2", + "next": "13.5.2" }, "devDependencies": { "@types/node": "^20.8.5" diff --git a/packages/common/tools/nextjs.ts b/packages/common/tools/nextjs.ts new file mode 100644 index 000000000..261b03efb --- /dev/null +++ b/packages/common/tools/nextjs.ts @@ -0,0 +1,19 @@ +import type { NextApiResponse, NextApiHandler, NextApiRequest } from 'next'; +import NextCors from 'nextjs-cors'; + +export function withNextCors(handler: NextApiHandler): NextApiHandler { + return async function nextApiHandlerWrappedWithNextCors( + req: NextApiRequest, + res: NextApiResponse + ) { + const methods = ['GET', 'eHEAD', 'PUT', 'PATCH', 'POST', 'DELETE']; + const origin = req.headers.origin; + await NextCors(req, res, { + methods, + origin: origin, + optionsSuccessStatus: 200 + }); + + return handler(req, res); + }; +} diff --git a/packages/common/tools/str.ts b/packages/common/tools/str.ts index 2f7a86a99..336dcd43d 100644 --- a/packages/common/tools/str.ts +++ b/packages/common/tools/str.ts @@ -13,20 +13,10 @@ export const hashStr = (psw: string) => { /* simple text, remove chinese space and extra \n */ export const simpleText = (text: string) => { text = text.replace(/([\u4e00-\u9fa5])[\s&&[^\n]]+([\u4e00-\u9fa5])/g, '$1$2'); - text = text.replace(/\n{2,}/g, '\n'); + text = text.replace(/\n{3,}/g, '\n\n'); text = text.replace(/[\s&&[^\n]]{2,}/g, ' '); text = text.replace(/[\x00-\x08]/g, ' '); + text = text.replace(/\r\n|\r/g, '\n'); - // replace empty \n - let newText = ''; - let lastChar = ''; - for (let i = 0; i < text.length; i++) { - const currentChar = text[i]; - if (currentChar === '\n' && !/[。?!;.?!;]/g.test(lastChar)) { - } else { - newText += currentChar; - } - lastChar = currentChar; - } - return newText; + return text; }; diff --git a/projects/app/src/service/common/stream.ts b/packages/common/tools/stream.ts similarity index 100% rename from projects/app/src/service/common/stream.ts rename to packages/common/tools/stream.ts diff --git a/packages/core/ai/config.ts b/packages/core/ai/config.ts index 821232689..c491ba10c 100644 --- a/packages/core/ai/config.ts +++ b/packages/core/ai/config.ts @@ -11,6 +11,7 @@ export const getAIApi = (props?: UserModelSchema['openaiAccount'], timeout = 600 apiKey: props?.key || systemAIChatKey, baseURL: props?.baseUrl || baseUrl, httpAgent: global.httpsAgent, - timeout + timeout, + maxRetries: 2 }); }; diff --git a/packages/core/ai/type.d.ts b/packages/core/ai/type.d.ts index 89a5a42d5..723af8e6a 100644 --- a/packages/core/ai/type.d.ts +++ b/packages/core/ai/type.d.ts @@ -4,3 +4,9 @@ export type ChatCompletion = OpenAI.Chat.ChatCompletion; export type CreateChatCompletionRequest = OpenAI.Chat.ChatCompletionCreateParams; export type StreamChatType = Stream; + +export type PromptTemplateItem = { + title: string; + desc: string; + value: string; +}; diff --git a/packages/core/package.json b/packages/core/package.json index 5013eac09..07f14749b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -5,7 +5,7 @@ "@fastgpt/common": "workspace:*", "@fastgpt/support": "workspace:*", "encoding": "^0.1.13", - "openai": "^4.11.1", + "openai": "^4.12.1", "tunnel": "^0.0.6" }, "devDependencies": { diff --git a/packages/support/outLink/auth.ts b/packages/support/outLink/auth.ts index bd5ee6c7c..1d4c06fe5 100644 --- a/packages/support/outLink/auth.ts +++ b/packages/support/outLink/auth.ts @@ -63,5 +63,6 @@ export type AuthShareChatInitProps = { }; export function authShareChatInit(data: AuthShareChatInitProps) { + if (!global.feConfigs?.isPlus) return; return POST('/support/outLink/authShareChatInit', data); } diff --git a/packages/support/package.json b/packages/support/package.json index 544a886ac..b1475373e 100644 --- a/packages/support/package.json +++ b/packages/support/package.json @@ -5,7 +5,8 @@ "@fastgpt/common": "workspace:*", "cookie": "^0.5.0", "jsonwebtoken": "^9.0.2", - "axios": "^1.5.1" + "axios": "^1.5.1", + "next": "13.5.2" }, "devDependencies": { "@types/cookie": "^0.5.2", diff --git a/packages/support/user/auth.ts b/packages/support/user/auth.ts index cce40bb3a..c645b9944 100644 --- a/packages/support/user/auth.ts +++ b/packages/support/user/auth.ts @@ -1,8 +1,8 @@ +import type { NextApiResponse, NextApiRequest } from 'next'; import Cookie from 'cookie'; -import { authJWT } from './tools'; +import jwt from 'jsonwebtoken'; import { authOpenApiKey } from '../openapi/auth'; import { authOutLinkId } from '../outLink/auth'; - import { MongoUser } from './schema'; import type { UserModelSchema } from './type.d'; import { ERROR_ENUM } from '@fastgpt/common/constant/errorCode'; @@ -39,7 +39,7 @@ export const authUser = async ({ authBalance = false, authOutLink }: { - req: any; + req: NextApiRequest; authToken?: boolean; authRoot?: boolean; authApiKey?: boolean; @@ -165,3 +165,42 @@ export const authUser = async ({ apikey: openApiKey }; }; + +/* 生成 token */ +export function generateToken(userId: string) { + const key = process.env.TOKEN_KEY as string; + const token = jwt.sign( + { + userId, + exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7 + }, + key + ); + return token; +} +// auth token +export function authJWT(token: string) { + return new Promise((resolve, reject) => { + const key = process.env.TOKEN_KEY as string; + + jwt.verify(token, key, function (err, decoded: any) { + if (err || !decoded?.userId) { + reject(ERROR_ENUM.unAuthorization); + return; + } + resolve(decoded.userId); + }); + }); +} + +/* set cookie */ +export const setCookie = (res: NextApiResponse, token: string) => { + res.setHeader( + 'Set-Cookie', + `token=${token}; Path=/; HttpOnly; Max-Age=604800; Samesite=None; Secure;` + ); +}; +/* clear cookie */ +export const clearCookie = (res: NextApiResponse) => { + res.setHeader('Set-Cookie', 'token=; Path=/; Max-Age=0'); +}; diff --git a/packages/support/user/tools.ts b/packages/support/user/tools.ts deleted file mode 100644 index 1806f2739..000000000 --- a/packages/support/user/tools.ts +++ /dev/null @@ -1,28 +0,0 @@ -import jwt from 'jsonwebtoken'; -import { ERROR_ENUM } from '@fastgpt/common/constant/errorCode'; - -/* 生成 token */ -export const generateToken = (userId: string) => { - const key = process.env.TOKEN_KEY as string; - const token = jwt.sign( - { - userId, - exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7 - }, - key - ); - return token; -}; -// auth token -export const authJWT = (token: string) => - new Promise((resolve, reject) => { - const key = process.env.TOKEN_KEY as string; - - jwt.verify(token, key, function (err, decoded: any) { - if (err || !decoded?.userId) { - reject(ERROR_ENUM.unAuthorization); - return; - } - resolve(decoded.userId); - }); - }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c2e3a88e1..452bf518d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,12 @@ importers: mongoose: specifier: ^7.0.2 version: registry.npmmirror.com/mongoose@7.0.2 + next: + specifier: 13.5.2 + version: registry.npmmirror.com/next@13.5.2(@babel/core@7.23.2)(react-dom@18.2.0)(react@18.2.0)(sass@1.58.3) + nextjs-cors: + specifier: ^2.1.2 + version: registry.npmmirror.com/nextjs-cors@2.1.2(next@13.5.2) winston: specifier: ^3.10.0 version: registry.npmmirror.com/winston@3.10.0 @@ -58,8 +64,8 @@ importers: specifier: ^0.1.13 version: registry.npmmirror.com/encoding@0.1.13 openai: - specifier: ^4.11.1 - version: registry.npmmirror.com/openai@4.11.1(encoding@0.1.13) + specifier: ^4.12.1 + version: registry.npmmirror.com/openai@4.12.1(encoding@0.1.13) tunnel: specifier: ^0.0.6 version: registry.npmmirror.com/tunnel@0.0.6 @@ -82,6 +88,9 @@ importers: jsonwebtoken: specifier: ^9.0.2 version: registry.npmmirror.com/jsonwebtoken@9.0.2 + next: + specifier: 13.5.2 + version: registry.npmmirror.com/next@13.5.2(@babel/core@7.23.2)(react-dom@18.2.0)(react@18.2.0)(sass@1.58.3) devDependencies: '@types/cookie': specifier: ^0.5.2 @@ -200,9 +209,6 @@ importers: next-i18next: specifier: ^14.0.0 version: registry.npmmirror.com/next-i18next@14.0.3(i18next@23.5.1)(next@13.5.2)(react-i18next@13.2.2)(react@18.2.0) - nextjs-cors: - specifier: ^2.1.2 - version: registry.npmmirror.com/nextjs-cors@2.1.2(next@13.5.2) nprogress: specifier: ^0.2.0 version: registry.npmmirror.com/nprogress@0.2.0 @@ -288,6 +294,9 @@ importers: '@types/multer': specifier: ^1.4.7 version: registry.npmmirror.com/@types/multer@1.4.7 + '@types/node': + specifier: ^20.8.5 + version: registry.npmmirror.com/@types/node@20.8.5 '@types/papaparse': specifier: ^5.3.7 version: registry.npmmirror.com/@types/papaparse@5.3.7 @@ -9581,11 +9590,11 @@ packages: mimic-fn: registry.npmmirror.com/mimic-fn@4.0.0 dev: true - registry.npmmirror.com/openai@4.11.1(encoding@0.1.13): - resolution: {integrity: sha512-GU0HQWbejXuVAQlDjxIE8pohqnjptFDIm32aPlNT1H9ucMz1VJJD0DaTJRQsagNaJ97awWjjVLEG7zCM6sm4SA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/openai/-/openai-4.11.1.tgz} - id: registry.npmmirror.com/openai/4.11.1 + registry.npmmirror.com/openai@4.12.1(encoding@0.1.13): + resolution: {integrity: sha512-EAoUwm4dtiWvFwBhOCK/VfF8sj1ZU8+aAIJnfT4NyeTfrt1DM/6Gdd6fOZWTjBYryTAqu9Vpb5+9Wu6JMtm/gA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/openai/-/openai-4.12.1.tgz} + id: registry.npmmirror.com/openai/4.12.1 name: openai - version: 4.11.1 + version: 4.12.1 hasBin: true dependencies: '@types/node': registry.npmmirror.com/@types/node@18.18.5 diff --git a/projects/app/data/config.json b/projects/app/data/config.json index 4668b59f4..e523f8aa9 100644 --- a/projects/app/data/config.json +++ b/projects/app/data/config.json @@ -8,68 +8,85 @@ { "model": "gpt-3.5-turbo", "name": "GPT35-4k", - "contextMaxToken": 4000, + "price": 0, + "maxToken": 4000, "quoteMaxToken": 2000, "maxTemperature": 1.2, - "price": 0, - "defaultSystem": "" + "censor": false, + "defaultSystemChatPrompt": "" }, { "model": "gpt-3.5-turbo-16k", "name": "GPT35-16k", - "contextMaxToken": 16000, + "maxToken": 16000, + "price": 0, "quoteMaxToken": 8000, "maxTemperature": 1.2, - "price": 0, - "defaultSystem": "" + "censor": false, + "defaultSystemChatPrompt": "" }, { "model": "gpt-4", "name": "GPT4-8k", - "contextMaxToken": 8000, + "maxToken": 8000, + "price": 0, "quoteMaxToken": 4000, "maxTemperature": 1.2, + "censor": false, + "defaultSystemChatPrompt": "" + } + ], + "QAModels": [ + { + "model": "gpt-3.5-turbo-16k", + "name": "GPT35-16k", + "maxToken": 16000, + "price": 0 + } + ], + "CQModels": [ + { + "model": "gpt-3.5-turbo-16k", + "name": "GPT35-16k", + "maxToken": 16000, "price": 0, - "defaultSystem": "" + "functionCall": true, + "functionPrompt": "" + }, + { + "model": "gpt-4", + "name": "GPT4-8k", + "maxToken": 8000, + "price": 0, + "functionCall": true, + "functionPrompt": "" + } + ], + "ExtractModels": [ + { + "model": "gpt-3.5-turbo-16k", + "name": "GPT35-16k", + "maxToken": 16000, + "price": 0, + "functionCall": true, + "functionPrompt": "" + } + ], + "QGModels": [ + { + "model": "gpt-3.5-turbo", + "name": "GPT35-4K", + "maxToken": 4000, + "price": 0 } ], "VectorModels": [ { "model": "text-embedding-ada-002", "name": "Embedding-2", - "price": 0, - "defaultToken": 500, + "price": 0.2, + "defaultToken": 700, "maxToken": 3000 } - ], - "QAModel": { - "model": "gpt-3.5-turbo-16k", - "name": "GPT35-16k", - "maxToken": 16000, - "price": 0 - }, - "ExtractModel": { - "model": "gpt-3.5-turbo-16k", - "functionCall": true, - "name": "GPT35-16k", - "maxToken": 16000, - "price": 0, - "prompt": "" - }, - "CQModel": { - "model": "gpt-3.5-turbo-16k", - "functionCall": true, - "name": "GPT35-16k", - "maxToken": 16000, - "price": 0, - "prompt": "" - }, - "QGModel": { - "model": "gpt-3.5-turbo", - "name": "GPT35-4k", - "maxToken": 4000, - "price": 0, - "prompt": "", - "functionCall": false - } + ] } diff --git a/projects/app/package.json b/projects/app/package.json index a5e55ed29..095d2f507 100644 --- a/projects/app/package.json +++ b/projects/app/package.json @@ -1,6 +1,6 @@ { "name": "app", - "version": "4.4.7", + "version": "4.5.0", "private": false, "scripts": { "dev": "next dev", @@ -31,6 +31,7 @@ "formidable": "^2.1.1", "framer-motion": "^9.0.6", "hyperdown": "^2.4.29", + "i18next": "^23.2.11", "immer": "^9.0.19", "js-cookie": "^3.0.5", "js-tiktoken": "^1.0.7", @@ -43,7 +44,7 @@ "multer": "1.4.5-lts.1", "nanoid": "^4.0.1", "next": "13.5.2", - "nextjs-cors": "^2.1.2", + "next-i18next": "^14.0.0", "nprogress": "^0.2.0", "papaparse": "^5.4.1", "pg": "^8.10.0", @@ -52,6 +53,7 @@ "react-day-picker": "^8.7.1", "react-dom": "18.2.0", "react-hook-form": "^7.43.1", + "react-i18next": "^13.0.2", "react-markdown": "^8.0.7", "react-syntax-highlighter": "^15.5.0", "reactflow": "^11.7.4", @@ -62,10 +64,7 @@ "request-ip": "^3.3.0", "sass": "^1.58.3", "timezones-list": "^3.0.2", - "zustand": "^4.3.5", - "i18next": "^23.2.11", - "react-i18next": "^13.0.2", - "next-i18next": "^14.0.0" + "zustand": "^4.3.5" }, "devDependencies": { "@svgr/webpack": "^6.5.1", @@ -76,6 +75,7 @@ "@types/jsonwebtoken": "^9.0.3", "@types/lodash": "^4.14.191", "@types/multer": "^1.4.7", + "@types/node": "^20.8.5", "@types/papaparse": "^5.3.7", "@types/pg": "^8.6.6", "@types/react": "18.0.28", diff --git a/projects/app/public/docs/versionIntro.md b/projects/app/public/docs/versionIntro.md index d8efed71d..70dfaebf4 100644 --- a/projects/app/public/docs/versionIntro.md +++ b/projects/app/public/docs/versionIntro.md @@ -1,6 +1,10 @@ -### Fast GPT V4.4.7 +### Fast GPT V4.5.0 -1. 优化数据集管理,区分手动录入和标注,可追数据至某个文件,保留链接读取的原始链接。 -2. [使用文档](https://doc.fastgpt.run/docs/intro/) -3. [点击查看高级编排介绍文档](https://doc.fastgpt.run/docs/workflow) -4. [点击查看商业版](https://doc.fastgpt.run/docs/commercial/) +1. 新增 - 升级 PgVector 插件,引入 HNSW 索引,极大加快的知识库搜索速度。 +2. 新增 - AI对话模块,增加【返回AI内容】选项,可控制 AI 的内容不直接返回浏览器。 +3. 优化 - TextSplitter,采用递归拆解法。 +4. 优化 - 高级编排 UX 性能 +5. 优化数据集管理,区分手动录入和标注,可追数据至某个文件,保留链接读取的原始链接。 +6. [使用文档](https://doc.fastgpt.run/docs/intro/) +7. [点击查看高级编排介绍文档](https://doc.fastgpt.run/docs/workflow) +8. [点击查看商业版](https://doc.fastgpt.run/docs/commercial/) diff --git a/projects/app/public/locales/en/common.json b/projects/app/public/locales/en/common.json index c1cfda343..0fa18ea00 100644 --- a/projects/app/public/locales/en/common.json +++ b/projects/app/public/locales/en/common.json @@ -39,7 +39,7 @@ "My Apps": "My Apps", "Output Field Settings": "Output Field Settings", "Paste Config": "Paste Config", - "Quote Prompt Settings": "Quote Prompt Settings", + "AI Settings": "AI Settings", "Variable Key Repeat Tip": "Variable Key Repeat", "module": { "Custom Title Tip": "The title name is displayed during the conversation" diff --git a/projects/app/public/locales/zh/common.json b/projects/app/public/locales/zh/common.json index bfb8a0bf9..62cd1e60a 100644 --- a/projects/app/public/locales/zh/common.json +++ b/projects/app/public/locales/zh/common.json @@ -39,7 +39,7 @@ "My Apps": "我的应用", "Output Field Settings": "输出字段编辑", "Paste Config": "粘贴配置", - "Quote Prompt Settings": "引用提示词配置", + "AI Settings": "AI 高级配置", "Variable Key Repeat Tip": "变量 key 重复", "module": { "Custom Title Tip": "该标题名字会展示在对话过程中" diff --git a/projects/app/src/components/ChatBox/utils.ts b/projects/app/src/components/ChatBox/utils.ts index db1fbbae0..0d502fef7 100644 --- a/projects/app/src/components/ChatBox/utils.ts +++ b/projects/app/src/components/ChatBox/utils.ts @@ -1,6 +1,5 @@ import { SystemInputEnum } from '@/constants/app'; import { FlowModuleTypeEnum } from '@/constants/flow'; -import { getChatModel } from '@/service/utils/data'; import { AppModuleItemType, VariableItemType } from '@/types/app'; export const getGuideModule = (modules: AppModuleItemType[]) => @@ -23,11 +22,3 @@ export const splitGuideModule = (guideModules?: AppModuleItemType) => { questionGuide }; }; -export const getChatModelNameList = (modules: AppModuleItemType[]): string[] => { - const chatModules = modules.filter((item) => item.flowType === FlowModuleTypeEnum.chatNode); - return chatModules - .map( - (item) => getChatModel(item.inputs.find((input) => input.key === 'model')?.value)?.name || '' - ) - .filter((item) => item); -}; diff --git a/projects/app/src/components/Markdown/index.tsx b/projects/app/src/components/Markdown/index.tsx index 535d9db42..f8c83a3f0 100644 --- a/projects/app/src/components/Markdown/index.tsx +++ b/projects/app/src/components/Markdown/index.tsx @@ -62,7 +62,9 @@ const Markdown = ({ source, isChatting = false }: { source: string; isChatting?: [] ); - const formatSource = source.replace(/\\n/g, '\n '); + const formatSource = source + .replace(/\\n/g, '\n ') + .replace(/(http[s]?:\/\/[^\s,。]+)([。,])/g, '$1 $2'); return ( {!!title && {title}} {onClose && } - + {children} diff --git a/projects/app/src/components/PromptTemplate/index.tsx b/projects/app/src/components/PromptTemplate/index.tsx new file mode 100644 index 000000000..182345364 --- /dev/null +++ b/projects/app/src/components/PromptTemplate/index.tsx @@ -0,0 +1,64 @@ +import React, { useState } from 'react'; +import MyModal from '../MyModal'; +import { Box, Button, Grid, useTheme } from '@chakra-ui/react'; +import { PromptTemplateItem } from '@fastgpt/core/ai/type'; +import { ModalBody, ModalFooter } from '@chakra-ui/react'; + +const PromptTemplate = ({ + title, + templates, + onClose, + onSuccess +}: { + title: string; + templates: PromptTemplateItem[]; + onClose: () => void; + onSuccess: (e: string) => void; +}) => { + const theme = useTheme(); + const [selectTemplateTitle, setSelectTemplateTitle] = useState(); + + return ( + + + + {templates.map((item) => ( + setSelectTemplateTitle(item)} + > + {item.title} + + {item.value} + + + ))} + + + + + + + ); +}; + +export default PromptTemplate; diff --git a/projects/app/src/constants/app.ts b/projects/app/src/constants/app.ts index e1763462b..523157014 100644 --- a/projects/app/src/constants/app.ts +++ b/projects/app/src/constants/app.ts @@ -5,7 +5,8 @@ export enum SystemInputEnum { 'switch' = 'switch', // a trigger switch 'history' = 'history', 'userChatInput' = 'userChatInput', - 'questionGuide' = 'questionGuide' + 'questionGuide' = 'questionGuide', + isResponseAnswerText = 'isResponseAnswerText' } export enum SystemOutputEnum { finish = 'finish' diff --git a/projects/app/src/constants/flow/ModuleTemplate.ts b/projects/app/src/constants/flow/ModuleTemplate.ts index 53443b568..461d93924 100644 --- a/projects/app/src/constants/flow/ModuleTemplate.ts +++ b/projects/app/src/constants/flow/ModuleTemplate.ts @@ -9,7 +9,7 @@ import { } from './index'; import type { AppItemType } from '@/types/app'; import type { FlowModuleTemplateType } from '@/types/core/app/flow'; -import { chatModelList } from '@/web/common/store/static'; +import { chatModelList, cqModelList } from '@/web/common/store/static'; import { Input_Template_History, Input_Template_TFSwitch, @@ -136,14 +136,14 @@ export const ChatModule: FlowModuleTemplateType = { key: 'model', type: FlowInputItemTypeEnum.selectChatModel, label: '对话模型', - value: chatModelList[0]?.model, - list: chatModelList.map((item) => ({ label: item.name, value: item.model })), + value: chatModelList?.[0]?.model, + customData: () => chatModelList, required: true, valueCheck: (val) => !!val }, { key: 'temperature', - type: FlowInputItemTypeEnum.slider, + type: FlowInputItemTypeEnum.hidden, label: '温度', value: 0, min: 0, @@ -156,20 +156,26 @@ export const ChatModule: FlowModuleTemplateType = { }, { key: 'maxToken', - type: FlowInputItemTypeEnum.maxToken, + type: FlowInputItemTypeEnum.hidden, label: '回复上限', - value: chatModelList[0] ? chatModelList[0].contextMaxToken / 2 : 2000, + value: chatModelList?.[0] ? chatModelList[0].maxToken / 2 : 2000, min: 100, - max: chatModelList[0]?.contextMaxToken || 4000, + max: chatModelList?.[0]?.maxToken || 4000, step: 50, markList: [ { label: '100', value: 100 }, { - label: `${chatModelList[0]?.contextMaxToken || 4000}`, - value: chatModelList[0]?.contextMaxToken || 4000 + label: `${chatModelList?.[0]?.maxToken || 4000}`, + value: chatModelList?.[0]?.maxToken || 4000 } ] }, + { + key: 'aiSettings', + type: FlowInputItemTypeEnum.aiSettings, + label: '', + connected: false + }, { key: 'systemPrompt', type: FlowInputItemTypeEnum.textarea, @@ -180,6 +186,13 @@ export const ChatModule: FlowModuleTemplateType = { placeholder: ChatModelSystemTip, value: '' }, + { + key: SystemInputEnum.isResponseAnswerText, + type: FlowInputItemTypeEnum.hidden, + label: '返回AI内容', + valueType: FlowValueTypeEnum.boolean, + value: true + }, { key: 'quoteTemplate', type: FlowInputItemTypeEnum.hidden, @@ -196,7 +209,7 @@ export const ChatModule: FlowModuleTemplateType = { }, { key: 'quoteQA', - type: FlowInputItemTypeEnum.quoteList, + type: FlowInputItemTypeEnum.target, label: '引用内容', description: "对象数组格式,结构:\n [{q:'问题',a:'回答'}]", valueType: FlowValueTypeEnum.kbQuote, @@ -216,7 +229,7 @@ export const ChatModule: FlowModuleTemplateType = { }, { key: TaskResponseKeyEnum.answerText, - label: '模型回复', + label: 'AI回复', description: '将在 stream 回复完毕后触发', valueType: FlowValueTypeEnum.string, type: FlowOutputItemTypeEnum.source, @@ -330,12 +343,21 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = { showStatus: true, inputs: [ Input_Template_TFSwitch, + { + key: 'model', + type: FlowInputItemTypeEnum.selectChatModel, + label: '分类模型', + value: cqModelList?.[0]?.model, + customData: () => cqModelList, + required: true, + valueCheck: (val) => !!val + }, { key: 'systemPrompt', type: FlowInputItemTypeEnum.textarea, valueType: FlowValueTypeEnum.string, value: '', - label: '系统提示词', + label: '背景知识', description: '你可以添加一些特定内容的介绍,从而更好的识别用户的问题类型。这个内容通常是给模型介绍一个它不知道的内容。', placeholder: '例如: \n1. Laf 是一个云函数开发平台……\n2. Sealos 是一个集群操作系统' @@ -504,7 +526,7 @@ export const AppModule: FlowModuleTemplateType = { }, { key: TaskResponseKeyEnum.answerText, - label: '模型回复', + label: 'AI回复', description: '将在应用完全结束后触发', valueType: FlowValueTypeEnum.string, type: FlowOutputItemTypeEnum.source, @@ -757,7 +779,7 @@ export const appTemplates: (AppItemType & { outputs: [ { key: 'answerText', - label: '模型回复', + label: 'AI回复', description: '直接响应,无需配置', type: 'hidden', targets: [] @@ -1094,7 +1116,7 @@ export const appTemplates: (AppItemType & { outputs: [ { key: 'answerText', - label: '模型回复', + label: 'AI回复', description: '直接响应,无需配置', type: 'hidden', targets: [] @@ -1401,7 +1423,7 @@ export const appTemplates: (AppItemType & { outputs: [ { key: 'answerText', - label: '模型回复', + label: 'AI回复', description: '将在 stream 回复完毕后触发', valueType: 'string', type: 'source', @@ -1863,7 +1885,7 @@ export const appTemplates: (AppItemType & { outputs: [ { key: 'answerText', - label: '模型回复', + label: 'AI回复', description: '将在 stream 回复完毕后触发', valueType: 'string', type: 'source', diff --git a/projects/app/src/constants/flow/index.ts b/projects/app/src/constants/flow/index.ts index 389ef3fe5..cbbb62841 100644 --- a/projects/app/src/constants/flow/index.ts +++ b/projects/app/src/constants/flow/index.ts @@ -13,7 +13,7 @@ export enum FlowInputItemTypeEnum { chatInput = 'chatInput', selectApp = 'selectApp', // chat special input - quoteList = 'quoteList', + aiSettings = 'aiSettings', maxToken = 'maxToken', selectChatModel = 'selectChatModel', // dataset special input diff --git a/projects/app/src/constants/model.ts b/projects/app/src/constants/model.ts index 67dab24c9..c0c6de529 100644 --- a/projects/app/src/constants/model.ts +++ b/projects/app/src/constants/model.ts @@ -1,5 +1,98 @@ import type { AppSchema } from '@/types/mongoSchema'; import type { OutLinkEditType } from '@fastgpt/support/outLink/type.d'; +import type { + LLMModelItemType, + ChatModelItemType, + FunctionModelItemType, + VectorModelItemType +} from '@/types/model'; + +export const defaultChatModels: ChatModelItemType[] = [ + { + model: 'gpt-3.5-turbo', + name: 'GPT35-4k', + price: 0, + maxToken: 4000, + quoteMaxToken: 2000, + maxTemperature: 1.2, + censor: false, + defaultSystemChatPrompt: '' + }, + { + model: 'gpt-3.5-turbo-16k', + name: 'GPT35-16k', + maxToken: 16000, + price: 0, + quoteMaxToken: 8000, + maxTemperature: 1.2, + censor: false, + defaultSystemChatPrompt: '' + }, + { + model: 'gpt-4', + name: 'GPT4-8k', + maxToken: 8000, + price: 0, + quoteMaxToken: 4000, + maxTemperature: 1.2, + censor: false, + defaultSystemChatPrompt: '' + } +]; +export const defaultQAModels: LLMModelItemType[] = [ + { + model: 'gpt-3.5-turbo-16k', + name: 'GPT35-16k', + maxToken: 16000, + price: 0 + } +]; +export const defaultCQModels: FunctionModelItemType[] = [ + { + model: 'gpt-3.5-turbo-16k', + name: 'GPT35-16k', + maxToken: 16000, + price: 0, + functionCall: true, + functionPrompt: '' + }, + { + model: 'gpt-4', + name: 'GPT4-8k', + maxToken: 8000, + price: 0, + functionCall: true, + functionPrompt: '' + } +]; +export const defaultExtractModels: FunctionModelItemType[] = [ + { + model: 'gpt-3.5-turbo-16k', + name: 'GPT35-16k', + maxToken: 16000, + price: 0, + functionCall: true, + functionPrompt: '' + } +]; +export const defaultQGModels: LLMModelItemType[] = [ + { + model: 'gpt-3.5-turbo', + name: 'GPT35-4K', + maxToken: 4000, + price: 0 + } +]; + +export const defaultVectorModels: VectorModelItemType[] = [ + { + model: 'text-embedding-ada-002', + name: 'Embedding-2', + price: 0, + defaultToken: 500, + maxToken: 3000 + } +]; export const defaultApp: AppSchema = { _id: '', diff --git a/projects/app/src/global/common/api/systemRes.d.ts b/projects/app/src/global/common/api/systemRes.d.ts index 7054569a6..a5d9d78af 100644 --- a/projects/app/src/global/common/api/systemRes.d.ts +++ b/projects/app/src/global/common/api/systemRes.d.ts @@ -1,14 +1,17 @@ -import { - type QAModelItemType, - type ChatModelItemType, - type VectorModelItemType, - FunctionModelItemType +import type { + ChatModelItemType, + FunctionModelItemType, + LLMModelItemType, + VectorModelItemType } from '@/types/model'; import type { FeConfigsType } from '@fastgpt/common/type/index.d'; export type InitDateResponse = { chatModels: ChatModelItemType[]; - qaModel: QAModelItemType; + qaModels: LLMModelItemType[]; + cqModels: FunctionModelItemType[]; + extractModels: FunctionModelItemType[]; + qgModels: LLMModelItemType[]; vectorModels: VectorModelItemType[]; feConfigs: FeConfigsType; priceMd: string; diff --git a/projects/app/src/global/core/prompt/AIChat.ts b/projects/app/src/global/core/prompt/AIChat.ts index 6fabd9b6d..66fa39f7a 100644 --- a/projects/app/src/global/core/prompt/AIChat.ts +++ b/projects/app/src/global/core/prompt/AIChat.ts @@ -1,5 +1,23 @@ -export const defaultQuoteTemplate = `{instruction:"{{q}}",output:"{{a}}"}`; -export const defaultQuotePrompt = `你的背景知识: +import { PromptTemplateItem } from '@fastgpt/core/ai/type.d'; + +export const Prompt_QuoteTemplateList: PromptTemplateItem[] = [ + { + title: '标准模板', + desc: '包含 q 和 a 两个变量的标准模板', + value: `{instruction:"{{q}}",output:"{{a}}"}` + }, + { + title: '全部变量', + desc: '包含 q 和 a 两个变量的标准模板', + value: `{instruction:"{{q}}",output:"{{a}}",source:"{{source}}",file_id:"{{file_id}}",index:"{{index}}"}` + } +]; + +export const Prompt_QuotePromptList: PromptTemplateItem[] = [ + { + title: '标准模式', + desc: '', + value: `你的背景知识: """ {{quote}} """ @@ -7,4 +25,19 @@ export const defaultQuotePrompt = `你的背景知识: 1. 背景知识是最新的,其中 instruction 是相关介绍,output 是预期回答或补充。 2. 使用背景知识回答问题。 3. 背景知识无法满足问题时,你需严谨的回答问题。 -我的问题是:"{{question}}"`; +我的问题是:"{{question}}"` + }, + { + title: '严格模式', + desc: '', + value: `你的背景知识: +""" +{{quote}} +""" +对话要求: +1. 背景知识是最新的,其中 instruction 是相关介绍,output 是预期回答或补充。 +2. 使用背景知识回答问题。 +3. 背景知识无法满足问题时,你需要回答:我不清楚关于xxx的内容。 +我的问题是:"{{question}}"` + } +]; diff --git a/projects/app/src/pages/_error.tsx b/projects/app/src/pages/_error.tsx index 43fcd60e3..d75ac6617 100644 --- a/projects/app/src/pages/_error.tsx +++ b/projects/app/src/pages/_error.tsx @@ -32,8 +32,6 @@ function Error() { } export async function getServerSideProps(context: any) { - console.log('[render error]: ', context); - return { props: { ...(await serviceSideProps(context)) } }; diff --git a/projects/app/src/pages/api/chat/chatTest.ts b/projects/app/src/pages/api/chat/chatTest.ts index 84c79a8c3..a16b01c63 100644 --- a/projects/app/src/pages/api/chat/chatTest.ts +++ b/projects/app/src/pages/api/chat/chatTest.ts @@ -3,7 +3,7 @@ import { connectToDatabase } from '@/service/mongo'; import { authUser } from '@fastgpt/support/user/auth'; import { sseErrRes } from '@/service/response'; import { sseResponseEventEnum } from '@/constants/chat'; -import { sseResponse } from '@/service/utils/tools'; +import { responseWrite } from '@fastgpt/common/tools/stream'; import { AppModuleItemType } from '@/types/app'; import { dispatchModules } from '@/pages/api/v1/chat/completions'; import { pushChatBill } from '@/service/common/bill/push'; @@ -59,12 +59,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) detail: true }); - sseResponse({ + responseWrite({ res, event: sseResponseEventEnum.answer, data: '[DONE]' }); - sseResponse({ + responseWrite({ res, event: sseResponseEventEnum.appStreamResponse, data: JSON.stringify(responseData) diff --git a/projects/app/src/pages/api/chat/init.ts b/projects/app/src/pages/api/chat/init.ts index 8aa39d8f7..a7eb86b6a 100644 --- a/projects/app/src/pages/api/chat/init.ts +++ b/projects/app/src/pages/api/chat/init.ts @@ -6,7 +6,8 @@ import { authUser } from '@fastgpt/support/user/auth'; import { ChatItemType } from '@/types/chat'; import { authApp } from '@/service/utils/auth'; import type { ChatSchema } from '@/types/mongoSchema'; -import { getChatModelNameList, getGuideModule } from '@/components/ChatBox/utils'; +import { getGuideModule } from '@/components/ChatBox/utils'; +import { getChatModelNameListByModules } from '@/service/core/app/module'; import { TaskResponseKeyEnum } from '@/constants/chat'; /* 初始化我的聊天框,需要身份验证 */ @@ -83,7 +84,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) appId, app: { userGuideModule: getGuideModule(app.modules), - chatModels: getChatModelNameList(app.modules), + chatModels: getChatModelNameListByModules(app.modules), name: app.name, avatar: app.avatar, intro: app.intro, diff --git a/projects/app/src/pages/api/common/bill/createTrainingBill.ts b/projects/app/src/pages/api/common/bill/createTrainingBill.ts index 0e9db615b..8f51b1479 100644 --- a/projects/app/src/pages/api/common/bill/createTrainingBill.ts +++ b/projects/app/src/pages/api/common/bill/createTrainingBill.ts @@ -12,6 +12,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const { userId } = await authUser({ req, authToken: true, authApiKey: true }); + const qaModel = global.qaModels[0]; + const { _id } = await Bill.create({ userId, appName: name, @@ -25,7 +27,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }, { moduleName: 'QA 拆分', - model: global.qaModel.name, + model: qaModel?.name, amount: 0, tokenLen: 0 } diff --git a/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts b/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts index 0cf5238e7..b0d0721b9 100644 --- a/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts +++ b/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts @@ -4,7 +4,6 @@ import { connectToDatabase } from '@/service/mongo'; import { authUser } from '@fastgpt/support/user/auth'; import type { CreateQuestionGuideParams } from '@/global/core/api/aiReq.d'; import { pushQuestionGuideBill } from '@/service/common/bill/push'; -import { defaultQGModel } from '@/pages/api/system/getInitData'; import { createQuestionGuide } from '@fastgpt/core/ai/functions/createQuestionGuide'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -23,9 +22,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< throw new Error('user not found'); } + const qgModel = global.qgModels[0]; + const { result, tokens } = await createQuestionGuide({ messages, - model: (global.qgModel || defaultQGModel).model + model: qgModel.model }); jsonRes(res, { diff --git a/projects/app/src/pages/api/core/dataset/allDataset.ts b/projects/app/src/pages/api/core/dataset/allDataset.ts index 3ded3987a..3c6141748 100644 --- a/projects/app/src/pages/api/core/dataset/allDataset.ts +++ b/projects/app/src/pages/api/core/dataset/allDataset.ts @@ -3,7 +3,7 @@ import { jsonRes } from '@/service/response'; import { connectToDatabase } from '@/service/mongo'; import { MongoDataset } from '@fastgpt/core/dataset/schema'; import { authUser } from '@fastgpt/support/user/auth'; -import { getVectorModel } from '@/service/utils/data'; +import { getVectorModel } from '@/service/core/ai/model'; import type { DatasetsItemType } from '@/types/core/dataset'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { diff --git a/projects/app/src/pages/api/core/dataset/data/delDataById.ts b/projects/app/src/pages/api/core/dataset/data/delDataById.ts index 30cd89b9f..163cd2b7e 100644 --- a/projects/app/src/pages/api/core/dataset/data/delDataById.ts +++ b/projects/app/src/pages/api/core/dataset/data/delDataById.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { authUser } from '@fastgpt/support/user/auth'; import { PgClient } from '@/service/pg'; -import { withNextCors } from '@/service/utils/tools'; +import { withNextCors } from '@fastgpt/common/tools/nextjs'; import { PgDatasetTableName } from '@/constants/plugin'; import { connectToDatabase } from '@/service/mongo'; diff --git a/projects/app/src/pages/api/core/dataset/data/exportAll.ts b/projects/app/src/pages/api/core/dataset/data/exportAll.ts index 2ccb95f26..89f08eaa9 100644 --- a/projects/app/src/pages/api/core/dataset/data/exportAll.ts +++ b/projects/app/src/pages/api/core/dataset/data/exportAll.ts @@ -8,7 +8,7 @@ import { findAllChildrenIds } from '../delete'; import QueryStream from 'pg-query-stream'; import { PgClient } from '@/service/pg'; import { addLog } from '@/service/utils/tools'; -import { responseWriteController } from '@/service/common/stream'; +import { responseWriteController } from '@fastgpt/common/tools/stream'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { diff --git a/projects/app/src/pages/api/core/dataset/data/insertData.ts b/projects/app/src/pages/api/core/dataset/data/insertData.ts index a0f01fb71..83e2ef4a8 100644 --- a/projects/app/src/pages/api/core/dataset/data/insertData.ts +++ b/projects/app/src/pages/api/core/dataset/data/insertData.ts @@ -7,10 +7,10 @@ import { jsonRes } from '@/service/response'; import { connectToDatabase } from '@/service/mongo'; import { authDataset } from '@/service/utils/auth'; import { authUser } from '@fastgpt/support/user/auth'; -import { withNextCors } from '@/service/utils/tools'; +import { withNextCors } from '@fastgpt/common/tools/nextjs'; import { PgDatasetTableName } from '@/constants/plugin'; import { insertData2Dataset, PgClient } from '@/service/pg'; -import { getVectorModel } from '@/service/utils/data'; +import { getVectorModel } from '@/service/core/ai/model'; import { getVector } from '@/pages/api/openapi/plugin/vector'; import { DatasetDataItemType } from '@/types/core/dataset/data'; import { countPromptTokens } from '@/utils/common/tiktoken'; diff --git a/projects/app/src/pages/api/core/dataset/data/pushData.ts b/projects/app/src/pages/api/core/dataset/data/pushData.ts index 5c24be68e..63d45ff9f 100644 --- a/projects/app/src/pages/api/core/dataset/data/pushData.ts +++ b/projects/app/src/pages/api/core/dataset/data/pushData.ts @@ -5,15 +5,15 @@ import { connectToDatabase, TrainingData } from '@/service/mongo'; import { MongoDataset } from '@fastgpt/core/dataset/schema'; import { authUser } from '@fastgpt/support/user/auth'; import { authDataset } from '@/service/utils/auth'; -import { withNextCors } from '@/service/utils/tools'; +import { withNextCors } from '@fastgpt/common/tools/nextjs'; import { TrainingModeEnum } from '@/constants/plugin'; import { startQueue } from '@/service/utils/tools'; -import { getVectorModel } from '@/service/utils/data'; import { DatasetDataItemType } from '@/types/core/dataset/data'; import { countPromptTokens } from '@/utils/common/tiktoken'; import type { PushDataResponse } from '@/global/core/api/datasetRes.d'; import type { PushDataProps } from '@/global/core/api/datasetReq.d'; import { authFileIdValid } from '@/service/dataset/auth'; +import { getVectorModel } from '@/service/core/ai/model'; const modeMap = { [TrainingModeEnum.index]: true, @@ -71,7 +71,7 @@ export async function pushDataToKb({ if (mode === TrainingModeEnum.index) { const vectorModel = (await MongoDataset.findById(kbId, 'vectorModel'))?.vectorModel; - return getVectorModel(vectorModel || global.vectorModels[0].model); + return getVectorModel(vectorModel); } return global.vectorModels[0]; })() @@ -79,7 +79,7 @@ export async function pushDataToKb({ const modeMaxToken = { [TrainingModeEnum.index]: vectorModel.maxToken * 1.5, - [TrainingModeEnum.qa]: global.qaModel.maxToken * 0.8 + [TrainingModeEnum.qa]: global.qaModels[0].maxToken * 0.8 }; // filter repeat or equal content diff --git a/projects/app/src/pages/api/core/dataset/data/updateData.ts b/projects/app/src/pages/api/core/dataset/data/updateData.ts index 12cca415c..d7548bb10 100644 --- a/projects/app/src/pages/api/core/dataset/data/updateData.ts +++ b/projects/app/src/pages/api/core/dataset/data/updateData.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { authUser } from '@fastgpt/support/user/auth'; import { PgClient } from '@/service/pg'; -import { withNextCors } from '@/service/utils/tools'; +import { withNextCors } from '@fastgpt/common/tools/nextjs'; import { connectToDatabase } from '@/service/mongo'; import { MongoDataset } from '@fastgpt/core/dataset/schema'; import { getVector } from '@/pages/api/openapi/plugin/vector'; diff --git a/projects/app/src/pages/api/core/dataset/detail.ts b/projects/app/src/pages/api/core/dataset/detail.ts index 75a4d6aae..c61592e32 100644 --- a/projects/app/src/pages/api/core/dataset/detail.ts +++ b/projects/app/src/pages/api/core/dataset/detail.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { connectToDatabase } from '@/service/mongo'; import { authUser } from '@fastgpt/support/user/auth'; -import { getVectorModel } from '@/service/utils/data'; +import { getVectorModel } from '@/service/core/ai/model'; import { MongoDataset } from '@fastgpt/core/dataset/schema'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { diff --git a/projects/app/src/pages/api/core/dataset/list.ts b/projects/app/src/pages/api/core/dataset/list.ts index 8d21a5988..accf5f580 100644 --- a/projects/app/src/pages/api/core/dataset/list.ts +++ b/projects/app/src/pages/api/core/dataset/list.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { connectToDatabase } from '@/service/mongo'; import { authUser } from '@fastgpt/support/user/auth'; -import { getVectorModel } from '@/service/utils/data'; +import { getVectorModel } from '@/service/core/ai/model'; import type { DatasetsItemType } from '@/types/core/dataset'; import { DatasetTypeEnum } from '@fastgpt/core/dataset/constant'; import { MongoDataset } from '@fastgpt/core/dataset/schema'; diff --git a/projects/app/src/pages/api/core/dataset/searchTest.ts b/projects/app/src/pages/api/core/dataset/searchTest.ts index 399283137..32aa72883 100644 --- a/projects/app/src/pages/api/core/dataset/searchTest.ts +++ b/projects/app/src/pages/api/core/dataset/searchTest.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { authUser } from '@fastgpt/support/user/auth'; import { PgClient } from '@/service/pg'; -import { withNextCors } from '@/service/utils/tools'; +import { withNextCors } from '@fastgpt/common/tools/nextjs'; import { getVector } from '../../openapi/plugin/vector'; import { PgDatasetTableName } from '@/constants/plugin'; import { MongoDataset } from '@fastgpt/core/dataset/schema'; diff --git a/projects/app/src/pages/api/openapi/plugin/vector.ts b/projects/app/src/pages/api/openapi/plugin/vector.ts index 7f6ea26fc..0987b95f6 100644 --- a/projects/app/src/pages/api/openapi/plugin/vector.ts +++ b/projects/app/src/pages/api/openapi/plugin/vector.ts @@ -1,7 +1,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { authBalanceByUid, authUser } from '@fastgpt/support/user/auth'; -import { withNextCors } from '@/service/utils/tools'; +import { withNextCors } from '@fastgpt/common/tools/nextjs'; import { getAIApi } from '@fastgpt/core/ai/config'; import { pushGenerateVectorBill } from '@/service/common/bill/push'; import { connectToDatabase } from '@/service/mongo'; diff --git a/projects/app/src/pages/api/openapi/v1/chat/completions.ts b/projects/app/src/pages/api/openapi/v1/chat/completions.ts index 1b20584fd..2a705e721 100644 --- a/projects/app/src/pages/api/openapi/v1/chat/completions.ts +++ b/projects/app/src/pages/api/openapi/v1/chat/completions.ts @@ -1,5 +1,5 @@ import type { NextApiRequest, NextApiResponse } from 'next'; -import { withNextCors } from '@/service/utils/tools'; +import { withNextCors } from '@fastgpt/common/tools/nextjs'; import ChatCompletion from '@/pages/api/v1/chat/completions'; export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse) { diff --git a/projects/app/src/pages/api/support/outLink/init.ts b/projects/app/src/pages/api/support/outLink/init.ts index 6f7704047..593c49192 100644 --- a/projects/app/src/pages/api/support/outLink/init.ts +++ b/projects/app/src/pages/api/support/outLink/init.ts @@ -6,8 +6,9 @@ import { MongoUser } from '@fastgpt/support/user/schema'; import type { InitShareChatResponse } from '@/global/support/api/outLinkRes.d'; import { authApp } from '@/service/utils/auth'; import { HUMAN_ICON } from '@/constants/chat'; -import { getChatModelNameList, getGuideModule } from '@/components/ChatBox/utils'; +import { getGuideModule } from '@/components/ChatBox/utils'; import { authShareChatInit } from '@fastgpt/support/outLink/auth'; +import { getChatModelNameListByModules } from '@/service/core/app/module'; /* init share chat window */ export default async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -51,7 +52,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) userAvatar: user?.avatar || HUMAN_ICON, app: { userGuideModule: getGuideModule(app.modules), - chatModels: getChatModelNameList(app.modules), + chatModels: getChatModelNameListByModules(app.modules), name: app.name, avatar: app.avatar, intro: app.intro diff --git a/projects/app/src/pages/api/system/getInitData.ts b/projects/app/src/pages/api/system/getInitData.ts index e39965368..a2f9ae9e7 100644 --- a/projects/app/src/pages/api/system/getInitData.ts +++ b/projects/app/src/pages/api/system/getInitData.ts @@ -4,10 +4,23 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { readFileSync } from 'fs'; import type { InitDateResponse } from '@/global/common/api/systemRes'; -import type { VectorModelItemType, FunctionModelItemType } from '@/types/model'; import { formatPrice } from '@fastgpt/common/bill'; import { getTikTokenEnc } from '@/utils/common/tiktoken'; import { initHttpAgent } from '@fastgpt/core/init'; +import { + defaultChatModels, + defaultQAModels, + defaultCQModels, + defaultExtractModels, + defaultQGModels, + defaultVectorModels +} from '@/constants/model'; +import { + ChatModelItemType, + FunctionModelItemType, + LLMModelItemType, + VectorModelItemType +} from '@/types/model'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { getInitConfig(); @@ -17,7 +30,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) data: { feConfigs: global.feConfigs, chatModels: global.chatModels, - qaModel: global.qaModel, + qaModels: global.qaModels, + cqModels: global.cqModels, + extractModels: global.extractModels, + qgModels: global.qgModels, vectorModels: global.vectorModels, priceMd: global.priceMd, systemVersion: global.systemVersion || '0.0.0' @@ -42,72 +58,6 @@ const defaultFeConfigs: FeConfigsType = { }, scripts: [] }; -const defaultChatModels = [ - { - model: 'gpt-3.5-turbo', - name: 'GPT35-4k', - contextMaxToken: 4000, - quoteMaxToken: 2400, - maxTemperature: 1.2, - price: 0 - }, - { - model: 'gpt-3.5-turbo-16k', - name: 'GPT35-16k', - contextMaxToken: 16000, - quoteMaxToken: 8000, - maxTemperature: 1.2, - price: 0 - }, - { - model: 'gpt-4', - name: 'GPT4-8k', - contextMaxToken: 8000, - quoteMaxToken: 4000, - maxTemperature: 1.2, - price: 0 - } -]; -const defaultQAModel = { - model: 'gpt-3.5-turbo-16k', - name: 'GPT35-16k', - maxToken: 16000, - price: 0 -}; -export const defaultExtractModel: FunctionModelItemType = { - model: 'gpt-3.5-turbo-16k', - name: 'GPT35-16k', - maxToken: 16000, - price: 0, - prompt: '', - functionCall: true -}; -export const defaultCQModel: FunctionModelItemType = { - model: 'gpt-3.5-turbo-16k', - name: 'GPT35-16k', - maxToken: 16000, - price: 0, - prompt: '', - functionCall: true -}; -export const defaultQGModel: FunctionModelItemType = { - model: 'gpt-3.5-turbo', - name: 'FastAI-4k', - maxToken: 4000, - price: 1.5, - prompt: '', - functionCall: false -}; - -const defaultVectorModels: VectorModelItemType[] = [ - { - model: 'text-embedding-ada-002', - name: 'Embedding-2', - price: 0, - defaultToken: 500, - maxToken: 3000 - } -]; export function initGlobal() { // init tikToken @@ -127,7 +77,16 @@ export function getInitConfig() { const filename = process.env.NODE_ENV === 'development' ? 'data/config.local.json' : '/app/data/config.json'; - const res = JSON.parse(readFileSync(filename, 'utf-8')); + const res = JSON.parse(readFileSync(filename, 'utf-8')) as { + FeConfig: FeConfigsType; + SystemParams: SystemEnvType; + ChatModels: ChatModelItemType[]; + QAModels: LLMModelItemType[]; + CQModels: FunctionModelItemType[]; + ExtractModels: FunctionModelItemType[]; + QGModels: LLMModelItemType[]; + VectorModels: VectorModelItemType[]; + }; console.log(`System Version: ${global.systemVersion}`); @@ -137,11 +96,13 @@ export function getInitConfig() { ? { ...defaultSystemEnv, ...res.SystemParams } : defaultSystemEnv; global.feConfigs = res.FeConfig ? { ...defaultFeConfigs, ...res.FeConfig } : defaultFeConfigs; + global.chatModels = res.ChatModels || defaultChatModels; - global.qaModel = res.QAModel || defaultQAModel; - global.extractModel = res.ExtractModel || defaultExtractModel; - global.cqModel = res.CQModel || defaultCQModel; - global.qgModel = res.QGModel || defaultQGModel; + global.qaModels = res.QAModels || defaultQAModels; + global.cqModels = res.CQModels || defaultCQModels; + global.extractModels = res.ExtractModels || defaultExtractModels; + global.qgModels = res.QGModels || defaultQGModels; + global.vectorModels = res.VectorModels || defaultVectorModels; } catch (error) { setDefaultData(); @@ -152,13 +113,27 @@ export function getInitConfig() { export function setDefaultData() { global.systemEnv = defaultSystemEnv; global.feConfigs = defaultFeConfigs; + global.chatModels = defaultChatModels; - global.qaModel = defaultQAModel; + global.qaModels = defaultQAModels; + global.cqModels = defaultCQModels; + global.extractModels = defaultExtractModels; + global.qgModels = defaultQGModels; + global.vectorModels = defaultVectorModels; - global.extractModel = defaultExtractModel; - global.cqModel = defaultCQModel; - global.qgModel = defaultQGModel; global.priceMd = ''; + + console.log('use default config'); + console.log({ + feConfigs: defaultFeConfigs, + systemEnv: defaultSystemEnv, + chatModels: defaultChatModels, + qaModels: defaultQAModels, + cqModels: defaultCQModels, + extractModels: defaultExtractModels, + qgModels: defaultQGModels, + vectorModels: defaultVectorModels + }); } export function getSystemVersion() { @@ -187,10 +162,18 @@ ${global.vectorModels ${global.chatModels ?.map((item) => `| 对话-${item.name} | ${formatPrice(item.price, 1000)} |`) .join('\n')} -| 文件QA拆分 | ${formatPrice(global.qaModel?.price, 1000)} | -| 高级编排 - 问题分类 | ${formatPrice(global.cqModel?.price, 1000)} | -| 高级编排 - 内容提取 | ${formatPrice(global.extractModel?.price, 1000)} | -| 下一步指引 | ${formatPrice(global.qgModel?.price, 1000)} | +${global.qaModels + ?.map((item) => `| 文件QA拆分-${item.name} | ${formatPrice(item.price, 1000)} |`) + .join('\n')} +${global.cqModels + ?.map((item) => `| 问题分类-${item.name} | ${formatPrice(item.price, 1000)} |`) + .join('\n')} +${global.extractModels + ?.map((item) => `| 内容提取-${item.name} | ${formatPrice(item.price, 1000)} |`) + .join('\n')} +${global.qgModels + ?.map((item) => `| 下一步指引-${item.name} | ${formatPrice(item.price, 1000)} |`) + .join('\n')} `; console.log(global.priceMd); } diff --git a/projects/app/src/pages/api/user/account/loginByPassword.ts b/projects/app/src/pages/api/user/account/loginByPassword.ts index 9b1dc7c69..482d2e452 100644 --- a/projects/app/src/pages/api/user/account/loginByPassword.ts +++ b/projects/app/src/pages/api/user/account/loginByPassword.ts @@ -2,8 +2,8 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { MongoUser } from '@fastgpt/support/user/schema'; -import { setCookie } from '@/service/utils/tools'; -import { generateToken } from '@fastgpt/support/user/tools'; +import { setCookie } from '@fastgpt/support/user/auth'; +import { generateToken } from '@fastgpt/support/user/auth'; import { connectToDatabase } from '@/service/mongo'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { diff --git a/projects/app/src/pages/api/user/account/loginout.ts b/projects/app/src/pages/api/user/account/loginout.ts index 3920f0d36..03c4be8d2 100644 --- a/projects/app/src/pages/api/user/account/loginout.ts +++ b/projects/app/src/pages/api/user/account/loginout.ts @@ -1,7 +1,7 @@ // Next.js API route support: https://nextjs.org/docs/api-routes/introduction import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; -import { clearCookie } from '@/service/utils/tools'; +import { clearCookie } from '@fastgpt/support/user/auth'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { diff --git a/projects/app/src/pages/api/v1/chat/completions.ts b/projects/app/src/pages/api/v1/chat/completions.ts index 6d80644e5..39d785f42 100644 --- a/projects/app/src/pages/api/v1/chat/completions.ts +++ b/projects/app/src/pages/api/v1/chat/completions.ts @@ -3,7 +3,8 @@ import { authApp } from '@/service/utils/auth'; import { authUser } from '@fastgpt/support/user/auth'; import { AuthUserTypeEnum } from '@fastgpt/support/user/auth'; import { sseErrRes, jsonRes } from '@/service/response'; -import { addLog, withNextCors } from '@/service/utils/tools'; +import { addLog } from '@/service/utils/tools'; +import { withNextCors } from '@fastgpt/common/tools/nextjs'; import { ChatRoleEnum, ChatSourceEnum, sseResponseEventEnum } from '@/constants/chat'; import { dispatchHistory, @@ -21,7 +22,7 @@ import type { MessageItemType } from '@/types/core/chat/type'; import { gptMessage2ChatType, textAdaptGptResponse } from '@/utils/adapt'; import { getChatHistory } from './getHistory'; import { saveChat } from '@/service/utils/chat/saveChat'; -import { sseResponse } from '@/service/utils/tools'; +import { responseWrite } from '@fastgpt/common/tools/stream'; import { TaskResponseKeyEnum } from '@/constants/chat'; import { FlowModuleTypeEnum, initModuleType } from '@/constants/flow'; import { AppModuleItemType, RunningModuleItemType } from '@/types/app'; @@ -217,7 +218,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex const feResponseData = isOwner ? responseData : selectShareResponse({ responseData }); if (stream) { - sseResponse({ + responseWrite({ res, event: detail ? sseResponseEventEnum.answer : undefined, data: textAdaptGptResponse({ @@ -225,14 +226,14 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex finish_reason: 'stop' }) }); - sseResponse({ + responseWrite({ res, event: detail ? sseResponseEventEnum.answer : undefined, data: '[DONE]' }); if (responseDetail && detail) { - sseResponse({ + responseWrite({ res, event: sseResponseEventEnum.appStreamResponse, data: JSON.stringify(feResponseData) @@ -323,13 +324,16 @@ export async function dispatchModules({ let chatAnswerText = ''; // AI answer let runningTime = Date.now(); - function pushStore({ - answerText = '', - responseData - }: { - answerText?: string; - responseData?: ChatHistoryItemResType | ChatHistoryItemResType[]; - }) { + function pushStore( + { inputs = [] }: RunningModuleItemType, + { + answerText = '', + responseData + }: { + answerText?: string; + responseData?: ChatHistoryItemResType | ChatHistoryItemResType[]; + } + ) { const time = Date.now(); if (responseData) { if (Array.isArray(responseData)) { @@ -342,7 +346,12 @@ export async function dispatchModules({ } } runningTime = time; - chatAnswerText += answerText; + + const isResponseAnswerText = + inputs.find((item) => item.key === SystemInputEnum.isResponseAnswerText)?.value ?? true; + if (isResponseAnswerText) { + chatAnswerText += answerText; + } } function moduleInput( module: RunningModuleItemType, @@ -376,7 +385,7 @@ export async function dispatchModules({ module: RunningModuleItemType, result: Record = {} ): Promise { - pushStore(result); + pushStore(module, result); return Promise.all( module.outputs.map((outputItem) => { if (result[outputItem.key] === undefined) return; @@ -505,7 +514,7 @@ export function responseStatus({ name?: string; }) { if (!name) return; - sseResponse({ + responseWrite({ res, event: sseResponseEventEnum.moduleStatus, data: JSON.stringify({ diff --git a/projects/app/src/pages/app/detail/components/AIChatSettingsModal.tsx b/projects/app/src/pages/app/detail/components/AIChatSettingsModal.tsx index 27c5b78fd..0fe128c77 100644 --- a/projects/app/src/pages/app/detail/components/AIChatSettingsModal.tsx +++ b/projects/app/src/pages/app/detail/components/AIChatSettingsModal.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo, useState } from 'react'; import MyModal from '@/components/MyModal'; import { useTranslation } from 'react-i18next'; import { EditFormType } from '@/utils/app'; @@ -11,43 +11,65 @@ import { Link, ModalBody, ModalFooter, + Switch, Textarea } from '@chakra-ui/react'; import MyTooltip from '@/components/MyTooltip'; import { QuestionOutlineIcon } from '@chakra-ui/icons'; -import { defaultQuotePrompt, defaultQuoteTemplate } from '@/global/core/prompt/AIChat'; -import { feConfigs } from '@/web/common/store/static'; +import { Prompt_QuotePromptList, Prompt_QuoteTemplateList } from '@/global/core/prompt/AIChat'; +import { chatModelList, feConfigs } from '@/web/common/store/static'; +import MySlider from '@/components/Slider'; +import { SystemInputEnum } from '@/constants/app'; +import dynamic from 'next/dynamic'; +import { PromptTemplateItem } from '@fastgpt/core/ai/type'; + +const PromptTemplate = dynamic(() => import('@/components/PromptTemplate')); const AIChatSettingsModal = ({ + isAdEdit, onClose, onSuccess, defaultData }: { + isAdEdit?: boolean; onClose: () => void; onSuccess: (e: EditFormType['chatModel']) => void; defaultData: EditFormType['chatModel']; }) => { const { t } = useTranslation(); + const [refresh, setRefresh] = useState(false); - const { register, handleSubmit } = useForm({ + const { register, handleSubmit, getValues, setValue } = useForm({ defaultValues: defaultData }); + const [selectTemplateData, setSelectTemplateData] = useState<{ + title: string; + key: 'quoteTemplate' | 'quotePrompt'; + templates: PromptTemplateItem[]; + }>(); + + const tokenLimit = useMemo(() => { + return chatModelList.find((item) => item.model === getValues('model'))?.maxToken || 4000; + }, [getValues, refresh]); + const LabelStyles: BoxProps = { - fontWeight: 'bold', - mb: 1, fontSize: ['sm', 'md'] }; + const selectTemplateBtn: BoxProps = { + color: 'myBlue.600', + cursor: 'pointer' + }; return ( - {t('app.Quote Prompt Settings')} + {t('app.AI Settings')} {feConfigs?.show_doc && ( } + isCentered w={'700px'} + h={['90vh', 'auto']} > - + + {isAdEdit && ( + + + 返回AI内容 + + + { + const value = e.target.checked; + setValue(SystemInputEnum.isResponseAnswerText, value); + setRefresh((state) => !state); + }} + /> + + + )} + + + 温度 + + + { + setValue('temperature', e); + setRefresh(!refresh); + }} + /> + + + + + 回复上限 + + + { + setValue('maxToken', val); + setRefresh(!refresh); + }} + /> + + - + 引用内容模板 - + + + setSelectTemplateData({ + title: '选择引用内容模板', + key: 'quoteTemplate', + templates: Prompt_QuoteTemplateList + }) + } + > + 选择模板 + +