v4.6 -1 (#459)
This commit is contained in:
parent
661ee79943
commit
8bb5588305
2
.github/ISSUE_TEMPLATE/bugs.md
vendored
2
.github/ISSUE_TEMPLATE/bugs.md
vendored
@ -11,7 +11,7 @@ assignees: ''
|
|||||||
[//]: # '方框内填 x 表示打钩'
|
[//]: # '方框内填 x 表示打钩'
|
||||||
|
|
||||||
- [ ] 我已确认目前没有类似 issue
|
- [ ] 我已确认目前没有类似 issue
|
||||||
- [ ] 我已完整查看过项目 README,以及[项目文档](https://doc.fastgpt.run/docs/intro/)
|
- [ ] 我已完整查看过项目 README,以及[项目文档](https://doc.fastgpt.in/docs/intro/)
|
||||||
- [ ] 我使用了自己的 key,并确认我的 key 是可正常使用的
|
- [ ] 我使用了自己的 key,并确认我的 key 是可正常使用的
|
||||||
- [ ] 我理解并愿意跟进此 issue,协助测试和提供反馈
|
- [ ] 我理解并愿意跟进此 issue,协助测试和提供反馈
|
||||||
- [x] 我理解并认可上述内容,并理解项目维护者精力有限,**不遵循规则的 issue 可能会被无视或直接关闭**
|
- [x] 我理解并认可上述内容,并理解项目维护者精力有限,**不遵循规则的 issue 可能会被无视或直接关闭**
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,5 +1,5 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: 微信交流群
|
- name: 微信交流群
|
||||||
url: https://doc.fastgpt.run/wechat-fastgpt.webp
|
url: https://doc.fastgpt.in/wechat-fastgpt.webp
|
||||||
about: FastGPT 全是问题群
|
about: FastGPT 全是问题群
|
||||||
|
|||||||
@ -17,10 +17,10 @@ FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开
|
|||||||
<a href="https://fastgpt.run/">
|
<a href="https://fastgpt.run/">
|
||||||
<img height="21" src="https://img.shields.io/badge/在线使用-d4eaf7?style=flat-square&logo=spoj&logoColor=7d09f1" alt="cloud">
|
<img height="21" src="https://img.shields.io/badge/在线使用-d4eaf7?style=flat-square&logo=spoj&logoColor=7d09f1" alt="cloud">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://doc.fastgpt.run/docs/intro">
|
<a href="https://doc.fastgpt.in/docs/intro">
|
||||||
<img height="21" src="https://img.shields.io/badge/相关文档-7d09f1?style=flat-square" alt="document">
|
<img height="21" src="https://img.shields.io/badge/相关文档-7d09f1?style=flat-square" alt="document">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://doc.fastgpt.run/docs/development">
|
<a href="https://doc.fastgpt.in/docs/development">
|
||||||
<img height="21" src="https://img.shields.io/badge/本地开发-%23d4eaf7?style=flat-square&logo=xcode&logoColor=7d09f1" alt="development">
|
<img height="21" src="https://img.shields.io/badge/本地开发-%23d4eaf7?style=flat-square&logo=xcode&logoColor=7d09f1" alt="development">
|
||||||
</a>
|
</a>
|
||||||
<a href="/#-%E7%9B%B8%E5%85%B3%E9%A1%B9%E7%9B%AE">
|
<a href="/#-%E7%9B%B8%E5%85%B3%E9%A1%B9%E7%9B%AE">
|
||||||
@ -119,7 +119,7 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b
|
|||||||
|
|
||||||
## 🤝 第三方生态
|
## 🤝 第三方生态
|
||||||
|
|
||||||
- [OnWeChat 个人微信/企微机器人](https://doc.fastgpt.run/docs/use-cases/onwechat/)
|
- [OnWeChat 个人微信/企微机器人](https://doc.fastgpt.in/docs/use-cases/onwechat/)
|
||||||
|
|
||||||
## 🌟 Star History
|
## 🌟 Star History
|
||||||
|
|
||||||
@ -132,4 +132,4 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b
|
|||||||
1. 允许作为后台服务直接商用,但不允许提供 SaaS 服务。
|
1. 允许作为后台服务直接商用,但不允许提供 SaaS 服务。
|
||||||
2. 未经商业授权,任何形式的商用服务均需保留相关版权信息。
|
2. 未经商业授权,任何形式的商用服务均需保留相关版权信息。
|
||||||
3. 完整请查看 [FastGPT Open Source License](./LICENSE)
|
3. 完整请查看 [FastGPT Open Source License](./LICENSE)
|
||||||
4. 联系方式:yujinlong@sealos.io,[点击查看商业版定价策略](https://doc.fastgpt.run/docs/commercial)
|
4. 联系方式:yujinlong@sealos.io,[点击查看商业版定价策略](https://doc.fastgpt.in/docs/commercial)
|
||||||
|
|||||||
@ -21,62 +21,61 @@ weight: 520
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"SystemParams": {
|
"SystemParams": {
|
||||||
|
"pluginBaseUrl": "", // 商业版接口地址
|
||||||
"vectorMaxProcess": 15, // 向量生成最大进程,结合数据库性能和 key 来设置
|
"vectorMaxProcess": 15, // 向量生成最大进程,结合数据库性能和 key 来设置
|
||||||
"qaMaxProcess": 15, // QA 生成最大进程,结合数据库性能和 key 来设置
|
"qaMaxProcess": 15, // QA 生成最大进程,结合数据库性能和 key 来设置
|
||||||
"pgHNSWEfSearch": 100 // pg vector 索引参数,越大精度高但速度慢
|
"pgHNSWEfSearch": 100 // pg vector 索引参数,越大精度高但速度慢
|
||||||
},
|
},
|
||||||
"ChatModels": [
|
"ChatModels": [
|
||||||
{
|
{
|
||||||
"model": "gpt-3.5-turbo", // 实际调用的模型
|
"model": "gpt-3.5-turbo-1106",
|
||||||
"name": "GPT35-4k", // 展示的名字
|
"name": "GPT35-1106",
|
||||||
"maxToken": 4000, // 最大token,均按 gpt35 计算
|
"price": 0, // 除以 100000 后等于1个token的价格
|
||||||
"quoteMaxToken": 2000, // 引用内容最大 token
|
"maxContext": 16000, // 最大上下文长度
|
||||||
"maxTemperature": 1.2, // 最大温度
|
"maxResponse": 4000, // 最大回复长度
|
||||||
"price": 0,
|
"quoteMaxToken": 2000, // 最大引用内容长度
|
||||||
|
"maxTemperature": 1.2, // 最大温度值
|
||||||
|
"censor": false, // 是否开启敏感词过滤(商业版)
|
||||||
"defaultSystemChatPrompt": ""
|
"defaultSystemChatPrompt": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"model": "gpt-3.5-turbo-16k",
|
"model": "gpt-3.5-turbo-16k",
|
||||||
"name": "GPT35-16k",
|
"name": "GPT35-16k",
|
||||||
"maxToken": 16000,
|
"maxContext": 16000,
|
||||||
|
"maxResponse": 16000,
|
||||||
|
"price": 0,
|
||||||
"quoteMaxToken": 8000,
|
"quoteMaxToken": 8000,
|
||||||
"maxTemperature": 1.2,
|
"maxTemperature": 1.2,
|
||||||
"price": 0,
|
"censor": false,
|
||||||
"defaultSystemChatPrompt": ""
|
"defaultSystemChatPrompt": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"model": "gpt-4",
|
"model": "gpt-4",
|
||||||
"name": "GPT4-8k",
|
"name": "GPT4-8k",
|
||||||
"maxToken": 8000,
|
"maxContext": 8000,
|
||||||
|
"maxResponse": 8000,
|
||||||
|
"price": 0,
|
||||||
"quoteMaxToken": 4000,
|
"quoteMaxToken": 4000,
|
||||||
"maxTemperature": 1.2,
|
"maxTemperature": 1.2,
|
||||||
"price": 0,
|
"censor": false,
|
||||||
"defaultSystemChatPrompt": ""
|
"defaultSystemChatPrompt": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"QAModels": [ // QA 拆分模型
|
"QAModels": [
|
||||||
{
|
{
|
||||||
"model": "gpt-3.5-turbo-16k",
|
"model": "gpt-3.5-turbo-16k",
|
||||||
"name": "GPT35-16k",
|
"name": "GPT35-16k",
|
||||||
"maxToken": 16000,
|
"maxContext": 16000,
|
||||||
|
"maxResponse": 16000,
|
||||||
"price": 0
|
"price": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ExtractModels": [ // 内容提取模型
|
"CQModels": [
|
||||||
{
|
{
|
||||||
"model": "gpt-3.5-turbo-16k",
|
"model": "gpt-3.5-turbo-1106",
|
||||||
"name": "GPT35-16k",
|
"name": "GPT35-1106",
|
||||||
"maxToken": 16000,
|
"maxContext": 16000,
|
||||||
"price": 0,
|
"maxResponse": 4000,
|
||||||
"functionCall": true, // 是否支持 function call
|
|
||||||
"functionPrompt": "" // 自定义非 function call 提示词
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"CQModels": [ // Classify Question: 问题分类模型
|
|
||||||
{
|
|
||||||
"model": "gpt-3.5-turbo-16k",
|
|
||||||
"name": "GPT35-16k",
|
|
||||||
"maxToken": 16000,
|
|
||||||
"price": 0,
|
"price": 0,
|
||||||
"functionCall": true,
|
"functionCall": true,
|
||||||
"functionPrompt": ""
|
"functionPrompt": ""
|
||||||
@ -84,17 +83,30 @@ weight: 520
|
|||||||
{
|
{
|
||||||
"model": "gpt-4",
|
"model": "gpt-4",
|
||||||
"name": "GPT4-8k",
|
"name": "GPT4-8k",
|
||||||
"maxToken": 8000,
|
"maxContext": 8000,
|
||||||
|
"maxResponse": 8000,
|
||||||
"price": 0,
|
"price": 0,
|
||||||
"functionCall": true,
|
"functionCall": true,
|
||||||
"functionPrompt": ""
|
"functionPrompt": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"QGModels": [ // Question Generation: 生成下一步指引模型
|
"ExtractModels": [
|
||||||
{
|
{
|
||||||
"model": "gpt-3.5-turbo",
|
"model": "gpt-3.5-turbo-1106",
|
||||||
"name": "GPT35-4k",
|
"name": "GPT35-1106",
|
||||||
"maxToken": 4000,
|
"maxContext": 16000,
|
||||||
|
"maxResponse": 4000,
|
||||||
|
"price": 0,
|
||||||
|
"functionCall": true,
|
||||||
|
"functionPrompt": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"QGModels": [
|
||||||
|
{
|
||||||
|
"model": "gpt-3.5-turbo-1106",
|
||||||
|
"name": "GPT35-1106",
|
||||||
|
"maxContext": 1600,
|
||||||
|
"maxResponse": 4000,
|
||||||
"price": 0
|
"price": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -102,10 +114,22 @@ weight: 520
|
|||||||
{
|
{
|
||||||
"model": "text-embedding-ada-002",
|
"model": "text-embedding-ada-002",
|
||||||
"name": "Embedding-2",
|
"name": "Embedding-2",
|
||||||
"price": 0,
|
"price": 0.2,
|
||||||
"defaultToken": 500,
|
"defaultToken": 700,
|
||||||
"maxToken": 3000
|
"maxToken": 3000
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"AudioSpeechModels": [
|
||||||
|
{
|
||||||
|
"model": "tts-1",
|
||||||
|
"name": "OpenAI TTS1",
|
||||||
|
"price": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "tts-1-hd",
|
||||||
|
"name": "OpenAI TTS1HD",
|
||||||
|
"price": 0
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@ -393,7 +393,7 @@ curl --location --request POST 'https://fastgpt.run/api/core/dataset/searchTest'
|
|||||||
**请求示例**
|
**请求示例**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --location --request POST 'https://fastgpt.run/api/common/bill/createTrainingBill' \
|
curl --location --request POST 'https://fastgpt.run/api/support/wallet/bill/createTrainingBill' \
|
||||||
--header 'Authorization: Bearer {{apikey}}' \
|
--header 'Authorization: Bearer {{apikey}}' \
|
||||||
--header 'Content-Type: application/json' \
|
--header 'Content-Type: application/json' \
|
||||||
--data-raw ''
|
--data-raw ''
|
||||||
|
|||||||
@ -99,9 +99,9 @@ CHAT_API_KEY=sk-xxxxxx
|
|||||||
{
|
{
|
||||||
"model": "ERNIE-Bot", // 这里的模型需要对应 One API 的模型
|
"model": "ERNIE-Bot", // 这里的模型需要对应 One API 的模型
|
||||||
"name": "文心一言", // 对外展示的名称
|
"name": "文心一言", // 对外展示的名称
|
||||||
"maxToken": 4000, // 最大长下文 token,无论什么模型都按 GPT35 的计算。GPT 外的模型需要自行大致计算下这个值。可以调用官方接口去比对 Token 的倍率,然后在这里粗略计算。
|
"maxContext": 8000, // 最大长下文 token,无论什么模型都按 GPT35 的计算。GPT 外的模型需要自行大致计算下这个值。可以调用官方接口去比对 Token 的倍率,然后在这里粗略计算。
|
||||||
|
"maxResponse": 4000, // 最大回复 token
|
||||||
// 例如:文心一言的中英文 token 基本是 1:1,而 GPT 的中文 Token 是 2:1,如果文心一言官方最大 Token 是 4000,那么这里就可以填 8000,保险点就填 7000.
|
// 例如:文心一言的中英文 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
|
"quoteMaxToken": 2000, // 引用知识库的最大 Token
|
||||||
"maxTemperature": 1, // 最大温度
|
"maxTemperature": 1, // 最大温度
|
||||||
"defaultSystemChatPrompt": "" // 默认的系统提示词
|
"defaultSystemChatPrompt": "" // 默认的系统提示词
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 'V4.4.7'
|
title: 'V4.4.7(需执行升级脚本)'
|
||||||
description: 'FastGPT V4.4.7 更新(需执行升级脚本)'
|
description: 'FastGPT V4.4.7 更新(需执行升级脚本)'
|
||||||
icon: 'upgrade'
|
icon: 'upgrade'
|
||||||
draft: false
|
draft: false
|
||||||
|
|||||||
45
docSite/content/docs/installation/upgrading/46.md
Normal file
45
docSite/content/docs/installation/upgrading/46.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
title: 'V4.6(需要初始化)'
|
||||||
|
description: 'FastGPT V4.6 更新'
|
||||||
|
icon: 'upgrade'
|
||||||
|
draft: false
|
||||||
|
toc: true
|
||||||
|
weight: 837
|
||||||
|
---
|
||||||
|
|
||||||
|
未正式发布。
|
||||||
|
|
||||||
|
V4.6 版本加入了简单的团队功能,可以邀请其他用户进来管理资源。该版本升级后无法执行旧的升级脚本,且无法回退。
|
||||||
|
|
||||||
|
## 1. 更新镜像并变更配置文件
|
||||||
|
|
||||||
|
更新镜像至 latest 或者 v4.6 版本。商业版镜像更新至 V0.2.
|
||||||
|
|
||||||
|
最新配置可参考: [V46版本最新 config.json](/docs/development/configuration),商业镜像配置文件也更新,参考最新的飞书文档。
|
||||||
|
|
||||||
|
|
||||||
|
## 2. 执行初始化 API
|
||||||
|
|
||||||
|
发起 1 个 HTTP 请求({{rootkey}} 替换成环境变量里的`rootkey`,{{host}}替换成自己域名)
|
||||||
|
|
||||||
|
1. https://xxxxx/api/admin/initv46
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --location --request POST 'https://{{host}}/api/admin/initv46' \
|
||||||
|
--header 'rootkey: {{rootkey}}' \
|
||||||
|
--header 'Content-Type: application/json'
|
||||||
|
```
|
||||||
|
|
||||||
|
初始化内容:
|
||||||
|
1. 创建默认团队
|
||||||
|
2. 初始化 Mongo 所有资源的团队字段
|
||||||
|
3. 初始化 Pg 的字段
|
||||||
|
|
||||||
|
**该初始化接口可能速度很慢,返回超时不用管,注意看日志即可**
|
||||||
|
|
||||||
|
|
||||||
|
## 功能介绍
|
||||||
|
|
||||||
|
### Fast GPT V4.6
|
||||||
|
|
||||||
|
1. 新增 - 团队空间
|
||||||
@ -73,7 +73,7 @@ weight: 340
|
|||||||

|

|
||||||
|
|
||||||
导入结果如上图。可以看到,我们均采用的是问答对的格式,而不是粗略的直接导入。目的就是为了模拟用户问题,进一步的提高向量搜索的匹配效果。可以为同一个问题设置多种问法,效果更佳。
|
导入结果如上图。可以看到,我们均采用的是问答对的格式,而不是粗略的直接导入。目的就是为了模拟用户问题,进一步的提高向量搜索的匹配效果。可以为同一个问题设置多种问法,效果更佳。
|
||||||
FastGPT 还提供了 openapi 功能,你可以在本地对特殊格式的文件进行处理后,再上传到 FastGPT,具体可以参考:[FastGPT Api Docs](https://doc.fastgpt.run/docs/development/openapi)
|
FastGPT 还提供了 openapi 功能,你可以在本地对特殊格式的文件进行处理后,再上传到 FastGPT,具体可以参考:[FastGPT Api Docs](https://doc.fastgpt.in/docs/development/openapi)
|
||||||
|
|
||||||
## 知识库微调和参数调整
|
## 知识库微调和参数调整
|
||||||
|
|
||||||
|
|||||||
10
package.json
10
package.json
@ -9,11 +9,12 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"lint-staged": "^13.2.1",
|
|
||||||
"prettier": "^3.0.3",
|
|
||||||
"i18next": "^22.5.1",
|
"i18next": "^22.5.1",
|
||||||
|
"lint-staged": "^13.2.1",
|
||||||
|
"next-i18next": "^13.3.0",
|
||||||
|
"prettier": "^3.0.3",
|
||||||
"react-i18next": "^12.3.1",
|
"react-i18next": "^12.3.1",
|
||||||
"next-i18next": "^13.3.0"
|
"zhlint": "^0.7.1"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"./**/**/*.{ts,tsx,scss}": "npm run format-code",
|
"./**/**/*.{ts,tsx,scss}": "npm run format-code",
|
||||||
@ -21,5 +22,8 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"openai": "4.16.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export const PRICE_SCALE = 100000;
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
export type CreateTrainingBillType = {
|
|
||||||
name: string;
|
|
||||||
};
|
|
||||||
28
packages/global/common/error/code/app.ts
Normal file
28
packages/global/common/error/code/app.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { ErrType } from '../errorCode';
|
||||||
|
|
||||||
|
/* dataset: 502000 */
|
||||||
|
export enum AppErrEnum {
|
||||||
|
unExist = 'unExist',
|
||||||
|
unAuthApp = 'unAuthApp'
|
||||||
|
}
|
||||||
|
const appErrList = [
|
||||||
|
{
|
||||||
|
statusText: AppErrEnum.unExist,
|
||||||
|
message: '应用不存在'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statusText: AppErrEnum.unAuthApp,
|
||||||
|
message: '无权操作该应用'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
export default appErrList.reduce((acc, cur, index) => {
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[cur.statusText]: {
|
||||||
|
code: 502000 + index,
|
||||||
|
statusText: cur.statusText,
|
||||||
|
message: cur.message,
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, {} as ErrType<`${AppErrEnum}`>);
|
||||||
23
packages/global/common/error/code/chat.ts
Normal file
23
packages/global/common/error/code/chat.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ErrType } from '../errorCode';
|
||||||
|
|
||||||
|
/* dataset: 504000 */
|
||||||
|
export enum ChatErrEnum {
|
||||||
|
unAuthChat = 'unAuthChat'
|
||||||
|
}
|
||||||
|
const errList = [
|
||||||
|
{
|
||||||
|
statusText: ChatErrEnum.unAuthChat,
|
||||||
|
message: '无权操作该对话记录'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
export default errList.reduce((acc, cur, index) => {
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[cur.statusText]: {
|
||||||
|
code: 504000 + index,
|
||||||
|
statusText: cur.statusText,
|
||||||
|
message: cur.message,
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, {} as ErrType<`${ChatErrEnum}`>);
|
||||||
43
packages/global/common/error/code/dataset.ts
Normal file
43
packages/global/common/error/code/dataset.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { ErrType } from '../errorCode';
|
||||||
|
|
||||||
|
/* dataset: 501000 */
|
||||||
|
export enum DatasetErrEnum {
|
||||||
|
unAuthDataset = 'unAuthDataset',
|
||||||
|
unCreateCollection = 'unCreateCollection',
|
||||||
|
unAuthDatasetCollection = 'unAuthDatasetCollection',
|
||||||
|
unAuthDatasetData = 'unAuthDatasetData',
|
||||||
|
unAuthDatasetFile = 'unAuthDatasetFile'
|
||||||
|
}
|
||||||
|
const datasetErr = [
|
||||||
|
{
|
||||||
|
statusText: DatasetErrEnum.unAuthDataset,
|
||||||
|
message: '无权操作该知识库'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statusText: DatasetErrEnum.unAuthDatasetCollection,
|
||||||
|
message: '无权操作该数据集'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statusText: DatasetErrEnum.unAuthDatasetData,
|
||||||
|
message: '无权操作该数据'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statusText: DatasetErrEnum.unAuthDatasetFile,
|
||||||
|
message: '无权操作该文件'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statusText: DatasetErrEnum.unCreateCollection,
|
||||||
|
message: '无权创建数据集'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
export default datasetErr.reduce((acc, cur, index) => {
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[cur.statusText]: {
|
||||||
|
code: 501000 + index,
|
||||||
|
statusText: cur.statusText,
|
||||||
|
message: cur.message,
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, {} as ErrType<`${DatasetErrEnum}`>);
|
||||||
28
packages/global/common/error/code/openapi.ts
Normal file
28
packages/global/common/error/code/openapi.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { ErrType } from '../errorCode';
|
||||||
|
|
||||||
|
/* dataset: 506000 */
|
||||||
|
export enum OpenApiErrEnum {
|
||||||
|
unExist = 'unExist',
|
||||||
|
unAuth = 'unAuth'
|
||||||
|
}
|
||||||
|
const errList = [
|
||||||
|
{
|
||||||
|
statusText: OpenApiErrEnum.unExist,
|
||||||
|
message: 'Api Key 不存在'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statusText: OpenApiErrEnum.unAuth,
|
||||||
|
message: '无权操作该 Api Key'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
export default errList.reduce((acc, cur, index) => {
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[cur.statusText]: {
|
||||||
|
code: 506000 + index,
|
||||||
|
statusText: cur.statusText,
|
||||||
|
message: cur.message,
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, {} as ErrType<`${OpenApiErrEnum}`>);
|
||||||
34
packages/global/common/error/code/outLink.ts
Normal file
34
packages/global/common/error/code/outLink.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { ErrType } from '../errorCode';
|
||||||
|
|
||||||
|
/* dataset: 505000 */
|
||||||
|
export enum OutLinkErrEnum {
|
||||||
|
unExist = 'unExist',
|
||||||
|
unAuthLink = 'unAuthLink',
|
||||||
|
linkUnInvalid = 'linkUnInvalid'
|
||||||
|
}
|
||||||
|
const errList = [
|
||||||
|
{
|
||||||
|
statusText: OutLinkErrEnum.unExist,
|
||||||
|
message: '分享链接不存在'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statusText: OutLinkErrEnum.unAuthLink,
|
||||||
|
message: '分享链接无效'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 501,
|
||||||
|
statusText: OutLinkErrEnum.linkUnInvalid,
|
||||||
|
message: '分享链接无效'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
export default errList.reduce((acc, cur, index) => {
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[cur.statusText]: {
|
||||||
|
code: cur?.code || 505000 + index,
|
||||||
|
statusText: cur.statusText,
|
||||||
|
message: cur.message,
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, {} as ErrType<`${OutLinkErrEnum}`>);
|
||||||
28
packages/global/common/error/code/plugin.ts
Normal file
28
packages/global/common/error/code/plugin.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { ErrType } from '../errorCode';
|
||||||
|
|
||||||
|
/* dataset: 507000 */
|
||||||
|
export enum PluginErrEnum {
|
||||||
|
unExist = 'unExist',
|
||||||
|
unAuth = 'unAuth'
|
||||||
|
}
|
||||||
|
const errList = [
|
||||||
|
{
|
||||||
|
statusText: PluginErrEnum.unExist,
|
||||||
|
message: '插件不存在'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statusText: PluginErrEnum.unAuth,
|
||||||
|
message: '无权操作该插件'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
export default errList.reduce((acc, cur, index) => {
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[cur.statusText]: {
|
||||||
|
code: 507000 + index,
|
||||||
|
statusText: cur.statusText,
|
||||||
|
message: cur.message,
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, {} as ErrType<`${PluginErrEnum}`>);
|
||||||
22
packages/global/common/error/code/team.ts
Normal file
22
packages/global/common/error/code/team.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { ErrType } from '../errorCode';
|
||||||
|
|
||||||
|
/* team: 500000 */
|
||||||
|
export enum TeamErrEnum {
|
||||||
|
teamOverSize = 'teamOverSize',
|
||||||
|
unAuthTeam = 'unAuthTeam'
|
||||||
|
}
|
||||||
|
const teamErr = [
|
||||||
|
{ statusText: TeamErrEnum.teamOverSize, message: 'error.team.overSize' },
|
||||||
|
{ statusText: TeamErrEnum.unAuthTeam, message: '无权操作该团队' }
|
||||||
|
];
|
||||||
|
export default teamErr.reduce((acc, cur, index) => {
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[cur.statusText]: {
|
||||||
|
code: 500000 + index,
|
||||||
|
statusText: cur.statusText,
|
||||||
|
message: cur.message,
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, {} as ErrType<`${TeamErrEnum}`>);
|
||||||
26
packages/global/common/error/code/user.ts
Normal file
26
packages/global/common/error/code/user.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { ErrType } from '../errorCode';
|
||||||
|
|
||||||
|
/* team: 503000 */
|
||||||
|
export enum UserErrEnum {
|
||||||
|
unAuthUser = 'unAuthUser',
|
||||||
|
unAuthRole = 'unAuthRole',
|
||||||
|
binVisitor = 'binVisitor',
|
||||||
|
balanceNotEnough = 'balanceNotEnough'
|
||||||
|
}
|
||||||
|
const errList = [
|
||||||
|
{ statusText: UserErrEnum.unAuthUser, message: '找不到该用户' },
|
||||||
|
{ statusText: UserErrEnum.binVisitor, message: '您的身份校验未通过' },
|
||||||
|
{ statusText: UserErrEnum.binVisitor, message: '您当前身份为游客,无权操作' },
|
||||||
|
{ statusText: UserErrEnum.balanceNotEnough, message: '账号余额不足~' }
|
||||||
|
];
|
||||||
|
export default errList.reduce((acc, cur, index) => {
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[cur.statusText]: {
|
||||||
|
code: 503000 + index,
|
||||||
|
statusText: cur.statusText,
|
||||||
|
message: cur.message,
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, {} as ErrType<`${UserErrEnum}`>);
|
||||||
@ -1,3 +1,12 @@
|
|||||||
|
import appErr from './code/app';
|
||||||
|
import chatErr from './code/chat';
|
||||||
|
import datasetErr from './code/dataset';
|
||||||
|
import openapiErr from './code/openapi';
|
||||||
|
import pluginErr from './code/plugin';
|
||||||
|
import outLinkErr from './code/outLink';
|
||||||
|
import teamErr from './code/team';
|
||||||
|
import userErr from './code/user';
|
||||||
|
|
||||||
export const ERROR_CODE: { [key: number]: string } = {
|
export const ERROR_CODE: { [key: number]: string } = {
|
||||||
400: '请求失败',
|
400: '请求失败',
|
||||||
401: '无权访问',
|
401: '无权访问',
|
||||||
@ -27,10 +36,19 @@ export enum ERROR_ENUM {
|
|||||||
insufficientQuota = 'insufficientQuota',
|
insufficientQuota = 'insufficientQuota',
|
||||||
unAuthModel = 'unAuthModel',
|
unAuthModel = 'unAuthModel',
|
||||||
unAuthApiKey = 'unAuthApiKey',
|
unAuthApiKey = 'unAuthApiKey',
|
||||||
unAuthDataset = 'unAuthDataset',
|
|
||||||
unAuthDatasetCollection = 'unAuthDatasetCollection',
|
|
||||||
unAuthFile = 'unAuthFile'
|
unAuthFile = 'unAuthFile'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ErrType<T> = Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
code: number;
|
||||||
|
statusText: T;
|
||||||
|
message: string;
|
||||||
|
data: null;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
||||||
export const ERROR_RESPONSE: Record<
|
export const ERROR_RESPONSE: Record<
|
||||||
any,
|
any,
|
||||||
{
|
{
|
||||||
@ -55,15 +73,10 @@ export const ERROR_RESPONSE: Record<
|
|||||||
[ERROR_ENUM.unAuthModel]: {
|
[ERROR_ENUM.unAuthModel]: {
|
||||||
code: 511,
|
code: 511,
|
||||||
statusText: ERROR_ENUM.unAuthModel,
|
statusText: ERROR_ENUM.unAuthModel,
|
||||||
message: '无权使用该模型',
|
message: '无权操作该模型',
|
||||||
data: null
|
|
||||||
},
|
|
||||||
[ERROR_ENUM.unAuthDataset]: {
|
|
||||||
code: 512,
|
|
||||||
statusText: ERROR_ENUM.unAuthDataset,
|
|
||||||
message: '无权使用该知识库',
|
|
||||||
data: null
|
data: null
|
||||||
},
|
},
|
||||||
|
|
||||||
[ERROR_ENUM.unAuthFile]: {
|
[ERROR_ENUM.unAuthFile]: {
|
||||||
code: 513,
|
code: 513,
|
||||||
statusText: ERROR_ENUM.unAuthFile,
|
statusText: ERROR_ENUM.unAuthFile,
|
||||||
@ -76,10 +89,12 @@ export const ERROR_RESPONSE: Record<
|
|||||||
message: 'Api Key 不合法',
|
message: 'Api Key 不合法',
|
||||||
data: null
|
data: null
|
||||||
},
|
},
|
||||||
[ERROR_ENUM.unAuthDatasetCollection]: {
|
...appErr,
|
||||||
code: 515,
|
...chatErr,
|
||||||
statusText: ERROR_ENUM.unAuthDatasetCollection,
|
...datasetErr,
|
||||||
message: '无权使用该知识库文件',
|
...openapiErr,
|
||||||
data: null
|
...outLinkErr,
|
||||||
}
|
...teamErr,
|
||||||
|
...userErr,
|
||||||
|
...pluginErr
|
||||||
};
|
};
|
||||||
|
|||||||
5
packages/global/common/file/constants.ts
Normal file
5
packages/global/common/file/constants.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export enum BucketNameEnum {
|
||||||
|
dataset = 'dataset'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FileBaseUrl = '/api/common/file/read';
|
||||||
8
packages/global/common/file/type.d.ts
vendored
Normal file
8
packages/global/common/file/type.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { BucketNameEnum } from './constants';
|
||||||
|
|
||||||
|
export type FileTokenQuery = {
|
||||||
|
bucketName: `${BucketNameEnum}`;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
fileId: string;
|
||||||
|
};
|
||||||
@ -2,5 +2,6 @@ export enum ChatCompletionRequestMessageRoleEnum {
|
|||||||
'System' = 'system',
|
'System' = 'system',
|
||||||
'User' = 'user',
|
'User' = 'user',
|
||||||
'Assistant' = 'assistant',
|
'Assistant' = 'assistant',
|
||||||
'Function' = 'function'
|
'Function' = 'function',
|
||||||
|
'Tool' = 'tool'
|
||||||
}
|
}
|
||||||
|
|||||||
2
packages/global/core/ai/index.ts
Normal file
2
packages/global/core/ai/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import OpenAI from 'openai';
|
||||||
|
export default OpenAI;
|
||||||
@ -1,9 +1,8 @@
|
|||||||
import { LLMModelUsageEnum } from '@/constants/model';
|
|
||||||
|
|
||||||
export type LLMModelItemType = {
|
export type LLMModelItemType = {
|
||||||
model: string;
|
model: string;
|
||||||
name: string;
|
name: string;
|
||||||
maxToken: number;
|
maxContext: number;
|
||||||
|
maxResponse: number;
|
||||||
price: number;
|
price: number;
|
||||||
};
|
};
|
||||||
export type ChatModelItemType = LLMModelItemType & {
|
export type ChatModelItemType = LLMModelItemType & {
|
||||||
@ -25,3 +24,9 @@ export type VectorModelItemType = {
|
|||||||
price: number;
|
price: number;
|
||||||
maxToken: number;
|
maxToken: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AudioSpeechModelType = {
|
||||||
|
model: string;
|
||||||
|
name: string;
|
||||||
|
price: number;
|
||||||
|
};
|
||||||
@ -1,18 +1,18 @@
|
|||||||
import type { AppSchema } from '@/types/mongoSchema';
|
|
||||||
import type { OutLinkEditType } from '@fastgpt/global/support/outLink/type.d';
|
|
||||||
import type {
|
import type {
|
||||||
LLMModelItemType,
|
LLMModelItemType,
|
||||||
ChatModelItemType,
|
ChatModelItemType,
|
||||||
FunctionModelItemType,
|
FunctionModelItemType,
|
||||||
VectorModelItemType
|
VectorModelItemType,
|
||||||
} from '@/types/model';
|
AudioSpeechModelType
|
||||||
|
} from './model.d';
|
||||||
|
|
||||||
export const defaultChatModels: ChatModelItemType[] = [
|
export const defaultChatModels: ChatModelItemType[] = [
|
||||||
{
|
{
|
||||||
model: 'gpt-3.5-turbo',
|
model: 'gpt-3.5-turbo-1106',
|
||||||
name: 'GPT35-4k',
|
name: 'GPT35-1106',
|
||||||
price: 0,
|
price: 0,
|
||||||
maxToken: 4000,
|
maxContext: 16000,
|
||||||
|
maxResponse: 4000,
|
||||||
quoteMaxToken: 2000,
|
quoteMaxToken: 2000,
|
||||||
maxTemperature: 1.2,
|
maxTemperature: 1.2,
|
||||||
censor: false,
|
censor: false,
|
||||||
@ -21,7 +21,8 @@ export const defaultChatModels: ChatModelItemType[] = [
|
|||||||
{
|
{
|
||||||
model: 'gpt-3.5-turbo-16k',
|
model: 'gpt-3.5-turbo-16k',
|
||||||
name: 'GPT35-16k',
|
name: 'GPT35-16k',
|
||||||
maxToken: 16000,
|
maxContext: 16000,
|
||||||
|
maxResponse: 16000,
|
||||||
price: 0,
|
price: 0,
|
||||||
quoteMaxToken: 8000,
|
quoteMaxToken: 8000,
|
||||||
maxTemperature: 1.2,
|
maxTemperature: 1.2,
|
||||||
@ -31,7 +32,8 @@ export const defaultChatModels: ChatModelItemType[] = [
|
|||||||
{
|
{
|
||||||
model: 'gpt-4',
|
model: 'gpt-4',
|
||||||
name: 'GPT4-8k',
|
name: 'GPT4-8k',
|
||||||
maxToken: 8000,
|
maxContext: 8000,
|
||||||
|
maxResponse: 8000,
|
||||||
price: 0,
|
price: 0,
|
||||||
quoteMaxToken: 4000,
|
quoteMaxToken: 4000,
|
||||||
maxTemperature: 1.2,
|
maxTemperature: 1.2,
|
||||||
@ -43,15 +45,17 @@ export const defaultQAModels: LLMModelItemType[] = [
|
|||||||
{
|
{
|
||||||
model: 'gpt-3.5-turbo-16k',
|
model: 'gpt-3.5-turbo-16k',
|
||||||
name: 'GPT35-16k',
|
name: 'GPT35-16k',
|
||||||
maxToken: 16000,
|
maxContext: 16000,
|
||||||
|
maxResponse: 16000,
|
||||||
price: 0
|
price: 0
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
export const defaultCQModels: FunctionModelItemType[] = [
|
export const defaultCQModels: FunctionModelItemType[] = [
|
||||||
{
|
{
|
||||||
model: 'gpt-3.5-turbo-16k',
|
model: 'gpt-3.5-turbo-1106',
|
||||||
name: 'GPT35-16k',
|
name: 'GPT35-1106',
|
||||||
maxToken: 16000,
|
maxContext: 16000,
|
||||||
|
maxResponse: 4000,
|
||||||
price: 0,
|
price: 0,
|
||||||
functionCall: true,
|
functionCall: true,
|
||||||
functionPrompt: ''
|
functionPrompt: ''
|
||||||
@ -59,7 +63,8 @@ export const defaultCQModels: FunctionModelItemType[] = [
|
|||||||
{
|
{
|
||||||
model: 'gpt-4',
|
model: 'gpt-4',
|
||||||
name: 'GPT4-8k',
|
name: 'GPT4-8k',
|
||||||
maxToken: 8000,
|
maxContext: 8000,
|
||||||
|
maxResponse: 8000,
|
||||||
price: 0,
|
price: 0,
|
||||||
functionCall: true,
|
functionCall: true,
|
||||||
functionPrompt: ''
|
functionPrompt: ''
|
||||||
@ -67,9 +72,10 @@ export const defaultCQModels: FunctionModelItemType[] = [
|
|||||||
];
|
];
|
||||||
export const defaultExtractModels: FunctionModelItemType[] = [
|
export const defaultExtractModels: FunctionModelItemType[] = [
|
||||||
{
|
{
|
||||||
model: 'gpt-3.5-turbo-16k',
|
model: 'gpt-3.5-turbo-1106',
|
||||||
name: 'GPT35-16k',
|
name: 'GPT35-1106',
|
||||||
maxToken: 16000,
|
maxContext: 16000,
|
||||||
|
maxResponse: 4000,
|
||||||
price: 0,
|
price: 0,
|
||||||
functionCall: true,
|
functionCall: true,
|
||||||
functionPrompt: ''
|
functionPrompt: ''
|
||||||
@ -77,9 +83,10 @@ export const defaultExtractModels: FunctionModelItemType[] = [
|
|||||||
];
|
];
|
||||||
export const defaultQGModels: LLMModelItemType[] = [
|
export const defaultQGModels: LLMModelItemType[] = [
|
||||||
{
|
{
|
||||||
model: 'gpt-3.5-turbo',
|
model: 'gpt-3.5-turbo-1106',
|
||||||
name: 'GPT35-4K',
|
name: 'GPT35-1106',
|
||||||
maxToken: 4000,
|
maxContext: 1600,
|
||||||
|
maxResponse: 4000,
|
||||||
price: 0
|
price: 0
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -94,27 +101,15 @@ export const defaultVectorModels: VectorModelItemType[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export const defaultApp: AppSchema = {
|
export const defaultAudioSpeechModels: AudioSpeechModelType[] = [
|
||||||
_id: '',
|
{
|
||||||
userId: 'userId',
|
model: 'tts-1',
|
||||||
name: '模型加载中',
|
name: 'OpenAI TTS1',
|
||||||
type: 'basic',
|
price: 0
|
||||||
avatar: '/icon/logo.svg',
|
|
||||||
intro: '',
|
|
||||||
updateTime: Date.now(),
|
|
||||||
share: {
|
|
||||||
isShare: false,
|
|
||||||
isShareDetail: false,
|
|
||||||
collection: 0
|
|
||||||
},
|
},
|
||||||
modules: []
|
{
|
||||||
};
|
model: 'tts-1-hd',
|
||||||
|
name: 'OpenAI TTS1',
|
||||||
export const defaultOutLinkForm: OutLinkEditType = {
|
price: 0
|
||||||
name: '',
|
|
||||||
responseDetail: false,
|
|
||||||
limit: {
|
|
||||||
QPM: 100,
|
|
||||||
credit: -1
|
|
||||||
}
|
}
|
||||||
};
|
];
|
||||||
8
packages/global/core/ai/speech/api.d.ts
vendored
Normal file
8
packages/global/core/ai/speech/api.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Text2SpeechVoiceEnum } from './constant';
|
||||||
|
|
||||||
|
export type Text2SpeechProps = {
|
||||||
|
model?: string;
|
||||||
|
voice?: `${Text2SpeechVoiceEnum}`;
|
||||||
|
input: string;
|
||||||
|
speed?: number;
|
||||||
|
};
|
||||||
17
packages/global/core/ai/speech/constant.ts
Normal file
17
packages/global/core/ai/speech/constant.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export enum Text2SpeechVoiceEnum {
|
||||||
|
alloy = 'alloy',
|
||||||
|
echo = 'echo',
|
||||||
|
fable = 'fable',
|
||||||
|
onyx = 'onyx',
|
||||||
|
nova = 'nova',
|
||||||
|
shimmer = 'shimmer'
|
||||||
|
}
|
||||||
|
export const openaiTTSList = [
|
||||||
|
Text2SpeechVoiceEnum.alloy,
|
||||||
|
Text2SpeechVoiceEnum.echo,
|
||||||
|
Text2SpeechVoiceEnum.fable,
|
||||||
|
Text2SpeechVoiceEnum.onyx,
|
||||||
|
Text2SpeechVoiceEnum.nova,
|
||||||
|
Text2SpeechVoiceEnum.shimmer
|
||||||
|
];
|
||||||
|
export const openaiTTSModel = 'tts-1';
|
||||||
20
packages/global/core/ai/type.d.ts
vendored
20
packages/global/core/ai/type.d.ts
vendored
@ -1,9 +1,19 @@
|
|||||||
import OpenAI from 'openai';
|
import type {
|
||||||
export type ChatCompletionRequestMessage = OpenAI.Chat.CreateChatCompletionRequestMessage;
|
ChatCompletion,
|
||||||
export type ChatCompletion = OpenAI.Chat.ChatCompletion;
|
ChatCompletionCreateParams,
|
||||||
export type CreateChatCompletionRequest = OpenAI.Chat.ChatCompletionCreateParams;
|
ChatCompletionChunk,
|
||||||
|
ChatCompletionMessageParam,
|
||||||
|
ChatCompletionContentPart
|
||||||
|
} from 'openai/resources';
|
||||||
|
export type ChatCompletionContentPart = ChatCompletionContentPart;
|
||||||
|
export type ChatCompletionCreateParams = ChatCompletionCreateParams;
|
||||||
|
export type ChatMessageItemType = Omit<ChatCompletionMessageParam> & {
|
||||||
|
dataId?: string;
|
||||||
|
content: any;
|
||||||
|
};
|
||||||
|
|
||||||
export type StreamChatType = Stream<OpenAI.Chat.ChatCompletionChunk>;
|
export type ChatCompletion = ChatCompletion;
|
||||||
|
export type StreamChatType = Stream<ChatCompletionChunk>;
|
||||||
|
|
||||||
export type PromptTemplateItem = {
|
export type PromptTemplateItem = {
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
18
packages/global/core/app/api.d.ts
vendored
Normal file
18
packages/global/core/app/api.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { AppTypeEnum } from './constants';
|
||||||
|
import { AppSchema } from './type';
|
||||||
|
|
||||||
|
export type CreateAppParams = {
|
||||||
|
name?: string;
|
||||||
|
avatar?: string;
|
||||||
|
type?: `${AppTypeEnum}`;
|
||||||
|
modules: AppSchema['modules'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface AppUpdateParams {
|
||||||
|
name?: string;
|
||||||
|
type?: `${AppTypeEnum}`;
|
||||||
|
avatar?: string;
|
||||||
|
intro?: string;
|
||||||
|
modules?: AppSchema['modules'];
|
||||||
|
permission?: AppSchema['permission'];
|
||||||
|
}
|
||||||
4
packages/global/core/app/constants.ts
Normal file
4
packages/global/core/app/constants.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export enum AppTypeEnum {
|
||||||
|
basic = 'basic',
|
||||||
|
advanced = 'advanced'
|
||||||
|
}
|
||||||
32
packages/global/core/app/type.d.ts
vendored
Normal file
32
packages/global/core/app/type.d.ts
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { ModuleItemType } from '../module/type';
|
||||||
|
import { AppTypeEnum } from './constants';
|
||||||
|
import { PermissionTypeEnum } from '../../support/permission/constant';
|
||||||
|
import { Text2SpeechVoiceEnum } from '../ai/speech/constant';
|
||||||
|
|
||||||
|
export interface AppSchema {
|
||||||
|
_id: string;
|
||||||
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
name: string;
|
||||||
|
type: `${AppTypeEnum}`;
|
||||||
|
avatar: string;
|
||||||
|
intro: string;
|
||||||
|
updateTime: number;
|
||||||
|
modules: ModuleItemType[];
|
||||||
|
permission: `${PermissionTypeEnum}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AppListItemType = {
|
||||||
|
_id: string;
|
||||||
|
name: string;
|
||||||
|
avatar: string;
|
||||||
|
intro: string;
|
||||||
|
isOwner: boolean;
|
||||||
|
permission: `${PermissionTypeEnum}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AppDetailType = AppSchema & {
|
||||||
|
isOwner: boolean;
|
||||||
|
canWrite: boolean;
|
||||||
|
};
|
||||||
34
packages/global/core/chat/api.d.ts
vendored
Normal file
34
packages/global/core/chat/api.d.ts
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { ModuleItemType } from '../module/type';
|
||||||
|
import { AdminFbkType, ChatItemType, moduleDispatchResType } from './type';
|
||||||
|
|
||||||
|
export type UpdateHistoryProps = {
|
||||||
|
chatId: string;
|
||||||
|
customTitle?: string;
|
||||||
|
top?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AdminUpdateFeedbackParams = AdminFbkType & {
|
||||||
|
chatItemId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InitChatResponse = {
|
||||||
|
chatId: string;
|
||||||
|
appId: string;
|
||||||
|
app: {
|
||||||
|
userGuideModule?: ModuleItemType;
|
||||||
|
chatModels?: string[];
|
||||||
|
name: string;
|
||||||
|
avatar: string;
|
||||||
|
intro: string;
|
||||||
|
canUse?: boolean;
|
||||||
|
};
|
||||||
|
title: string;
|
||||||
|
variables: Record<string, any>;
|
||||||
|
history: ChatItemType[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChatHistoryItemResType = moduleDispatchResType & {
|
||||||
|
moduleType: `${FlowNodeTypeEnum}`;
|
||||||
|
moduleName: string;
|
||||||
|
moduleLogo?: string;
|
||||||
|
};
|
||||||
@ -1,16 +1,9 @@
|
|||||||
import dayjs from 'dayjs';
|
|
||||||
|
|
||||||
export enum sseResponseEventEnum {
|
|
||||||
error = 'error',
|
|
||||||
answer = 'answer',
|
|
||||||
moduleStatus = 'moduleStatus',
|
|
||||||
appStreamResponse = 'appStreamResponse' // sse response request
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ChatRoleEnum {
|
export enum ChatRoleEnum {
|
||||||
System = 'System',
|
System = 'System',
|
||||||
Human = 'Human',
|
Human = 'Human',
|
||||||
AI = 'AI'
|
AI = 'AI',
|
||||||
|
Function = 'Function',
|
||||||
|
Tool = 'Tool'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TaskResponseKeyEnum {
|
export enum TaskResponseKeyEnum {
|
||||||
@ -28,6 +21,12 @@ export const ChatRoleMap = {
|
|||||||
},
|
},
|
||||||
[ChatRoleEnum.AI]: {
|
[ChatRoleEnum.AI]: {
|
||||||
name: 'AI'
|
name: 'AI'
|
||||||
|
},
|
||||||
|
[ChatRoleEnum.Function]: {
|
||||||
|
name: 'Function'
|
||||||
|
},
|
||||||
|
[ChatRoleEnum.Tool]: {
|
||||||
|
name: 'Tool'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
111
packages/global/core/chat/type.d.ts
vendored
Normal file
111
packages/global/core/chat/type.d.ts
vendored
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import { ClassifyQuestionAgentItemType } from '../module/type';
|
||||||
|
import { SearchDataResponseItemType } from '../dataset/type';
|
||||||
|
import { ChatRoleEnum, ChatSourceEnum, TaskResponseKeyEnum } from './constants';
|
||||||
|
import { FlowNodeTypeEnum } from '../module/node/constant';
|
||||||
|
import { AppSchema } from 'core/app/type';
|
||||||
|
|
||||||
|
export type ChatSchema = {
|
||||||
|
_id: string;
|
||||||
|
chatId: string;
|
||||||
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
appId: string;
|
||||||
|
updateTime: Date;
|
||||||
|
title: string;
|
||||||
|
customTitle: string;
|
||||||
|
top: boolean;
|
||||||
|
variables: Record<string, any>;
|
||||||
|
source: `${ChatSourceEnum}`;
|
||||||
|
shareId?: string;
|
||||||
|
isInit: boolean;
|
||||||
|
content: ChatItemType[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChatWithAppSchema = Omit<ChatSchema, 'appId'> & {
|
||||||
|
appId: AppSchema;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChatItemSchema = {
|
||||||
|
dataId: string;
|
||||||
|
chatId: string;
|
||||||
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
appId: string;
|
||||||
|
time: Date;
|
||||||
|
obj: `${ChatRoleEnum}`;
|
||||||
|
value: string;
|
||||||
|
userFeedback?: string;
|
||||||
|
adminFeedback?: AdminFbkType;
|
||||||
|
[TaskResponseKeyEnum.responseData]?: ChatHistoryItemResType[];
|
||||||
|
tts?: Buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AdminFbkType = {
|
||||||
|
dataId: string;
|
||||||
|
datasetId: string;
|
||||||
|
collectionId: string;
|
||||||
|
q: string;
|
||||||
|
a?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChatItemType = {
|
||||||
|
dataId?: string;
|
||||||
|
obj: ChatItemSchema['obj'];
|
||||||
|
value: any;
|
||||||
|
userFeedback?: string;
|
||||||
|
adminFeedback?: ChatItemSchema['feedback'];
|
||||||
|
[TaskResponseKeyEnum.responseData]?: ChatItemSchema[TaskResponseKeyEnum.responseData];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChatSiteItemType = {
|
||||||
|
status: 'loading' | 'running' | 'finish';
|
||||||
|
moduleName?: string;
|
||||||
|
ttsBuffer?: Buffer;
|
||||||
|
} & ChatItemType;
|
||||||
|
|
||||||
|
export type HistoryItemType = {
|
||||||
|
chatId: string;
|
||||||
|
updateTime: Date;
|
||||||
|
customTitle?: string;
|
||||||
|
title: string;
|
||||||
|
};
|
||||||
|
export type ChatHistoryItemType = HistoryItemType & {
|
||||||
|
appId: string;
|
||||||
|
top: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// response data
|
||||||
|
export type moduleDispatchResType = {
|
||||||
|
price: number;
|
||||||
|
runningTime?: number;
|
||||||
|
tokens?: number;
|
||||||
|
model?: string;
|
||||||
|
|
||||||
|
// chat
|
||||||
|
question?: string;
|
||||||
|
temperature?: number;
|
||||||
|
maxToken?: number;
|
||||||
|
quoteList?: SearchDataResponseItemType[];
|
||||||
|
historyPreview?: ChatItemType[]; // completion context array. history will slice
|
||||||
|
|
||||||
|
// dataset search
|
||||||
|
similarity?: number;
|
||||||
|
limit?: number;
|
||||||
|
|
||||||
|
// cq
|
||||||
|
cqList?: ClassifyQuestionAgentItemType[];
|
||||||
|
cqResult?: string;
|
||||||
|
|
||||||
|
// content extract
|
||||||
|
extractDescription?: string;
|
||||||
|
extractResult?: Record<string, any>;
|
||||||
|
|
||||||
|
// http
|
||||||
|
body?: Record<string, any>;
|
||||||
|
httpResult?: Record<string, any>;
|
||||||
|
|
||||||
|
// plugin output
|
||||||
|
pluginOutput?: Record<string, any>;
|
||||||
|
};
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
export const PgDatasetTableName = 'modeldata';
|
||||||
|
|
||||||
export enum DatasetTypeEnum {
|
export enum DatasetTypeEnum {
|
||||||
folder = 'folder',
|
folder = 'folder',
|
||||||
dataset = 'dataset'
|
dataset = 'dataset'
|
||||||
|
|||||||
50
packages/global/core/dataset/type.d.ts
vendored
50
packages/global/core/dataset/type.d.ts
vendored
@ -1,20 +1,26 @@
|
|||||||
|
import { PermissionTypeEnum } from '../../support/permission/constant';
|
||||||
import { DatasetCollectionTypeEnum, DatasetTypeEnum, TrainingModeEnum } from './constant';
|
import { DatasetCollectionTypeEnum, DatasetTypeEnum, TrainingModeEnum } from './constant';
|
||||||
|
|
||||||
export type DatasetSchemaType = {
|
export type DatasetSchemaType = {
|
||||||
_id: string;
|
_id: string;
|
||||||
userId: string;
|
|
||||||
parentId: string;
|
parentId: string;
|
||||||
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
updateTime: Date;
|
updateTime: Date;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
name: string;
|
name: string;
|
||||||
vectorModel: string;
|
vectorModel: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
type: `${DatasetTypeEnum}`;
|
type: `${DatasetTypeEnum}`;
|
||||||
|
permission: `${PermissionTypeEnum}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DatasetCollectionSchemaType = {
|
export type DatasetCollectionSchemaType = {
|
||||||
_id: string;
|
_id: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
datasetId: string;
|
datasetId: string;
|
||||||
parentId?: string;
|
parentId?: string;
|
||||||
name: string;
|
name: string;
|
||||||
@ -30,6 +36,8 @@ export type DatasetCollectionSchemaType = {
|
|||||||
export type DatasetTrainingSchemaType = {
|
export type DatasetTrainingSchemaType = {
|
||||||
_id: string;
|
_id: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
datasetId: string;
|
datasetId: string;
|
||||||
datasetCollectionId: string;
|
datasetCollectionId: string;
|
||||||
billId: string;
|
billId: string;
|
||||||
@ -42,17 +50,35 @@ export type DatasetTrainingSchemaType = {
|
|||||||
a: string;
|
a: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CollectionWithDatasetType = Omit<DatasetCollectionSchemaType, 'datasetId'> & {
|
||||||
|
datasetId: DatasetSchemaType;
|
||||||
|
};
|
||||||
|
|
||||||
/* ================= dataset ===================== */
|
/* ================= dataset ===================== */
|
||||||
|
|
||||||
/* ================= collection ===================== */
|
/* ================= collection ===================== */
|
||||||
|
export type DatasetCollectionItemType = DatasetCollectionSchemaType & {
|
||||||
|
canWrite: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
/* ================= data ===================== */
|
/* ================= data ===================== */
|
||||||
|
export type PgRawDataItemType = {
|
||||||
|
id: string;
|
||||||
|
q: string;
|
||||||
|
a: string;
|
||||||
|
team_id: string;
|
||||||
|
tmb_id: string;
|
||||||
|
dataset_id: string;
|
||||||
|
collection_id: string;
|
||||||
|
};
|
||||||
export type PgDataItemType = {
|
export type PgDataItemType = {
|
||||||
id: string;
|
id: string;
|
||||||
q: string;
|
q: string;
|
||||||
a: string;
|
a: string;
|
||||||
dataset_id: string;
|
teamId: string;
|
||||||
collection_id: string;
|
tmbId: string;
|
||||||
|
datasetId: string;
|
||||||
|
collectionId: string;
|
||||||
};
|
};
|
||||||
export type DatasetChunkItemType = {
|
export type DatasetChunkItemType = {
|
||||||
q: string;
|
q: string;
|
||||||
@ -66,8 +92,24 @@ export type DatasetDataItemType = DatasetChunkItemType & {
|
|||||||
sourceId?: string;
|
sourceId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* --------------- file ---------------------- */
|
||||||
|
export type DatasetFileSchema = {
|
||||||
|
_id: string;
|
||||||
|
length: number;
|
||||||
|
chunkSize: number;
|
||||||
|
uploadDate: Date;
|
||||||
|
filename: string;
|
||||||
|
contentType: string;
|
||||||
|
metadata: {
|
||||||
|
contentType: string;
|
||||||
|
datasetId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/* ============= search =============== */
|
/* ============= search =============== */
|
||||||
export type SearchDataResultItemType = PgDataItemType & {
|
export type SearchDataResultItemType = PgRawDataItemType & {
|
||||||
score: number;
|
score: number;
|
||||||
};
|
};
|
||||||
export type SearchDataResponseItemType = DatasetDataItemType & {
|
export type SearchDataResponseItemType = DatasetDataItemType & {
|
||||||
|
|||||||
0
packages/global/core/module/api.d.ts
vendored
Normal file
0
packages/global/core/module/api.d.ts
vendored
Normal file
13
packages/global/core/module/type.d.ts
vendored
13
packages/global/core/module/type.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
import { FlowNodeTypeEnum } from './node/constant';
|
import { FlowNodeTypeEnum, FlowNodeValTypeEnum } from './node/constant';
|
||||||
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './node/type';
|
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './node/type';
|
||||||
|
|
||||||
export type FlowModuleTemplateType = {
|
export type FlowModuleTemplateType = {
|
||||||
@ -42,3 +42,14 @@ export type SelectAppItemType = {
|
|||||||
name: string;
|
name: string;
|
||||||
logo: string;
|
logo: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* agent */
|
||||||
|
export type ClassifyQuestionAgentItemType = {
|
||||||
|
value: string;
|
||||||
|
key: string;
|
||||||
|
};
|
||||||
|
export type ContextExtractAgentItemType = {
|
||||||
|
desc: string;
|
||||||
|
key: string;
|
||||||
|
required: boolean;
|
||||||
|
};
|
||||||
|
|||||||
2
packages/global/core/plugin/type.d.ts
vendored
2
packages/global/core/plugin/type.d.ts
vendored
@ -3,6 +3,8 @@ import type { ModuleItemType } from '../module/type.d';
|
|||||||
export type PluginItemSchema = {
|
export type PluginItemSchema = {
|
||||||
_id: string;
|
_id: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
name: string;
|
name: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
intro: string;
|
intro: string;
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
"timezones-list": "^3.0.2",
|
"timezones-list": "^3.0.2",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"encoding": "^0.1.13",
|
"encoding": "^0.1.13",
|
||||||
"openai": "^4.12.1"
|
"openai": "^4.16.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.8.5"
|
"@types/node": "^20.8.5"
|
||||||
|
|||||||
2
packages/global/support/openapi/type.d.ts
vendored
2
packages/global/support/openapi/type.d.ts
vendored
@ -1,6 +1,8 @@
|
|||||||
export type OpenApiSchema = {
|
export type OpenApiSchema = {
|
||||||
_id: string;
|
_id: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
createTime: Date;
|
createTime: Date;
|
||||||
lastUsedTime?: Date;
|
lastUsedTime?: Date;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
|
|||||||
27
packages/global/support/outLink/api.d.ts
vendored
Normal file
27
packages/global/support/outLink/api.d.ts
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import type { HistoryItemType, ChatSiteItemType } from '../../core/chat/type.d';
|
||||||
|
import type { InitChatResponse } from '../../core/chat/api.d';
|
||||||
|
import { OutLinkSchema } from '@fastgpt/global/support/outLink/type';
|
||||||
|
|
||||||
|
export type InitShareChatResponse = {
|
||||||
|
userAvatar: string;
|
||||||
|
app: InitChatResponse['app'];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* one page type */
|
||||||
|
export type ShareChatType = InitShareChatResponse & {
|
||||||
|
history: ShareChatHistoryItemType;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* history list item type */
|
||||||
|
export type ShareChatHistoryItemType = HistoryItemType & {
|
||||||
|
shareId: string;
|
||||||
|
variables?: Record<string, any>;
|
||||||
|
chats: ChatSiteItemType[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AuthLinkChatProps = { ip?: string | null; authToken?: string; question: string };
|
||||||
|
export type AuthLinkLimitProps = AuthLinkChatProps & { outLink: OutLinkSchema };
|
||||||
|
export type AuthShareChatInitProps = {
|
||||||
|
authToken?: string;
|
||||||
|
tokenUrl?: string;
|
||||||
|
};
|
||||||
2
packages/global/support/outLink/type.d.ts
vendored
2
packages/global/support/outLink/type.d.ts
vendored
@ -4,6 +4,8 @@ export type OutLinkSchema = {
|
|||||||
_id: string;
|
_id: string;
|
||||||
shareId: string;
|
shareId: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
appId: string;
|
appId: string;
|
||||||
name: string;
|
name: string;
|
||||||
total: number;
|
total: number;
|
||||||
|
|||||||
21
packages/global/support/permission/constant.ts
Normal file
21
packages/global/support/permission/constant.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export enum AuthUserTypeEnum {
|
||||||
|
token = 'token',
|
||||||
|
root = 'root',
|
||||||
|
apikey = 'apikey',
|
||||||
|
outLink = 'outLink'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum PermissionTypeEnum {
|
||||||
|
'private' = 'private',
|
||||||
|
'public' = 'public'
|
||||||
|
}
|
||||||
|
export const PermissionTypeMap = {
|
||||||
|
[PermissionTypeEnum.private]: {
|
||||||
|
iconLight: 'support/permission/privateLight',
|
||||||
|
label: 'permission.Private'
|
||||||
|
},
|
||||||
|
[PermissionTypeEnum.public]: {
|
||||||
|
iconLight: 'support/permission/publicLight',
|
||||||
|
label: 'permission.Public'
|
||||||
|
}
|
||||||
|
};
|
||||||
12
packages/global/support/permission/type.d.ts
vendored
Normal file
12
packages/global/support/permission/type.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { AuthUserTypeEnum } from './constant';
|
||||||
|
|
||||||
|
export type AuthResponseType = {
|
||||||
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
isOwner: boolean;
|
||||||
|
canWrite: boolean;
|
||||||
|
authType?: `${AuthUserTypeEnum}`;
|
||||||
|
appId?: string;
|
||||||
|
apikey?: string;
|
||||||
|
};
|
||||||
27
packages/global/support/permission/utils.ts
Normal file
27
packages/global/support/permission/utils.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { TeamMemberRoleEnum } from '../user/team/constant';
|
||||||
|
import { PermissionTypeEnum } from './constant';
|
||||||
|
|
||||||
|
/* team public source, or owner source in team */
|
||||||
|
export function mongoRPermission({
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
role
|
||||||
|
}: {
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
role: `${TeamMemberRoleEnum}`;
|
||||||
|
}) {
|
||||||
|
return {
|
||||||
|
teamId,
|
||||||
|
...(role === TeamMemberRoleEnum.visitor && { permission: PermissionTypeEnum.public }),
|
||||||
|
...(role === TeamMemberRoleEnum.admin && {
|
||||||
|
$or: [{ permission: PermissionTypeEnum.public }, { tmbId }]
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export function mongoOwnerPermission({ teamId, tmbId }: { teamId: string; tmbId: string }) {
|
||||||
|
return {
|
||||||
|
teamId,
|
||||||
|
tmbId
|
||||||
|
};
|
||||||
|
}
|
||||||
15
packages/global/support/user/api.d.ts
vendored
Normal file
15
packages/global/support/user/api.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { OAuthEnum } from './constant';
|
||||||
|
|
||||||
|
export type PostLoginProps = {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
tmbId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type OauthLoginProps = {
|
||||||
|
type: `${OAuthEnum}`;
|
||||||
|
code: string;
|
||||||
|
callbackUrl: string;
|
||||||
|
inviterId?: string;
|
||||||
|
tmbId?: string;
|
||||||
|
};
|
||||||
@ -1,30 +1,4 @@
|
|||||||
export enum InformTypeEnum {
|
export enum OAuthEnum {
|
||||||
system = 'system'
|
github = 'github',
|
||||||
|
google = 'google'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InformTypeMap = {
|
|
||||||
[InformTypeEnum.system]: {
|
|
||||||
label: '系统通知'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum TeamMemberRoleEnum {
|
|
||||||
owner = 'owner',
|
|
||||||
admin = 'admin',
|
|
||||||
member = 'member',
|
|
||||||
visitor = 'visitor'
|
|
||||||
}
|
|
||||||
export const TeamMemberRoleMap = {
|
|
||||||
[TeamMemberRoleEnum.owner]: {
|
|
||||||
label: 'user.team.role.owner'
|
|
||||||
},
|
|
||||||
[TeamMemberRoleEnum.admin]: {
|
|
||||||
label: 'user.team.role.admin'
|
|
||||||
},
|
|
||||||
[TeamMemberRoleEnum.member]: {
|
|
||||||
label: 'user.team.role.member'
|
|
||||||
},
|
|
||||||
[TeamMemberRoleEnum.visitor]: {
|
|
||||||
label: 'user.team.role.visitor'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
21
packages/global/support/user/controller.d.ts
vendored
21
packages/global/support/user/controller.d.ts
vendored
@ -1,21 +0,0 @@
|
|||||||
export type CreateTeamProps = {
|
|
||||||
ownerId: string;
|
|
||||||
name: string;
|
|
||||||
avatar?: string;
|
|
||||||
};
|
|
||||||
export type UpdateTeamProps = {
|
|
||||||
id: string;
|
|
||||||
name?: string;
|
|
||||||
avatar?: string;
|
|
||||||
};
|
|
||||||
export type updateTeamBalanceProps = {
|
|
||||||
id: string;
|
|
||||||
balance: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CreateTeamMemberProps = {
|
|
||||||
ownerId: string;
|
|
||||||
teamId: string;
|
|
||||||
userId: string;
|
|
||||||
name?: string;
|
|
||||||
};
|
|
||||||
9
packages/global/support/user/inform/constants.ts
Normal file
9
packages/global/support/user/inform/constants.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export enum InformTypeEnum {
|
||||||
|
system = 'system'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const InformTypeMap = {
|
||||||
|
[InformTypeEnum.system]: {
|
||||||
|
label: '系统通知'
|
||||||
|
}
|
||||||
|
};
|
||||||
18
packages/global/support/user/inform/type.d.ts
vendored
Normal file
18
packages/global/support/user/inform/type.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { InformTypeEnum } from './constant';
|
||||||
|
|
||||||
|
export type SendInformProps = {
|
||||||
|
tmbId?: string;
|
||||||
|
type: `${InformTypeEnum}`;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UserInformSchema = {
|
||||||
|
_id: string;
|
||||||
|
userId: string;
|
||||||
|
time: Date;
|
||||||
|
type: `${InformTypeEnum}`;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
read: boolean;
|
||||||
|
};
|
||||||
42
packages/global/support/user/team/constant.ts
Normal file
42
packages/global/support/user/team/constant.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
export const TeamCollectionName = 'teams';
|
||||||
|
export const TeamMemberCollectionName = 'team.members';
|
||||||
|
|
||||||
|
export enum TeamMemberRoleEnum {
|
||||||
|
owner = 'owner',
|
||||||
|
admin = 'admin',
|
||||||
|
visitor = 'visitor'
|
||||||
|
}
|
||||||
|
export const TeamMemberRoleMap = {
|
||||||
|
[TeamMemberRoleEnum.owner]: {
|
||||||
|
value: TeamMemberRoleEnum.owner,
|
||||||
|
label: 'user.team.role.Owner'
|
||||||
|
},
|
||||||
|
[TeamMemberRoleEnum.admin]: {
|
||||||
|
value: TeamMemberRoleEnum.admin,
|
||||||
|
label: 'user.team.role.Admin'
|
||||||
|
},
|
||||||
|
[TeamMemberRoleEnum.visitor]: {
|
||||||
|
value: TeamMemberRoleEnum.visitor,
|
||||||
|
label: 'user.team.role.Visitor'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum TeamMemberStatusEnum {
|
||||||
|
waiting = 'waiting',
|
||||||
|
active = 'active',
|
||||||
|
reject = 'reject'
|
||||||
|
}
|
||||||
|
export const TeamMemberStatusMap = {
|
||||||
|
[TeamMemberStatusEnum.waiting]: {
|
||||||
|
label: 'user.team.member.waiting',
|
||||||
|
color: 'orange.600'
|
||||||
|
},
|
||||||
|
[TeamMemberStatusEnum.active]: {
|
||||||
|
label: 'user.team.member.active',
|
||||||
|
color: 'green.600'
|
||||||
|
},
|
||||||
|
[TeamMemberStatusEnum.reject]: {
|
||||||
|
label: 'user.team.member.reject',
|
||||||
|
color: 'red.600'
|
||||||
|
}
|
||||||
|
};
|
||||||
40
packages/global/support/user/team/controller.d.ts
vendored
Normal file
40
packages/global/support/user/team/controller.d.ts
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { TeamMemberRoleEnum } from './constant';
|
||||||
|
import { TeamMemberSchema } from './type';
|
||||||
|
|
||||||
|
export type AuthTeamRoleProps = {
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
role?: `${TeamMemberRoleEnum}`;
|
||||||
|
};
|
||||||
|
export type CreateTeamProps = {
|
||||||
|
name: string;
|
||||||
|
avatar?: string;
|
||||||
|
defaultTeam?: boolean;
|
||||||
|
};
|
||||||
|
export type UpdateTeamProps = {
|
||||||
|
teamId: string;
|
||||||
|
name?: string;
|
||||||
|
avatar?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ------------- member ----------- */
|
||||||
|
export type DelMemberProps = {
|
||||||
|
teamId: string;
|
||||||
|
memberId: string;
|
||||||
|
};
|
||||||
|
export type UpdateTeamMemberProps = {
|
||||||
|
teamId: string;
|
||||||
|
memberId: string;
|
||||||
|
role?: TeamMemberSchema['role'];
|
||||||
|
status?: TeamMemberSchema['status'];
|
||||||
|
};
|
||||||
|
export type InviteMemberProps = {
|
||||||
|
teamId: string;
|
||||||
|
usernames: string[];
|
||||||
|
role: `${TeamMemberRoleEnum}`;
|
||||||
|
};
|
||||||
|
export type UpdateInviteProps = {
|
||||||
|
tmbId: string;
|
||||||
|
status: TeamMemberSchema['status'];
|
||||||
|
};
|
||||||
|
export type InviteMemberResponse = Record<'invite' | 'inValid' | 'inTeam', string[]>;
|
||||||
46
packages/global/support/user/team/type.d.ts
vendored
Normal file
46
packages/global/support/user/team/type.d.ts
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { UserModelSchema } from '../type';
|
||||||
|
import { TeamMemberRoleEnum, TeamMemberStatusEnum } from './constant';
|
||||||
|
|
||||||
|
export type TeamSchema = {
|
||||||
|
_id: string;
|
||||||
|
name: string;
|
||||||
|
ownerId: string;
|
||||||
|
avatar: string;
|
||||||
|
createTime: Date;
|
||||||
|
balance: number;
|
||||||
|
maxSize: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TeamMemberSchema = {
|
||||||
|
_id: string;
|
||||||
|
teamId: string;
|
||||||
|
userId: string;
|
||||||
|
createTime: Date;
|
||||||
|
role: `${TeamMemberRoleEnum}`;
|
||||||
|
status: `${TeamMemberStatusEnum}`;
|
||||||
|
defaultTeam: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TeamItemType = {
|
||||||
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
teamName: string;
|
||||||
|
avatar: string;
|
||||||
|
balance: number;
|
||||||
|
tmbId: string;
|
||||||
|
defaultTeam: boolean;
|
||||||
|
role: `${TeamMemberRoleEnum}`;
|
||||||
|
status: `${TeamMemberStatusEnum}`;
|
||||||
|
canWrite: boolean;
|
||||||
|
maxSize: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TeamMemberItemType = {
|
||||||
|
userId: string;
|
||||||
|
tmbId: string;
|
||||||
|
teamId: string;
|
||||||
|
memberUsername: string;
|
||||||
|
avatar: string;
|
||||||
|
role: `${TeamMemberRoleEnum}`;
|
||||||
|
status: `${TeamMemberStatusEnum}`;
|
||||||
|
};
|
||||||
32
packages/global/support/user/type.d.ts
vendored
32
packages/global/support/user/type.d.ts
vendored
@ -1,4 +1,5 @@
|
|||||||
import { InformTypeEnum, TeamMemberRoleEnum } from './constant';
|
import { InformTypeEnum } from './constant';
|
||||||
|
import { TeamItemType } from './team/type';
|
||||||
|
|
||||||
export type UserModelSchema = {
|
export type UserModelSchema = {
|
||||||
_id: string;
|
_id: string;
|
||||||
@ -21,28 +22,13 @@ export type UserModelSchema = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserInformSchema = {
|
export type UserType = {
|
||||||
_id: string;
|
_id: string;
|
||||||
userId: string;
|
username: string;
|
||||||
time: Date;
|
|
||||||
type: `${InformTypeEnum}`;
|
|
||||||
title: string;
|
|
||||||
content: string;
|
|
||||||
read: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TeamSchema = {
|
|
||||||
_id: string;
|
|
||||||
name: string;
|
|
||||||
ownerId: string;
|
|
||||||
avatar: string;
|
avatar: string;
|
||||||
createTime: Date;
|
balance: number;
|
||||||
};
|
timezone: string;
|
||||||
|
promotionRate: UserModelSchema['promotionRate'];
|
||||||
export type TeamMemberSchema = {
|
openaiAccount: UserModelSchema['openaiAccount'];
|
||||||
_id: string;
|
team: TeamItemType;
|
||||||
name: string;
|
|
||||||
teamId: string;
|
|
||||||
userId: string;
|
|
||||||
role: `${TeamMemberRoleEnum}`;
|
|
||||||
};
|
};
|
||||||
|
|||||||
25
packages/global/support/wallet/bill/api.d.ts
vendored
Normal file
25
packages/global/support/wallet/bill/api.d.ts
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { BillSourceEnum } from './constants';
|
||||||
|
import { BillListItemType } from './type';
|
||||||
|
|
||||||
|
export type CreateTrainingBillProps = {
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ConcatBillProps = {
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
billId?: string;
|
||||||
|
total: number;
|
||||||
|
listIndex?: number;
|
||||||
|
tokens?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateBillProps = {
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
appName: string;
|
||||||
|
appId?: string;
|
||||||
|
total: number;
|
||||||
|
source: `${BillSourceEnum}`;
|
||||||
|
list: BillListItemType[];
|
||||||
|
};
|
||||||
16
packages/global/support/wallet/bill/constants.ts
Normal file
16
packages/global/support/wallet/bill/constants.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// ¥1 = 100000
|
||||||
|
export const PRICE_SCALE = 100000;
|
||||||
|
|
||||||
|
export enum BillSourceEnum {
|
||||||
|
fastgpt = 'fastgpt',
|
||||||
|
api = 'api',
|
||||||
|
shareLink = 'shareLink',
|
||||||
|
training = 'training'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BillSourceMap: Record<`${BillSourceEnum}`, string> = {
|
||||||
|
[BillSourceEnum.fastgpt]: '在线使用',
|
||||||
|
[BillSourceEnum.api]: 'Api',
|
||||||
|
[BillSourceEnum.shareLink]: '免登录链接',
|
||||||
|
[BillSourceEnum.training]: '数据训练'
|
||||||
|
};
|
||||||
@ -1,5 +1,6 @@
|
|||||||
/* bill common */
|
/* bill common */
|
||||||
import { PRICE_SCALE } from './constants';
|
import { PRICE_SCALE } from './constants';
|
||||||
|
import { BillItemType, BillSchema } from './type';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dataset price / PRICE_SCALE = real price
|
* dataset price / PRICE_SCALE = real price
|
||||||
24
packages/global/support/wallet/bill/type.d.ts
vendored
Normal file
24
packages/global/support/wallet/bill/type.d.ts
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { CreateBillProps } from './api';
|
||||||
|
import { BillSourceEnum } from './constants';
|
||||||
|
|
||||||
|
export type BillListItemType = {
|
||||||
|
moduleName: string;
|
||||||
|
amount: number;
|
||||||
|
model?: string;
|
||||||
|
tokenLen?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BillSchema = CreateBillProps & {
|
||||||
|
_id: string;
|
||||||
|
time: Date;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BillItemType = {
|
||||||
|
id: string;
|
||||||
|
username: string;
|
||||||
|
time: Date;
|
||||||
|
appName: string;
|
||||||
|
source: BillSchema['source'];
|
||||||
|
total: number;
|
||||||
|
list: BillSchema['list'];
|
||||||
|
};
|
||||||
@ -1,6 +1,8 @@
|
|||||||
export type PaySchema = {
|
export type PaySchema = {
|
||||||
_id: string;
|
_id: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
createTime: Date;
|
createTime: Date;
|
||||||
price: number;
|
price: number;
|
||||||
orderId: string;
|
orderId: string;
|
||||||
@ -18,7 +18,6 @@ function requestStart(config: InternalAxiosRequestConfig): InternalAxiosRequestC
|
|||||||
if (config.headers) {
|
if (config.headers) {
|
||||||
config.headers.rootkey = process.env.ROOT_KEY;
|
config.headers.rootkey = process.env.ROOT_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +61,8 @@ function responseError(err: any) {
|
|||||||
const instance = axios.create({
|
const instance = axios.create({
|
||||||
timeout: 60000, // 超时时间
|
timeout: 60000, // 超时时间
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'application/json'
|
'content-type': 'application/json',
|
||||||
|
'Cache-Control': 'no-cache'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ instance.interceptors.response.use(responseSuccess, (err) => Promise.reject(err)
|
|||||||
|
|
||||||
export function request(url: string, data: any, config: ConfigType, method: Method): any {
|
export function request(url: string, data: any, config: ConfigType, method: Method): any {
|
||||||
if (!global.systemEnv?.pluginBaseUrl) {
|
if (!global.systemEnv?.pluginBaseUrl) {
|
||||||
return Promise.reject('商业版插件加载中...');
|
return Promise.reject('该功能为商业版特有...');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 去空 */
|
/* 去空 */
|
||||||
|
|||||||
111
packages/service/common/file/gridfs/controller.ts
Normal file
111
packages/service/common/file/gridfs/controller.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import { Types, connectionMongo } from '../../mongo';
|
||||||
|
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
|
||||||
|
import fsp from 'fs/promises';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { DatasetFileSchema } from '@fastgpt/global/core/dataset/type';
|
||||||
|
|
||||||
|
export function getGFSCollection(bucket: `${BucketNameEnum}`) {
|
||||||
|
return connectionMongo.connection.db.collection(`${bucket}.files`);
|
||||||
|
}
|
||||||
|
export function getGridBucket(bucket: `${BucketNameEnum}`) {
|
||||||
|
return new connectionMongo.mongo.GridFSBucket(connectionMongo.connection.db, {
|
||||||
|
bucketName: bucket
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* crud file */
|
||||||
|
export async function uploadFile({
|
||||||
|
bucketName,
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
path,
|
||||||
|
filename,
|
||||||
|
metadata = {}
|
||||||
|
}: {
|
||||||
|
bucketName: `${BucketNameEnum}`;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
path: string;
|
||||||
|
filename: string;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}) {
|
||||||
|
if (!path) return Promise.reject(`filePath is empty`);
|
||||||
|
if (!filename) return Promise.reject(`filename is empty`);
|
||||||
|
|
||||||
|
const stats = await fsp.stat(path);
|
||||||
|
if (!stats.isFile()) return Promise.reject(`${path} is not a file`);
|
||||||
|
|
||||||
|
metadata.teamId = teamId;
|
||||||
|
metadata.tmbId = tmbId;
|
||||||
|
|
||||||
|
// create a gridfs bucket
|
||||||
|
const bucket = getGridBucket(bucketName);
|
||||||
|
|
||||||
|
const stream = bucket.openUploadStream(filename, {
|
||||||
|
metadata,
|
||||||
|
contentType: metadata?.contentType
|
||||||
|
});
|
||||||
|
|
||||||
|
// save to gridfs
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
fs.createReadStream(path)
|
||||||
|
.pipe(stream as any)
|
||||||
|
.on('finish', resolve)
|
||||||
|
.on('error', reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
return String(stream.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getFileById({
|
||||||
|
bucketName,
|
||||||
|
fileId
|
||||||
|
}: {
|
||||||
|
bucketName: `${BucketNameEnum}`;
|
||||||
|
fileId: string;
|
||||||
|
}) {
|
||||||
|
const db = getGFSCollection(bucketName);
|
||||||
|
const file = await db.findOne<DatasetFileSchema>({
|
||||||
|
_id: new Types.ObjectId(fileId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
return Promise.reject('File not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function delFileById({
|
||||||
|
bucketName,
|
||||||
|
fileId
|
||||||
|
}: {
|
||||||
|
bucketName: `${BucketNameEnum}`;
|
||||||
|
fileId: string;
|
||||||
|
}) {
|
||||||
|
const bucket = getGridBucket(bucketName);
|
||||||
|
|
||||||
|
await bucket.delete(new Types.ObjectId(fileId));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getDownloadBuf({
|
||||||
|
bucketName,
|
||||||
|
fileId
|
||||||
|
}: {
|
||||||
|
bucketName: `${BucketNameEnum}`;
|
||||||
|
fileId: string;
|
||||||
|
}) {
|
||||||
|
const bucket = getGridBucket(bucketName);
|
||||||
|
|
||||||
|
const stream = bucket.openDownloadStream(new Types.ObjectId(fileId));
|
||||||
|
|
||||||
|
const buf: Buffer = await new Promise((resolve, reject) => {
|
||||||
|
const buffers: Buffer[] = [];
|
||||||
|
stream.on('data', (data) => buffers.push(data));
|
||||||
|
stream.on('error', reject);
|
||||||
|
stream.on('end', () => resolve(Buffer.concat(buffers)));
|
||||||
|
});
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
26
packages/service/common/mongo/controller.ts
Normal file
26
packages/service/common/mongo/controller.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/* add logger */
|
||||||
|
export const addLog = {
|
||||||
|
info: (msg: string, obj?: Record<string, any>) => {
|
||||||
|
global.logger?.info(msg, { meta: obj });
|
||||||
|
},
|
||||||
|
error: (msg: string, error?: any) => {
|
||||||
|
global.logger?.error(msg, {
|
||||||
|
meta: {
|
||||||
|
stack: error?.stack,
|
||||||
|
...(error?.config && {
|
||||||
|
config: {
|
||||||
|
headers: error.config.headers,
|
||||||
|
url: error.config.url,
|
||||||
|
data: error.config.data
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
...(error?.response && {
|
||||||
|
response: {
|
||||||
|
status: error.response.status,
|
||||||
|
statusText: error.response.statusText
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import mongoose from './index';
|
import mongoose from './index';
|
||||||
import 'winston-mongodb';
|
|
||||||
import { createLogger, format, transports } from 'winston';
|
import { createLogger, format, transports } from 'winston';
|
||||||
|
import 'winston-mongodb';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* connect MongoDB and init data
|
* connect MongoDB and init data
|
||||||
@ -19,9 +19,6 @@ export async function connectMongo({
|
|||||||
|
|
||||||
beforeHook && (await beforeHook());
|
beforeHook && (await beforeHook());
|
||||||
|
|
||||||
// logger
|
|
||||||
initLogger();
|
|
||||||
|
|
||||||
console.log('mongo start connect');
|
console.log('mongo start connect');
|
||||||
try {
|
try {
|
||||||
mongoose.set('strictQuery', true);
|
mongoose.set('strictQuery', true);
|
||||||
@ -35,9 +32,11 @@ export async function connectMongo({
|
|||||||
});
|
});
|
||||||
|
|
||||||
console.log('mongo connected');
|
console.log('mongo connected');
|
||||||
|
initLogger();
|
||||||
|
|
||||||
afterHook && (await afterHook());
|
afterHook && (await afterHook());
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
global.mongodb.disconnect();
|
||||||
console.log('error->', 'mongo connect error', error);
|
console.log('error->', 'mongo connect error', error);
|
||||||
global.mongodb = undefined;
|
global.mongodb = undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,39 +1,21 @@
|
|||||||
import mongoose from './index';
|
import mongoose, { connectionMongo } from './index';
|
||||||
|
|
||||||
export class MongoSession {
|
export async function mongoSessionTask(
|
||||||
tasks: (() => Promise<any>)[] = [];
|
fn: (session: mongoose.mongo.ClientSession) => Promise<any>
|
||||||
session: mongoose.mongo.ClientSession | null = null;
|
|
||||||
opts: {
|
|
||||||
session: mongoose.mongo.ClientSession;
|
|
||||||
new: boolean;
|
|
||||||
} | null = null;
|
|
||||||
|
|
||||||
constructor() {}
|
|
||||||
async init() {
|
|
||||||
this.session = await mongoose.startSession();
|
|
||||||
this.opts = { session: this.session, new: true };
|
|
||||||
}
|
|
||||||
push(
|
|
||||||
tasks: ((opts: {
|
|
||||||
session: mongoose.mongo.ClientSession;
|
|
||||||
new: boolean;
|
|
||||||
}) => () => Promise<any>)[] = []
|
|
||||||
) {
|
) {
|
||||||
if (!this.opts) return;
|
const session = await connectionMongo.startSession();
|
||||||
// this.tasks = this.tasks.concat(tasks.map((item) => item(this.opts)));
|
|
||||||
}
|
|
||||||
async run() {
|
|
||||||
if (!this.session || !this.opts) return;
|
|
||||||
try {
|
try {
|
||||||
this.session.startTransaction();
|
session.startTransaction();
|
||||||
|
|
||||||
const opts = { session: this.session, new: true };
|
await fn(session);
|
||||||
|
|
||||||
await this.session.commitTransaction();
|
await session.commitTransaction();
|
||||||
|
await session.endSession();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await this.session.abortTransaction();
|
await session.abortTransaction();
|
||||||
|
await session.endSession();
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
return Promise.reject(error);
|
||||||
this.session.endSession();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { Pool } from 'pg';
|
import { Pool } from 'pg';
|
||||||
import type { QueryResultRow } from 'pg';
|
import type { QueryResultRow } from 'pg';
|
||||||
import { PgDatasetTableName } from '@/constants/plugin';
|
import { PgDatasetTableName } from '@fastgpt/global/core/dataset/constant';
|
||||||
import { DatasetSpecialIdEnum } from '@fastgpt/global/core/dataset/constant';
|
|
||||||
|
|
||||||
export const connectPg = async (): Promise<Pool> => {
|
export const connectPg = async (): Promise<Pool> => {
|
||||||
if (global.pgClient) {
|
if (global.pgClient) {
|
||||||
@ -55,7 +54,7 @@ type InsertProps = {
|
|||||||
values: ValuesProps[];
|
values: ValuesProps[];
|
||||||
};
|
};
|
||||||
|
|
||||||
class Pg {
|
class PgClass {
|
||||||
private getWhereStr(where?: WhereProps) {
|
private getWhereStr(where?: WhereProps) {
|
||||||
return where
|
return where
|
||||||
? `WHERE ${where
|
? `WHERE ${where
|
||||||
@ -160,27 +159,6 @@ class Pg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PgClient = new Pg();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update data file_id
|
|
||||||
*/
|
|
||||||
export const updateDataFileId = async ({
|
|
||||||
oldFileId,
|
|
||||||
userId,
|
|
||||||
newFileId = DatasetSpecialIdEnum.manual
|
|
||||||
}: {
|
|
||||||
oldFileId: string;
|
|
||||||
userId: string;
|
|
||||||
newFileId?: string;
|
|
||||||
}) => {
|
|
||||||
await PgClient.update(PgDatasetTableName, {
|
|
||||||
where: [['file_id', oldFileId], 'AND', ['user_id', userId]],
|
|
||||||
values: [{ key: 'file_id', value: newFileId }]
|
|
||||||
});
|
|
||||||
return newFileId;
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function initPg() {
|
export async function initPg() {
|
||||||
try {
|
try {
|
||||||
await connectPg();
|
await connectPg();
|
||||||
@ -189,13 +167,14 @@ export async function initPg() {
|
|||||||
CREATE TABLE IF NOT EXISTS ${PgDatasetTableName} (
|
CREATE TABLE IF NOT EXISTS ${PgDatasetTableName} (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
vector VECTOR(1536) NOT NULL,
|
vector VECTOR(1536) NOT NULL,
|
||||||
user_id VARCHAR(50) NOT NULL,
|
team_id VARCHAR(50) NOT NULL,
|
||||||
|
tmb_id VARCHAR(50) NOT NULL,
|
||||||
dataset_id VARCHAR(50) NOT NULL,
|
dataset_id VARCHAR(50) NOT NULL,
|
||||||
collection_id VARCHAR(50) NOT NULL,
|
collection_id VARCHAR(50) NOT NULL,
|
||||||
q TEXT NOT NULL,
|
q TEXT NOT NULL,
|
||||||
a TEXT
|
a TEXT
|
||||||
);
|
);
|
||||||
CREATE INDEX IF NOT EXISTS vector_index ON ${PgDatasetTableName} USING hnsw (vector vector_ip_ops) WITH (m = 24, ef_construction = 48);
|
CREATE INDEX IF NOT EXISTS vector_index ON ${PgDatasetTableName} USING hnsw (vector vector_ip_ops) WITH (m = 24, ef_construction = 64);
|
||||||
`);
|
`);
|
||||||
|
|
||||||
console.log('init pg successful');
|
console.log('init pg successful');
|
||||||
@ -203,3 +182,6 @@ export async function initPg() {
|
|||||||
console.log('init pg error', error);
|
console.log('init pg error', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const PgClient = new PgClass();
|
||||||
|
export const Pg = global.pgClient;
|
||||||
5
packages/service/common/pg/type.d.ts
vendored
Normal file
5
packages/service/common/pg/type.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import type { Pool } from 'pg';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
var pgClient: Pool | null;
|
||||||
|
}
|
||||||
6
packages/service/common/response/constant.ts
Normal file
6
packages/service/common/response/constant.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export enum sseResponseEventEnum {
|
||||||
|
error = 'error',
|
||||||
|
answer = 'answer',
|
||||||
|
moduleStatus = 'moduleStatus',
|
||||||
|
appStreamResponse = 'appStreamResponse' // sse response request
|
||||||
|
}
|
||||||
@ -1,4 +1,98 @@
|
|||||||
import type { NextApiResponse } from 'next';
|
import type { NextApiResponse } from 'next';
|
||||||
|
import { sseResponseEventEnum } from './constant';
|
||||||
|
import { proxyError, ERROR_RESPONSE, ERROR_ENUM } from '@fastgpt/global/common/error/errorCode';
|
||||||
|
import { addLog } from '../mongo/controller';
|
||||||
|
import { clearCookie } from '../../support/permission/controller';
|
||||||
|
|
||||||
|
export interface ResponseType<T = any> {
|
||||||
|
code: number;
|
||||||
|
message: string;
|
||||||
|
data: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const jsonRes = <T = any>(
|
||||||
|
res: NextApiResponse,
|
||||||
|
props?: {
|
||||||
|
code?: number;
|
||||||
|
message?: string;
|
||||||
|
data?: T;
|
||||||
|
error?: any;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
const { code = 200, message = '', data = null, error } = props || {};
|
||||||
|
|
||||||
|
const errResponseKey = typeof error === 'string' ? error : error?.message;
|
||||||
|
// Specified error
|
||||||
|
if (ERROR_RESPONSE[errResponseKey]) {
|
||||||
|
// login is expired
|
||||||
|
if (errResponseKey === ERROR_ENUM.unAuthorization) {
|
||||||
|
clearCookie(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json(ERROR_RESPONSE[errResponseKey]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// another error
|
||||||
|
let msg = '';
|
||||||
|
if ((code < 200 || code >= 400) && !message) {
|
||||||
|
msg = error?.response?.statusText || error?.message || '请求错误';
|
||||||
|
if (typeof error === 'string') {
|
||||||
|
msg = error;
|
||||||
|
} else if (proxyError[error?.code]) {
|
||||||
|
msg = '网络连接异常';
|
||||||
|
} else if (error?.response?.data?.error?.message) {
|
||||||
|
msg = error?.response?.data?.error?.message;
|
||||||
|
} else if (error?.error?.message) {
|
||||||
|
msg = error?.error?.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
addLog.error(`response error: ${msg}`, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(code).json({
|
||||||
|
code,
|
||||||
|
statusText: '',
|
||||||
|
message: message || msg,
|
||||||
|
data: data !== undefined ? data : null
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sseErrRes = (res: NextApiResponse, error: any) => {
|
||||||
|
const errResponseKey = typeof error === 'string' ? error : error?.message;
|
||||||
|
|
||||||
|
// Specified error
|
||||||
|
if (ERROR_RESPONSE[errResponseKey]) {
|
||||||
|
// login is expired
|
||||||
|
if (errResponseKey === ERROR_ENUM.unAuthorization) {
|
||||||
|
clearCookie(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseWrite({
|
||||||
|
res,
|
||||||
|
event: sseResponseEventEnum.error,
|
||||||
|
data: JSON.stringify(ERROR_RESPONSE[errResponseKey])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let msg = error?.response?.statusText || error?.message || '请求错误';
|
||||||
|
if (typeof error === 'string') {
|
||||||
|
msg = error;
|
||||||
|
} else if (proxyError[error?.code]) {
|
||||||
|
msg = '网络连接异常';
|
||||||
|
} else if (error?.response?.data?.error?.message) {
|
||||||
|
msg = error?.response?.data?.error?.message;
|
||||||
|
} else if (error?.error?.message) {
|
||||||
|
msg = error?.error?.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
addLog.error(`sse error: ${msg}`, error);
|
||||||
|
|
||||||
|
responseWrite({
|
||||||
|
res,
|
||||||
|
event: sseResponseEventEnum.error,
|
||||||
|
data: JSON.stringify({ message: msg })
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export function responseWriteController({
|
export function responseWriteController({
|
||||||
res,
|
res,
|
||||||
|
|||||||
26
packages/service/core/ai/audio/speech.ts
Normal file
26
packages/service/core/ai/audio/speech.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { Text2SpeechProps } from '@fastgpt/global/core/ai/speech/api';
|
||||||
|
import { getAIApi } from '../config';
|
||||||
|
import { defaultAudioSpeechModels } from '../../../../global/core/ai/model';
|
||||||
|
import { Text2SpeechVoiceEnum } from '@fastgpt/global/core/ai/speech/constant';
|
||||||
|
|
||||||
|
export async function text2Speech({
|
||||||
|
model = defaultAudioSpeechModels[0].model,
|
||||||
|
voice = Text2SpeechVoiceEnum.alloy,
|
||||||
|
input,
|
||||||
|
speed = 1
|
||||||
|
}: Text2SpeechProps) {
|
||||||
|
const ai = getAIApi();
|
||||||
|
const mp3 = await ai.audio.speech.create({
|
||||||
|
model,
|
||||||
|
voice,
|
||||||
|
input,
|
||||||
|
response_format: 'mp3',
|
||||||
|
speed
|
||||||
|
});
|
||||||
|
const buffer = Buffer.from(await mp3.arrayBuffer());
|
||||||
|
return {
|
||||||
|
model,
|
||||||
|
voice,
|
||||||
|
tts: buffer
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import type { UserModelSchema } from '@fastgpt/global/support/user/type';
|
import type { UserModelSchema } from '@fastgpt/global/support/user/type';
|
||||||
import OpenAI from 'openai';
|
import OpenAI from '@fastgpt/global/core/ai';
|
||||||
|
|
||||||
export const openaiBaseUrl = process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1';
|
export const openaiBaseUrl = process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1';
|
||||||
export const baseUrl = process.env.ONEAPI_URL || openaiBaseUrl;
|
export const baseUrl = process.env.ONEAPI_URL || openaiBaseUrl;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { ChatCompletionRequestMessage } from '@fastgpt/global/core/ai/type.d';
|
import type { ChatMessageItemType } from '@fastgpt/global/core/ai/type.d';
|
||||||
import { getAIApi } from '../config';
|
import { getAIApi } from '../config';
|
||||||
|
|
||||||
export const Prompt_QuestionGuide = `我不太清楚问你什么问题,请帮我生成 3 个问题,引导我继续提问。问题的长度应小于20个字符,按 JSON 格式返回: ["问题1", "问题2", "问题3"]`;
|
export const Prompt_QuestionGuide = `我不太清楚问你什么问题,请帮我生成 3 个问题,引导我继续提问。问题的长度应小于20个字符,按 JSON 格式返回: ["问题1", "问题2", "问题3"]`;
|
||||||
@ -7,7 +7,7 @@ export async function createQuestionGuide({
|
|||||||
messages,
|
messages,
|
||||||
model
|
model
|
||||||
}: {
|
}: {
|
||||||
messages: ChatCompletionRequestMessage[];
|
messages: ChatMessageItemType[];
|
||||||
model: string;
|
model: string;
|
||||||
}) {
|
}) {
|
||||||
const ai = getAIApi(undefined, 48000);
|
const ai = getAIApi(undefined, 48000);
|
||||||
|
|||||||
70
packages/service/core/app/schema.ts
Normal file
70
packages/service/core/app/schema.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { connectionMongo, type Model } from '../../common/mongo';
|
||||||
|
const { Schema, model, models } = connectionMongo;
|
||||||
|
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
|
||||||
|
import { PermissionTypeEnum, PermissionTypeMap } from '@fastgpt/global/support/permission/constant';
|
||||||
|
import {
|
||||||
|
TeamCollectionName,
|
||||||
|
TeamMemberCollectionName
|
||||||
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
|
|
||||||
|
export const appCollectionName = 'apps';
|
||||||
|
|
||||||
|
const AppSchema = new Schema({
|
||||||
|
userId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: 'user'
|
||||||
|
},
|
||||||
|
teamId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamCollectionName,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
tmbId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamMemberCollectionName,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'advanced',
|
||||||
|
enum: ['basic', 'advanced']
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
type: String,
|
||||||
|
default: '/icon/logo.svg'
|
||||||
|
},
|
||||||
|
intro: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
updateTime: {
|
||||||
|
type: Date,
|
||||||
|
default: () => new Date()
|
||||||
|
},
|
||||||
|
modules: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
inited: {
|
||||||
|
type: Boolean
|
||||||
|
},
|
||||||
|
permission: {
|
||||||
|
type: String,
|
||||||
|
enum: Object.keys(PermissionTypeMap),
|
||||||
|
default: PermissionTypeEnum.private
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
AppSchema.index({ updateTime: -1 });
|
||||||
|
AppSchema.index({ 'share.collection': -1 });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MongoApp: Model<AppType> =
|
||||||
|
models[appCollectionName] || model(appCollectionName, AppSchema);
|
||||||
@ -1,9 +1,15 @@
|
|||||||
import { connectionMongo, type Model } from '@fastgpt/service/common/mongo';
|
import { connectionMongo, type Model } from '../../common/mongo';
|
||||||
const { Schema, model, models } = connectionMongo;
|
const { Schema, model, models } = connectionMongo;
|
||||||
import { ChatItemSchema as ChatItemType } from '@/types/mongoSchema';
|
import { ChatItemSchema as ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||||
import { ChatRoleMap, TaskResponseKeyEnum } from '@/constants/chat';
|
import { ChatRoleMap, TaskResponseKeyEnum } from '@fastgpt/global/core/chat/constants';
|
||||||
import { customAlphabet } from 'nanoid';
|
import { customAlphabet } from 'nanoid';
|
||||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
|
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
|
||||||
|
import {
|
||||||
|
TeamCollectionName,
|
||||||
|
TeamMemberCollectionName
|
||||||
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
|
import { appCollectionName } from '../app/schema';
|
||||||
|
import { userCollectionName } from '../../support/user/schema';
|
||||||
|
|
||||||
const ChatItemSchema = new Schema({
|
const ChatItemSchema = new Schema({
|
||||||
dataId: {
|
dataId: {
|
||||||
@ -11,18 +17,27 @@ const ChatItemSchema = new Schema({
|
|||||||
require: true,
|
require: true,
|
||||||
default: () => nanoid()
|
default: () => nanoid()
|
||||||
},
|
},
|
||||||
|
appId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: appCollectionName,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
chatId: {
|
chatId: {
|
||||||
type: String,
|
type: String,
|
||||||
require: true
|
require: true
|
||||||
},
|
},
|
||||||
userId: {
|
userId: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'user',
|
ref: userCollectionName
|
||||||
|
},
|
||||||
|
teamId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamCollectionName,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
appId: {
|
tmbId: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'model',
|
ref: TeamMemberCollectionName,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
time: {
|
time: {
|
||||||
@ -53,6 +68,9 @@ const ChatItemSchema = new Schema({
|
|||||||
[TaskResponseKeyEnum.responseData]: {
|
[TaskResponseKeyEnum.responseData]: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: []
|
default: []
|
||||||
|
},
|
||||||
|
tts: {
|
||||||
|
type: Buffer
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -66,5 +84,5 @@ try {
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChatItem: Model<ChatItemType> =
|
export const MongoChatItem: Model<ChatItemType> =
|
||||||
models['chatItem'] || model('chatItem', ChatItemSchema);
|
models['chatItem'] || model('chatItem', ChatItemSchema);
|
||||||
@ -1,8 +1,18 @@
|
|||||||
import { connectionMongo, type Model } from '@fastgpt/service/common/mongo';
|
import { connectionMongo, type Model } from '../../common/mongo';
|
||||||
const { Schema, model, models } = connectionMongo;
|
const { Schema, model, models } = connectionMongo;
|
||||||
import { ChatSchema as ChatType } from '@/types/mongoSchema';
|
import { ChatSchema as ChatType } from '@fastgpt/global/core/chat/type.d';
|
||||||
import { ChatRoleMap, TaskResponseKeyEnum } from '@/constants/chat';
|
import {
|
||||||
import { ChatSourceMap } from '@/constants/chat';
|
ChatRoleMap,
|
||||||
|
ChatSourceMap,
|
||||||
|
TaskResponseKeyEnum
|
||||||
|
} from '@fastgpt/global/core/chat/constants';
|
||||||
|
import {
|
||||||
|
TeamCollectionName,
|
||||||
|
TeamMemberCollectionName
|
||||||
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
|
import { appCollectionName } from '../app/schema';
|
||||||
|
|
||||||
|
export const chatCollectionName = 'chat';
|
||||||
|
|
||||||
const ChatSchema = new Schema({
|
const ChatSchema = new Schema({
|
||||||
chatId: {
|
chatId: {
|
||||||
@ -11,12 +21,21 @@ const ChatSchema = new Schema({
|
|||||||
},
|
},
|
||||||
userId: {
|
userId: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'user',
|
ref: 'user'
|
||||||
|
},
|
||||||
|
teamId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamCollectionName,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
tmbId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamMemberCollectionName,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
appId: {
|
appId: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'model',
|
ref: appCollectionName,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
updateTime: {
|
updateTime: {
|
||||||
@ -80,4 +99,5 @@ try {
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Chat: Model<ChatType> = models['chat'] || model('chat', ChatSchema);
|
export const MongoChat: Model<ChatType> =
|
||||||
|
models[chatCollectionName] || model(chatCollectionName, ChatSchema);
|
||||||
@ -1,26 +0,0 @@
|
|||||||
import { ERROR_ENUM } from '@fastgpt/global/common/error/errorCode';
|
|
||||||
import { MongoDatasetCollection } from './collection/schema';
|
|
||||||
import { DatasetSchemaType } from '@fastgpt/global/core/dataset/type';
|
|
||||||
|
|
||||||
export async function authCollection({
|
|
||||||
collectionId,
|
|
||||||
userId
|
|
||||||
}: {
|
|
||||||
collectionId: string;
|
|
||||||
userId: string;
|
|
||||||
}) {
|
|
||||||
const collection = await MongoDatasetCollection.findOne({
|
|
||||||
_id: collectionId,
|
|
||||||
userId
|
|
||||||
})
|
|
||||||
.populate('datasetId')
|
|
||||||
.lean();
|
|
||||||
|
|
||||||
if (collection) {
|
|
||||||
return {
|
|
||||||
...collection,
|
|
||||||
dataset: collection.datasetId as unknown as DatasetSchemaType
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return Promise.reject(ERROR_ENUM.unAuthDataset);
|
|
||||||
}
|
|
||||||
@ -3,6 +3,10 @@ const { Schema, model, models } = connectionMongo;
|
|||||||
import { DatasetCollectionSchemaType } from '@fastgpt/global/core/dataset/type.d';
|
import { DatasetCollectionSchemaType } from '@fastgpt/global/core/dataset/type.d';
|
||||||
import { DatasetCollectionTypeMap } from '@fastgpt/global/core/dataset/constant';
|
import { DatasetCollectionTypeMap } from '@fastgpt/global/core/dataset/constant';
|
||||||
import { DatasetCollectionName } from '../schema';
|
import { DatasetCollectionName } from '../schema';
|
||||||
|
import {
|
||||||
|
TeamCollectionName,
|
||||||
|
TeamMemberCollectionName
|
||||||
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
|
|
||||||
export const DatasetColCollectionName = 'dataset.collections';
|
export const DatasetColCollectionName = 'dataset.collections';
|
||||||
|
|
||||||
@ -13,8 +17,18 @@ const DatasetCollectionSchema = new Schema({
|
|||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
userId: {
|
userId: {
|
||||||
|
// abandoned
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'user',
|
ref: 'user'
|
||||||
|
},
|
||||||
|
teamId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamCollectionName,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
tmbId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamMemberCollectionName,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
datasetId: {
|
datasetId: {
|
||||||
|
|||||||
@ -31,18 +31,16 @@ export async function findCollectionAndChild(id: string, fields = '_id parentId
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getDatasetCollectionPaths({
|
export async function getDatasetCollectionPaths({
|
||||||
parentId = '',
|
parentId = ''
|
||||||
userId
|
|
||||||
}: {
|
}: {
|
||||||
parentId?: string;
|
parentId?: string;
|
||||||
userId: string;
|
|
||||||
}): Promise<ParentTreePathItemType[]> {
|
}): Promise<ParentTreePathItemType[]> {
|
||||||
async function find(parentId?: string): Promise<ParentTreePathItemType[]> {
|
async function find(parentId?: string): Promise<ParentTreePathItemType[]> {
|
||||||
if (!parentId) {
|
if (!parentId) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const parent = await MongoDatasetCollection.findOne({ _id: parentId, userId }, 'name parentId');
|
const parent = await MongoDatasetCollection.findOne({ _id: parentId }, 'name parentId');
|
||||||
|
|
||||||
if (!parent) return [];
|
if (!parent) return [];
|
||||||
|
|
||||||
|
|||||||
12
packages/service/core/dataset/controller.ts
Normal file
12
packages/service/core/dataset/controller.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { CollectionWithDatasetType } from '@fastgpt/global/core/dataset/type';
|
||||||
|
import { MongoDatasetCollection } from './collection/schema';
|
||||||
|
|
||||||
|
export async function getCollectionWithDataset(collectionId: string) {
|
||||||
|
const data = (
|
||||||
|
await MongoDatasetCollection.findById(collectionId).populate('datasetId')
|
||||||
|
)?.toJSON() as CollectionWithDatasetType;
|
||||||
|
if (!data) {
|
||||||
|
return Promise.reject('Collection is not exist');
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
9
packages/service/core/dataset/file/controller.ts
Normal file
9
packages/service/core/dataset/file/controller.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
|
||||||
|
import { getGFSCollection } from '../../../common/file/gridfs/controller';
|
||||||
|
|
||||||
|
export async function delDatasetFiles({ datasetId }: { datasetId: string }) {
|
||||||
|
const db = getGFSCollection(BucketNameEnum.dataset);
|
||||||
|
await db.deleteMany({
|
||||||
|
'metadata.datasetId': String(datasetId)
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -2,6 +2,11 @@ import { connectionMongo, type Model } from '../../common/mongo';
|
|||||||
const { Schema, model, models } = connectionMongo;
|
const { Schema, model, models } = connectionMongo;
|
||||||
import { DatasetSchemaType } from '@fastgpt/global/core/dataset/type.d';
|
import { DatasetSchemaType } from '@fastgpt/global/core/dataset/type.d';
|
||||||
import { DatasetTypeMap } from '@fastgpt/global/core/dataset/constant';
|
import { DatasetTypeMap } from '@fastgpt/global/core/dataset/constant';
|
||||||
|
import {
|
||||||
|
TeamCollectionName,
|
||||||
|
TeamMemberCollectionName
|
||||||
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
|
import { PermissionTypeEnum, PermissionTypeMap } from '@fastgpt/global/support/permission/constant';
|
||||||
|
|
||||||
export const DatasetCollectionName = 'datasets';
|
export const DatasetCollectionName = 'datasets';
|
||||||
|
|
||||||
@ -12,8 +17,18 @@ const DatasetSchema = new Schema({
|
|||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
userId: {
|
userId: {
|
||||||
|
//abandon
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'user',
|
ref: 'user'
|
||||||
|
},
|
||||||
|
teamId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamCollectionName,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
tmbId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamMemberCollectionName,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
updateTime: {
|
updateTime: {
|
||||||
@ -41,7 +56,16 @@ const DatasetSchema = new Schema({
|
|||||||
},
|
},
|
||||||
tags: {
|
tags: {
|
||||||
type: [String],
|
type: [String],
|
||||||
default: []
|
default: [],
|
||||||
|
set(val: string | string[]) {
|
||||||
|
if (Array.isArray(val)) return val;
|
||||||
|
return val.split(' ').filter((item) => item);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
permission: {
|
||||||
|
type: String,
|
||||||
|
enum: Object.keys(PermissionTypeMap),
|
||||||
|
default: PermissionTypeEnum.private
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -5,13 +5,27 @@ import { DatasetTrainingSchemaType } from '@fastgpt/global/core/dataset/type';
|
|||||||
import { TrainingTypeMap } from '@fastgpt/global/core/dataset/constant';
|
import { TrainingTypeMap } from '@fastgpt/global/core/dataset/constant';
|
||||||
import { DatasetColCollectionName } from '../collection/schema';
|
import { DatasetColCollectionName } from '../collection/schema';
|
||||||
import { DatasetCollectionName } from '../schema';
|
import { DatasetCollectionName } from '../schema';
|
||||||
|
import {
|
||||||
|
TeamCollectionName,
|
||||||
|
TeamMemberCollectionName
|
||||||
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
|
|
||||||
export const DatasetTrainingCollectionName = 'dataset.trainings';
|
export const DatasetTrainingCollectionName = 'dataset.trainings';
|
||||||
|
|
||||||
const TrainingDataSchema = new Schema({
|
const TrainingDataSchema = new Schema({
|
||||||
userId: {
|
userId: {
|
||||||
|
// abandon
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'user',
|
ref: 'user'
|
||||||
|
},
|
||||||
|
teamId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamCollectionName,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
tmbId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamMemberCollectionName,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
datasetId: {
|
datasetId: {
|
||||||
|
|||||||
@ -1,38 +1,15 @@
|
|||||||
import { CreateOnePluginParams, UpdatePluginParams } from '@fastgpt/global/core/plugin/controller';
|
|
||||||
import { MongoPlugin } from './schema';
|
import { MongoPlugin } from './schema';
|
||||||
import { FlowModuleTemplateType } from '@fastgpt/global/core/module/type';
|
import { FlowModuleTemplateType } from '@fastgpt/global/core/module/type';
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||||
import { formatPluginIOModules } from '@fastgpt/global/core/module/utils';
|
import { formatPluginIOModules } from '@fastgpt/global/core/module/utils';
|
||||||
|
|
||||||
export async function createOnePlugin(data: CreateOnePluginParams & { userId: string }) {
|
|
||||||
const { _id } = await MongoPlugin.create(data);
|
|
||||||
return _id;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function updateOnePlugin({
|
|
||||||
id,
|
|
||||||
userId,
|
|
||||||
...data
|
|
||||||
}: UpdatePluginParams & { userId: string }) {
|
|
||||||
await MongoPlugin.findOneAndUpdate({ _id: id, userId }, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deleteOnePlugin({ id, userId }: { id: string; userId: string }) {
|
|
||||||
await MongoPlugin.findOneAndDelete({ _id: id, userId });
|
|
||||||
}
|
|
||||||
export async function getUserPlugins({ userId }: { userId: string }) {
|
|
||||||
return MongoPlugin.find({ userId }, 'name avatar intro');
|
|
||||||
}
|
|
||||||
export async function getOnePluginDetail({ id, userId }: { userId: string; id: string }) {
|
|
||||||
return MongoPlugin.findOne({ _id: id, userId });
|
|
||||||
}
|
|
||||||
/* plugin templates */
|
/* plugin templates */
|
||||||
export async function getUserPlugins2Templates({
|
export async function getUserPlugins2Templates({
|
||||||
userId
|
teamId
|
||||||
}: {
|
}: {
|
||||||
userId: string;
|
teamId: string;
|
||||||
}): Promise<FlowModuleTemplateType[]> {
|
}): Promise<FlowModuleTemplateType[]> {
|
||||||
const plugins = await MongoPlugin.find({ userId }).lean();
|
const plugins = await MongoPlugin.find({ teamId }).lean();
|
||||||
|
|
||||||
return plugins.map((plugin) => ({
|
return plugins.map((plugin) => ({
|
||||||
id: String(plugin._id),
|
id: String(plugin._id),
|
||||||
@ -47,8 +24,8 @@ export async function getUserPlugins2Templates({
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
/* one plugin 2 module detail */
|
/* one plugin 2 module detail */
|
||||||
export async function getPluginModuleDetail({ id, userId }: { userId: string; id: string }) {
|
export async function getPluginModuleDetail({ id }: { id: string }) {
|
||||||
const plugin = await getOnePluginDetail({ id, userId });
|
const plugin = await MongoPlugin.findById(id);
|
||||||
if (!plugin) return Promise.reject('plugin not found');
|
if (!plugin) return Promise.reject('plugin not found');
|
||||||
return {
|
return {
|
||||||
id: String(plugin._id),
|
id: String(plugin._id),
|
||||||
|
|||||||
@ -1,13 +1,26 @@
|
|||||||
import { connectionMongo, type Model } from '../../common/mongo';
|
import { connectionMongo, type Model } from '../../common/mongo';
|
||||||
const { Schema, model, models } = connectionMongo;
|
const { Schema, model, models } = connectionMongo;
|
||||||
import type { PluginItemSchema } from '@fastgpt/global/core/plugin/type.d';
|
import type { PluginItemSchema } from '@fastgpt/global/core/plugin/type.d';
|
||||||
|
import {
|
||||||
|
TeamCollectionName,
|
||||||
|
TeamMemberCollectionName
|
||||||
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
|
|
||||||
export const ModuleCollectionName = 'plugins';
|
export const ModuleCollectionName = 'plugins';
|
||||||
|
|
||||||
const PluginSchema = new Schema({
|
const PluginSchema = new Schema({
|
||||||
userId: {
|
userId: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'user',
|
ref: 'user'
|
||||||
|
},
|
||||||
|
teamId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamCollectionName,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
tmbId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamMemberCollectionName,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
|
|||||||
@ -13,10 +13,12 @@
|
|||||||
"winston-mongodb": "^5.1.1",
|
"winston-mongodb": "^5.1.1",
|
||||||
"tunnel": "^0.0.6",
|
"tunnel": "^0.0.6",
|
||||||
"encoding": "^0.1.13",
|
"encoding": "^0.1.13",
|
||||||
"openai": "^4.12.4"
|
"pg": "^8.10.0",
|
||||||
|
"nanoid": "^4.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/tunnel": "^0.0.4",
|
"@types/tunnel": "^0.0.4",
|
||||||
|
"@types/pg": "^8.6.6",
|
||||||
"@types/node": "^20.8.5",
|
"@types/node": "^20.8.5",
|
||||||
"@types/cookie": "^0.5.2",
|
"@types/cookie": "^0.5.2",
|
||||||
"@types/jsonwebtoken": "^9.0.3"
|
"@types/jsonwebtoken": "^9.0.3"
|
||||||
|
|||||||
@ -10,13 +10,11 @@ export async function authOpenApiKey({ apikey }: { apikey: string }) {
|
|||||||
if (!apikey) {
|
if (!apikey) {
|
||||||
return Promise.reject(ERROR_ENUM.unAuthApiKey);
|
return Promise.reject(ERROR_ENUM.unAuthApiKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const openApi = await MongoOpenApi.findOne({ apiKey: apikey });
|
const openApi = await MongoOpenApi.findOne({ apiKey: apikey });
|
||||||
if (!openApi) {
|
if (!openApi) {
|
||||||
return Promise.reject(ERROR_ENUM.unAuthApiKey);
|
return Promise.reject(ERROR_ENUM.unAuthApiKey);
|
||||||
}
|
}
|
||||||
const userId = String(openApi.userId);
|
|
||||||
|
|
||||||
// auth limit
|
// auth limit
|
||||||
if (global.feConfigs?.isPlus) {
|
if (global.feConfigs?.isPlus) {
|
||||||
@ -25,7 +23,13 @@ export async function authOpenApiKey({ apikey }: { apikey: string }) {
|
|||||||
|
|
||||||
updateApiKeyUsedTime(openApi._id);
|
updateApiKeyUsedTime(openApi._id);
|
||||||
|
|
||||||
return { apikey, userId, appId: openApi.appId };
|
return {
|
||||||
|
apikey,
|
||||||
|
userId: String(openApi.userId),
|
||||||
|
teamId: String(openApi.teamId),
|
||||||
|
tmbId: String(openApi.tmbId),
|
||||||
|
appId: openApi.appId || ''
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,27 @@
|
|||||||
import { connectionMongo, type Model } from '../../common/mongo';
|
import { connectionMongo, type Model } from '../../common/mongo';
|
||||||
const { Schema, model, models } = connectionMongo;
|
const { Schema, model, models } = connectionMongo;
|
||||||
import type { OpenApiSchema } from '@fastgpt/global/support/openapi/type';
|
import type { OpenApiSchema } from '@fastgpt/global/support/openapi/type';
|
||||||
import { PRICE_SCALE } from '@fastgpt/global/common/bill/constants';
|
import { PRICE_SCALE } from '@fastgpt/global/support/wallet/bill/constants';
|
||||||
import { formatPrice } from '@fastgpt/global/common/bill/tools';
|
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||||
|
import {
|
||||||
|
TeamCollectionName,
|
||||||
|
TeamMemberCollectionName
|
||||||
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
|
|
||||||
const OpenApiSchema = new Schema(
|
const OpenApiSchema = new Schema(
|
||||||
{
|
{
|
||||||
userId: {
|
userId: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'user',
|
ref: 'user'
|
||||||
|
},
|
||||||
|
teamId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamCollectionName,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
tmbId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamMemberCollectionName,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
apiKey: {
|
apiKey: {
|
||||||
|
|||||||
@ -1,68 +0,0 @@
|
|||||||
import { AuthUserTypeEnum, authBalanceByUid } from '../user/auth';
|
|
||||||
import { MongoOutLink } from './schema';
|
|
||||||
import { POST } from '../../common/api/plusRequest';
|
|
||||||
import { OutLinkSchema } from '@fastgpt/global/support/outLink/type';
|
|
||||||
|
|
||||||
export type AuthLinkProps = { ip?: string | null; authToken?: string; question: string };
|
|
||||||
export type AuthLinkLimitProps = AuthLinkProps & { outLink: OutLinkSchema };
|
|
||||||
|
|
||||||
export async function authOutLinkChat({
|
|
||||||
shareId,
|
|
||||||
ip,
|
|
||||||
authToken,
|
|
||||||
question
|
|
||||||
}: AuthLinkProps & {
|
|
||||||
shareId: string;
|
|
||||||
}) {
|
|
||||||
// get outLink
|
|
||||||
const outLink = await MongoOutLink.findOne({
|
|
||||||
shareId
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!outLink) {
|
|
||||||
return Promise.reject('分享链接无效');
|
|
||||||
}
|
|
||||||
|
|
||||||
const uid = String(outLink.userId);
|
|
||||||
|
|
||||||
const [user] = await Promise.all([
|
|
||||||
authBalanceByUid(uid), // authBalance
|
|
||||||
...(global.feConfigs?.isPlus ? [authOutLinkLimit({ outLink, ip, authToken, question })] : []) // limit auth
|
|
||||||
]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
user,
|
|
||||||
userId: String(outLink.userId),
|
|
||||||
appId: String(outLink.appId),
|
|
||||||
authType: AuthUserTypeEnum.token,
|
|
||||||
responseDetail: outLink.responseDetail
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function authOutLinkLimit(data: AuthLinkLimitProps) {
|
|
||||||
return POST('/support/outLink/authLimit', data);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function authOutLinkId({ id }: { id: string }) {
|
|
||||||
const outLink = await MongoOutLink.findOne({
|
|
||||||
shareId: id
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!outLink) {
|
|
||||||
return Promise.reject('分享链接无效');
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
userId: String(outLink.userId)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AuthShareChatInitProps = {
|
|
||||||
authToken?: string;
|
|
||||||
tokenUrl?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function authShareChatInit(data: AuthShareChatInitProps) {
|
|
||||||
if (!global.feConfigs?.isPlus) return;
|
|
||||||
return POST('/support/outLink/authShareChatInit', data);
|
|
||||||
}
|
|
||||||
@ -2,6 +2,10 @@ import { connectionMongo, type Model } from '../../common/mongo';
|
|||||||
const { Schema, model, models } = connectionMongo;
|
const { Schema, model, models } = connectionMongo;
|
||||||
import { OutLinkSchema as SchemaType } from '@fastgpt/global/support/outLink/type';
|
import { OutLinkSchema as SchemaType } from '@fastgpt/global/support/outLink/type';
|
||||||
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
|
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
|
||||||
|
import {
|
||||||
|
TeamCollectionName,
|
||||||
|
TeamMemberCollectionName
|
||||||
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
|
|
||||||
const OutLinkSchema = new Schema({
|
const OutLinkSchema = new Schema({
|
||||||
shareId: {
|
shareId: {
|
||||||
@ -10,7 +14,16 @@ const OutLinkSchema = new Schema({
|
|||||||
},
|
},
|
||||||
userId: {
|
userId: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'user',
|
ref: 'user'
|
||||||
|
},
|
||||||
|
teamId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamCollectionName,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
tmbId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: TeamMemberCollectionName,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
appId: {
|
appId: {
|
||||||
|
|||||||
72
packages/service/support/permission/auth/app.ts
Normal file
72
packages/service/support/permission/auth/app.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { MongoApp } from '../../../core/app/schema';
|
||||||
|
import { AppDetailType } from '@fastgpt/global/core/app/type.d';
|
||||||
|
import { AuthModeType } from '../type';
|
||||||
|
import { AuthResponseType } from '@fastgpt/global/support/permission/type';
|
||||||
|
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||||
|
import { parseHeaderCert } from '../controller';
|
||||||
|
import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||||
|
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
|
||||||
|
import { getTeamInfoByTmbId } from '../../user/team/controller';
|
||||||
|
|
||||||
|
// 模型使用权校验
|
||||||
|
export async function authApp({
|
||||||
|
appId,
|
||||||
|
per = 'owner',
|
||||||
|
...props
|
||||||
|
}: AuthModeType & {
|
||||||
|
appId: string;
|
||||||
|
}): Promise<
|
||||||
|
AuthResponseType & {
|
||||||
|
teamOwner: boolean;
|
||||||
|
app: AppDetailType;
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
const result = await parseHeaderCert(props);
|
||||||
|
const { userId, teamId, tmbId } = result;
|
||||||
|
const { role } = await getTeamInfoByTmbId({ tmbId });
|
||||||
|
|
||||||
|
const { app, isOwner, canWrite } = await (async () => {
|
||||||
|
// get app
|
||||||
|
const app = (await MongoApp.findOne({ _id: appId, teamId }))?.toJSON();
|
||||||
|
if (!app) {
|
||||||
|
return Promise.reject(AppErrEnum.unAuthApp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOwner =
|
||||||
|
role !== TeamMemberRoleEnum.visitor &&
|
||||||
|
(String(app.tmbId) === tmbId || role === TeamMemberRoleEnum.owner);
|
||||||
|
const canWrite =
|
||||||
|
isOwner ||
|
||||||
|
(app.permission === PermissionTypeEnum.public && role !== TeamMemberRoleEnum.visitor);
|
||||||
|
|
||||||
|
if (per === 'r') {
|
||||||
|
if (!isOwner && app.permission !== PermissionTypeEnum.public) {
|
||||||
|
return Promise.reject(AppErrEnum.unAuthApp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (per === 'w' && !canWrite) {
|
||||||
|
return Promise.reject(AppErrEnum.unAuthApp);
|
||||||
|
}
|
||||||
|
if (per === 'owner' && !isOwner) {
|
||||||
|
return Promise.reject(AppErrEnum.unAuthApp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
app: {
|
||||||
|
...app,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
},
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
app,
|
||||||
|
isOwner,
|
||||||
|
canWrite,
|
||||||
|
teamOwner: role === TeamMemberRoleEnum.owner
|
||||||
|
};
|
||||||
|
}
|
||||||
67
packages/service/support/permission/auth/chat.ts
Normal file
67
packages/service/support/permission/auth/chat.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { AuthResponseType } from '@fastgpt/global/support/permission/type';
|
||||||
|
import { AuthModeType } from '../type';
|
||||||
|
import type { ChatSchema, ChatWithAppSchema } from '@fastgpt/global/core/chat/type';
|
||||||
|
import { parseHeaderCert } from '../controller';
|
||||||
|
import { MongoChat } from '../../../core/chat/chatSchema';
|
||||||
|
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
|
||||||
|
import { getTeamInfoByTmbId } from '../../user/team/controller';
|
||||||
|
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||||
|
import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||||
|
|
||||||
|
export async function authChat({
|
||||||
|
chatId,
|
||||||
|
per = 'owner',
|
||||||
|
...props
|
||||||
|
}: AuthModeType & {
|
||||||
|
chatId: string;
|
||||||
|
}): Promise<
|
||||||
|
AuthResponseType & {
|
||||||
|
chat: ChatSchema;
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
const { userId, teamId, tmbId } = await parseHeaderCert(props);
|
||||||
|
const { role } = await getTeamInfoByTmbId({ tmbId });
|
||||||
|
|
||||||
|
const { chat, isOwner, canWrite } = await (async () => {
|
||||||
|
// get chat
|
||||||
|
const chat = (
|
||||||
|
await MongoChat.findOne({ chatId, teamId }).populate('appId')
|
||||||
|
)?.toJSON() as ChatWithAppSchema;
|
||||||
|
|
||||||
|
if (!chat) {
|
||||||
|
return Promise.reject('Chat is not exists');
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOwner = role === TeamMemberRoleEnum.owner || String(chat.tmbId) === tmbId;
|
||||||
|
const canWrite = isOwner;
|
||||||
|
|
||||||
|
if (
|
||||||
|
per === 'r' &&
|
||||||
|
role !== TeamMemberRoleEnum.owner &&
|
||||||
|
chat.appId.permission !== PermissionTypeEnum.public
|
||||||
|
) {
|
||||||
|
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||||
|
}
|
||||||
|
if (per === 'w' && !canWrite) {
|
||||||
|
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||||
|
}
|
||||||
|
if (per === 'owner' && !isOwner) {
|
||||||
|
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
chat,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId,
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
chat,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
}
|
||||||
12
packages/service/support/permission/auth/common.ts
Normal file
12
packages/service/support/permission/auth/common.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { parseHeaderCert } from '../controller';
|
||||||
|
import { AuthModeType } from '../type';
|
||||||
|
|
||||||
|
export const authCert = async (props: AuthModeType) => {
|
||||||
|
const result = await parseHeaderCert(props);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
isOwner: true,
|
||||||
|
canWrite: true
|
||||||
|
};
|
||||||
|
};
|
||||||
181
packages/service/support/permission/auth/dataset.ts
Normal file
181
packages/service/support/permission/auth/dataset.ts
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
import { AuthModeType } from '../type';
|
||||||
|
import { parseHeaderCert } from '../controller';
|
||||||
|
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
|
||||||
|
import { MongoDataset } from '../../../core/dataset/schema';
|
||||||
|
import { getCollectionWithDataset } from '../../../core/dataset/controller';
|
||||||
|
import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||||
|
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||||
|
import { AuthResponseType } from '@fastgpt/global/support/permission/type';
|
||||||
|
import {
|
||||||
|
CollectionWithDatasetType,
|
||||||
|
DatasetFileSchema,
|
||||||
|
DatasetSchemaType
|
||||||
|
} from '@fastgpt/global/core/dataset/type';
|
||||||
|
import { getFileById } from '../../../common/file/gridfs/controller';
|
||||||
|
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
|
||||||
|
import { getTeamInfoByTmbId } from '../../user/team/controller';
|
||||||
|
|
||||||
|
export async function authDataset({
|
||||||
|
datasetId,
|
||||||
|
per = 'owner',
|
||||||
|
...props
|
||||||
|
}: AuthModeType & {
|
||||||
|
datasetId: string;
|
||||||
|
}): Promise<
|
||||||
|
AuthResponseType & {
|
||||||
|
dataset: DatasetSchemaType;
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
const result = await parseHeaderCert(props);
|
||||||
|
const { userId, teamId, tmbId } = result;
|
||||||
|
const { role } = await getTeamInfoByTmbId({ tmbId });
|
||||||
|
|
||||||
|
const { dataset, isOwner, canWrite } = await (async () => {
|
||||||
|
const dataset = (await MongoDataset.findOne({ _id: datasetId, teamId }))?.toJSON();
|
||||||
|
|
||||||
|
if (!dataset) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDataset);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOwner =
|
||||||
|
role !== TeamMemberRoleEnum.visitor &&
|
||||||
|
(String(dataset.tmbId) === tmbId || role === TeamMemberRoleEnum.owner);
|
||||||
|
const canWrite =
|
||||||
|
isOwner ||
|
||||||
|
(role !== TeamMemberRoleEnum.visitor && dataset.permission === PermissionTypeEnum.public);
|
||||||
|
if (per === 'r') {
|
||||||
|
if (!isOwner && dataset.permission !== PermissionTypeEnum.public) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDataset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (per === 'w' && !canWrite) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDataset);
|
||||||
|
}
|
||||||
|
if (per === 'owner' && !isOwner) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDataset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { dataset, isOwner, canWrite };
|
||||||
|
})();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
dataset,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read: in team and dataset permission is public
|
||||||
|
Write: in team, not visitor and dataset permission is public
|
||||||
|
*/
|
||||||
|
export async function authDatasetCollection({
|
||||||
|
collectionId,
|
||||||
|
per = 'owner',
|
||||||
|
...props
|
||||||
|
}: AuthModeType & {
|
||||||
|
collectionId: string;
|
||||||
|
}): Promise<
|
||||||
|
AuthResponseType & {
|
||||||
|
collection: CollectionWithDatasetType;
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
const { userId, teamId, tmbId } = await parseHeaderCert(props);
|
||||||
|
const { role } = await getTeamInfoByTmbId({ tmbId });
|
||||||
|
|
||||||
|
const { collection, isOwner, canWrite } = await (async () => {
|
||||||
|
const collection = await getCollectionWithDataset(collectionId);
|
||||||
|
|
||||||
|
if (!collection || String(collection.teamId) !== teamId) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDatasetCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOwner =
|
||||||
|
String(collection.datasetId.tmbId) === tmbId || role === TeamMemberRoleEnum.owner;
|
||||||
|
const canWrite =
|
||||||
|
isOwner ||
|
||||||
|
(role !== TeamMemberRoleEnum.visitor &&
|
||||||
|
collection.datasetId.permission === PermissionTypeEnum.public);
|
||||||
|
|
||||||
|
if (per === 'r') {
|
||||||
|
if (!isOwner && collection.datasetId.permission !== PermissionTypeEnum.public) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDatasetCollection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (per === 'w' && !canWrite) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDatasetCollection);
|
||||||
|
}
|
||||||
|
if (per === 'owner' && !isOwner) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDatasetCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
collection,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId,
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
collection,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function authDatasetFile({
|
||||||
|
fileId,
|
||||||
|
per = 'owner',
|
||||||
|
...props
|
||||||
|
}: AuthModeType & {
|
||||||
|
fileId: string;
|
||||||
|
}): Promise<
|
||||||
|
AuthResponseType & {
|
||||||
|
file: DatasetFileSchema;
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
const { userId, teamId, tmbId } = await parseHeaderCert(props);
|
||||||
|
const { role } = await getTeamInfoByTmbId({ tmbId });
|
||||||
|
|
||||||
|
const file = await getFileById({ bucketName: BucketNameEnum.dataset, fileId });
|
||||||
|
|
||||||
|
if (file.metadata.teamId !== teamId) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDatasetFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { dataset } = await authDataset({
|
||||||
|
...props,
|
||||||
|
datasetId: file.metadata.datasetId,
|
||||||
|
per
|
||||||
|
});
|
||||||
|
const isOwner =
|
||||||
|
role !== TeamMemberRoleEnum.visitor &&
|
||||||
|
(String(dataset.tmbId) === tmbId || role === TeamMemberRoleEnum.owner);
|
||||||
|
|
||||||
|
const canWrite =
|
||||||
|
isOwner ||
|
||||||
|
(role !== TeamMemberRoleEnum.visitor && dataset.permission === PermissionTypeEnum.public);
|
||||||
|
|
||||||
|
if (per === 'r' && !isOwner && dataset.permission !== PermissionTypeEnum.public) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDatasetFile);
|
||||||
|
}
|
||||||
|
if (per === 'w' && !canWrite) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDatasetFile);
|
||||||
|
}
|
||||||
|
if (per === 'owner' && !isOwner) {
|
||||||
|
return Promise.reject(DatasetErrEnum.unAuthDatasetFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId,
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
file,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
}
|
||||||
61
packages/service/support/permission/auth/openapi.ts
Normal file
61
packages/service/support/permission/auth/openapi.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { AuthResponseType } from '@fastgpt/global/support/permission/type';
|
||||||
|
import { AuthModeType } from '../type';
|
||||||
|
import { OpenApiSchema } from '@fastgpt/global/support/openapi/type';
|
||||||
|
import { parseHeaderCert } from '../controller';
|
||||||
|
import { getTeamInfoByTmbId } from '../../user/team/controller';
|
||||||
|
import { MongoOpenApi } from '../../openapi/schema';
|
||||||
|
import { OpenApiErrEnum } from '@fastgpt/global/common/error/code/openapi';
|
||||||
|
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||||
|
import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||||
|
|
||||||
|
export async function authOpenApiKeyCrud({
|
||||||
|
id,
|
||||||
|
per = 'owner',
|
||||||
|
...props
|
||||||
|
}: AuthModeType & {
|
||||||
|
id: string;
|
||||||
|
}): Promise<
|
||||||
|
AuthResponseType & {
|
||||||
|
openapi: OpenApiSchema;
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
const result = await parseHeaderCert(props);
|
||||||
|
const { tmbId, teamId } = result;
|
||||||
|
|
||||||
|
const { role } = await getTeamInfoByTmbId({ tmbId });
|
||||||
|
|
||||||
|
const { openapi, isOwner, canWrite } = await (async () => {
|
||||||
|
const openapi = await MongoOpenApi.findOne({ _id: id, teamId });
|
||||||
|
|
||||||
|
if (!openapi) {
|
||||||
|
throw new Error(OpenApiErrEnum.unExist);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOwner = String(openapi.tmbId) === tmbId || role === TeamMemberRoleEnum.owner;
|
||||||
|
const canWrite =
|
||||||
|
isOwner || (String(openapi.tmbId) === tmbId && role !== TeamMemberRoleEnum.visitor);
|
||||||
|
|
||||||
|
if (per === 'r' && !canWrite) {
|
||||||
|
return Promise.reject(OpenApiErrEnum.unAuth);
|
||||||
|
}
|
||||||
|
if (per === 'w' && !canWrite) {
|
||||||
|
return Promise.reject(OpenApiErrEnum.unAuth);
|
||||||
|
}
|
||||||
|
if (per === 'owner' && !isOwner) {
|
||||||
|
return Promise.reject(OpenApiErrEnum.unAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
openapi,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
openapi,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
}
|
||||||
98
packages/service/support/permission/auth/outLink.ts
Normal file
98
packages/service/support/permission/auth/outLink.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||||
|
import { AuthModeType } from '../type';
|
||||||
|
import { AuthResponseType } from '@fastgpt/global/support/permission/type';
|
||||||
|
import { AppDetailType } from '@fastgpt/global/core/app/type';
|
||||||
|
import { OutLinkSchema } from '@fastgpt/global/support/outLink/type';
|
||||||
|
import { parseHeaderCert } from '../controller';
|
||||||
|
import { MongoOutLink } from '../../outLink/schema';
|
||||||
|
import { MongoApp } from '../../../core/app/schema';
|
||||||
|
import { OutLinkErrEnum } from '@fastgpt/global/common/error/code/outLink';
|
||||||
|
import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||||
|
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
|
||||||
|
import { getTeamInfoByTmbId } from '../../user/team/controller';
|
||||||
|
|
||||||
|
/* crud outlink permission */
|
||||||
|
export async function authOutLinkCrud({
|
||||||
|
outLinkId,
|
||||||
|
per = 'owner',
|
||||||
|
...props
|
||||||
|
}: AuthModeType & {
|
||||||
|
outLinkId: string;
|
||||||
|
}): Promise<
|
||||||
|
AuthResponseType & {
|
||||||
|
app: AppDetailType;
|
||||||
|
outLink: OutLinkSchema;
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
const result = await parseHeaderCert(props);
|
||||||
|
const { tmbId, teamId } = result;
|
||||||
|
|
||||||
|
const { role } = await getTeamInfoByTmbId({ tmbId });
|
||||||
|
|
||||||
|
const { app, outLink, isOwner, canWrite } = await (async () => {
|
||||||
|
const outLink = await MongoOutLink.findOne({ _id: outLinkId, teamId });
|
||||||
|
|
||||||
|
if (!outLink) {
|
||||||
|
throw new Error(OutLinkErrEnum.unExist);
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = await MongoApp.findById(outLink.appId);
|
||||||
|
|
||||||
|
if (!app) {
|
||||||
|
return Promise.reject(AppErrEnum.unExist);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOwner = String(outLink.tmbId) === tmbId || role === TeamMemberRoleEnum.owner;
|
||||||
|
const canWrite =
|
||||||
|
isOwner ||
|
||||||
|
(app.permission === PermissionTypeEnum.public && role !== TeamMemberRoleEnum.visitor);
|
||||||
|
|
||||||
|
if (per === 'r' && !isOwner && app.permission !== PermissionTypeEnum.public) {
|
||||||
|
return Promise.reject(OutLinkErrEnum.unAuthLink);
|
||||||
|
}
|
||||||
|
if (per === 'w' && !canWrite) {
|
||||||
|
return Promise.reject(OutLinkErrEnum.unAuthLink);
|
||||||
|
}
|
||||||
|
if (per === 'owner' && !isOwner) {
|
||||||
|
return Promise.reject(OutLinkErrEnum.unAuthLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
app: {
|
||||||
|
...app,
|
||||||
|
isOwner: String(app.tmbId) === tmbId,
|
||||||
|
canWrite
|
||||||
|
},
|
||||||
|
outLink,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
app,
|
||||||
|
outLink,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function authOutLinkValid({ shareId }: { shareId?: string }) {
|
||||||
|
const shareChat = await MongoOutLink.findOne({ shareId });
|
||||||
|
|
||||||
|
if (!shareChat) {
|
||||||
|
return Promise.reject(OutLinkErrEnum.linkUnInvalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = await MongoApp.findById(shareChat.appId);
|
||||||
|
|
||||||
|
if (!app) {
|
||||||
|
return Promise.reject(AppErrEnum.unExist);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
app,
|
||||||
|
shareChat
|
||||||
|
};
|
||||||
|
}
|
||||||
56
packages/service/support/permission/auth/plugin.ts
Normal file
56
packages/service/support/permission/auth/plugin.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { AuthResponseType } from '@fastgpt/global/support/permission/type';
|
||||||
|
import { AuthModeType } from '../type';
|
||||||
|
import { parseHeaderCert } from '../controller';
|
||||||
|
import { getTeamInfoByTmbId } from '../../user/team/controller';
|
||||||
|
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||||
|
import { MongoPlugin } from '../../../core/plugin/schema';
|
||||||
|
import { PluginErrEnum } from '@fastgpt/global/common/error/code/plugin';
|
||||||
|
import { PluginItemSchema } from '@fastgpt/global/core/plugin/type';
|
||||||
|
|
||||||
|
export async function authPluginCrud({
|
||||||
|
id,
|
||||||
|
per = 'owner',
|
||||||
|
...props
|
||||||
|
}: AuthModeType & {
|
||||||
|
id: string;
|
||||||
|
}): Promise<
|
||||||
|
AuthResponseType & {
|
||||||
|
plugin: PluginItemSchema;
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
const result = await parseHeaderCert(props);
|
||||||
|
const { tmbId, teamId } = result;
|
||||||
|
|
||||||
|
const { role } = await getTeamInfoByTmbId({ tmbId });
|
||||||
|
|
||||||
|
const { plugin, isOwner, canWrite } = await (async () => {
|
||||||
|
const plugin = await MongoPlugin.findOne({ _id: id, teamId });
|
||||||
|
|
||||||
|
if (!plugin) {
|
||||||
|
throw new Error(PluginErrEnum.unExist);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOwner = String(plugin.tmbId) === tmbId || role === TeamMemberRoleEnum.owner;
|
||||||
|
const canWrite = isOwner;
|
||||||
|
|
||||||
|
if (per === 'w' && !canWrite) {
|
||||||
|
return Promise.reject(PluginErrEnum.unAuth);
|
||||||
|
}
|
||||||
|
if (per === 'owner' && !isOwner) {
|
||||||
|
return Promise.reject(PluginErrEnum.unAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
plugin,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
plugin,
|
||||||
|
isOwner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
}
|
||||||
52
packages/service/support/permission/auth/user.ts
Normal file
52
packages/service/support/permission/auth/user.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { AuthResponseType } from '@fastgpt/global/support/permission/type';
|
||||||
|
import { AuthModeType } from '../type';
|
||||||
|
import { TeamItemType } from '@fastgpt/global/support/user/team/type';
|
||||||
|
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||||
|
import { parseHeaderCert } from '../controller';
|
||||||
|
import { getTeamInfoByTmbId } from '../../user/team/controller';
|
||||||
|
import { UserErrEnum } from '../../../../global/common/error/code/user';
|
||||||
|
|
||||||
|
export async function authUserNotVisitor(props: AuthModeType): Promise<
|
||||||
|
AuthResponseType & {
|
||||||
|
team: TeamItemType;
|
||||||
|
role: `${TeamMemberRoleEnum}`;
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
const { userId, teamId, tmbId } = await parseHeaderCert(props);
|
||||||
|
const team = await getTeamInfoByTmbId({ tmbId });
|
||||||
|
|
||||||
|
if (team.role === TeamMemberRoleEnum.visitor) {
|
||||||
|
return Promise.reject(UserErrEnum.binVisitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId,
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
team,
|
||||||
|
role: team.role,
|
||||||
|
isOwner: team.role === TeamMemberRoleEnum.owner, // teamOwner
|
||||||
|
canWrite: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* auth user role */
|
||||||
|
export async function authUserRole(props: AuthModeType): Promise<
|
||||||
|
AuthResponseType & {
|
||||||
|
role: `${TeamMemberRoleEnum}`;
|
||||||
|
teamOwner: boolean;
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
const { userId, teamId, tmbId } = await parseHeaderCert(props);
|
||||||
|
const { role: userRole, canWrite } = await getTeamInfoByTmbId({ tmbId });
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId,
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
isOwner: true,
|
||||||
|
role: userRole,
|
||||||
|
teamOwner: userRole === TeamMemberRoleEnum.owner,
|
||||||
|
canWrite
|
||||||
|
};
|
||||||
|
}
|
||||||
241
packages/service/support/permission/controller.ts
Normal file
241
packages/service/support/permission/controller.ts
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
import Cookie from 'cookie';
|
||||||
|
import { ERROR_ENUM } from '@fastgpt/global/common/error/errorCode';
|
||||||
|
import jwt from 'jsonwebtoken';
|
||||||
|
import { NextApiResponse } from 'next';
|
||||||
|
import type { AuthModeType, ReqHeaderAuthType } from './type.d';
|
||||||
|
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||||
|
import { authOpenApiKey } from '../openapi/auth';
|
||||||
|
import { FileTokenQuery } from '@fastgpt/global/common/file/type';
|
||||||
|
|
||||||
|
/* create token */
|
||||||
|
export function createJWT(user: { _id?: string; team?: { teamId?: string; tmbId: string } }) {
|
||||||
|
const key = process.env.TOKEN_KEY as string;
|
||||||
|
const token = jwt.sign(
|
||||||
|
{
|
||||||
|
userId: String(user._id),
|
||||||
|
teamId: String(user.team?.teamId),
|
||||||
|
tmbId: String(user.team?.tmbId),
|
||||||
|
exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7
|
||||||
|
},
|
||||||
|
key
|
||||||
|
);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
// auth token
|
||||||
|
export function authJWT(token: string) {
|
||||||
|
return new Promise<{
|
||||||
|
userId: string;
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
}>((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({
|
||||||
|
userId: decoded.userId,
|
||||||
|
teamId: decoded.teamId || '',
|
||||||
|
tmbId: decoded.tmbId
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function parseHeaderCert({
|
||||||
|
req,
|
||||||
|
authToken = false,
|
||||||
|
authRoot = false,
|
||||||
|
authApiKey = false
|
||||||
|
}: AuthModeType) {
|
||||||
|
// parse jwt
|
||||||
|
async function authCookieToken(cookie?: string, token?: string) {
|
||||||
|
// 获取 cookie
|
||||||
|
const cookies = Cookie.parse(cookie || '');
|
||||||
|
const cookieToken = cookies.token || token;
|
||||||
|
|
||||||
|
if (!cookieToken) {
|
||||||
|
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await authJWT(cookieToken);
|
||||||
|
}
|
||||||
|
// from authorization get apikey
|
||||||
|
async function parseAuthorization(authorization?: string) {
|
||||||
|
if (!authorization) {
|
||||||
|
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bearer fastgpt-xxxx-appId
|
||||||
|
const auth = authorization.split(' ')[1];
|
||||||
|
if (!auth) {
|
||||||
|
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { apikey, appId: authorizationAppid = '' } = await (async () => {
|
||||||
|
const arr = auth.split('-');
|
||||||
|
// abandon
|
||||||
|
if (arr.length === 3) {
|
||||||
|
return {
|
||||||
|
apikey: `${arr[0]}-${arr[1]}`,
|
||||||
|
appId: arr[2]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (arr.length === 2) {
|
||||||
|
return {
|
||||||
|
apikey: auth
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// auth apikey
|
||||||
|
const { userId, teamId, tmbId, appId: apiKeyAppId = '' } = await authOpenApiKey({ apikey });
|
||||||
|
|
||||||
|
return {
|
||||||
|
uid: userId,
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
apikey,
|
||||||
|
appId: apiKeyAppId || authorizationAppid
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// root user
|
||||||
|
async function parseRootKey(rootKey?: string, userId = '') {
|
||||||
|
if (!rootKey || !process.env.ROOT_KEY || rootKey !== process.env.ROOT_KEY) {
|
||||||
|
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||||
|
}
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { cookie, token, apikey, rootkey, userid, authorization } = (req.headers ||
|
||||||
|
{}) as ReqHeaderAuthType;
|
||||||
|
|
||||||
|
const { uid, teamId, tmbId, appId, openApiKey, authType } = await (async () => {
|
||||||
|
if (authToken && (cookie || token)) {
|
||||||
|
// user token(from fastgpt web)
|
||||||
|
const res = await authCookieToken(cookie, token);
|
||||||
|
return {
|
||||||
|
uid: res.userId,
|
||||||
|
teamId: res.teamId,
|
||||||
|
tmbId: res.tmbId,
|
||||||
|
appId: '',
|
||||||
|
openApiKey: '',
|
||||||
|
authType: AuthUserTypeEnum.token
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (authRoot && rootkey) {
|
||||||
|
// root user
|
||||||
|
return {
|
||||||
|
uid: await parseRootKey(rootkey, userid),
|
||||||
|
teamId: '',
|
||||||
|
tmbId: '',
|
||||||
|
appId: '',
|
||||||
|
openApiKey: '',
|
||||||
|
authType: AuthUserTypeEnum.root
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (authApiKey && apikey) {
|
||||||
|
// apikey
|
||||||
|
const parseResult = await authOpenApiKey({ apikey });
|
||||||
|
return {
|
||||||
|
uid: parseResult.userId,
|
||||||
|
teamId: parseResult.teamId,
|
||||||
|
tmbId: parseResult.tmbId,
|
||||||
|
appId: parseResult.appId,
|
||||||
|
openApiKey: parseResult.apikey,
|
||||||
|
authType: AuthUserTypeEnum.apikey
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authApiKey && authorization) {
|
||||||
|
// apikey from authorization
|
||||||
|
const authResponse = await parseAuthorization(authorization);
|
||||||
|
return {
|
||||||
|
uid: authResponse.uid,
|
||||||
|
teamId: authResponse.teamId,
|
||||||
|
tmbId: authResponse.tmbId,
|
||||||
|
appId: authResponse.appId,
|
||||||
|
openApiKey: authResponse.apikey,
|
||||||
|
authType: AuthUserTypeEnum.apikey
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
uid: '',
|
||||||
|
teamId: '',
|
||||||
|
tmbId: '',
|
||||||
|
appId: '',
|
||||||
|
openApiKey: '',
|
||||||
|
authType: AuthUserTypeEnum.token
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
// not rootUser and no uid, reject request
|
||||||
|
if (!rootkey && !uid && !teamId && !tmbId) {
|
||||||
|
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: String(uid),
|
||||||
|
teamId: String(teamId),
|
||||||
|
tmbId: String(tmbId),
|
||||||
|
appId,
|
||||||
|
authType,
|
||||||
|
apikey: openApiKey
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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');
|
||||||
|
};
|
||||||
|
|
||||||
|
/* file permission */
|
||||||
|
export const createFileToken = (data: FileTokenQuery) => {
|
||||||
|
if (!process.env.FILE_TOKEN_KEY) {
|
||||||
|
return Promise.reject('System unset FILE_TOKEN_KEY');
|
||||||
|
}
|
||||||
|
const expiredTime = Math.floor(Date.now() / 1000) + 60 * 30;
|
||||||
|
|
||||||
|
const key = process.env.FILE_TOKEN_KEY as string;
|
||||||
|
const token = jwt.sign(
|
||||||
|
{
|
||||||
|
...data,
|
||||||
|
exp: expiredTime
|
||||||
|
},
|
||||||
|
key
|
||||||
|
);
|
||||||
|
return Promise.resolve(token);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const authFileToken = (token?: string) =>
|
||||||
|
new Promise<FileTokenQuery>((resolve, reject) => {
|
||||||
|
if (!token) {
|
||||||
|
return reject(ERROR_ENUM.unAuthFile);
|
||||||
|
}
|
||||||
|
const key = process.env.FILE_TOKEN_KEY as string;
|
||||||
|
|
||||||
|
jwt.verify(token, key, function (err, decoded: any) {
|
||||||
|
if (err || !decoded.bucketName || !decoded?.teamId || !decoded?.tmbId || !decoded?.fileId) {
|
||||||
|
reject(ERROR_ENUM.unAuthFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve({
|
||||||
|
bucketName: decoded.bucketName,
|
||||||
|
teamId: decoded.teamId,
|
||||||
|
tmbId: decoded.tmbId,
|
||||||
|
fileId: decoded.fileId
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user