mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 05:12:39 +00:00
4.8.8 test fix (#2143)
* perf: transcriptions api * perf: variable picker tip * perf: variable picker tip * perf: chat select app * feat: router to app detail * perf: variable avoid space * perf: variable picker * perf: doc2x icon and params * perf: sandbox support countToken * feat: sandbox support delay and countToken
This commit is contained in:
@@ -4,3 +4,5 @@ dist
|
||||
node_modules
|
||||
docSite/
|
||||
*.md
|
||||
|
||||
cl100l_base.ts
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -20,5 +20,8 @@
|
||||
"i18n-ally.displayLanguage": "zh", // 显示语言
|
||||
"i18n-ally.namespace": true,
|
||||
"i18n-ally.pathMatcher": "{locale}/{namespaces}.json",
|
||||
"i18n-ally.extract.targetPickingStrategy": "most-similar-by-key"
|
||||
"i18n-ally.extract.targetPickingStrategy": "most-similar-by-key",
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||
}
|
||||
}
|
@@ -18,13 +18,17 @@ weight: 816
|
||||
|
||||
-------
|
||||
|
||||
## V4.8. 8 更新说明
|
||||
## V4.8.8 更新说明
|
||||
|
||||
1. 新增 - 重构系统插件的结构。允许向开源社区 PR 系统插件,具体可见: [如何向 FastGPT 社区提交系统插件](https://fael3z0zfze.feishu.cn/wiki/ERZnw9R26iRRG0kXZRec6WL9nwh)。
|
||||
2. 新增 - DuckDuckGo 系统插件。
|
||||
3. 优化 - 节点图标。
|
||||
4. 优化 - 对话框引用增加额外复制案件,便于复制。增加引用内容折叠。
|
||||
5. 修复 - Permission 表声明问题。
|
||||
6. 修复 - 并行执行节点,运行时间未正确记录。
|
||||
7. 修复 - 简易模式,首次进入,无法正确获取知识库配置。
|
||||
8. 修复 - Log level 配置
|
||||
3. 新增 - 修改变量填写方式。提示词输入框以以及工作流中所有 Textarea 输入框,支持输入 / 唤起变量选择,可直接选择所有上游输出值,无需动态引入。
|
||||
4. 优化 - 移动端快速切换应用交互。
|
||||
5. 优化 - 节点图标。
|
||||
6. 优化 - 对话框引用增加额外复制案件,便于复制。增加引用内容折叠。
|
||||
7. 优化 - 对话框底部增加复制,简便复制交互,无需滚动到消息开头。
|
||||
8. 优化 - OpenAI sdk 升级,并自定义了 whisper 模型接口(未仔细查看 sdk 实现,但 sdk 中 whisper 接口,似乎无法适配一般 fastapi 接口)
|
||||
9. 修复 - Permission 表声明问题。
|
||||
10. 修复 - 并行执行节点,运行时间未正确记录。
|
||||
11. 修复 - 简易模式,首次进入,无法正确获取知识库配置。
|
||||
12. 修复 - Log debug level 配置无效。
|
||||
|
@@ -11,7 +11,7 @@
|
||||
"jschardet": "3.1.1",
|
||||
"nanoid": "^4.0.1",
|
||||
"next": "14.2.5",
|
||||
"openai": "4.28.0",
|
||||
"openai": "4.53.0",
|
||||
"openapi-types": "^12.1.3",
|
||||
"timezones-list": "^3.0.2"
|
||||
},
|
||||
|
@@ -7,7 +7,7 @@ import { cloneDeep } from 'lodash';
|
||||
import { WorkerNameEnum, runWorker } from '@fastgpt/service/worker/utils';
|
||||
|
||||
// Run in main thread
|
||||
const staticPluginList = ['getTime', 'fetchUrl'];
|
||||
const staticPluginList = ['getTime', 'fetchUrl', 'Doc2X', 'Doc2X/URLPDF2text', 'Doc2X/URLImg2text'];
|
||||
// Run in worker thread (Have npm packages)
|
||||
const packagePluginList = [
|
||||
'mathExprVal',
|
||||
@@ -15,10 +15,7 @@ const packagePluginList = [
|
||||
'duckduckgo/search',
|
||||
'duckduckgo/searchImg',
|
||||
'duckduckgo/searchNews',
|
||||
'duckduckgo/searchVideo',
|
||||
'Doc2X',
|
||||
'Doc2X/URLPDF2text',
|
||||
'Doc2X/URLImg2text'
|
||||
'duckduckgo/searchVideo'
|
||||
];
|
||||
|
||||
const list = [...staticPluginList, ...packagePluginList];
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"author": "",
|
||||
"version": "486",
|
||||
"version": "488",
|
||||
"name": "Doc2X 图像(URL)识别",
|
||||
"avatar": "/imgs/workflow/textEditor.svg",
|
||||
"avatar": "plugins/doc2x",
|
||||
"intro": "将传入的图片(URL)发送至Doc2X进行解析,返回带LaTeX公式的markdown格式的文本",
|
||||
"showStatus": true,
|
||||
"weight": 10,
|
||||
@@ -26,9 +26,7 @@
|
||||
"version": "481",
|
||||
"inputs": [
|
||||
{
|
||||
"renderTypeList": [
|
||||
"input"
|
||||
],
|
||||
"renderTypeList": ["input"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
@@ -36,13 +34,11 @@
|
||||
"label": "apikey",
|
||||
"description": "Doc2X的验证密匙,对于个人用户可以从Doc2X官网 - 个人信息 - 身份令牌获得",
|
||||
"required": true,
|
||||
"toolDescription": "Doc2X的验证密匙,对于个人用户可以从Doc2X官网 - 个人信息 - 身份令牌获得",
|
||||
"toolDescription": "",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
@@ -53,9 +49,7 @@
|
||||
"toolDescription": "待处理图片的URL"
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"switch"
|
||||
],
|
||||
"renderTypeList": ["switch"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "boolean",
|
||||
"canEdit": true,
|
||||
@@ -63,13 +57,11 @@
|
||||
"label": "img_correction",
|
||||
"description": "是否启用图形矫正功能",
|
||||
"required": true,
|
||||
"toolDescription": "是否启用图形矫正功能",
|
||||
"toolDescription": "",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"switch"
|
||||
],
|
||||
"renderTypeList": ["switch"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "boolean",
|
||||
"canEdit": true,
|
||||
@@ -77,7 +69,7 @@
|
||||
"label": "formula",
|
||||
"description": "是否开启纯公式识别(仅适用于图片内容仅有公式时)",
|
||||
"required": true,
|
||||
"toolDescription": "是否开启纯公式识别(仅适用于图片内容仅有公式时)",
|
||||
"toolDescription": "",
|
||||
"defaultValue": false
|
||||
}
|
||||
],
|
||||
@@ -126,32 +118,22 @@
|
||||
"version": "481",
|
||||
"inputs": [
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
"key": "result",
|
||||
"label": "result",
|
||||
"description": "处理结果(或者是报错信息)",
|
||||
"value": [
|
||||
"zHG5jJBkXmjB",
|
||||
"xWQuEf50F3mr"
|
||||
]
|
||||
"value": ["zHG5jJBkXmjB", "xWQuEf50F3mr"]
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "boolean",
|
||||
"canEdit": true,
|
||||
"key": "success",
|
||||
"label": "success",
|
||||
"description": "是否处理成功",
|
||||
"value": [
|
||||
"zHG5jJBkXmjB",
|
||||
"m6CJJj7GFud5"
|
||||
]
|
||||
"value": ["zHG5jJBkXmjB", "m6CJJj7GFud5"]
|
||||
}
|
||||
],
|
||||
"outputs": []
|
||||
@@ -171,9 +153,7 @@
|
||||
"inputs": [
|
||||
{
|
||||
"key": "system_addInputParam",
|
||||
"renderTypeList": [
|
||||
"addInputParam"
|
||||
],
|
||||
"renderTypeList": ["addInputParam"],
|
||||
"valueType": "dynamic",
|
||||
"label": "",
|
||||
"required": false,
|
||||
@@ -201,9 +181,7 @@
|
||||
},
|
||||
{
|
||||
"key": "system_httpMethod",
|
||||
"renderTypeList": [
|
||||
"custom"
|
||||
],
|
||||
"renderTypeList": ["custom"],
|
||||
"valueType": "string",
|
||||
"label": "",
|
||||
"value": "POST",
|
||||
@@ -211,9 +189,7 @@
|
||||
},
|
||||
{
|
||||
"key": "system_httpReqUrl",
|
||||
"renderTypeList": [
|
||||
"hidden"
|
||||
],
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "string",
|
||||
"label": "",
|
||||
"description": "core.module.input.description.Http Request Url",
|
||||
@@ -223,9 +199,7 @@
|
||||
},
|
||||
{
|
||||
"key": "system_httpHeader",
|
||||
"renderTypeList": [
|
||||
"custom"
|
||||
],
|
||||
"renderTypeList": ["custom"],
|
||||
"valueType": "any",
|
||||
"value": [],
|
||||
"label": "",
|
||||
@@ -235,9 +209,7 @@
|
||||
},
|
||||
{
|
||||
"key": "system_httpParams",
|
||||
"renderTypeList": [
|
||||
"hidden"
|
||||
],
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "any",
|
||||
"value": [],
|
||||
"label": "",
|
||||
@@ -245,18 +217,14 @@
|
||||
},
|
||||
{
|
||||
"key": "system_httpJsonBody",
|
||||
"renderTypeList": [
|
||||
"hidden"
|
||||
],
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "any",
|
||||
"value": "{\n \"apikey\": \"{{apikey}}\",\n \"url\": \"{{url}}\",\n \"img_correction\": \"{{img_correction}}\",\n \"formula\": \"{{img_correction}}\"\n}",
|
||||
"label": "",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
"key": "apikey",
|
||||
@@ -282,15 +250,10 @@
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"required": true,
|
||||
"value": [
|
||||
"pluginInput",
|
||||
"apikey"
|
||||
]
|
||||
"value": ["pluginInput", "apikey"]
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
"key": "url",
|
||||
@@ -316,15 +279,10 @@
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"required": true,
|
||||
"value": [
|
||||
"pluginInput",
|
||||
"url"
|
||||
]
|
||||
"value": ["pluginInput", "url"]
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "boolean",
|
||||
"canEdit": true,
|
||||
"key": "img_correction",
|
||||
@@ -350,15 +308,10 @@
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"required": true,
|
||||
"value": [
|
||||
"pluginInput",
|
||||
"img_correction"
|
||||
]
|
||||
"value": ["pluginInput", "img_correction"]
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "boolean",
|
||||
"canEdit": true,
|
||||
"key": "formula",
|
||||
@@ -384,10 +337,7 @@
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"required": true,
|
||||
"value": [
|
||||
"pluginInput",
|
||||
"formula"
|
||||
]
|
||||
"value": ["pluginInput", "formula"]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"author": "",
|
||||
"version": "486",
|
||||
"version": "488",
|
||||
"name": "Doc2X PDF文件(URL)识别",
|
||||
"avatar": "/imgs/workflow/textEditor.svg",
|
||||
"avatar": "plugins/doc2x",
|
||||
"intro": "将传入的PDF文件(URL)发送至Doc2X进行解析,返回带LaTeX公式的markdown格式的文本",
|
||||
"showStatus": true,
|
||||
"weight": 10,
|
||||
@@ -26,9 +26,7 @@
|
||||
"version": "481",
|
||||
"inputs": [
|
||||
{
|
||||
"renderTypeList": [
|
||||
"input"
|
||||
],
|
||||
"renderTypeList": ["input"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
@@ -36,13 +34,11 @@
|
||||
"label": "apikey",
|
||||
"description": "Doc2X的验证密匙,对于个人用户可以从Doc2X官网 - 个人信息 - 身份令牌获得",
|
||||
"required": true,
|
||||
"toolDescription": "Doc2X的验证密匙,对于个人用户可以从Doc2X官网 - 个人信息 - 身份令牌获得",
|
||||
"toolDescription": "",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
@@ -53,9 +49,7 @@
|
||||
"toolDescription": "待处理PDF文件的URL"
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"switch"
|
||||
],
|
||||
"renderTypeList": ["switch"],
|
||||
"selectedTypeIndex": 0,
|
||||
"valueType": "boolean",
|
||||
"canEdit": true,
|
||||
@@ -63,7 +57,7 @@
|
||||
"label": "ocr",
|
||||
"description": "是否开启对PDF文件内图片的OCR识别,建议开启",
|
||||
"required": true,
|
||||
"toolDescription": "是否开启对PDF文件内图片的OCR识别,建议开启",
|
||||
"toolDescription": "",
|
||||
"defaultValue": true
|
||||
}
|
||||
],
|
||||
@@ -105,32 +99,22 @@
|
||||
"version": "481",
|
||||
"inputs": [
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
"key": "result",
|
||||
"label": "result",
|
||||
"description": "处理结果(或者是报错信息)",
|
||||
"value": [
|
||||
"zHG5jJBkXmjB",
|
||||
"xWQuEf50F3mr"
|
||||
]
|
||||
"value": ["zHG5jJBkXmjB", "xWQuEf50F3mr"]
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "boolean",
|
||||
"canEdit": true,
|
||||
"key": "success",
|
||||
"label": "success",
|
||||
"description": "是否处理成功",
|
||||
"value": [
|
||||
"zHG5jJBkXmjB",
|
||||
"m6CJJj7GFud5"
|
||||
]
|
||||
"value": ["zHG5jJBkXmjB", "m6CJJj7GFud5"]
|
||||
}
|
||||
],
|
||||
"outputs": []
|
||||
@@ -150,9 +134,7 @@
|
||||
"inputs": [
|
||||
{
|
||||
"key": "system_addInputParam",
|
||||
"renderTypeList": [
|
||||
"addInputParam"
|
||||
],
|
||||
"renderTypeList": ["addInputParam"],
|
||||
"valueType": "dynamic",
|
||||
"label": "",
|
||||
"required": false,
|
||||
@@ -180,9 +162,7 @@
|
||||
},
|
||||
{
|
||||
"key": "system_httpMethod",
|
||||
"renderTypeList": [
|
||||
"custom"
|
||||
],
|
||||
"renderTypeList": ["custom"],
|
||||
"valueType": "string",
|
||||
"label": "",
|
||||
"value": "POST",
|
||||
@@ -190,9 +170,7 @@
|
||||
},
|
||||
{
|
||||
"key": "system_httpReqUrl",
|
||||
"renderTypeList": [
|
||||
"hidden"
|
||||
],
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "string",
|
||||
"label": "",
|
||||
"description": "core.module.input.description.Http Request Url",
|
||||
@@ -202,9 +180,7 @@
|
||||
},
|
||||
{
|
||||
"key": "system_httpHeader",
|
||||
"renderTypeList": [
|
||||
"custom"
|
||||
],
|
||||
"renderTypeList": ["custom"],
|
||||
"valueType": "any",
|
||||
"value": [],
|
||||
"label": "",
|
||||
@@ -214,9 +190,7 @@
|
||||
},
|
||||
{
|
||||
"key": "system_httpParams",
|
||||
"renderTypeList": [
|
||||
"hidden"
|
||||
],
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "any",
|
||||
"value": [],
|
||||
"label": "",
|
||||
@@ -224,18 +198,14 @@
|
||||
},
|
||||
{
|
||||
"key": "system_httpJsonBody",
|
||||
"renderTypeList": [
|
||||
"hidden"
|
||||
],
|
||||
"renderTypeList": ["hidden"],
|
||||
"valueType": "any",
|
||||
"value": "{\n \"apikey\": \"{{apikey}}\",\n \"url\": \"{{url}}\",\n \"ocr\": \"{{ocr}}\"\n}",
|
||||
"label": "",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
"key": "apikey",
|
||||
@@ -261,15 +231,10 @@
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"required": true,
|
||||
"value": [
|
||||
"pluginInput",
|
||||
"apikey"
|
||||
]
|
||||
"value": ["pluginInput", "apikey"]
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "string",
|
||||
"canEdit": true,
|
||||
"key": "url",
|
||||
@@ -295,15 +260,10 @@
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"required": true,
|
||||
"value": [
|
||||
"pluginInput",
|
||||
"url"
|
||||
]
|
||||
"value": ["pluginInput", "url"]
|
||||
},
|
||||
{
|
||||
"renderTypeList": [
|
||||
"reference"
|
||||
],
|
||||
"renderTypeList": ["reference"],
|
||||
"valueType": "boolean",
|
||||
"canEdit": true,
|
||||
"key": "ocr",
|
||||
@@ -329,10 +289,7 @@
|
||||
"showDefaultValue": true
|
||||
},
|
||||
"required": true,
|
||||
"value": [
|
||||
"pluginInput",
|
||||
"formula"
|
||||
]
|
||||
"value": ["pluginInput", "formula"]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"author": "",
|
||||
"version": "486",
|
||||
"version": "488",
|
||||
"name": "Doc2X服务",
|
||||
"avatar": "/imgs/workflow/textEditor.svg",
|
||||
"avatar": "plugins/doc2x",
|
||||
"intro": "传入的URL形式的图片或PDF文件发送至Doc2X进行解析,返回带LaTeX公式的markdown格式的文本。",
|
||||
"showStatus": true,
|
||||
"weight": 10,
|
||||
|
30
packages/service/core/ai/audio/transcriptions.ts
Normal file
30
packages/service/core/ai/audio/transcriptions.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import fs from 'fs';
|
||||
import { getAxiosConfig } from '../config';
|
||||
import axios from 'axios';
|
||||
import FormData from 'form-data';
|
||||
|
||||
export const aiTranscriptions = async ({
|
||||
model,
|
||||
fileStream
|
||||
}: {
|
||||
model: string;
|
||||
fileStream: fs.ReadStream;
|
||||
}) => {
|
||||
const data = new FormData();
|
||||
data.append('model', model);
|
||||
data.append('file', fileStream);
|
||||
|
||||
const aiAxiosConfig = getAxiosConfig();
|
||||
const { data: result } = await axios<{ text: string }>({
|
||||
method: 'post',
|
||||
baseURL: aiAxiosConfig.baseUrl,
|
||||
url: '/audio/transcriptions',
|
||||
headers: {
|
||||
Authorization: aiAxiosConfig.authorization,
|
||||
...data.getHeaders()
|
||||
},
|
||||
data: data
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
@@ -21,3 +21,16 @@ export const getAIApi = (props?: {
|
||||
maxRetries: 2
|
||||
});
|
||||
};
|
||||
|
||||
export const getAxiosConfig = (props?: { userKey?: UserModelSchema['openaiAccount'] }) => {
|
||||
const { userKey } = props || {};
|
||||
|
||||
const baseUrl =
|
||||
userKey?.baseUrl || global?.systemEnv?.oneapiUrl || process.env.ONEAPI_URL || openaiBaseUrl;
|
||||
const apiKey = userKey?.key || global?.systemEnv?.chatApiKey || process.env.CHAT_API_KEY || '';
|
||||
|
||||
return {
|
||||
baseUrl,
|
||||
authorization: `Bearer ${apiKey}`
|
||||
};
|
||||
};
|
||||
|
@@ -55,7 +55,6 @@ import { surrenderProcess } from '../../../common/system/tools';
|
||||
import { dispatchRunCode } from './code/run';
|
||||
import { dispatchTextEditor } from './tools/textEditor';
|
||||
import { dispatchCustomFeedback } from './tools/customFeedback';
|
||||
import { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
|
||||
|
||||
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
||||
|
@@ -16,6 +16,7 @@
|
||||
"domino-ext": "^2.1.4",
|
||||
"encoding": "^0.1.13",
|
||||
"file-type": "^19.0.0",
|
||||
"form-data": "^4.0.0",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"joplin-turndown-plugin-gfm": "^1.0.12",
|
||||
"json5": "^2.2.3",
|
||||
|
@@ -29,6 +29,7 @@ export const iconPaths = {
|
||||
'common/gitLight': () => import('./icons/common/gitLight.svg'),
|
||||
'common/googleFill': () => import('./icons/common/googleFill.svg'),
|
||||
'common/importLight': () => import('./icons/common/importLight.svg'),
|
||||
'common/info': () => import('./icons/common/info.svg'),
|
||||
'common/inviteLight': () => import('./icons/common/inviteLight.svg'),
|
||||
'common/language/en': () => import('./icons/common/language/en.svg'),
|
||||
'common/language/zh': () => import('./icons/common/language/zh.svg'),
|
||||
@@ -97,24 +98,24 @@ export const iconPaths = {
|
||||
'core/app/variable/textarea': () => import('./icons/core/app/variable/textarea.svg'),
|
||||
'core/chat/QGFill': () => import('./icons/core/chat/QGFill.svg'),
|
||||
'core/chat/cancelSpeak': () => import('./icons/core/chat/cancelSpeak.svg'),
|
||||
'core/chat/chevronSelector': () => import('./icons/core/chat/chevronSelector.svg'),
|
||||
'core/chat/sideLine': () => import('./icons/core/chat/sideLine.svg'),
|
||||
'core/chat/chatFill': () => import('./icons/core/chat/chatFill.svg'),
|
||||
'core/chat/chatLight': () => import('./icons/core/chat/chatLight.svg'),
|
||||
'core/chat/chatModelTag': () => import('./icons/core/chat/chatModelTag.svg'),
|
||||
'core/chat/chevronDown': () => import('./icons/core/chat/chevronDown.svg'),
|
||||
'core/chat/chevronSelector': () => import('./icons/core/chat/chevronSelector.svg'),
|
||||
'core/chat/chevronUp': () => import('./icons/core/chat/chevronUp.svg'),
|
||||
'core/chat/export/pdf': () => import('./icons/core/chat/export/pdf.svg'),
|
||||
'core/chat/feedback/badLight': () => import('./icons/core/chat/feedback/badLight.svg'),
|
||||
'core/chat/feedback/goodLight': () => import('./icons/core/chat/feedback/goodLight.svg'),
|
||||
'core/chat/fileSelect': () => import('./icons/core/chat/fileSelect.svg'),
|
||||
'core/chat/finishSpeak': () => import('./icons/core/chat/finishSpeak.svg'),
|
||||
'core/chat/quoteFill': () => import('./icons/core/chat/quoteFill.svg'),
|
||||
'core/chat/chevronDown': () => import('./icons/core/chat/chevronDown.svg'),
|
||||
'core/chat/chevronUp': () => import('./icons/core/chat/chevronUp.svg'),
|
||||
'core/chat/quoteSign': () => import('./icons/core/chat/quoteSign.svg'),
|
||||
'core/chat/recordFill': () => import('./icons/core/chat/recordFill.svg'),
|
||||
'core/chat/sendFill': () => import('./icons/core/chat/sendFill.svg'),
|
||||
'core/chat/sendLight': () => import('./icons/core/chat/sendLight.svg'),
|
||||
'core/chat/setTopLight': () => import('./icons/core/chat/setTopLight.svg'),
|
||||
'core/chat/sideLine': () => import('./icons/core/chat/sideLine.svg'),
|
||||
'core/chat/speaking': () => import('./icons/core/chat/speaking.svg'),
|
||||
'core/chat/stopSpeech': () => import('./icons/core/chat/stopSpeech.svg'),
|
||||
'core/dataset/commonDataset': () => import('./icons/core/dataset/commonDataset.svg'),
|
||||
@@ -250,6 +251,7 @@ export const iconPaths = {
|
||||
'phoneTabbar/me': () => import('./icons/phoneTabbar/me.svg'),
|
||||
'phoneTabbar/tool': () => import('./icons/phoneTabbar/tool.svg'),
|
||||
'phoneTabbar/toolFill': () => import('./icons/phoneTabbar/toolFill.svg'),
|
||||
'plugins/doc2x': () => import('./icons/plugins/doc2x.svg'),
|
||||
'plugins/textEditor': () => import('./icons/plugins/textEditor.svg'),
|
||||
'price/bg': () => import('./icons/price/bg.svg'),
|
||||
'price/right': () => import('./icons/price/right.svg'),
|
||||
|
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 24" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.8999 3.51941C8.21617 3.51941 4.41928 7.3163 4.41928 12C4.41928 16.6837 8.21617 20.4806 12.8999 20.4806C17.5836 20.4806 21.3805 16.6837 21.3805 12C21.3805 7.3163 17.5836 3.51941 12.8999 3.51941ZM2.41928 12C2.41928 6.21173 7.1116 1.51941 12.8999 1.51941C18.6881 1.51941 23.3805 6.21173 23.3805 12C23.3805 17.7883 18.6881 22.4806 12.8999 22.4806C7.1116 22.4806 2.41928 17.7883 2.41928 12ZM11.8999 8.20776C11.8999 7.65548 12.3476 7.20776 12.8999 7.20776H12.9094C13.4616 7.20776 13.9094 7.65548 13.9094 8.20776C13.9094 8.76005 13.4616 9.20776 12.9094 9.20776H12.8999C12.3476 9.20776 11.8999 8.76005 11.8999 8.20776ZM12.8999 11C13.4522 11 13.8999 11.4477 13.8999 12V15.7922C13.8999 16.3445 13.4522 16.7922 12.8999 16.7922C12.3476 16.7922 11.8999 16.3445 11.8999 15.7922V12C11.8999 11.4477 12.3476 11 12.8999 11Z" />
|
||||
</svg>
|
After Width: | Height: | Size: 944 B |
@@ -1,3 +1,3 @@
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.28082 5.72828C6.95538 6.05372 6.95538 6.58136 7.28082 6.90679C7.60626 7.23223 8.1339 7.23223 8.45933 6.90679L10.5 4.86615L12.5406 6.90679C12.8661 7.23223 13.3937 7.23223 13.7191 6.90679C14.0446 6.58136 14.0446 6.05372 13.7191 5.72828L11.0892 3.09839C10.7638 2.77295 10.2362 2.77295 9.91072 3.09839L7.28082 5.72828ZM7.28082 13.0893C6.95538 13.4147 6.95538 13.9424 7.28082 14.2678L9.91072 16.8977C9.9514 16.9384 9.99524 16.974 10.0414 17.0045C10.3649 17.2181 10.8045 17.1825 11.0892 16.8977L13.7191 14.2678C14.0446 13.9424 14.0446 13.4147 13.7191 13.0893C13.3937 12.7639 12.8661 12.7639 12.5406 13.0893L10.5 15.1299L8.45933 13.0893C8.1339 12.7639 7.60626 12.7639 7.28082 13.0893Z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 836 B After Width: | Height: | Size: 814 B |
@@ -0,0 +1,6 @@
|
||||
<svg viewBox="0 0 42 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="28.6606" y="8.44495" width="6.92163" height="12.0376" rx="3.46082" transform="rotate(45 28.6606 8.44495)" fill="#7748F9"/>
|
||||
<rect x="16.957" y="20.1488" width="6.92163" height="12.0376" rx="3.46082" transform="rotate(45 16.957 20.1488)" fill="#7748F9"/>
|
||||
<rect x="20.1489" y="25.0432" width="6.92163" height="12.0376" rx="3.46082" transform="rotate(-45 20.1489 25.0432)" fill="#BFABFB"/>
|
||||
<rect x="8.44482" y="13.3394" width="6.92163" height="12.0376" rx="3.46082" transform="rotate(-45 8.44482 13.3394)" fill="#BFABFB"/>
|
||||
</svg>
|
After Width: | Height: | Size: 609 B |
@@ -52,6 +52,7 @@ const LightRowTabs = <ValueType = string,>({
|
||||
fontSize={sizeMap.fontSize}
|
||||
overflowX={'auto'}
|
||||
userSelect={'none'}
|
||||
display={'inline-grid'}
|
||||
{...props}
|
||||
>
|
||||
{list.map((item) => (
|
||||
|
@@ -94,8 +94,7 @@ export default function VariableLabelPickerPlugin({
|
||||
<Box
|
||||
bg={'white'}
|
||||
boxShadow={'lg'}
|
||||
borderWidth={'1px'}
|
||||
borderColor={'borderColor.base'}
|
||||
border={'base'}
|
||||
p={2}
|
||||
borderRadius={'md'}
|
||||
position={'absolute'}
|
||||
|
@@ -29,9 +29,9 @@ export default function VariableLabel({
|
||||
<span>
|
||||
<Avatar
|
||||
src={nodeAvatar as any}
|
||||
w={'16px'}
|
||||
w={'1rem'}
|
||||
mr={1}
|
||||
borderRadius={'2.8px'}
|
||||
borderRadius={'xs'}
|
||||
display={'inline-flex'}
|
||||
verticalAlign={'middle'}
|
||||
mb={'3px'}
|
||||
|
@@ -1,23 +1,19 @@
|
||||
{
|
||||
"add_new": "Add new",
|
||||
"App": "App",
|
||||
"all_apps": "All Apps",
|
||||
"click_to_resume": "Resume",
|
||||
"code_editor": "Code edit",
|
||||
"Export": "Export",
|
||||
"field_name": "Name",
|
||||
"Folder": "Folder",
|
||||
"is_open": "Opened",
|
||||
"Login": "Login",
|
||||
"Move": "Move",
|
||||
"Name": "Name",
|
||||
"new_create": "Create New",
|
||||
"no_data": "No data",
|
||||
"Rename": "Rename",
|
||||
"Resume": "Resume",
|
||||
"Running": "Running",
|
||||
"UnKnow": "Unknown",
|
||||
"Warning": "Warning",
|
||||
"add_new": "Add new",
|
||||
"common": {
|
||||
"Action": "Action",
|
||||
"Add": "Add",
|
||||
@@ -294,7 +290,7 @@
|
||||
},
|
||||
"tip": {
|
||||
"Add a intro to app": "Come and give the app an introduction~",
|
||||
"chatNodeSystemPromptTip": "Model fixed guide words, by adjusting this content, you can guide the model's chat direction. This content will be fixed at the beginning of the context. Variables can be used, for example, {{language}}\nIf a knowledge base is associated, you can also guide the model when to call the knowledge base search by appropriately describing it. For example:\nYou are the assistant for the movie 'Interstellar', when the user asks about content related to 'Interstellar', please search the knowledge base and combine the search results for answers.",
|
||||
"chatNodeSystemPromptTip": "The model has a fixed guide word. By adjusting this content, you can guide the model in the chat direction. \nThe content will be anchored at the beginning of the context. \nVariables can be selected via input/insert\n\nIf a knowledge base is associated, you can also use appropriate descriptions to guide the model when to call the knowledge base search. \nFor example:\n\nYou are an assistant in the movie \"Interstellar\". When users ask about content related to \"Interstellar\", please search the knowledge base and answer based on the search results.",
|
||||
"variableTip": "You can ask the user to fill in some content as specific variables for this round of conversation before the conversation starts. This module is located after the opening guide.\nVariables can be injected into other module string type inputs through the form of {{variable key}}, such as: prompt words, limiting words, etc.",
|
||||
"welcomeTextTip": "Send an initial content before each conversation starts. Supports standard Markdown syntax, additional tags available:\n[Shortcut key]: User can click to send the question directly"
|
||||
},
|
||||
@@ -902,7 +898,9 @@
|
||||
"overSize": "Team members exceed the limit"
|
||||
}
|
||||
},
|
||||
"field_name": "Name",
|
||||
"invalid_variable": "Invalid variable",
|
||||
"is_open": "Opened",
|
||||
"navbar": {
|
||||
"Account": "Account",
|
||||
"Chat": "Chat",
|
||||
@@ -910,6 +908,8 @@
|
||||
"Studio": "Studio",
|
||||
"Tools": "Tools"
|
||||
},
|
||||
"new_create": "Create New",
|
||||
"no_data": "No data",
|
||||
"permission": {
|
||||
"Collaborator": "collaborator",
|
||||
"Default permission": "Default permission",
|
||||
@@ -1148,6 +1148,7 @@
|
||||
"Quote Content Tip": "You can customize the structure of the quote content to better adapt to different scenarios. You can use some variables for template configuration:\n{{q}} - search content, {{a}} - expected content, {{source}} - source, {{sourceId}} - source file name, {{index}} - the nth quote, they are all optional, here are the default values:\n{{default}}",
|
||||
"Quote Prompt Tip": "You can use {{quote}} to insert the quote content template, and use {{question}} to insert the question. Here are the default values:\n{{default}}"
|
||||
},
|
||||
"textarea_variable_picker_tip": "Input / to select variables",
|
||||
"unusable_variable": "no usable variable",
|
||||
"user": {
|
||||
"Account": "Account",
|
||||
|
@@ -28,5 +28,5 @@
|
||||
"Error": "Error"
|
||||
},
|
||||
"tool_input": "Tool",
|
||||
"variable_picker_tips": "tips: enter node name or variable name to search"
|
||||
"variable_picker_tips": "enter node name or variable name to search"
|
||||
}
|
||||
|
@@ -1,23 +1,19 @@
|
||||
{
|
||||
"add_new": "新增",
|
||||
"App": "应用",
|
||||
"all_apps": "全部应用",
|
||||
"click_to_resume": "点击恢复",
|
||||
"code_editor": "代码编辑",
|
||||
"Export": "导出",
|
||||
"field_name": "字段名",
|
||||
"Folder": "文件夹",
|
||||
"is_open": "是否开启",
|
||||
"Login": "登录",
|
||||
"Move": "移动",
|
||||
"Name": "名称",
|
||||
"new_create": "新建",
|
||||
"no_data": "暂无数据",
|
||||
"Rename": "重命名",
|
||||
"Resume": "恢复",
|
||||
"Running": "运行中",
|
||||
"UnKnow": "未知",
|
||||
"Warning": "提示",
|
||||
"add_new": "新增",
|
||||
"common": {
|
||||
"Action": "操作",
|
||||
"Add": "添加",
|
||||
@@ -294,7 +290,7 @@
|
||||
},
|
||||
"tip": {
|
||||
"Add a intro to app": "快来给应用一个介绍~",
|
||||
"chatNodeSystemPromptTip": "模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}\n如果关联了知识库,你还可以通过适当的描述,来引导模型何时去调用知识库搜索。例如:\n你是电影《星际穿越》的助手,当用户询问与《星际穿越》相关的内容时,请搜索知识库并结合搜索结果进行回答。",
|
||||
"chatNodeSystemPromptTip": "模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可通过输入 / 插入选择变量\n如果关联了知识库,你还可以通过适当的描述,来引导模型何时去调用知识库搜索。例如:\n你是电影《星际穿越》的助手,当用户询问与《星际穿越》相关的内容时,请搜索知识库并结合搜索结果进行回答。",
|
||||
"variableTip": "可以在对话开始前,要求用户填写一些内容作为本轮对话的特定变量。该模块位于开场引导之后。\n变量可以通过 {{变量key}} 的形式注入到其他模块 string 类型的输入中,例如:提示词、限定词等",
|
||||
"welcomeTextTip": "每次对话开始前,发送一个初始内容。支持标准 Markdown 语法,可使用的额外标记:\n[快捷按键]:用户点击后可以直接发送该问题"
|
||||
},
|
||||
@@ -902,7 +898,9 @@
|
||||
"overSize": "团队成员超出上限"
|
||||
}
|
||||
},
|
||||
"field_name": "字段名",
|
||||
"invalid_variable": "无效变量",
|
||||
"is_open": "是否开启",
|
||||
"navbar": {
|
||||
"Account": "账号",
|
||||
"Chat": "聊天",
|
||||
@@ -910,6 +908,8 @@
|
||||
"Studio": "工作台",
|
||||
"Tools": "工具"
|
||||
},
|
||||
"new_create": "新建",
|
||||
"no_data": "暂无数据",
|
||||
"permission": {
|
||||
"Collaborator": "协作者",
|
||||
"Default permission": "默认权限",
|
||||
@@ -1148,6 +1148,7 @@
|
||||
"Quote Content Tip": "可以自定义引用内容的结构,以更好的适配不同场景。可以使用一些变量来进行模板配置:\n{{q}} - 检索内容,{{a}} - 预期内容,{{source}} - 来源,{{sourceId}} - 来源文件名,{{index}} - 第 n 个引用,他们都是可选的,下面是默认值:\n{{default}}",
|
||||
"Quote Prompt Tip": "可以用 {{quote}} 来插入引用内容模板,使用 {{question}} 来插入问题。下面是默认值:\n{{default}}"
|
||||
},
|
||||
"textarea_variable_picker_tip": "输入 / 可选择变量",
|
||||
"unusable_variable": "无可用变量",
|
||||
"user": {
|
||||
"Account": "账号",
|
||||
|
@@ -28,5 +28,5 @@
|
||||
"Error": "错误信息"
|
||||
},
|
||||
"tool_input": "工具参数",
|
||||
"variable_picker_tips": "tips: 可输入节点名或变量名搜索"
|
||||
"variable_picker_tips": "可输入节点名或变量名搜索"
|
||||
}
|
||||
|
63
pnpm-lock.yaml
generated
63
pnpm-lock.yaml
generated
@@ -63,8 +63,8 @@ importers:
|
||||
specifier: 14.2.5
|
||||
version: 14.2.5(@babel/core@7.24.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
|
||||
openai:
|
||||
specifier: 4.28.0
|
||||
version: 4.28.0(encoding@0.1.13)
|
||||
specifier: 4.53.0
|
||||
version: 4.53.0(encoding@0.1.13)
|
||||
openapi-types:
|
||||
specifier: ^12.1.3
|
||||
version: 12.1.3
|
||||
@@ -151,6 +151,9 @@ importers:
|
||||
file-type:
|
||||
specifier: ^19.0.0
|
||||
version: 19.1.1
|
||||
form-data:
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0
|
||||
iconv-lite:
|
||||
specifier: ^0.6.3
|
||||
version: 0.6.3
|
||||
@@ -577,6 +580,9 @@ importers:
|
||||
'@nestjs/swagger':
|
||||
specifier: ^7.3.1
|
||||
version: 7.4.0(@fastify/static@7.0.4)(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
version: 1.11.11
|
||||
fastify:
|
||||
specifier: ^4.27.0
|
||||
version: 4.28.1
|
||||
@@ -592,6 +598,9 @@ importers:
|
||||
rxjs:
|
||||
specifier: ^7.8.1
|
||||
version: 7.8.1
|
||||
tiktoken:
|
||||
specifier: ^1.0.15
|
||||
version: 1.0.15
|
||||
devDependencies:
|
||||
'@nestjs/cli':
|
||||
specifier: ^10.0.0
|
||||
@@ -3864,9 +3873,6 @@ packages:
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
base-64@0.1.0:
|
||||
resolution: {integrity: sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==}
|
||||
|
||||
base64-js@1.5.1:
|
||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||
|
||||
@@ -4027,9 +4033,6 @@ packages:
|
||||
chardet@0.7.0:
|
||||
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
|
||||
|
||||
charenc@0.0.2:
|
||||
resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
|
||||
|
||||
check-error@1.0.3:
|
||||
resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
|
||||
|
||||
@@ -4303,9 +4306,6 @@ packages:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
crypt@0.0.2:
|
||||
resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
|
||||
|
||||
css-box-model@1.2.1:
|
||||
resolution: {integrity: sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==}
|
||||
|
||||
@@ -4654,9 +4654,6 @@ packages:
|
||||
resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
|
||||
digest-fetch@1.3.0:
|
||||
resolution: {integrity: sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==}
|
||||
|
||||
dingbat-to-unicode@1.0.1:
|
||||
resolution: {integrity: sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==}
|
||||
|
||||
@@ -5619,9 +5616,6 @@ packages:
|
||||
resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-buffer@1.1.6:
|
||||
resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
|
||||
|
||||
is-buffer@2.0.5:
|
||||
resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -6287,9 +6281,6 @@ packages:
|
||||
markdown-table@3.0.3:
|
||||
resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
|
||||
|
||||
md5@2.3.0:
|
||||
resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
|
||||
|
||||
mdast-util-definitions@5.1.2:
|
||||
resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==}
|
||||
|
||||
@@ -6849,8 +6840,8 @@ packages:
|
||||
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
openai@4.28.0:
|
||||
resolution: {integrity: sha512-JM8fhcpmpGN0vrUwGquYIzdcEQHtFuom6sRCbbCM6CfzZXNuRk33G7KfeRAIfnaCxSpzrP5iHtwJzIm6biUZ2Q==}
|
||||
openai@4.53.0:
|
||||
resolution: {integrity: sha512-XoMaJsSLuedW5eoMEMmZbdNoXgML3ujcU5KfwRnC6rnbmZkHE2Q4J/SArwhqCxQRqJwHnQUj1LpiROmKPExZJA==}
|
||||
hasBin: true
|
||||
|
||||
openapi-types@12.1.3:
|
||||
@@ -12661,8 +12652,6 @@ snapshots:
|
||||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
base-64@0.1.0: {}
|
||||
|
||||
base64-js@1.5.1: {}
|
||||
|
||||
big.js@5.2.2: {}
|
||||
@@ -12849,8 +12838,6 @@ snapshots:
|
||||
|
||||
chardet@0.7.0: {}
|
||||
|
||||
charenc@0.0.2: {}
|
||||
|
||||
check-error@1.0.3:
|
||||
dependencies:
|
||||
get-func-name: 2.0.2
|
||||
@@ -13129,8 +13116,6 @@ snapshots:
|
||||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
crypt@0.0.2: {}
|
||||
|
||||
css-box-model@1.2.1:
|
||||
dependencies:
|
||||
tiny-invariant: 1.3.3
|
||||
@@ -13519,11 +13504,6 @@ snapshots:
|
||||
|
||||
diff@5.2.0: {}
|
||||
|
||||
digest-fetch@1.3.0:
|
||||
dependencies:
|
||||
base-64: 0.1.0
|
||||
md5: 2.3.0
|
||||
|
||||
dingbat-to-unicode@1.0.1: {}
|
||||
|
||||
dir-glob@3.0.1:
|
||||
@@ -13826,7 +13806,7 @@ snapshots:
|
||||
eslint: 8.56.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint@8.56.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint@8.56.0))(eslint@8.56.0)
|
||||
eslint-plugin-jsx-a11y: 6.9.0(eslint@8.56.0)
|
||||
eslint-plugin-react: 7.34.4(eslint@8.56.0)
|
||||
eslint-plugin-react-hooks: 4.6.2(eslint@8.56.0)
|
||||
@@ -13850,7 +13830,7 @@ snapshots:
|
||||
enhanced-resolve: 5.17.0
|
||||
eslint: 8.56.0
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint@8.56.0))(eslint@8.56.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint@8.56.0))(eslint@8.56.0)
|
||||
fast-glob: 3.3.2
|
||||
get-tsconfig: 4.7.5
|
||||
is-core-module: 2.14.0
|
||||
@@ -13872,7 +13852,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0):
|
||||
eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint@8.56.0))(eslint@8.56.0):
|
||||
dependencies:
|
||||
array-includes: 3.1.8
|
||||
array.prototype.findlastindex: 1.2.5
|
||||
@@ -14838,8 +14818,6 @@ snapshots:
|
||||
call-bind: 1.0.7
|
||||
has-tostringtag: 1.0.2
|
||||
|
||||
is-buffer@1.1.6: {}
|
||||
|
||||
is-buffer@2.0.5: {}
|
||||
|
||||
is-callable@1.2.7: {}
|
||||
@@ -15689,12 +15667,6 @@ snapshots:
|
||||
|
||||
markdown-table@3.0.3: {}
|
||||
|
||||
md5@2.3.0:
|
||||
dependencies:
|
||||
charenc: 0.0.2
|
||||
crypt: 0.0.2
|
||||
is-buffer: 1.1.6
|
||||
|
||||
mdast-util-definitions@5.1.2:
|
||||
dependencies:
|
||||
'@types/mdast': 3.0.15
|
||||
@@ -16442,13 +16414,12 @@ snapshots:
|
||||
dependencies:
|
||||
mimic-fn: 4.0.0
|
||||
|
||||
openai@4.28.0(encoding@0.1.13):
|
||||
openai@4.53.0(encoding@0.1.13):
|
||||
dependencies:
|
||||
'@types/node': 18.19.40
|
||||
'@types/node-fetch': 2.6.11
|
||||
abort-controller: 3.0.0
|
||||
agentkeepalive: 4.5.0
|
||||
digest-fetch: 1.3.0
|
||||
form-data-encoder: 1.7.2
|
||||
formdata-node: 4.4.1
|
||||
node-fetch: 2.7.0(encoding@0.1.13)
|
||||
|
@@ -35,22 +35,22 @@
|
||||
"formidable": "^2.1.1",
|
||||
"framer-motion": "9.1.7",
|
||||
"hyperdown": "^2.4.29",
|
||||
"i18next": "23.11.5",
|
||||
"immer": "^9.0.19",
|
||||
"js-yaml": "^4.1.0",
|
||||
"json5": "^2.2.3",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"mermaid": "^10.2.3",
|
||||
"nanoid": "^4.0.1",
|
||||
"next": "14.2.5",
|
||||
"json5": "^2.2.3",
|
||||
"next-i18next": "15.3.0",
|
||||
"nextjs-node-loader": "^1.1.5",
|
||||
"nprogress": "^0.2.0",
|
||||
"react": "18.3.1",
|
||||
"react-day-picker": "^8.7.1",
|
||||
"react-dom": "18.3.1",
|
||||
"react-hook-form": "7.43.1",
|
||||
"i18next": "23.11.5",
|
||||
"next-i18next": "15.3.0",
|
||||
"react-i18next": "14.1.2",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
|
@@ -0,0 +1,16 @@
|
||||
import { Box, HStack, StackProps } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const VariableTip = (props: StackProps) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<HStack fontSize={'xs'} spacing={1} {...props}>
|
||||
<MyIcon name={'common/info'} w={'0.9rem'} transform={'translateY(1px)'} />
|
||||
<Box>{t('common:textarea_variable_picker_tip')}</Box>
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
|
||||
export default VariableTip;
|
@@ -127,6 +127,7 @@ const DatasetParamsModal = ({
|
||||
>
|
||||
<ModalBody flex={'auto'} overflow={'auto'}>
|
||||
<LightRowTabs<SearchSettingTabEnum>
|
||||
width={'100%'}
|
||||
mb={3}
|
||||
list={[
|
||||
{
|
||||
|
@@ -299,6 +299,8 @@ const VariableEdit = ({
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleSubmitEdit(({ variable }) => {
|
||||
variable.key = variable.key.trim();
|
||||
|
||||
// check select
|
||||
if (variable.type === VariableInputEnum.select) {
|
||||
const enums = variable.enums.filter((item) => item.value);
|
||||
|
@@ -157,6 +157,7 @@ export const ResponseBox = React.memo(function ResponseBox({
|
||||
{!hideTabs && (
|
||||
<Box>
|
||||
<LightRowTabs
|
||||
w={'100%'}
|
||||
list={list}
|
||||
value={currentTab}
|
||||
inlineStyles={{ pt: 0 }}
|
||||
|
@@ -3,15 +3,14 @@ import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { getUploadModel } from '@fastgpt/service/common/file/multer';
|
||||
import { removeFilesByPaths } from '@fastgpt/service/common/file/utils';
|
||||
import fs from 'fs';
|
||||
import { getAIApi } from '@fastgpt/service/core/ai/config';
|
||||
import { pushWhisperUsage } from '@/service/support/wallet/usage/push';
|
||||
import { authChatCert } from '@/service/support/permission/auth/chat';
|
||||
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { aiTranscriptions } from '@fastgpt/service/core/ai/audio/transcriptions';
|
||||
|
||||
const upload = getUploadModel({
|
||||
maxSize: 2
|
||||
maxSize: 20
|
||||
});
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
@@ -45,6 +44,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
|
||||
// auth role
|
||||
const { teamId, tmbId } = await authChatCert({ req, authToken: true });
|
||||
|
||||
// auth app
|
||||
// const app = await MongoApp.findById(appId, 'modules').lean();
|
||||
// if (!app) {
|
||||
@@ -54,11 +54,9 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
// throw new Error('Whisper is not open in the app');
|
||||
// }
|
||||
|
||||
const ai = getAIApi();
|
||||
|
||||
const result = await ai.audio.transcriptions.create({
|
||||
file: fs.createReadStream(file.path),
|
||||
model: global.whisperModel.model
|
||||
const result = await aiTranscriptions({
|
||||
model: global.whisperModel.model,
|
||||
fileStream: fs.createReadStream(file.path)
|
||||
});
|
||||
|
||||
pushWhisperUsage({
|
||||
|
@@ -34,6 +34,7 @@ import { useContextSelector } from 'use-context-selector';
|
||||
import { AppContext } from '@/pages/app/detail/components/context';
|
||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
|
||||
import VariableTip from '@/components/common/Textarea/MyTextarea/VariableTip';
|
||||
|
||||
const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal'));
|
||||
const DatasetParamsModal = dynamic(() => import('@/components/core/app/DatasetParamsModal'));
|
||||
@@ -57,7 +58,8 @@ const LabelStyles: BoxProps = {
|
||||
w: ['60px', '100px'],
|
||||
whiteSpace: 'nowrap',
|
||||
flexShrink: 0,
|
||||
fontSize: 'xs'
|
||||
fontSize: 'sm',
|
||||
color: 'myGray.900'
|
||||
};
|
||||
|
||||
const EditForm = ({
|
||||
@@ -162,10 +164,13 @@ const EditForm = ({
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<Box mt={3}>
|
||||
<HStack {...LabelStyles}>
|
||||
<Box mt={4}>
|
||||
<HStack {...LabelStyles} w={'100%'}>
|
||||
<Box>{t('common:core.ai.Prompt')}</Box>
|
||||
<QuestionTip label={t('common:core.app.tip.chatNodeSystemPromptTip')} />
|
||||
|
||||
<Box flex={1} />
|
||||
<VariableTip color={'myGray.500'} />
|
||||
</HStack>
|
||||
<Box mt={1}>
|
||||
<PromptEditor
|
||||
|
@@ -309,6 +309,7 @@ export function RenderHttpProps({
|
||||
></QuestionTip>
|
||||
</Flex>
|
||||
<LightRowTabs<TabEnum>
|
||||
width={'100%'}
|
||||
list={[
|
||||
{ label: <RenderPropsItem text="Params" num={paramsLength} />, value: TabEnum.params },
|
||||
...(!['GET', 'DELETE'].includes(requestMethods)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { Box, Flex, HStack } from '@chakra-ui/react';
|
||||
|
||||
import NodeInputSelect from '@fastgpt/web/components/core/workflow/NodeInputSelect';
|
||||
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
@@ -10,6 +10,10 @@ import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/pages/app/detail/components/WorkflowComponents/context';
|
||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
|
||||
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyTag from '@fastgpt/web/components/common/Tag/index';
|
||||
import VariableTip from '@/components/common/Textarea/MyTextarea/VariableTip';
|
||||
|
||||
type Props = {
|
||||
nodeId: string;
|
||||
@@ -68,6 +72,14 @@ const InputLabel = ({ nodeId, input }: Props) => {
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Variable picker tip */}
|
||||
{input.renderTypeList[input.selectedTypeIndex ?? 0] === FlowNodeInputTypeEnum.textarea && (
|
||||
<>
|
||||
<Box flex={1} />
|
||||
<VariableTip transform={'translateY(2px)'} />
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}, [
|
||||
|
@@ -27,20 +27,19 @@ const ChatHeader = ({
|
||||
chatData,
|
||||
history,
|
||||
showHistory,
|
||||
onRoute2AppDetail,
|
||||
apps
|
||||
apps,
|
||||
onRouteToAppDetail
|
||||
}: {
|
||||
history: ChatItemType[];
|
||||
showHistory?: boolean;
|
||||
onRoute2AppDetail?: () => void;
|
||||
apps?: AppListItemType[];
|
||||
chatData: InitChatResponse;
|
||||
apps?: AppListItemType[];
|
||||
onRouteToAppDetail?: () => void;
|
||||
}) => {
|
||||
const isPlugin = chatData.app.type === AppTypeEnum.plugin;
|
||||
const { isPc } = useSystem();
|
||||
return (
|
||||
<>
|
||||
{isPc && isPlugin ? null : (
|
||||
|
||||
return isPc && isPlugin ? null : (
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
px={[3, 5]}
|
||||
@@ -50,16 +49,14 @@ const ChatHeader = ({
|
||||
fontSize={'sm'}
|
||||
>
|
||||
{isPc ? (
|
||||
<PcHeader
|
||||
title={chatData.title}
|
||||
chatModels={chatData.app.chatModels}
|
||||
history={history}
|
||||
/>
|
||||
<>
|
||||
<PcHeader title={chatData.title} chatModels={chatData.app.chatModels} history={history} />
|
||||
<Box flex={1} />
|
||||
</>
|
||||
) : (
|
||||
<MobileHeader
|
||||
apps={apps}
|
||||
appId={chatData.appId}
|
||||
go2AppDetail={onRoute2AppDetail}
|
||||
name={chatData.app.name}
|
||||
avatar={chatData.app.avatar}
|
||||
showHistory={showHistory}
|
||||
@@ -67,10 +64,8 @@ const ChatHeader = ({
|
||||
)}
|
||||
|
||||
{/* control */}
|
||||
{!isPlugin && <ToolMenu history={history} />}
|
||||
{!isPlugin && <ToolMenu history={history} onRouteToAppDetail={onRouteToAppDetail} />}
|
||||
</Flex>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -88,7 +83,6 @@ const MobileDrawer = ({
|
||||
app = 'app'
|
||||
}
|
||||
const { t } = useTranslation();
|
||||
const { isPc } = useSystem();
|
||||
const router = useRouter();
|
||||
const isTeamChat = router.pathname === '/chat/team';
|
||||
const [currentTab, setCurrentTab] = useState<TabEnum>(TabEnum.recently);
|
||||
@@ -103,8 +97,12 @@ const MobileDrawer = ({
|
||||
);
|
||||
}, []);
|
||||
const { onChangeAppId } = useContextSelector(ChatContext, (v) => v);
|
||||
const onclickApp = (id: string) => {
|
||||
onChangeAppId(id);
|
||||
onCloseDrawer();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
position={'absolute'}
|
||||
top={'45px'}
|
||||
@@ -126,13 +124,10 @@ const MobileDrawer = ({
|
||||
background={'white'}
|
||||
position={'relative'}
|
||||
>
|
||||
{!isPc && appId && (
|
||||
<LightRowTabs<TabEnum>
|
||||
flex={'1 0 0'}
|
||||
width={isTeamChat ? '30%' : '60%'}
|
||||
mr={10}
|
||||
gap={3}
|
||||
inlineStyles={{
|
||||
px: 1
|
||||
px: 2
|
||||
}}
|
||||
list={[
|
||||
...(isTeamChat
|
||||
@@ -145,26 +140,22 @@ const MobileDrawer = ({
|
||||
value={currentTab}
|
||||
onChange={setCurrentTab}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<Box
|
||||
width={'100vw'}
|
||||
height={'auto'}
|
||||
width={'100%'}
|
||||
minH={'10vh'}
|
||||
maxH={'60vh'}
|
||||
overflow={'auto'}
|
||||
background={'white'}
|
||||
zIndex={3}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
borderRadius={'0 0 10px 10px'}
|
||||
position={'relative'}
|
||||
padding={3}
|
||||
py={3}
|
||||
pt={0}
|
||||
pb={4}
|
||||
h={'65vh'}
|
||||
>
|
||||
{/* history */}
|
||||
{currentTab === TabEnum.recently && (
|
||||
<>
|
||||
<Box px={3} overflow={'auto'} h={'100%'}>
|
||||
{Array.isArray(apps) &&
|
||||
apps.map((item) => (
|
||||
<Flex justify={'center'} key={item._id}>
|
||||
@@ -180,7 +171,7 @@ const MobileDrawer = ({
|
||||
color: 'primary.600'
|
||||
}
|
||||
: {
|
||||
onClick: () => onChangeAppId(item._id)
|
||||
onClick: () => onclickApp(item._id)
|
||||
})}
|
||||
>
|
||||
<Avatar src={item.avatar} w={'24px'} />
|
||||
@@ -190,42 +181,36 @@ const MobileDrawer = ({
|
||||
</Flex>
|
||||
</Flex>
|
||||
))}
|
||||
</>
|
||||
</Box>
|
||||
)}
|
||||
{currentTab === TabEnum.app && !isPc && (
|
||||
<>
|
||||
{currentTab === TabEnum.app && (
|
||||
<SelectOneResource
|
||||
value={appId}
|
||||
onSelect={(id) => {
|
||||
if (!id) return;
|
||||
onChangeAppId(id);
|
||||
onclickApp(id);
|
||||
}}
|
||||
server={getAppList}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const MobileHeader = ({
|
||||
showHistory,
|
||||
go2AppDetail,
|
||||
name,
|
||||
avatar,
|
||||
appId,
|
||||
apps
|
||||
}: {
|
||||
showHistory?: boolean;
|
||||
go2AppDetail?: () => void;
|
||||
avatar: string;
|
||||
name: string;
|
||||
apps?: AppListItemType[];
|
||||
appId: string;
|
||||
}) => {
|
||||
const { isPc } = useSystem();
|
||||
const router = useRouter();
|
||||
const onOpenSlider = useContextSelector(ChatContext, (v) => v.onOpenSlider);
|
||||
const { isOpen: isOpenDrawer, onToggle: toggleDrawer, onClose: onCloseDrawer } = useDisclosure();
|
||||
@@ -237,22 +222,21 @@ const MobileHeader = ({
|
||||
<MyIcon name={'menu'} w={'20px'} h={'20px'} color={'myGray.900'} onClick={onOpenSlider} />
|
||||
)}
|
||||
<Flex px={3} alignItems={'center'} flex={'1 0 0'} w={0} justifyContent={'center'}>
|
||||
<Avatar src={avatar} w={'16px'} />
|
||||
<Box ml={1} className="textEllipsis" onClick={go2AppDetail}>
|
||||
<Flex alignItems={'center'} onClick={toggleDrawer}>
|
||||
<Avatar src={avatar} w={'1rem'} />
|
||||
<Box ml={1} className="textEllipsis">
|
||||
{name}
|
||||
</Box>
|
||||
{isShareChat ? null : (
|
||||
<MyIcon
|
||||
_active={{ transform: 'scale(0.9)' }}
|
||||
name={'core/chat/chevronSelector'}
|
||||
w={'20px'}
|
||||
h={'20px'}
|
||||
w={'1.25rem'}
|
||||
color={isOpenDrawer ? 'primary.600' : 'myGray.900'}
|
||||
onClick={toggleDrawer}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
{!isPc && isOpenDrawer && !isShareChat && (
|
||||
</Flex>
|
||||
{isOpenDrawer && !isShareChat && (
|
||||
<MobileDrawer apps={apps} appId={appId} onCloseDrawer={onCloseDrawer} />
|
||||
)}
|
||||
</>
|
||||
@@ -292,7 +276,6 @@ const PcHeader = ({
|
||||
</MyTag>
|
||||
</MyTooltip>
|
||||
)}
|
||||
<Box flex={1} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@@ -27,7 +27,6 @@ const ChatHistorySlider = ({
|
||||
appId,
|
||||
appName,
|
||||
appAvatar,
|
||||
apps = [],
|
||||
confirmClearText,
|
||||
onDelHistory,
|
||||
onClearHistory,
|
||||
@@ -37,7 +36,6 @@ const ChatHistorySlider = ({
|
||||
appId?: string;
|
||||
appName: string;
|
||||
appAvatar: string;
|
||||
apps?: AppListItemType[];
|
||||
confirmClearText: string;
|
||||
onDelHistory: (e: { chatId: string }) => void;
|
||||
onClearHistory: () => void;
|
||||
@@ -46,10 +44,9 @@ const ChatHistorySlider = ({
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const isTeamChat = router.pathname === '/chat/team';
|
||||
const isUserChatPage = router.pathname === '/chat';
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
|
||||
const { isPc } = useSystem();
|
||||
const { userInfo } = useUserStore();
|
||||
@@ -103,7 +100,7 @@ const ChatHistorySlider = ({
|
||||
whiteSpace={'nowrap'}
|
||||
>
|
||||
{isPc && (
|
||||
<MyTooltip label={canRouteToDetail ? appT('app_detail') : ''} offset={[0, 0]}>
|
||||
<MyTooltip label={canRouteToDetail ? t('app:app_detail') : ''} offset={[0, 0]}>
|
||||
<Flex
|
||||
pt={5}
|
||||
pb={2}
|
||||
@@ -136,7 +133,7 @@ const ChatHistorySlider = ({
|
||||
justify={['space-between', '']}
|
||||
alignItems={'center'}
|
||||
>
|
||||
{!isPc && appId && (
|
||||
{!isPc && (
|
||||
<Flex height={'100%'} align={'center'} justify={'center'}>
|
||||
<MyIcon ml={2} name="core/chat/sideLine" />
|
||||
<Box ml={2} fontWeight={'bold'}>
|
||||
@@ -147,8 +144,9 @@ const ChatHistorySlider = ({
|
||||
|
||||
<Button
|
||||
variant={'whitePrimary'}
|
||||
flex={[appId ? '0 0 auto' : 1, 1]}
|
||||
flex={['0 0 auto', 1]}
|
||||
h={'100%'}
|
||||
px={6}
|
||||
color={'primary.600'}
|
||||
borderRadius={'xl'}
|
||||
leftIcon={<MyIcon name={'core/chat/chatLight'} w={'16px'} />}
|
||||
@@ -158,7 +156,7 @@ const ChatHistorySlider = ({
|
||||
{t('common:core.chat.New Chat')}
|
||||
</Button>
|
||||
{/* Clear */}
|
||||
{isPc && (
|
||||
{isPc && histories.length > 0 && (
|
||||
<IconButton
|
||||
ml={3}
|
||||
h={'100%'}
|
||||
@@ -288,7 +286,7 @@ const ChatHistorySlider = ({
|
||||
</Box>
|
||||
|
||||
{/* exec */}
|
||||
{!isPc && appId && !isTeamChat && (
|
||||
{!isPc && isUserChatPage && (
|
||||
<Flex
|
||||
mt={2}
|
||||
borderTop={theme.borders.base}
|
||||
|
@@ -7,7 +7,13 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useRouter } from 'next/router';
|
||||
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
||||
|
||||
const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
const ToolMenu = ({
|
||||
history,
|
||||
onRouteToAppDetail
|
||||
}: {
|
||||
history: ChatItemType[];
|
||||
onRouteToAppDetail?: () => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { onExportChat } = useChatBox();
|
||||
const router = useRouter();
|
||||
@@ -57,7 +63,20 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
// onClick: () => onExportChat({ type: 'pdf', history })
|
||||
// }
|
||||
]
|
||||
},
|
||||
...(onRouteToAppDetail
|
||||
? [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
icon: 'core/app/aiLight',
|
||||
label: t('app:app_detail'),
|
||||
onClick: onRouteToAppDetail
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
: [])
|
||||
]}
|
||||
/>
|
||||
) : (
|
||||
|
@@ -195,7 +195,6 @@ const Chat = ({
|
||||
);
|
||||
})(
|
||||
<ChatHistorySlider
|
||||
apps={myApps}
|
||||
confirmClearText={t('common:core.chat.Confirm to clear history')}
|
||||
appId={appId}
|
||||
appName={chatData.app.name}
|
||||
@@ -229,8 +228,8 @@ const Chat = ({
|
||||
apps={myApps}
|
||||
chatData={chatData}
|
||||
history={chatRecords}
|
||||
onRoute2AppDetail={() => router.push(`/app/detail?appId=${appId}`)}
|
||||
showHistory
|
||||
onRouteToAppDetail={() => router.push(`/app/detail?appId=${appId}`)}
|
||||
/>
|
||||
|
||||
{/* chat box */}
|
||||
@@ -341,7 +340,7 @@ export async function getServerSideProps(context: any) {
|
||||
props: {
|
||||
appId: context?.query?.appId || '',
|
||||
chatId: context?.query?.chatId || '',
|
||||
...(await serviceSideProps(context, ['file']))
|
||||
...(await serviceSideProps(context, ['file', 'app']))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -292,7 +292,7 @@ const OutLink = ({ appName, appIntro, appAvatar }: Props) => {
|
||||
{showHead === '1' ? (
|
||||
<ChatHeader
|
||||
chatData={chatData}
|
||||
history={chatData.history}
|
||||
history={chatRecords}
|
||||
showHistory={showHistory === '1'}
|
||||
/>
|
||||
) : null}
|
||||
@@ -396,7 +396,7 @@ export async function getServerSideProps(context: any) {
|
||||
appIntro: app?.appId?.intro ?? 'intro',
|
||||
shareId: shareId ?? '',
|
||||
authToken: authToken ?? '',
|
||||
...(await serviceSideProps(context, ['file']))
|
||||
...(await serviceSideProps(context, ['file', 'app']))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -199,7 +199,6 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
||||
})(
|
||||
<ChatHistorySlider
|
||||
appId={appId}
|
||||
apps={myApps}
|
||||
appName={chatData.app.name}
|
||||
appAvatar={chatData.app.avatar}
|
||||
confirmClearText={t('common:core.chat.Confirm to clear history')}
|
||||
@@ -230,7 +229,7 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
|
||||
flexDirection={'column'}
|
||||
>
|
||||
{/* header */}
|
||||
<ChatHeader apps={myApps} chatData={chatData} history={chatData.history} showHistory />
|
||||
<ChatHeader apps={myApps} chatData={chatData} history={chatRecords} showHistory />
|
||||
{/* chat box */}
|
||||
<Box flex={1}>
|
||||
{chatData.app.type === AppTypeEnum.plugin ? (
|
||||
@@ -340,7 +339,7 @@ export async function getServerSideProps(context: any) {
|
||||
chatId: context?.query?.chatId || '',
|
||||
teamId: context?.query?.teamId || '',
|
||||
teamToken: context?.query?.teamToken || '',
|
||||
...(await serviceSideProps(context, ['file']))
|
||||
...(await serviceSideProps(context, ['file', 'app']))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -128,7 +128,7 @@ const Login = () => {
|
||||
|
||||
export async function getServerSideProps(context: any) {
|
||||
return {
|
||||
props: { ...(await serviceSideProps(context)) }
|
||||
props: { ...(await serviceSideProps(context, ['app'])) }
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -439,7 +439,7 @@ export const simpleBotTemplates: TemplateType = [
|
||||
label: 'core.ai.Prompt',
|
||||
description: 'core.app.tip.chatNodeSystemPromptTip',
|
||||
placeholder: 'core.app.tip.chatNodeSystemPromptTip',
|
||||
value: '请直接将我的问题翻译成{{language}},不需要回答问题。'
|
||||
value: '请直接将我的问题翻译成{{$VARIABLE_NODE_ID.language$}},不需要回答问题。'
|
||||
},
|
||||
{
|
||||
key: 'history',
|
||||
|
@@ -25,7 +25,9 @@
|
||||
"@nestjs/platform-fastify": "^10.3.8",
|
||||
"@nestjs/swagger": "^7.3.1",
|
||||
"fastify": "^4.27.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"isolated-vm": "^4.7.2",
|
||||
"tiktoken": "^1.0.15",
|
||||
"node-gyp": "^10.1.0",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1"
|
||||
|
10
projects/sandbox/src/sandbox/jsFn/delay.ts
Normal file
10
projects/sandbox/src/sandbox/jsFn/delay.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export const timeDelay = (time: number) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (time > 10000) {
|
||||
reject('Delay time must be less than 10');
|
||||
}
|
||||
setTimeout(() => {
|
||||
resolve('');
|
||||
}, time);
|
||||
});
|
||||
};
|
8
projects/sandbox/src/sandbox/jsFn/tiktoken/index.ts
Normal file
8
projects/sandbox/src/sandbox/jsFn/tiktoken/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Tiktoken } from 'tiktoken/lite';
|
||||
const cl100k_base = require('tiktoken/encoders/cl100k_base');
|
||||
|
||||
export const countToken = (text: string = '') => {
|
||||
const enc = new Tiktoken(cl100k_base.bpe_ranks, cl100k_base.special_tokens, cl100k_base.pat_str);
|
||||
const encodeText = enc.encode(text);
|
||||
return encodeText.length;
|
||||
};
|
@@ -1,15 +1,14 @@
|
||||
import { Controller, Post, Body, HttpCode } from '@nestjs/common';
|
||||
import { SandboxService } from './sandbox.service';
|
||||
import { RunCodeDto, RunCodeResponse } from './dto/create-sandbox.dto';
|
||||
import { WorkerNameEnum, runWorker } from 'src/worker/utils';
|
||||
import { RunCodeDto } from './dto/create-sandbox.dto';
|
||||
import { runSandbox } from './utils';
|
||||
|
||||
@Controller('sandbox')
|
||||
export class SandboxController {
|
||||
constructor(private readonly sandboxService: SandboxService) {}
|
||||
constructor() {}
|
||||
|
||||
@Post('/js')
|
||||
@HttpCode(200)
|
||||
runJs(@Body() codeProps: RunCodeDto) {
|
||||
return runWorker<RunCodeResponse>(WorkerNameEnum.runJs, codeProps);
|
||||
return runSandbox(codeProps);
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,9 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { RunCodeDto } from './dto/create-sandbox.dto';
|
||||
import { WorkerNameEnum, runWorker } from 'src/worker/utils';
|
||||
|
||||
@Injectable()
|
||||
export class SandboxService {
|
||||
runJs(params: RunCodeDto) {
|
||||
return runWorker(WorkerNameEnum.runJs, params);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
102
projects/sandbox/src/sandbox/utils.ts
Normal file
102
projects/sandbox/src/sandbox/utils.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { RunCodeDto, RunCodeResponse } from 'src/sandbox/dto/create-sandbox.dto';
|
||||
import IsolatedVM, { ExternalCopy, Isolate, Reference } from 'isolated-vm';
|
||||
import { countToken } from './jsFn/tiktoken';
|
||||
import { timeDelay } from './jsFn/delay';
|
||||
|
||||
const CustomLogStr = 'CUSTOM_LOG';
|
||||
|
||||
/*
|
||||
Rewrite code to add custom functions: Promise function; Log.
|
||||
*/
|
||||
function getFnCode(code: string) {
|
||||
const rewriteSystemFn = `
|
||||
const thisDelay = (...args) => global_delay.applySyncPromise(undefined,args)
|
||||
`;
|
||||
|
||||
// rewrite delay
|
||||
code = code.replace(/delay\((.*)\)/g, `thisDelay($1)`);
|
||||
|
||||
// rewrite log
|
||||
code = code.replace(/console\.log/g, `${CustomLogStr}`);
|
||||
|
||||
const runCode = `
|
||||
(async() => {
|
||||
try {
|
||||
${rewriteSystemFn}
|
||||
${code}
|
||||
|
||||
const res = await main(variables, {})
|
||||
return JSON.stringify(res);
|
||||
} catch(err) {
|
||||
return JSON.stringify({ERROR: err?.message ?? err})
|
||||
}
|
||||
})
|
||||
`;
|
||||
return runCode;
|
||||
}
|
||||
|
||||
function registerSystemFn(jail: IsolatedVM.Reference<Record<string | number | symbol, any>>) {
|
||||
return Promise.all([
|
||||
// delay
|
||||
jail.set('global_delay', new Reference(timeDelay)),
|
||||
jail.set('countToken', countToken)
|
||||
]);
|
||||
}
|
||||
|
||||
export const runSandbox = async ({
|
||||
code,
|
||||
variables = {}
|
||||
}: RunCodeDto): Promise<RunCodeResponse> => {
|
||||
const logData = [];
|
||||
|
||||
const isolate = new Isolate({ memoryLimit: 32 });
|
||||
const context = await isolate.createContext();
|
||||
const jail = context.global;
|
||||
|
||||
try {
|
||||
// Add global variables
|
||||
await Promise.all([
|
||||
jail.set('variables', new ExternalCopy(variables).copyInto()),
|
||||
jail.set(CustomLogStr, function (...args) {
|
||||
logData.push(
|
||||
args
|
||||
.map((item) => (typeof item === 'object' ? JSON.stringify(item, null, 2) : item))
|
||||
.join(', ')
|
||||
);
|
||||
}),
|
||||
registerSystemFn(jail)
|
||||
]);
|
||||
|
||||
// Run code
|
||||
const fn = await context.eval(getFnCode(code), { reference: true, timeout: 10000 });
|
||||
|
||||
try {
|
||||
// Get result and parse
|
||||
const value = await fn.apply(undefined, [], { result: { promise: true } });
|
||||
const result = JSON.parse(value.toLocaleString());
|
||||
|
||||
// release memory
|
||||
context.release();
|
||||
isolate.dispose();
|
||||
|
||||
if (result.ERROR) {
|
||||
return Promise.reject(result.ERROR);
|
||||
}
|
||||
|
||||
return {
|
||||
codeReturn: result,
|
||||
log: logData.join('\n')
|
||||
};
|
||||
} catch (error) {
|
||||
context.release();
|
||||
isolate.dispose();
|
||||
return Promise.reject('Not an invalid response.You must return an object');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
|
||||
context.release();
|
||||
isolate.dispose();
|
||||
return Promise.reject(err);
|
||||
}
|
||||
};
|
@@ -1,53 +0,0 @@
|
||||
import { RunCodeDto, RunCodeResponse } from 'src/sandbox/dto/create-sandbox.dto';
|
||||
import { parentPort } from 'worker_threads';
|
||||
import { workerResponse } from './utils';
|
||||
|
||||
// @ts-ignore
|
||||
const ivm = require('isolated-vm');
|
||||
|
||||
parentPort?.on('message', ({ code, variables = {} }: RunCodeDto) => {
|
||||
const resolve = (data: RunCodeResponse) => workerResponse({ parentPort, type: 'success', data });
|
||||
const reject = (error: any) => workerResponse({ parentPort, type: 'error', data: error });
|
||||
try {
|
||||
const isolate = new ivm.Isolate({ memoryLimit: 32 });
|
||||
const context = isolate.createContextSync();
|
||||
const jail = context.global;
|
||||
|
||||
// custom function
|
||||
const logData = [];
|
||||
const CustomLogStr = 'CUSTOM_LOG';
|
||||
code = code.replace(/console\.log/g, `${CustomLogStr}`);
|
||||
jail.setSync(CustomLogStr, function (...args) {
|
||||
logData.push(
|
||||
args
|
||||
.map((item) => (typeof item === 'object' ? JSON.stringify(item, null, 2) : item))
|
||||
.join(', ')
|
||||
);
|
||||
});
|
||||
|
||||
jail.setSync('responseData', function (args: any): any {
|
||||
if (typeof args === 'object') {
|
||||
resolve({
|
||||
codeReturn: args,
|
||||
log: logData.join('\n')
|
||||
});
|
||||
} else {
|
||||
reject('Not an invalid response, must return an object');
|
||||
}
|
||||
});
|
||||
|
||||
// Add global variables
|
||||
jail.setSync('variables', new ivm.ExternalCopy(variables).copyInto());
|
||||
|
||||
const scriptCode = `
|
||||
${code}
|
||||
responseData(main(variables))`;
|
||||
|
||||
context.evalSync(scriptCode, { timeout: 6000 });
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
reject(err);
|
||||
}
|
||||
|
||||
process.exit();
|
||||
});
|
@@ -1,47 +0,0 @@
|
||||
import { type MessagePort, Worker } from 'worker_threads';
|
||||
import * as path from 'path';
|
||||
|
||||
export enum WorkerNameEnum {
|
||||
runJs = 'runJs',
|
||||
runPy = 'runPy'
|
||||
}
|
||||
|
||||
type WorkerResponseType = { type: 'success' | 'error'; data: any };
|
||||
|
||||
export const getWorker = (name: WorkerNameEnum) => {
|
||||
const baseUrl =
|
||||
process.env.NODE_ENV === 'production' ? 'projects/sandbox/dist/worker' : 'dist/worker';
|
||||
const workerPath = path.join(process.cwd(), baseUrl, `${name}.js`);
|
||||
return new Worker(workerPath);
|
||||
};
|
||||
|
||||
export const runWorker = <T = any>(name: WorkerNameEnum, params?: Record<string, any>) => {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
const worker = getWorker(name);
|
||||
|
||||
worker.postMessage(params);
|
||||
|
||||
worker.on('message', (msg: WorkerResponseType) => {
|
||||
if (msg.type === 'error') return reject(msg.data);
|
||||
|
||||
resolve(msg.data);
|
||||
worker.terminate();
|
||||
});
|
||||
|
||||
worker.on('error', (err) => {
|
||||
reject(err);
|
||||
worker.terminate();
|
||||
});
|
||||
worker.on('messageerror', (err) => {
|
||||
reject(err);
|
||||
worker.terminate();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const workerResponse = ({
|
||||
parentPort,
|
||||
...data
|
||||
}: WorkerResponseType & { parentPort?: MessagePort }) => {
|
||||
parentPort?.postMessage(data);
|
||||
};
|
Reference in New Issue
Block a user