mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 13:03:50 +00:00
v4.6 -1 (#459)
This commit is contained in:
2
.github/ISSUE_TEMPLATE/bugs.md
vendored
2
.github/ISSUE_TEMPLATE/bugs.md
vendored
@@ -11,7 +11,7 @@ assignees: ''
|
||||
[//]: # '方框内填 x 表示打钩'
|
||||
|
||||
- [ ] 我已确认目前没有类似 issue
|
||||
- [ ] 我已完整查看过项目 README,以及[项目文档](https://doc.fastgpt.run/docs/intro/)
|
||||
- [ ] 我已完整查看过项目 README,以及[项目文档](https://doc.fastgpt.in/docs/intro/)
|
||||
- [ ] 我使用了自己的 key,并确认我的 key 是可正常使用的
|
||||
- [ ] 我理解并愿意跟进此 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
|
||||
contact_links:
|
||||
- name: 微信交流群
|
||||
url: https://doc.fastgpt.run/wechat-fastgpt.webp
|
||||
url: https://doc.fastgpt.in/wechat-fastgpt.webp
|
||||
about: FastGPT 全是问题群
|
||||
|
@@ -17,10 +17,10 @@ FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开
|
||||
<a href="https://fastgpt.run/">
|
||||
<img height="21" src="https://img.shields.io/badge/在线使用-d4eaf7?style=flat-square&logo=spoj&logoColor=7d09f1" alt="cloud">
|
||||
</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">
|
||||
</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">
|
||||
</a>
|
||||
<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
|
||||
|
||||
@@ -132,4 +132,4 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b
|
||||
1. 允许作为后台服务直接商用,但不允许提供 SaaS 服务。
|
||||
2. 未经商业授权,任何形式的商用服务均需保留相关版权信息。
|
||||
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
|
||||
{
|
||||
"SystemParams": {
|
||||
"pluginBaseUrl": "", // 商业版接口地址
|
||||
"vectorMaxProcess": 15, // 向量生成最大进程,结合数据库性能和 key 来设置
|
||||
"qaMaxProcess": 15, // QA 生成最大进程,结合数据库性能和 key 来设置
|
||||
"pgHNSWEfSearch": 100 // pg vector 索引参数,越大精度高但速度慢
|
||||
},
|
||||
"ChatModels": [
|
||||
{
|
||||
"model": "gpt-3.5-turbo", // 实际调用的模型
|
||||
"name": "GPT35-4k", // 展示的名字
|
||||
"maxToken": 4000, // 最大token,均按 gpt35 计算
|
||||
"quoteMaxToken": 2000, // 引用内容最大 token
|
||||
"maxTemperature": 1.2, // 最大温度
|
||||
"price": 0,
|
||||
"model": "gpt-3.5-turbo-1106",
|
||||
"name": "GPT35-1106",
|
||||
"price": 0, // 除以 100000 后等于1个token的价格
|
||||
"maxContext": 16000, // 最大上下文长度
|
||||
"maxResponse": 4000, // 最大回复长度
|
||||
"quoteMaxToken": 2000, // 最大引用内容长度
|
||||
"maxTemperature": 1.2, // 最大温度值
|
||||
"censor": false, // 是否开启敏感词过滤(商业版)
|
||||
"defaultSystemChatPrompt": ""
|
||||
},
|
||||
{
|
||||
"model": "gpt-3.5-turbo-16k",
|
||||
"name": "GPT35-16k",
|
||||
"maxToken": 16000,
|
||||
"maxContext": 16000,
|
||||
"maxResponse": 16000,
|
||||
"price": 0,
|
||||
"quoteMaxToken": 8000,
|
||||
"maxTemperature": 1.2,
|
||||
"price": 0,
|
||||
"censor": false,
|
||||
"defaultSystemChatPrompt": ""
|
||||
},
|
||||
{
|
||||
"model": "gpt-4",
|
||||
"name": "GPT4-8k",
|
||||
"maxToken": 8000,
|
||||
"maxContext": 8000,
|
||||
"maxResponse": 8000,
|
||||
"price": 0,
|
||||
"quoteMaxToken": 4000,
|
||||
"maxTemperature": 1.2,
|
||||
"price": 0,
|
||||
"censor": false,
|
||||
"defaultSystemChatPrompt": ""
|
||||
}
|
||||
],
|
||||
"QAModels": [ // QA 拆分模型
|
||||
{
|
||||
"QAModels": [
|
||||
{
|
||||
"model": "gpt-3.5-turbo-16k",
|
||||
"name": "GPT35-16k",
|
||||
"maxToken": 16000,
|
||||
"maxContext": 16000,
|
||||
"maxResponse": 16000,
|
||||
"price": 0
|
||||
}
|
||||
],
|
||||
"ExtractModels": [ // 内容提取模型
|
||||
{
|
||||
"model": "gpt-3.5-turbo-16k",
|
||||
"name": "GPT35-16k",
|
||||
"maxToken": 16000,
|
||||
"price": 0,
|
||||
"functionCall": true, // 是否支持 function call
|
||||
"functionPrompt": "" // 自定义非 function call 提示词
|
||||
}
|
||||
],
|
||||
"CQModels": [ // Classify Question: 问题分类模型
|
||||
"CQModels": [
|
||||
{
|
||||
"model": "gpt-3.5-turbo-16k",
|
||||
"name": "GPT35-16k",
|
||||
"maxToken": 16000,
|
||||
"model": "gpt-3.5-turbo-1106",
|
||||
"name": "GPT35-1106",
|
||||
"maxContext": 16000,
|
||||
"maxResponse": 4000,
|
||||
"price": 0,
|
||||
"functionCall": true,
|
||||
"functionPrompt": ""
|
||||
@@ -84,17 +83,30 @@ weight: 520
|
||||
{
|
||||
"model": "gpt-4",
|
||||
"name": "GPT4-8k",
|
||||
"maxToken": 8000,
|
||||
"maxContext": 8000,
|
||||
"maxResponse": 8000,
|
||||
"price": 0,
|
||||
"functionCall": true,
|
||||
"functionPrompt": ""
|
||||
}
|
||||
],
|
||||
"QGModels": [ // Question Generation: 生成下一步指引模型
|
||||
{
|
||||
"model": "gpt-3.5-turbo",
|
||||
"name": "GPT35-4k",
|
||||
"maxToken": 4000,
|
||||
"ExtractModels": [
|
||||
{
|
||||
"model": "gpt-3.5-turbo-1106",
|
||||
"name": "GPT35-1106",
|
||||
"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
|
||||
}
|
||||
],
|
||||
@@ -102,10 +114,22 @@ weight: 520
|
||||
{
|
||||
"model": "text-embedding-ada-002",
|
||||
"name": "Embedding-2",
|
||||
"price": 0,
|
||||
"defaultToken": 500,
|
||||
"price": 0.2,
|
||||
"defaultToken": 700,
|
||||
"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
|
||||
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 'Content-Type: application/json' \
|
||||
--data-raw ''
|
||||
|
@@ -99,9 +99,9 @@ CHAT_API_KEY=sk-xxxxxx
|
||||
{
|
||||
"model": "ERNIE-Bot", // 这里的模型需要对应 One API 的模型
|
||||
"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.
|
||||
"price": 0, // 1个token 价格 => 1.5 / 100000 * 1000 = 0.015元/1k token
|
||||
"quoteMaxToken": 2000, // 引用知识库的最大 Token
|
||||
"maxTemperature": 1, // 最大温度
|
||||
"defaultSystemChatPrompt": "" // 默认的系统提示词
|
||||
|
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: 'V4.4.7'
|
||||
title: 'V4.4.7(需执行升级脚本)'
|
||||
description: 'FastGPT V4.4.7 更新(需执行升级脚本)'
|
||||
icon: 'upgrade'
|
||||
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": {
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^13.2.1",
|
||||
"prettier": "^3.0.3",
|
||||
"i18next": "^22.5.1",
|
||||
"lint-staged": "^13.2.1",
|
||||
"next-i18next": "^13.3.0",
|
||||
"prettier": "^3.0.3",
|
||||
"react-i18next": "^12.3.1",
|
||||
"next-i18next": "^13.3.0"
|
||||
"zhlint": "^0.7.1"
|
||||
},
|
||||
"lint-staged": {
|
||||
"./**/**/*.{ts,tsx,scss}": "npm run format-code",
|
||||
@@ -21,5 +22,8 @@
|
||||
},
|
||||
"engines": {
|
||||
"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 } = {
|
||||
400: '请求失败',
|
||||
401: '无权访问',
|
||||
@@ -27,10 +36,19 @@ export enum ERROR_ENUM {
|
||||
insufficientQuota = 'insufficientQuota',
|
||||
unAuthModel = 'unAuthModel',
|
||||
unAuthApiKey = 'unAuthApiKey',
|
||||
unAuthDataset = 'unAuthDataset',
|
||||
unAuthDatasetCollection = 'unAuthDatasetCollection',
|
||||
unAuthFile = 'unAuthFile'
|
||||
}
|
||||
|
||||
export type ErrType<T> = Record<
|
||||
string,
|
||||
{
|
||||
code: number;
|
||||
statusText: T;
|
||||
message: string;
|
||||
data: null;
|
||||
}
|
||||
>;
|
||||
|
||||
export const ERROR_RESPONSE: Record<
|
||||
any,
|
||||
{
|
||||
@@ -55,15 +73,10 @@ export const ERROR_RESPONSE: Record<
|
||||
[ERROR_ENUM.unAuthModel]: {
|
||||
code: 511,
|
||||
statusText: ERROR_ENUM.unAuthModel,
|
||||
message: '无权使用该模型',
|
||||
data: null
|
||||
},
|
||||
[ERROR_ENUM.unAuthDataset]: {
|
||||
code: 512,
|
||||
statusText: ERROR_ENUM.unAuthDataset,
|
||||
message: '无权使用该知识库',
|
||||
message: '无权操作该模型',
|
||||
data: null
|
||||
},
|
||||
|
||||
[ERROR_ENUM.unAuthFile]: {
|
||||
code: 513,
|
||||
statusText: ERROR_ENUM.unAuthFile,
|
||||
@@ -76,10 +89,12 @@ export const ERROR_RESPONSE: Record<
|
||||
message: 'Api Key 不合法',
|
||||
data: null
|
||||
},
|
||||
[ERROR_ENUM.unAuthDatasetCollection]: {
|
||||
code: 515,
|
||||
statusText: ERROR_ENUM.unAuthDatasetCollection,
|
||||
message: '无权使用该知识库文件',
|
||||
data: null
|
||||
}
|
||||
...appErr,
|
||||
...chatErr,
|
||||
...datasetErr,
|
||||
...openapiErr,
|
||||
...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',
|
||||
'User' = 'user',
|
||||
'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 = {
|
||||
model: string;
|
||||
name: string;
|
||||
maxToken: number;
|
||||
maxContext: number;
|
||||
maxResponse: number;
|
||||
price: number;
|
||||
};
|
||||
export type ChatModelItemType = LLMModelItemType & {
|
||||
@@ -25,3 +24,9 @@ export type VectorModelItemType = {
|
||||
price: 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 {
|
||||
LLMModelItemType,
|
||||
ChatModelItemType,
|
||||
FunctionModelItemType,
|
||||
VectorModelItemType
|
||||
} from '@/types/model';
|
||||
VectorModelItemType,
|
||||
AudioSpeechModelType
|
||||
} from './model.d';
|
||||
|
||||
export const defaultChatModels: ChatModelItemType[] = [
|
||||
{
|
||||
model: 'gpt-3.5-turbo',
|
||||
name: 'GPT35-4k',
|
||||
model: 'gpt-3.5-turbo-1106',
|
||||
name: 'GPT35-1106',
|
||||
price: 0,
|
||||
maxToken: 4000,
|
||||
maxContext: 16000,
|
||||
maxResponse: 4000,
|
||||
quoteMaxToken: 2000,
|
||||
maxTemperature: 1.2,
|
||||
censor: false,
|
||||
@@ -21,7 +21,8 @@ export const defaultChatModels: ChatModelItemType[] = [
|
||||
{
|
||||
model: 'gpt-3.5-turbo-16k',
|
||||
name: 'GPT35-16k',
|
||||
maxToken: 16000,
|
||||
maxContext: 16000,
|
||||
maxResponse: 16000,
|
||||
price: 0,
|
||||
quoteMaxToken: 8000,
|
||||
maxTemperature: 1.2,
|
||||
@@ -31,7 +32,8 @@ export const defaultChatModels: ChatModelItemType[] = [
|
||||
{
|
||||
model: 'gpt-4',
|
||||
name: 'GPT4-8k',
|
||||
maxToken: 8000,
|
||||
maxContext: 8000,
|
||||
maxResponse: 8000,
|
||||
price: 0,
|
||||
quoteMaxToken: 4000,
|
||||
maxTemperature: 1.2,
|
||||
@@ -43,15 +45,17 @@ export const defaultQAModels: LLMModelItemType[] = [
|
||||
{
|
||||
model: 'gpt-3.5-turbo-16k',
|
||||
name: 'GPT35-16k',
|
||||
maxToken: 16000,
|
||||
maxContext: 16000,
|
||||
maxResponse: 16000,
|
||||
price: 0
|
||||
}
|
||||
];
|
||||
export const defaultCQModels: FunctionModelItemType[] = [
|
||||
{
|
||||
model: 'gpt-3.5-turbo-16k',
|
||||
name: 'GPT35-16k',
|
||||
maxToken: 16000,
|
||||
model: 'gpt-3.5-turbo-1106',
|
||||
name: 'GPT35-1106',
|
||||
maxContext: 16000,
|
||||
maxResponse: 4000,
|
||||
price: 0,
|
||||
functionCall: true,
|
||||
functionPrompt: ''
|
||||
@@ -59,7 +63,8 @@ export const defaultCQModels: FunctionModelItemType[] = [
|
||||
{
|
||||
model: 'gpt-4',
|
||||
name: 'GPT4-8k',
|
||||
maxToken: 8000,
|
||||
maxContext: 8000,
|
||||
maxResponse: 8000,
|
||||
price: 0,
|
||||
functionCall: true,
|
||||
functionPrompt: ''
|
||||
@@ -67,9 +72,10 @@ export const defaultCQModels: FunctionModelItemType[] = [
|
||||
];
|
||||
export const defaultExtractModels: FunctionModelItemType[] = [
|
||||
{
|
||||
model: 'gpt-3.5-turbo-16k',
|
||||
name: 'GPT35-16k',
|
||||
maxToken: 16000,
|
||||
model: 'gpt-3.5-turbo-1106',
|
||||
name: 'GPT35-1106',
|
||||
maxContext: 16000,
|
||||
maxResponse: 4000,
|
||||
price: 0,
|
||||
functionCall: true,
|
||||
functionPrompt: ''
|
||||
@@ -77,9 +83,10 @@ export const defaultExtractModels: FunctionModelItemType[] = [
|
||||
];
|
||||
export const defaultQGModels: LLMModelItemType[] = [
|
||||
{
|
||||
model: 'gpt-3.5-turbo',
|
||||
name: 'GPT35-4K',
|
||||
maxToken: 4000,
|
||||
model: 'gpt-3.5-turbo-1106',
|
||||
name: 'GPT35-1106',
|
||||
maxContext: 1600,
|
||||
maxResponse: 4000,
|
||||
price: 0
|
||||
}
|
||||
];
|
||||
@@ -94,27 +101,15 @@ export const defaultVectorModels: VectorModelItemType[] = [
|
||||
}
|
||||
];
|
||||
|
||||
export const defaultApp: AppSchema = {
|
||||
_id: '',
|
||||
userId: 'userId',
|
||||
name: '模型加载中',
|
||||
type: 'basic',
|
||||
avatar: '/icon/logo.svg',
|
||||
intro: '',
|
||||
updateTime: Date.now(),
|
||||
share: {
|
||||
isShare: false,
|
||||
isShareDetail: false,
|
||||
collection: 0
|
||||
export const defaultAudioSpeechModels: AudioSpeechModelType[] = [
|
||||
{
|
||||
model: 'tts-1',
|
||||
name: 'OpenAI TTS1',
|
||||
price: 0
|
||||
},
|
||||
modules: []
|
||||
};
|
||||
|
||||
export const defaultOutLinkForm: OutLinkEditType = {
|
||||
name: '',
|
||||
responseDetail: false,
|
||||
limit: {
|
||||
QPM: 100,
|
||||
credit: -1
|
||||
{
|
||||
model: 'tts-1-hd',
|
||||
name: 'OpenAI TTS1',
|
||||
price: 0
|
||||
}
|
||||
};
|
||||
];
|
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';
|
||||
export type ChatCompletionRequestMessage = OpenAI.Chat.CreateChatCompletionRequestMessage;
|
||||
export type ChatCompletion = OpenAI.Chat.ChatCompletion;
|
||||
export type CreateChatCompletionRequest = OpenAI.Chat.ChatCompletionCreateParams;
|
||||
import type {
|
||||
ChatCompletion,
|
||||
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 = {
|
||||
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 {
|
||||
System = 'System',
|
||||
Human = 'Human',
|
||||
AI = 'AI'
|
||||
AI = 'AI',
|
||||
Function = 'Function',
|
||||
Tool = 'Tool'
|
||||
}
|
||||
|
||||
export enum TaskResponseKeyEnum {
|
||||
@@ -28,6 +21,12 @@ export const ChatRoleMap = {
|
||||
},
|
||||
[ChatRoleEnum.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 {
|
||||
folder = 'folder',
|
||||
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';
|
||||
|
||||
export type DatasetSchemaType = {
|
||||
_id: string;
|
||||
userId: string;
|
||||
parentId: string;
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
updateTime: Date;
|
||||
avatar: string;
|
||||
name: string;
|
||||
vectorModel: string;
|
||||
tags: string[];
|
||||
type: `${DatasetTypeEnum}`;
|
||||
permission: `${PermissionTypeEnum}`;
|
||||
};
|
||||
|
||||
export type DatasetCollectionSchemaType = {
|
||||
_id: string;
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
datasetId: string;
|
||||
parentId?: string;
|
||||
name: string;
|
||||
@@ -30,6 +36,8 @@ export type DatasetCollectionSchemaType = {
|
||||
export type DatasetTrainingSchemaType = {
|
||||
_id: string;
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
datasetId: string;
|
||||
datasetCollectionId: string;
|
||||
billId: string;
|
||||
@@ -42,17 +50,35 @@ export type DatasetTrainingSchemaType = {
|
||||
a: string;
|
||||
};
|
||||
|
||||
export type CollectionWithDatasetType = Omit<DatasetCollectionSchemaType, 'datasetId'> & {
|
||||
datasetId: DatasetSchemaType;
|
||||
};
|
||||
|
||||
/* ================= dataset ===================== */
|
||||
|
||||
/* ================= collection ===================== */
|
||||
export type DatasetCollectionItemType = DatasetCollectionSchemaType & {
|
||||
canWrite: boolean;
|
||||
};
|
||||
|
||||
/* ================= 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 = {
|
||||
id: string;
|
||||
q: string;
|
||||
a: string;
|
||||
dataset_id: string;
|
||||
collection_id: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
datasetId: string;
|
||||
collectionId: string;
|
||||
};
|
||||
export type DatasetChunkItemType = {
|
||||
q: string;
|
||||
@@ -66,8 +92,24 @@ export type DatasetDataItemType = DatasetChunkItemType & {
|
||||
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 =============== */
|
||||
export type SearchDataResultItemType = PgDataItemType & {
|
||||
export type SearchDataResultItemType = PgRawDataItemType & {
|
||||
score: number;
|
||||
};
|
||||
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';
|
||||
|
||||
export type FlowModuleTemplateType = {
|
||||
@@ -42,3 +42,14 @@ export type SelectAppItemType = {
|
||||
name: 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 = {
|
||||
_id: string;
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
intro: string;
|
||||
|
@@ -6,7 +6,7 @@
|
||||
"timezones-list": "^3.0.2",
|
||||
"dayjs": "^1.11.7",
|
||||
"encoding": "^0.1.13",
|
||||
"openai": "^4.12.1"
|
||||
"openai": "^4.16.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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 = {
|
||||
_id: string;
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
createTime: Date;
|
||||
lastUsedTime?: Date;
|
||||
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;
|
||||
shareId: string;
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
appId: string;
|
||||
name: string;
|
||||
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 {
|
||||
system = 'system'
|
||||
export enum OAuthEnum {
|
||||
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 = {
|
||||
_id: string;
|
||||
@@ -21,28 +22,13 @@ export type UserModelSchema = {
|
||||
};
|
||||
};
|
||||
|
||||
export type UserInformSchema = {
|
||||
export type UserType = {
|
||||
_id: string;
|
||||
userId: string;
|
||||
time: Date;
|
||||
type: `${InformTypeEnum}`;
|
||||
title: string;
|
||||
content: string;
|
||||
read: boolean;
|
||||
};
|
||||
|
||||
export type TeamSchema = {
|
||||
_id: string;
|
||||
name: string;
|
||||
ownerId: string;
|
||||
username: string;
|
||||
avatar: string;
|
||||
createTime: Date;
|
||||
};
|
||||
|
||||
export type TeamMemberSchema = {
|
||||
_id: string;
|
||||
name: string;
|
||||
teamId: string;
|
||||
userId: string;
|
||||
role: `${TeamMemberRoleEnum}`;
|
||||
balance: number;
|
||||
timezone: string;
|
||||
promotionRate: UserModelSchema['promotionRate'];
|
||||
openaiAccount: UserModelSchema['openaiAccount'];
|
||||
team: TeamItemType;
|
||||
};
|
||||
|
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 */
|
||||
import { PRICE_SCALE } from './constants';
|
||||
import { BillItemType, BillSchema } from './type';
|
||||
|
||||
/**
|
||||
* 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 = {
|
||||
_id: string;
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
createTime: Date;
|
||||
price: number;
|
||||
orderId: string;
|
@@ -18,7 +18,6 @@ function requestStart(config: InternalAxiosRequestConfig): InternalAxiosRequestC
|
||||
if (config.headers) {
|
||||
config.headers.rootkey = process.env.ROOT_KEY;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -62,7 +61,8 @@ function responseError(err: any) {
|
||||
const instance = axios.create({
|
||||
timeout: 60000, // 超时时间
|
||||
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 {
|
||||
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 'winston-mongodb';
|
||||
import { createLogger, format, transports } from 'winston';
|
||||
import 'winston-mongodb';
|
||||
|
||||
/**
|
||||
* connect MongoDB and init data
|
||||
@@ -19,9 +19,6 @@ export async function connectMongo({
|
||||
|
||||
beforeHook && (await beforeHook());
|
||||
|
||||
// logger
|
||||
initLogger();
|
||||
|
||||
console.log('mongo start connect');
|
||||
try {
|
||||
mongoose.set('strictQuery', true);
|
||||
@@ -35,9 +32,11 @@ export async function connectMongo({
|
||||
});
|
||||
|
||||
console.log('mongo connected');
|
||||
initLogger();
|
||||
|
||||
afterHook && (await afterHook());
|
||||
} catch (error) {
|
||||
global.mongodb.disconnect();
|
||||
console.log('error->', 'mongo connect error', error);
|
||||
global.mongodb = undefined;
|
||||
}
|
||||
|
@@ -1,39 +1,21 @@
|
||||
import mongoose from './index';
|
||||
import mongoose, { connectionMongo } from './index';
|
||||
|
||||
export class MongoSession {
|
||||
tasks: (() => Promise<any>)[] = [];
|
||||
session: mongoose.mongo.ClientSession | null = null;
|
||||
opts: {
|
||||
session: mongoose.mongo.ClientSession;
|
||||
new: boolean;
|
||||
} | null = null;
|
||||
export async function mongoSessionTask(
|
||||
fn: (session: mongoose.mongo.ClientSession) => Promise<any>
|
||||
) {
|
||||
const session = await connectionMongo.startSession();
|
||||
|
||||
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;
|
||||
// this.tasks = this.tasks.concat(tasks.map((item) => item(this.opts)));
|
||||
}
|
||||
async run() {
|
||||
if (!this.session || !this.opts) return;
|
||||
try {
|
||||
this.session.startTransaction();
|
||||
try {
|
||||
session.startTransaction();
|
||||
|
||||
const opts = { session: this.session, new: true };
|
||||
await fn(session);
|
||||
|
||||
await this.session.commitTransaction();
|
||||
} catch (error) {
|
||||
await this.session.abortTransaction();
|
||||
console.error(error);
|
||||
}
|
||||
this.session.endSession();
|
||||
await session.commitTransaction();
|
||||
await session.endSession();
|
||||
} catch (error) {
|
||||
await session.abortTransaction();
|
||||
await session.endSession();
|
||||
console.error(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { Pool } from 'pg';
|
||||
import type { QueryResultRow } from 'pg';
|
||||
import { PgDatasetTableName } from '@/constants/plugin';
|
||||
import { DatasetSpecialIdEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
import { PgDatasetTableName } from '@fastgpt/global/core/dataset/constant';
|
||||
|
||||
export const connectPg = async (): Promise<Pool> => {
|
||||
if (global.pgClient) {
|
||||
@@ -55,7 +54,7 @@ type InsertProps = {
|
||||
values: ValuesProps[];
|
||||
};
|
||||
|
||||
class Pg {
|
||||
class PgClass {
|
||||
private getWhereStr(where?: WhereProps) {
|
||||
return 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() {
|
||||
try {
|
||||
await connectPg();
|
||||
@@ -189,13 +167,14 @@ export async function initPg() {
|
||||
CREATE TABLE IF NOT EXISTS ${PgDatasetTableName} (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
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,
|
||||
collection_id VARCHAR(50) NOT NULL,
|
||||
q TEXT NOT NULL,
|
||||
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');
|
||||
@@ -203,3 +182,6 @@ export async function initPg() {
|
||||
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 { 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({
|
||||
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 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 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';
|
||||
|
||||
export const Prompt_QuestionGuide = `我不太清楚问你什么问题,请帮我生成 3 个问题,引导我继续提问。问题的长度应小于20个字符,按 JSON 格式返回: ["问题1", "问题2", "问题3"]`;
|
||||
@@ -7,7 +7,7 @@ export async function createQuestionGuide({
|
||||
messages,
|
||||
model
|
||||
}: {
|
||||
messages: ChatCompletionRequestMessage[];
|
||||
messages: ChatMessageItemType[];
|
||||
model: string;
|
||||
}) {
|
||||
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;
|
||||
import { ChatItemSchema as ChatItemType } from '@/types/mongoSchema';
|
||||
import { ChatRoleMap, TaskResponseKeyEnum } from '@/constants/chat';
|
||||
import { ChatItemSchema as ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { ChatRoleMap, TaskResponseKeyEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
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({
|
||||
dataId: {
|
||||
@@ -11,18 +17,27 @@ const ChatItemSchema = new Schema({
|
||||
require: true,
|
||||
default: () => nanoid()
|
||||
},
|
||||
appId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: appCollectionName,
|
||||
required: true
|
||||
},
|
||||
chatId: {
|
||||
type: String,
|
||||
require: true
|
||||
},
|
||||
userId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'user',
|
||||
ref: userCollectionName
|
||||
},
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName,
|
||||
required: true
|
||||
},
|
||||
appId: {
|
||||
tmbId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'model',
|
||||
ref: TeamMemberCollectionName,
|
||||
required: true
|
||||
},
|
||||
time: {
|
||||
@@ -53,6 +68,9 @@ const ChatItemSchema = new Schema({
|
||||
[TaskResponseKeyEnum.responseData]: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
tts: {
|
||||
type: Buffer
|
||||
}
|
||||
});
|
||||
|
||||
@@ -66,5 +84,5 @@ try {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
export const ChatItem: Model<ChatItemType> =
|
||||
export const MongoChatItem: Model<ChatItemType> =
|
||||
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;
|
||||
import { ChatSchema as ChatType } from '@/types/mongoSchema';
|
||||
import { ChatRoleMap, TaskResponseKeyEnum } from '@/constants/chat';
|
||||
import { ChatSourceMap } from '@/constants/chat';
|
||||
import { ChatSchema as ChatType } from '@fastgpt/global/core/chat/type.d';
|
||||
import {
|
||||
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({
|
||||
chatId: {
|
||||
@@ -11,12 +21,21 @@ const ChatSchema = new Schema({
|
||||
},
|
||||
userId: {
|
||||
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
|
||||
},
|
||||
appId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'model',
|
||||
ref: appCollectionName,
|
||||
required: true
|
||||
},
|
||||
updateTime: {
|
||||
@@ -80,4 +99,5 @@ try {
|
||||
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 { DatasetCollectionTypeMap } from '@fastgpt/global/core/dataset/constant';
|
||||
import { DatasetCollectionName } from '../schema';
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
|
||||
export const DatasetColCollectionName = 'dataset.collections';
|
||||
|
||||
@@ -13,8 +17,18 @@ const DatasetCollectionSchema = new Schema({
|
||||
default: null
|
||||
},
|
||||
userId: {
|
||||
// abandoned
|
||||
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
|
||||
},
|
||||
datasetId: {
|
||||
|
@@ -31,18 +31,16 @@ export async function findCollectionAndChild(id: string, fields = '_id parentId
|
||||
}
|
||||
|
||||
export async function getDatasetCollectionPaths({
|
||||
parentId = '',
|
||||
userId
|
||||
parentId = ''
|
||||
}: {
|
||||
parentId?: string;
|
||||
userId: string;
|
||||
}): Promise<ParentTreePathItemType[]> {
|
||||
async function find(parentId?: string): Promise<ParentTreePathItemType[]> {
|
||||
if (!parentId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const parent = await MongoDatasetCollection.findOne({ _id: parentId, userId }, 'name parentId');
|
||||
const parent = await MongoDatasetCollection.findOne({ _id: parentId }, 'name parentId');
|
||||
|
||||
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;
|
||||
import { DatasetSchemaType } from '@fastgpt/global/core/dataset/type.d';
|
||||
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';
|
||||
|
||||
@@ -12,8 +17,18 @@ const DatasetSchema = new Schema({
|
||||
default: null
|
||||
},
|
||||
userId: {
|
||||
//abandon
|
||||
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
|
||||
},
|
||||
updateTime: {
|
||||
@@ -41,7 +56,16 @@ const DatasetSchema = new Schema({
|
||||
},
|
||||
tags: {
|
||||
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 { DatasetColCollectionName } from '../collection/schema';
|
||||
import { DatasetCollectionName } from '../schema';
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
|
||||
export const DatasetTrainingCollectionName = 'dataset.trainings';
|
||||
|
||||
const TrainingDataSchema = new Schema({
|
||||
userId: {
|
||||
// abandon
|
||||
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
|
||||
},
|
||||
datasetId: {
|
||||
|
@@ -1,38 +1,15 @@
|
||||
import { CreateOnePluginParams, UpdatePluginParams } from '@fastgpt/global/core/plugin/controller';
|
||||
import { MongoPlugin } from './schema';
|
||||
import { FlowModuleTemplateType } from '@fastgpt/global/core/module/type';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||
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 */
|
||||
export async function getUserPlugins2Templates({
|
||||
userId
|
||||
teamId
|
||||
}: {
|
||||
userId: string;
|
||||
teamId: string;
|
||||
}): Promise<FlowModuleTemplateType[]> {
|
||||
const plugins = await MongoPlugin.find({ userId }).lean();
|
||||
const plugins = await MongoPlugin.find({ teamId }).lean();
|
||||
|
||||
return plugins.map((plugin) => ({
|
||||
id: String(plugin._id),
|
||||
@@ -47,8 +24,8 @@ export async function getUserPlugins2Templates({
|
||||
}));
|
||||
}
|
||||
/* one plugin 2 module detail */
|
||||
export async function getPluginModuleDetail({ id, userId }: { userId: string; id: string }) {
|
||||
const plugin = await getOnePluginDetail({ id, userId });
|
||||
export async function getPluginModuleDetail({ id }: { id: string }) {
|
||||
const plugin = await MongoPlugin.findById(id);
|
||||
if (!plugin) return Promise.reject('plugin not found');
|
||||
return {
|
||||
id: String(plugin._id),
|
||||
|
@@ -1,13 +1,26 @@
|
||||
import { connectionMongo, type Model } from '../../common/mongo';
|
||||
const { Schema, model, models } = connectionMongo;
|
||||
import type { PluginItemSchema } from '@fastgpt/global/core/plugin/type.d';
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
|
||||
export const ModuleCollectionName = 'plugins';
|
||||
|
||||
const PluginSchema = new Schema({
|
||||
userId: {
|
||||
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
|
||||
},
|
||||
name: {
|
||||
|
@@ -13,10 +13,12 @@
|
||||
"winston-mongodb": "^5.1.1",
|
||||
"tunnel": "^0.0.6",
|
||||
"encoding": "^0.1.13",
|
||||
"openai": "^4.12.4"
|
||||
"pg": "^8.10.0",
|
||||
"nanoid": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/tunnel": "^0.0.4",
|
||||
"@types/pg": "^8.6.6",
|
||||
"@types/node": "^20.8.5",
|
||||
"@types/cookie": "^0.5.2",
|
||||
"@types/jsonwebtoken": "^9.0.3"
|
||||
|
@@ -10,13 +10,11 @@ export async function authOpenApiKey({ apikey }: { apikey: string }) {
|
||||
if (!apikey) {
|
||||
return Promise.reject(ERROR_ENUM.unAuthApiKey);
|
||||
}
|
||||
|
||||
try {
|
||||
const openApi = await MongoOpenApi.findOne({ apiKey: apikey });
|
||||
if (!openApi) {
|
||||
return Promise.reject(ERROR_ENUM.unAuthApiKey);
|
||||
}
|
||||
const userId = String(openApi.userId);
|
||||
|
||||
// auth limit
|
||||
if (global.feConfigs?.isPlus) {
|
||||
@@ -25,7 +23,13 @@ export async function authOpenApiKey({ apikey }: { apikey: string }) {
|
||||
|
||||
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) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
@@ -1,14 +1,27 @@
|
||||
import { connectionMongo, type Model } from '../../common/mongo';
|
||||
const { Schema, model, models } = connectionMongo;
|
||||
import type { OpenApiSchema } from '@fastgpt/global/support/openapi/type';
|
||||
import { PRICE_SCALE } from '@fastgpt/global/common/bill/constants';
|
||||
import { formatPrice } from '@fastgpt/global/common/bill/tools';
|
||||
import { PRICE_SCALE } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
|
||||
const OpenApiSchema = new Schema(
|
||||
{
|
||||
userId: {
|
||||
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
|
||||
},
|
||||
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;
|
||||
import { OutLinkSchema as SchemaType } from '@fastgpt/global/support/outLink/type';
|
||||
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
|
||||
const OutLinkSchema = new Schema({
|
||||
shareId: {
|
||||
@@ -10,7 +14,16 @@ const OutLinkSchema = new Schema({
|
||||
},
|
||||
userId: {
|
||||
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
|
||||
},
|
||||
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
Reference in New Issue
Block a user