diff --git a/.prettierignore b/.prettierignore index 33bf7e6cfa58..942a7f4e8812 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,4 +3,6 @@ dist **/.DS_Store node_modules docSite/ -*.md \ No newline at end of file +*.md + +cl100l_base.ts \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index e793cbcd8f61..7ebe8d48ba33 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" + } } \ No newline at end of file diff --git a/docSite/content/zh-cn/docs/development/upgrading/488.md b/docSite/content/zh-cn/docs/development/upgrading/488.md index 72c8d146f4ed..c45eee7f13a9 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/488.md +++ b/docSite/content/zh-cn/docs/development/upgrading/488.md @@ -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 配置无效。 diff --git a/packages/global/package.json b/packages/global/package.json index 53986c42f6ad..ca6a5cf50b52 100644 --- a/packages/global/package.json +++ b/packages/global/package.json @@ -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" }, diff --git a/packages/plugins/register.ts b/packages/plugins/register.ts index dac556a6e32f..cdaabb8989af 100644 --- a/packages/plugins/register.ts +++ b/packages/plugins/register.ts @@ -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]; diff --git a/packages/plugins/src/Doc2X/URLImg2text/template.json b/packages/plugins/src/Doc2X/URLImg2text/template.json index c7ce70bb43ee..0b54f3ce3fab 100644 --- a/packages/plugins/src/Doc2X/URLImg2text/template.json +++ b/packages/plugins/src/Doc2X/URLImg2text/template.json @@ -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": [ diff --git a/packages/plugins/src/Doc2X/URLPDF2text/template.json b/packages/plugins/src/Doc2X/URLPDF2text/template.json index 834786cfe1b3..bdacb3f649e0 100644 --- a/packages/plugins/src/Doc2X/URLPDF2text/template.json +++ b/packages/plugins/src/Doc2X/URLPDF2text/template.json @@ -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": [ diff --git a/packages/plugins/src/Doc2X/template.json b/packages/plugins/src/Doc2X/template.json index c6cdfce8e922..cb540443dda4 100644 --- a/packages/plugins/src/Doc2X/template.json +++ b/packages/plugins/src/Doc2X/template.json @@ -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, diff --git a/packages/service/core/ai/audio/transcriptions.ts b/packages/service/core/ai/audio/transcriptions.ts new file mode 100644 index 000000000000..718dd5ad1bcc --- /dev/null +++ b/packages/service/core/ai/audio/transcriptions.ts @@ -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; +}; diff --git a/packages/service/core/ai/config.ts b/packages/service/core/ai/config.ts index bc9832639251..e1073b4c46c9 100644 --- a/packages/service/core/ai/config.ts +++ b/packages/service/core/ai/config.ts @@ -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}` + }; +}; diff --git a/packages/service/core/workflow/dispatch/index.ts b/packages/service/core/workflow/dispatch/index.ts index b2b783547642..4cc8ce8988b4 100644 --- a/packages/service/core/workflow/dispatch/index.ts +++ b/packages/service/core/workflow/dispatch/index.ts @@ -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.workflowStart]: dispatchWorkflowStart, diff --git a/packages/service/package.json b/packages/service/package.json index cb279948e4c8..ee19788fffcc 100644 --- a/packages/service/package.json +++ b/packages/service/package.json @@ -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", diff --git a/packages/web/components/common/Icon/constants.ts b/packages/web/components/common/Icon/constants.ts index 3e6b6975eab3..4ac0cbc6a10e 100644 --- a/packages/web/components/common/Icon/constants.ts +++ b/packages/web/components/common/Icon/constants.ts @@ -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'), diff --git a/packages/web/components/common/Icon/icons/common/info.svg b/packages/web/components/common/Icon/icons/common/info.svg new file mode 100644 index 000000000000..dfcaefb4dee7 --- /dev/null +++ b/packages/web/components/common/Icon/icons/common/info.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/web/components/common/Icon/icons/core/chat/chevronSelector.svg b/packages/web/components/common/Icon/icons/core/chat/chevronSelector.svg index 7262690df8ca..f0aa1b02d16e 100644 --- a/packages/web/components/common/Icon/icons/core/chat/chevronSelector.svg +++ b/packages/web/components/common/Icon/icons/core/chat/chevronSelector.svg @@ -1,3 +1,3 @@ - + diff --git a/packages/web/components/common/Icon/icons/plugins/doc2x.svg b/packages/web/components/common/Icon/icons/plugins/doc2x.svg new file mode 100644 index 000000000000..1c4a7762c25c --- /dev/null +++ b/packages/web/components/common/Icon/icons/plugins/doc2x.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/web/components/common/Tabs/LightRowTabs.tsx b/packages/web/components/common/Tabs/LightRowTabs.tsx index 069d290dc67a..1752808fff62 100644 --- a/packages/web/components/common/Tabs/LightRowTabs.tsx +++ b/packages/web/components/common/Tabs/LightRowTabs.tsx @@ -52,6 +52,7 @@ const LightRowTabs = ({ fontSize={sizeMap.fontSize} overflowX={'auto'} userSelect={'none'} + display={'inline-grid'} {...props} > {list.map((item) => ( diff --git a/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPickerPlugin/index.tsx b/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPickerPlugin/index.tsx index 5ea71044033a..98da771d71ae 100644 --- a/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPickerPlugin/index.tsx +++ b/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPickerPlugin/index.tsx @@ -94,8 +94,7 @@ export default function VariableLabelPickerPlugin({ = 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) diff --git a/projects/app/package.json b/projects/app/package.json index f2a461abdb83..8786e8000357 100644 --- a/projects/app/package.json +++ b/projects/app/package.json @@ -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", diff --git a/projects/app/src/components/common/Textarea/MyTextarea/VariableTip.tsx b/projects/app/src/components/common/Textarea/MyTextarea/VariableTip.tsx new file mode 100644 index 000000000000..bd3313c4ccf3 --- /dev/null +++ b/projects/app/src/components/common/Textarea/MyTextarea/VariableTip.tsx @@ -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 ( + + + {t('common:textarea_variable_picker_tip')} + + ); +}; + +export default VariableTip; diff --git a/projects/app/src/components/core/app/DatasetParamsModal.tsx b/projects/app/src/components/core/app/DatasetParamsModal.tsx index 58221c3803f1..2e8386e5110f 100644 --- a/projects/app/src/components/core/app/DatasetParamsModal.tsx +++ b/projects/app/src/components/core/app/DatasetParamsModal.tsx @@ -127,6 +127,7 @@ const DatasetParamsModal = ({ > + width={'100%'} mb={3} list={[ { diff --git a/projects/app/src/components/core/app/VariableEdit.tsx b/projects/app/src/components/core/app/VariableEdit.tsx index 384cee7c7240..0f0802e21fb7 100644 --- a/projects/app/src/components/core/app/VariableEdit.tsx +++ b/projects/app/src/components/core/app/VariableEdit.tsx @@ -299,6 +299,8 @@ const VariableEdit = ({ {/* Clear */} - {isPc && ( + {isPc && histories.length > 0 && ( {/* exec */} - {!isPc && appId && !isTeamChat && ( + {!isPc && isUserChatPage && ( { +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 + } + ] + } + ] + : []) ]} /> ) : ( diff --git a/projects/app/src/pages/chat/index.tsx b/projects/app/src/pages/chat/index.tsx index 90e2e5264f4c..417cdca24d6e 100644 --- a/projects/app/src/pages/chat/index.tsx +++ b/projects/app/src/pages/chat/index.tsx @@ -195,7 +195,6 @@ const Chat = ({ ); })( 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'])) } }; } diff --git a/projects/app/src/pages/chat/share.tsx b/projects/app/src/pages/chat/share.tsx index 551b4c2f7344..a6cedb853b96 100644 --- a/projects/app/src/pages/chat/share.tsx +++ b/projects/app/src/pages/chat/share.tsx @@ -292,7 +292,7 @@ const OutLink = ({ appName, appIntro, appAvatar }: Props) => { {showHead === '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'])) } }; } diff --git a/projects/app/src/pages/chat/team.tsx b/projects/app/src/pages/chat/team.tsx index 34f8e26b2637..3c5dba3c1bef 100644 --- a/projects/app/src/pages/chat/team.tsx +++ b/projects/app/src/pages/chat/team.tsx @@ -199,7 +199,6 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => { })( { flexDirection={'column'} > {/* header */} - + {/* chat box */} {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'])) } }; } diff --git a/projects/app/src/pages/login/index.tsx b/projects/app/src/pages/login/index.tsx index bcea81f598f9..c57dbddf5c0d 100644 --- a/projects/app/src/pages/login/index.tsx +++ b/projects/app/src/pages/login/index.tsx @@ -128,7 +128,7 @@ const Login = () => { export async function getServerSideProps(context: any) { return { - props: { ...(await serviceSideProps(context)) } + props: { ...(await serviceSideProps(context, ['app'])) } }; } diff --git a/projects/app/src/web/core/app/templates.ts b/projects/app/src/web/core/app/templates.ts index 5a48c60b645c..2a4df5796ac4 100644 --- a/projects/app/src/web/core/app/templates.ts +++ b/projects/app/src/web/core/app/templates.ts @@ -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', diff --git a/projects/sandbox/package.json b/projects/sandbox/package.json index e0a3818a8b03..c7181fc865bc 100644 --- a/projects/sandbox/package.json +++ b/projects/sandbox/package.json @@ -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" diff --git a/projects/sandbox/src/sandbox/jsFn/delay.ts b/projects/sandbox/src/sandbox/jsFn/delay.ts new file mode 100644 index 000000000000..67ceeee4b11a --- /dev/null +++ b/projects/sandbox/src/sandbox/jsFn/delay.ts @@ -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); + }); +}; diff --git a/projects/sandbox/src/sandbox/jsFn/tiktoken/index.ts b/projects/sandbox/src/sandbox/jsFn/tiktoken/index.ts new file mode 100644 index 000000000000..f28e15aac2a7 --- /dev/null +++ b/projects/sandbox/src/sandbox/jsFn/tiktoken/index.ts @@ -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; +}; diff --git a/projects/sandbox/src/sandbox/sandbox.controller.ts b/projects/sandbox/src/sandbox/sandbox.controller.ts index bd865b94361d..46517ffc74a1 100644 --- a/projects/sandbox/src/sandbox/sandbox.controller.ts +++ b/projects/sandbox/src/sandbox/sandbox.controller.ts @@ -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(WorkerNameEnum.runJs, codeProps); + return runSandbox(codeProps); } } diff --git a/projects/sandbox/src/sandbox/sandbox.service.ts b/projects/sandbox/src/sandbox/sandbox.service.ts index 13e5cbb747dc..d76ddbd309fb 100644 --- a/projects/sandbox/src/sandbox/sandbox.service.ts +++ b/projects/sandbox/src/sandbox/sandbox.service.ts @@ -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 {}; } } diff --git a/projects/sandbox/src/sandbox/utils.ts b/projects/sandbox/src/sandbox/utils.ts new file mode 100644 index 000000000000..9f067ea088ab --- /dev/null +++ b/projects/sandbox/src/sandbox/utils.ts @@ -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>) { + return Promise.all([ + // delay + jail.set('global_delay', new Reference(timeDelay)), + jail.set('countToken', countToken) + ]); +} + +export const runSandbox = async ({ + code, + variables = {} +}: RunCodeDto): Promise => { + 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); + } +}; diff --git a/projects/sandbox/src/worker/runJs.ts b/projects/sandbox/src/worker/runJs.ts deleted file mode 100644 index 0c0647b3b5e6..000000000000 --- a/projects/sandbox/src/worker/runJs.ts +++ /dev/null @@ -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(); -}); diff --git a/projects/sandbox/src/worker/utils.ts b/projects/sandbox/src/worker/utils.ts deleted file mode 100644 index 23887d63cb82..000000000000 --- a/projects/sandbox/src/worker/utils.ts +++ /dev/null @@ -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 = (name: WorkerNameEnum, params?: Record) => { - return new Promise((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); -};