From d2948d7e5770d74fe941c1ac0f33326b72dd8501 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Fri, 24 Jan 2025 23:42:04 +0800 Subject: [PATCH] feat: markdown extension (#3663) * feat: markdown extension * media cros * rerank test * default price * perf: default model * fix: cannot custom provider * fix: default model select * update bg * perf: default model selector * fix: usage export * i18n * fix: rerank * update init extension * perf: ip limit check * doubao model order * web default modle * perf: tts selector * perf: tts error * qrcode package --- .../zh-cn/docs/development/upgrading/4820.md | 5 +- .../common/middle/reqFrequencyLimit.ts | 17 +- packages/service/common/response/index.ts | 10 +- .../core/ai/config/provider/Doubao.json | 78 ++++----- .../core/ai/config/provider/MiniMax.json | 96 +++++------ .../core/ai/config/provider/OpenAI.json | 12 +- packages/service/core/ai/config/utils.ts | 25 ++- packages/service/core/ai/rerank/index.ts | 11 +- .../common/Input/NumberInput/index.tsx | 5 +- .../common/MySelect/MultipleRowSelect.tsx | 89 +++++----- packages/web/i18n/en/account.json | 1 + packages/web/i18n/en/app.json | 3 + packages/web/i18n/en/common.json | 6 +- packages/web/i18n/zh-CN/account.json | 1 + packages/web/i18n/zh-CN/app.json | 3 + packages/web/i18n/zh-CN/common.json | 2 - packages/web/i18n/zh-Hant/account.json | 1 + packages/web/i18n/zh-Hant/app.json | 3 + packages/web/i18n/zh-Hant/common.json | 2 - pnpm-lock.yaml | 162 +++++++++++++++++- projects/app/package.json | 2 + projects/app/public/js/qrcode.min.js | 1 - .../components/Markdown/codeBlock/Audio.tsx | 31 ++++ .../Markdown/{ => codeBlock}/CodeLight.tsx | 0 .../components/Markdown/codeBlock/Video.tsx | 31 ++++ .../Markdown/codeBlock/iframe-html.tsx | 2 +- .../app/src/components/Markdown/index.tsx | 10 +- projects/app/src/components/Markdown/utils.ts | 4 +- .../core/ai/AISettingModal/index.tsx | 6 +- .../core/ai/SettingLLMModel/index.tsx | 13 +- .../core/app/DatasetParamsModal.tsx | 4 +- .../app/src/components/core/app/TTSSelect.tsx | 84 ++++++--- .../components/core/app/WelcomeTextConfig.tsx | 2 +- .../support/wallet/QRCodePayModal.tsx | 72 ++++---- .../account/model/ModelConfigTable.tsx | 39 ++++- .../account/usage/UsageTable.tsx | 50 +++--- .../RenderInput/templates/SelectLLMModel.tsx | 10 +- .../pageComponents/dataset/detail/Test.tsx | 2 +- .../dataset/list/CreateModal.tsx | 3 +- .../app/src/pages/api/common/tracks/push.ts | 2 +- .../api/core/ai/model/getDefaultConfig.ts | 22 +++ .../app/src/pages/api/core/ai/model/test.ts | 3 +- .../pages/api/core/ai/model/updateDefault.ts | 5 +- .../src/pages/api/core/dataset/searchTest.ts | 2 +- .../support/user/account/loginByPassword.ts | 5 +- .../src/pages/api/v1/audio/transcriptions.ts | 5 +- projects/app/src/web/common/system/utils.ts | 13 +- projects/app/src/web/common/utils/voice.ts | 4 - projects/app/src/web/core/ai/config.ts | 3 + 49 files changed, 672 insertions(+), 290 deletions(-) delete mode 100644 projects/app/public/js/qrcode.min.js create mode 100644 projects/app/src/components/Markdown/codeBlock/Audio.tsx rename projects/app/src/components/Markdown/{ => codeBlock}/CodeLight.tsx (100%) create mode 100644 projects/app/src/components/Markdown/codeBlock/Video.tsx create mode 100644 projects/app/src/pages/api/core/ai/model/getDefaultConfig.ts diff --git a/docSite/content/zh-cn/docs/development/upgrading/4820.md b/docSite/content/zh-cn/docs/development/upgrading/4820.md index 0a2965e1a..5da394a42 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/4820.md +++ b/docSite/content/zh-cn/docs/development/upgrading/4820.md @@ -32,5 +32,6 @@ curl --location --request POST 'https://{{host}}/api/admin/initv4820' \ 1. 新增 - 可视化模型参数配置。预设超过 100 个模型配置。同时支持所有类型模型的一键测试。(预计下个版本会完全支持在页面上配置渠道)。 2. 新增 - 使用记录导出和仪表盘。 -3. 优化 - 页面组件抽离,减少页面组件路由。 -4. 优化 - 全文检索,忽略大小写。 \ No newline at end of file +3. 新增 - markdown 语法扩展,支持音视频(代码块 audio 和 video)。 +4. 优化 - 页面组件抽离,减少页面组件路由。 +5. 优化 - 全文检索,忽略大小写。 \ No newline at end of file diff --git a/packages/service/common/middle/reqFrequencyLimit.ts b/packages/service/common/middle/reqFrequencyLimit.ts index 1084f2b7c..6205c47c6 100644 --- a/packages/service/common/middle/reqFrequencyLimit.ts +++ b/packages/service/common/middle/reqFrequencyLimit.ts @@ -1,6 +1,5 @@ import { ApiRequestProps } from '../../type/next'; import requestIp from 'request-ip'; -import { ERROR_ENUM } from '@fastgpt/global/common/error/errorCode'; import { authFrequencyLimit } from '../system/frequencyLimit/utils'; import { addSeconds } from 'date-fns'; import { NextApiResponse } from 'next'; @@ -9,7 +8,17 @@ import { jsonRes } from '../response'; // unit: times/s // how to use? // export default NextAPI(useQPSLimit(10), handler); // limit 10 times per second for a ip -export function useIPFrequencyLimit(seconds: number, limit: number, force = false) { +export function useIPFrequencyLimit({ + id, + seconds, + limit, + force = false +}: { + id: string; + seconds: number; + limit: number; + force?: boolean; +}) { return async (req: ApiRequestProps, res: NextApiResponse) => { const ip = requestIp.getClientIp(req); if (!ip || (process.env.USE_IP_LIMIT !== 'true' && !force)) { @@ -17,14 +26,14 @@ export function useIPFrequencyLimit(seconds: number, limit: number, force = fals } try { await authFrequencyLimit({ - eventId: 'ip-qps-limit' + ip, + eventId: `ip-qps-limit-${id}-` + ip, maxAmount: limit, expiredTime: addSeconds(new Date(), seconds) }); } catch (_) { jsonRes(res, { code: 429, - error: ERROR_ENUM.tooManyRequest + error: `Too many request, request ${limit} times every ${seconds} seconds` }); } }; diff --git a/packages/service/common/response/index.ts b/packages/service/common/response/index.ts index a6de2e38a..e713433d9 100644 --- a/packages/service/common/response/index.ts +++ b/packages/service/common/response/index.ts @@ -33,7 +33,15 @@ export const jsonRes = ( addLog.error(`Api response error: ${url}`, ERROR_RESPONSE[errResponseKey]); - return res.status(code).json(ERROR_RESPONSE[errResponseKey]); + res.status(code); + + if (message) { + res.send(message); + } else { + res.json(ERROR_RESPONSE[errResponseKey]); + } + + return; } // another error diff --git a/packages/service/core/ai/config/provider/Doubao.json b/packages/service/core/ai/config/provider/Doubao.json index dfb2e22d8..64924b0e4 100644 --- a/packages/service/core/ai/config/provider/Doubao.json +++ b/packages/service/core/ai/config/provider/Doubao.json @@ -2,11 +2,11 @@ "provider": "Doubao", "list": [ { - "model": "Doubao-lite-128k", - "name": "Doubao-lite-128k", - "maxContext": 128000, + "model": "Doubao-lite-4k", + "name": "Doubao-lite-4k", + "maxContext": 4000, "maxResponse": 4000, - "quoteMaxToken": 120000, + "quoteMaxToken": 4000, "maxTemperature": 1, "vision": false, "toolChoice": true, @@ -46,11 +46,11 @@ "type": "llm" }, { - "model": "Doubao-lite-4k", - "name": "Doubao-lite-4k", - "maxContext": 4000, + "model": "Doubao-lite-128k", + "name": "Doubao-lite-128k", + "maxContext": 128000, "maxResponse": 4000, - "quoteMaxToken": 4000, + "quoteMaxToken": 120000, "maxTemperature": 1, "vision": false, "toolChoice": true, @@ -68,11 +68,33 @@ "type": "llm" }, { - "model": "Doubao-pro-128k", - "name": "Doubao-pro-128k", - "maxContext": 128000, + "model": "Doubao-vision-lite-32k", + "name": "Doubao-vision-lite-32k", + "maxContext": 32000, "maxResponse": 4000, - "quoteMaxToken": 120000, + "quoteMaxToken": 32000, + "maxTemperature": 1, + "vision": true, + "toolChoice": false, + "functionCall": false, + "defaultSystemChatPrompt": "", + "datasetProcess": true, + "usedInClassify": true, + "customCQPrompt": "", + "usedInExtractFields": true, + "usedInQueryExtension": true, + "customExtractPrompt": "", + "usedInToolCall": true, + "defaultConfig": {}, + "fieldMap": {}, + "type": "llm" + }, + { + "model": "Doubao-pro-4k", + "name": "Doubao-pro-4k", + "maxContext": 4000, + "maxResponse": 4000, + "quoteMaxToken": 4000, "maxTemperature": 1, "vision": false, "toolChoice": true, @@ -112,11 +134,11 @@ "type": "llm" }, { - "model": "Doubao-pro-4k", - "name": "Doubao-pro-4k", - "maxContext": 4000, + "model": "Doubao-pro-128k", + "name": "Doubao-pro-128k", + "maxContext": 128000, "maxResponse": 4000, - "quoteMaxToken": 4000, + "quoteMaxToken": 120000, "maxTemperature": 1, "vision": false, "toolChoice": true, @@ -133,28 +155,6 @@ "fieldMap": {}, "type": "llm" }, - { - "model": "Doubao-vision-lite-32k", - "name": "Doubao-vision-lite-32k", - "maxContext": 32000, - "maxResponse": 4000, - "quoteMaxToken": 32000, - "maxTemperature": 1, - "vision": true, - "toolChoice": false, - "functionCall": false, - "defaultSystemChatPrompt": "", - "datasetProcess": true, - "usedInClassify": true, - "customCQPrompt": "", - "usedInExtractFields": true, - "usedInQueryExtension": true, - "customExtractPrompt": "", - "usedInToolCall": true, - "defaultConfig": {}, - "fieldMap": {}, - "type": "llm" - }, { "model": "Doubao-vision-pro-32k", "name": "Doubao-vision-pro-32k", @@ -192,4 +192,4 @@ "type": "embedding" } ] -} \ No newline at end of file +} diff --git a/packages/service/core/ai/config/provider/MiniMax.json b/packages/service/core/ai/config/provider/MiniMax.json index f05f1504d..de0520088 100644 --- a/packages/service/core/ai/config/provider/MiniMax.json +++ b/packages/service/core/ai/config/provider/MiniMax.json @@ -47,194 +47,194 @@ }, { "model": "speech-01-turbo", - "name": "Minimax-speech-01-turbo", + "name": "speech-01-turbo", "voices": [ { - "label": "minimax-male-qn-qingse", + "label": "male-qn-qingse", "value": "male-qn-qingse" }, { - "label": "minimax-male-qn-jingying", + "label": "male-qn-jingying", "value": "male-qn-jingying" }, { - "label": "minimax-male-qn-badao", + "label": "male-qn-badao", "value": "male-qn-badao" }, { - "label": "minimax-male-qn-daxuesheng", + "label": "male-qn-daxuesheng", "value": "male-qn-daxuesheng" }, { - "label": "minimax-female-shaonv", + "label": "female-shaonv", "value": "female-shaonv" }, { - "label": "minimax-female-yujie", + "label": "female-yujie", "value": "female-yujie" }, { - "label": "minimax-female-chengshu", + "label": "female-chengshu", "value": "female-chengshu" }, { - "label": "minimax-female-tianmei", + "label": "female-tianmei", "value": "female-tianmei" }, { - "label": "minimax-presenter_male", + "label": "presenter_male", "value": "presenter_male" }, { - "label": "minimax-presenter_female", + "label": "presenter_female", "value": "presenter_female" }, { - "label": "minimax-audiobook_male_1", + "label": "audiobook_male_1", "value": "audiobook_male_1" }, { - "label": "minimax-audiobook_male_2", + "label": "audiobook_male_2", "value": "audiobook_male_2" }, { - "label": "minimax-audiobook_female_1", + "label": "audiobook_female_1", "value": "audiobook_female_1" }, { - "label": "minimax-audiobook_female_2", + "label": "audiobook_female_2", "value": "audiobook_female_2" }, { - "label": "minimax-male-qn-qingse-jingpin", + "label": "male-qn-qingse-jingpin", "value": "male-qn-qingse-jingpin" }, { - "label": "minimax-male-qn-jingying-jingpin", + "label": "male-qn-jingying-jingpin", "value": "male-qn-jingying-jingpin" }, { - "label": "minimax-male-qn-badao-jingpin", + "label": "male-qn-badao-jingpin", "value": "male-qn-badao-jingpin" }, { - "label": "minimax-male-qn-daxuesheng-jingpin", + "label": "male-qn-daxuesheng-jingpin", "value": "male-qn-daxuesheng-jingpin" }, { - "label": "minimax-female-shaonv-jingpin", + "label": "female-shaonv-jingpin", "value": "female-shaonv-jingpin" }, { - "label": "minimax-female-yujie-jingpin", + "label": "female-yujie-jingpin", "value": "female-yujie-jingpin" }, { - "label": "minimax-female-chengshu-jingpin", + "label": "female-chengshu-jingpin", "value": "female-chengshu-jingpin" }, { - "label": "minimax-female-tianmei-jingpin", + "label": "female-tianmei-jingpin", "value": "female-tianmei-jingpin" }, { - "label": "minimax-clever_boy", + "label": "clever_boy", "value": "clever_boy" }, { - "label": "minimax-cute_boy", + "label": "cute_boy", "value": "cute_boy" }, { - "label": "minimax-lovely_girl", + "label": "lovely_girl", "value": "lovely_girl" }, { - "label": "minimax-cartoon_pig", + "label": "cartoon_pig", "value": "cartoon_pig" }, { - "label": "minimax-bingjiao_didi", + "label": "bingjiao_didi", "value": "bingjiao_didi" }, { - "label": "minimax-junlang_nanyou", + "label": "junlang_nanyou", "value": "junlang_nanyou" }, { - "label": "minimax-chunzhen_xuedi", + "label": "chunzhen_xuedi", "value": "chunzhen_xuedi" }, { - "label": "minimax-lengdan_xiongzhang", + "label": "lengdan_xiongzhang", "value": "lengdan_xiongzhang" }, { - "label": "minimax-badao_shaoye", + "label": "badao_shaoye", "value": "badao_shaoye" }, { - "label": "minimax-tianxin_xiaoling", + "label": "tianxin_xiaoling", "value": "tianxin_xiaoling" }, { - "label": "minimax-qiaopi_mengmei", + "label": "qiaopi_mengmei", "value": "qiaopi_mengmei" }, { - "label": "minimax-wumei_yujie", + "label": "wumei_yujie", "value": "wumei_yujie" }, { - "label": "minimax-diadia_xuemei", + "label": "diadia_xuemei", "value": "diadia_xuemei" }, { - "label": "minimax-danya_xuejie", + "label": "danya_xuejie", "value": "danya_xuejie" }, { - "label": "minimax-Santa_Claus", + "label": "Santa_Claus", "value": "Santa_Claus" }, { - "label": "minimax-Grinch", + "label": "Grinch", "value": "Grinch" }, { - "label": "minimax-Rudolph", + "label": "Rudolph", "value": "Rudolph" }, { - "label": "minimax-Arnold", + "label": "Arnold", "value": "Arnold" }, { - "label": "minimax-Charming_Santa", + "label": "Charming_Santa", "value": "Charming_Santa" }, { - "label": "minimax-Charming_Lady", + "label": "Charming_Lady", "value": "Charming_Lady" }, { - "label": "minimax-Sweet_Girl", + "label": "Sweet_Girl", "value": "Sweet_Girl" }, { - "label": "minimax-Cute_Elf", + "label": "Cute_Elf", "value": "Cute_Elf" }, { - "label": "minimax-Attractive_Girl", + "label": "Attractive_Girl", "value": "Attractive_Girl" }, { - "label": "minimax-Serene_Woman", + "label": "Serene_Woman", "value": "Serene_Woman" } ], "type": "tts" } ] -} \ No newline at end of file +} diff --git a/packages/service/core/ai/config/provider/OpenAI.json b/packages/service/core/ai/config/provider/OpenAI.json index fd573c620..4bfcc461e 100644 --- a/packages/service/core/ai/config/provider/OpenAI.json +++ b/packages/service/core/ai/config/provider/OpenAI.json @@ -10,7 +10,7 @@ "maxTemperature": 1.2, "vision": true, "toolChoice": true, - "functionCall": false, + "functionCall": true, "defaultSystemChatPrompt": "", "datasetProcess": true, "usedInClassify": true, @@ -53,7 +53,7 @@ "maxTemperature": 1.2, "vision": false, "toolChoice": false, - "functionCall": false, + "functionCall": true, "defaultSystemChatPrompt": "", "datasetProcess": true, "usedInClassify": true, @@ -77,7 +77,7 @@ "maxTemperature": 1.2, "vision": false, "toolChoice": false, - "functionCall": false, + "functionCall": true, "defaultSystemChatPrompt": "", "datasetProcess": true, "usedInClassify": true, @@ -102,7 +102,7 @@ "maxTemperature": 1.2, "vision": false, "toolChoice": false, - "functionCall": false, + "functionCall": true, "defaultSystemChatPrompt": "", "datasetProcess": true, "usedInClassify": true, @@ -127,7 +127,7 @@ "maxTemperature": 1.2, "vision": false, "toolChoice": true, - "functionCall": false, + "functionCall": true, "defaultSystemChatPrompt": "", "datasetProcess": true, "usedInClassify": true, @@ -147,7 +147,7 @@ "maxTemperature": 1.2, "vision": true, "toolChoice": true, - "functionCall": false, + "functionCall": true, "defaultSystemChatPrompt": "", "datasetProcess": true, "usedInClassify": true, diff --git a/packages/service/core/ai/config/utils.ts b/packages/service/core/ai/config/utils.ts index 8e0397eaf..f6b997813 100644 --- a/packages/service/core/ai/config/utils.ts +++ b/packages/service/core/ai/config/utils.ts @@ -12,6 +12,7 @@ import { } from '@fastgpt/global/core/ai/model.d'; import { debounce } from 'lodash'; import { ModelProviderType } from '@fastgpt/global/core/ai/provider'; +import { findModelFromAlldata } from '../model'; /* TODO: 分优先级读取: @@ -95,7 +96,7 @@ export const loadSystemModels = async (init = false) => { const modelData: any = { ...fileModel, ...dbModel?.metadata, - provider: fileContent.provider, + provider: dbModel?.metadata?.provider || fileContent.provider, type: dbModel?.metadata?.type || fileModel.type, isCustom: false }; @@ -140,6 +141,28 @@ export const loadSystemModels = async (init = false) => { } }; +export const getSystemModelConfig = async (model: string): Promise => { + const modelData = findModelFromAlldata(model); + if (!modelData) return Promise.reject('Model is not found'); + if (modelData.isCustom) return Promise.reject('Custom model not data'); + + // Read file + const fileContent = (await import(`./provider/${modelData.provider}`))?.default as { + provider: ModelProviderType; + list: SystemModelItemType[]; + }; + + const config = fileContent.list.find((item) => item.model === model); + + if (!config) return Promise.reject('Model config is not found'); + + return { + ...config, + provider: modelData.provider, + isCustom: false + }; +}; + export const watchSystemModelUpdate = () => { const changeStream = MongoSystemModel.watch(); diff --git a/packages/service/core/ai/rerank/index.ts b/packages/service/core/ai/rerank/index.ts index d99cd26ad..9ad231d89 100644 --- a/packages/service/core/ai/rerank/index.ts +++ b/packages/service/core/ai/rerank/index.ts @@ -2,6 +2,7 @@ import { addLog } from '../../../common/system/log'; import { POST } from '../../../common/api/serverRequest'; import { getDefaultRerankModel } from '../model'; import { getAxiosConfig } from '../config'; +import { ReRankModelItemType } from '@fastgpt/global/core/ai/model.d'; type PostReRankResponse = { id: string; @@ -13,15 +14,15 @@ type PostReRankResponse = { type ReRankCallResult = { id: string; score?: number }[]; export function reRankRecall({ + model = getDefaultRerankModel(), query, documents }: { + model?: ReRankModelItemType; query: string; documents: { id: string; text: string }[]; }): Promise { - const model = getDefaultRerankModel(); - - if (!model || !model?.requestUrl) { + if (!model) { return Promise.reject('no rerank model'); } @@ -29,7 +30,7 @@ export function reRankRecall({ let start = Date.now(); return POST( - model.requestUrl ? model.requestUrl : `${baseUrl}/v1/rerank`, + model.requestUrl ? model.requestUrl : `${baseUrl}/rerank`, { model: model.model, query, @@ -57,6 +58,6 @@ export function reRankRecall({ .catch((err) => { addLog.error('rerank error', err); - return []; + return Promise.reject(err); }); } diff --git a/packages/web/components/common/Input/NumberInput/index.tsx b/packages/web/components/common/Input/NumberInput/index.tsx index 3e2a4564e..3f87817bd 100644 --- a/packages/web/components/common/Input/NumberInput/index.tsx +++ b/packages/web/components/common/Input/NumberInput/index.tsx @@ -26,11 +26,12 @@ const MyNumberInput = (props: Props) => { {...restProps} onChange={(e) => { if (!onChange) return; - if (e === '') { + const numE = Number(e); + if (isNaN(numE)) { // @ts-ignore onChange(''); } else { - onChange(Number(e)); + onChange(numE); } }} > diff --git a/packages/web/components/common/MySelect/MultipleRowSelect.tsx b/packages/web/components/common/MySelect/MultipleRowSelect.tsx index 52cf223b3..b8ef6270f 100644 --- a/packages/web/components/common/MySelect/MultipleRowSelect.tsx +++ b/packages/web/components/common/MySelect/MultipleRowSelect.tsx @@ -58,7 +58,6 @@ export const MultipleRowSelect = ({ const selectedValue = cloneValue[index]; const selectedIndex = list.findIndex((item) => item.value === selectedValue); const children = list[selectedIndex]?.children || []; - const hasChildren = list.some((item) => item.children && item.children?.length > 0); // Store current scroll position before update const currentScrollTop = MenuRef.current[index]?.scrollTop; @@ -84,54 +83,58 @@ export const MultipleRowSelect = ({ overflowY={'auto'} whiteSpace={'nowrap'} > - {list.map((item) => ( - { - if (item.value === selectedValue) { - SelectedItemRef.current[index] = ref; - } - }} - py={1.5} - _notLast={{ mb: 1 }} - cursor={'pointer'} - px={1.5} - borderRadius={'sm'} - _hover={{ - bg: 'primary.50' - }} - onClick={() => { - const newValue = [...cloneValue]; + {list.map((item) => { + const hasChildren = item.children && item.children.length > 0; - if (item.value === selectedValue) { - for (let i = index; i < newValue.length; i++) { - newValue[i] = undefined; + return ( + { + if (item.value === selectedValue) { + SelectedItemRef.current[index] = ref; } - setCloneValue(newValue); - onSelect(newValue); - } else { - newValue[index] = item.value; - setCloneValue(newValue); + }} + py={1.5} + _notLast={{ mb: 1 }} + cursor={'pointer'} + px={1.5} + borderRadius={'sm'} + _hover={{ + bg: 'primary.50' + }} + onClick={() => { + const newValue = [...cloneValue]; - if (changeOnEverySelect || !hasChildren) { + if (item.value === selectedValue) { + for (let i = index; i < newValue.length; i++) { + newValue[i] = undefined; + } + setCloneValue(newValue); onSelect(newValue); - } + } else { + newValue[index] = item.value; + setCloneValue(newValue); - if (!hasChildren) { - onClose(); + if (changeOnEverySelect || !hasChildren) { + onSelect(newValue); + } + + if (!hasChildren) { + onClose(); + } } - } - }} - {...(item.value === selectedValue - ? { - bg: 'primary.50', - color: 'primary.600' - } - : {})} - > - {item.label} - - ))} + }} + {...(item.value === selectedValue + ? { + bg: 'primary.50', + color: 'primary.600' + } + : {})} + > + {item.label} + + ); + })} {list.length === 0 && ( =12'} @@ -4767,6 +4779,10 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} @@ -4897,6 +4913,9 @@ packages: resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + dingbat-to-unicode@1.0.1: resolution: {integrity: sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==} @@ -7571,6 +7590,10 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -7701,6 +7724,11 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} + engines: {node: '>=10.13.0'} + hasBin: true + qs@6.11.0: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} @@ -8003,6 +8031,9 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + resize-observer-polyfill@1.5.1: resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} @@ -9160,6 +9191,9 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + which-typed-array@1.1.15: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} @@ -9231,6 +9265,9 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -9249,10 +9286,18 @@ packages: resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} engines: {node: '>= 14'} + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -10537,6 +10582,14 @@ snapshots: next: 14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) react: 18.3.1 + '@chakra-ui/next-js@2.1.5(@chakra-ui/react@2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1)': + dependencies: + '@chakra-ui/react': 2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@emotion/cache': 11.11.0 + '@emotion/react': 11.11.1(@types/react@18.3.1)(react@18.3.1) + next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) + react: 18.3.1 + '@chakra-ui/number-input@2.1.1(@chakra-ui/system@2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: '@chakra-ui/counter': 2.1.0(react@18.3.1) @@ -12623,6 +12676,10 @@ snapshots: '@types/prop-types@15.7.12': {} + '@types/qrcode@1.5.5': + dependencies: + '@types/node': 20.14.11 + '@types/qs@6.9.15': {} '@types/qs@6.9.16': {} @@ -13276,7 +13333,7 @@ snapshots: axios@1.7.7: dependencies: - follow-redirects: 1.15.9(debug@4.3.7) + follow-redirects: 1.15.9 form-data: 4.0.1 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -13674,6 +13731,12 @@ snapshots: client-only@0.0.1: {} + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -14125,6 +14188,8 @@ snapshots: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + decimal.js-light@2.5.1: {} decode-named-character-reference@1.0.2: @@ -14269,6 +14334,8 @@ snapshots: diff@5.2.0: {} + dijkstrajs@1.0.3: {} + dingbat-to-unicode@1.0.1: {} dir-glob@3.0.1: @@ -15070,6 +15137,8 @@ snapshots: follow-redirects@1.15.6: {} + follow-redirects@1.15.9: {} + follow-redirects@1.15.9(debug@4.3.4): optionalDependencies: debug: 4.3.4 @@ -17417,6 +17486,18 @@ snapshots: react: 18.3.1 react-i18next: 14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next-i18next@15.3.0(i18next@23.11.5)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): + dependencies: + '@babel/runtime': 7.24.8 + '@types/hoist-non-react-statics': 3.3.5 + core-js: 3.37.1 + hoist-non-react-statics: 3.3.2 + i18next: 23.11.5 + i18next-fs-backend: 2.3.1 + next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) + react: 18.3.1 + react-i18next: 14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next@14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8): dependencies: '@next/env': 14.2.5 @@ -17443,10 +17524,36 @@ snapshots: - '@babel/core' - babel-plugin-macros + next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8): + dependencies: + '@next/env': 14.2.5 + '@swc/helpers': 0.5.5 + busboy: 1.6.0 + caniuse-lite: 1.0.30001669 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + styled-jsx: 5.1.1(react@18.3.1) + optionalDependencies: + '@next/swc-darwin-arm64': 14.2.5 + '@next/swc-darwin-x64': 14.2.5 + '@next/swc-linux-arm64-gnu': 14.2.5 + '@next/swc-linux-arm64-musl': 14.2.5 + '@next/swc-linux-x64-gnu': 14.2.5 + '@next/swc-linux-x64-musl': 14.2.5 + '@next/swc-win32-arm64-msvc': 14.2.5 + '@next/swc-win32-ia32-msvc': 14.2.5 + '@next/swc-win32-x64-msvc': 14.2.5 + sass: 1.77.8 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + nextjs-cors@2.2.0(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)): dependencies: cors: 2.8.5 - next: 14.2.5(@babel/core@7.24.9)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) + next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) nextjs-node-loader@1.1.5(webpack@5.92.1): dependencies: @@ -17870,6 +17977,8 @@ snapshots: pluralize@8.0.0: {} + pngjs@5.0.0: {} + possible-typed-array-names@1.0.0: {} postcss@8.4.31: @@ -17998,6 +18107,12 @@ snapshots: pure-rand@6.1.0: {} + qrcode@1.5.4: + dependencies: + dijkstrajs: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + qs@6.11.0: dependencies: side-channel: 1.0.6 @@ -18417,6 +18532,8 @@ snapshots: require-from-string@2.0.2: {} + require-main-filename@2.0.0: {} + resize-observer-polyfill@1.5.1: {} resolve-cwd@3.0.0: @@ -18597,8 +18714,7 @@ snapshots: transitivePeerDependencies: - supports-color - set-blocking@2.0.0: - optional: true + set-blocking@2.0.0: {} set-cookie-parser@2.6.0: {} @@ -18883,6 +18999,11 @@ snapshots: '@babel/core': 7.24.9 babel-plugin-macros: 3.1.0 + styled-jsx@5.1.1(react@18.3.1): + dependencies: + client-only: 0.0.1 + react: 18.3.1 + stylis@4.2.0: {} stylis@4.3.2: {} @@ -19662,6 +19783,8 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.3 + which-module@2.0.1: {} + which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 @@ -19749,6 +19872,8 @@ snapshots: xtend@4.0.2: {} + y18n@4.0.3: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -19759,8 +19884,27 @@ snapshots: yaml@2.3.1: {} + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + yargs-parser@21.1.1: {} + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + yargs@17.7.2: dependencies: cliui: 8.0.1 diff --git a/projects/app/package.json b/projects/app/package.json index 217146eb3..0288929ab 100644 --- a/projects/app/package.json +++ b/projects/app/package.json @@ -51,6 +51,7 @@ "next-i18next": "15.3.0", "nextjs-node-loader": "^1.1.5", "nprogress": "^0.2.0", + "qrcode": "^1.5.4", "react": "18.3.1", "react-day-picker": "^8.7.1", "react-dom": "18.3.1", @@ -81,6 +82,7 @@ "@types/jsonwebtoken": "^9.0.3", "@types/lodash": "^4.14.191", "@types/node": "^20.14.2", + "@types/qrcode": "^1.5.5", "@types/react": "18.3.1", "@types/react-dom": "18.3.0", "@types/react-syntax-highlighter": "^15.5.6", diff --git a/projects/app/public/js/qrcode.min.js b/projects/app/public/js/qrcode.min.js deleted file mode 100644 index 993e88f39..000000000 --- a/projects/app/public/js/qrcode.min.js +++ /dev/null @@ -1 +0,0 @@ -var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j=0?p.get(q):0}}for(var r=0,m=0;mm;m++)for(var j=0;jm;m++)for(var j=0;j=0;)b^=f.G15<=0;)b^=f.G18<>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;cf;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=[''],h=0;d>h;h++){g.push("");for(var i=0;d>i;i++)g.push('');g.push("")}g.push("
"),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}(); \ No newline at end of file diff --git a/projects/app/src/components/Markdown/codeBlock/Audio.tsx b/projects/app/src/components/Markdown/codeBlock/Audio.tsx new file mode 100644 index 000000000..a1510bc4d --- /dev/null +++ b/projects/app/src/components/Markdown/codeBlock/Audio.tsx @@ -0,0 +1,31 @@ +import React, { useEffect } from 'react'; +import { Box } from '@chakra-ui/react'; +import { useMarkdownWidth } from '../hooks'; + +const AudioBlock = ({ code: audioUrl }: { code: string }) => { + const { width, Ref } = useMarkdownWidth(); + + useEffect(() => { + fetch(audioUrl?.trim(), { + mode: 'cors', + credentials: 'omit' + }) + .then((response) => response.blob()) + .then((blob) => { + const url = URL.createObjectURL(blob); + const audio = document.getElementById('player'); + audio?.setAttribute('src', url); + }) + .catch((err) => { + console.log(err); + }); + }, [audioUrl]); + + return ( + + + ); +}; + +export default AudioBlock; diff --git a/projects/app/src/components/Markdown/CodeLight.tsx b/projects/app/src/components/Markdown/codeBlock/CodeLight.tsx similarity index 100% rename from projects/app/src/components/Markdown/CodeLight.tsx rename to projects/app/src/components/Markdown/codeBlock/CodeLight.tsx diff --git a/projects/app/src/components/Markdown/codeBlock/Video.tsx b/projects/app/src/components/Markdown/codeBlock/Video.tsx new file mode 100644 index 000000000..459f5bcb3 --- /dev/null +++ b/projects/app/src/components/Markdown/codeBlock/Video.tsx @@ -0,0 +1,31 @@ +import React, { useEffect } from 'react'; +import { Box } from '@chakra-ui/react'; +import { useMarkdownWidth } from '../hooks'; + +const VideoBlock = ({ code: videoUrl }: { code: string }) => { + const { width, Ref } = useMarkdownWidth(); + + useEffect(() => { + fetch(videoUrl?.trim(), { + mode: 'cors', + credentials: 'omit' + }) + .then((response) => response.blob()) + .then((blob) => { + const url = URL.createObjectURL(blob); + const video = document.getElementById('player'); + video?.setAttribute('src', url); + }) + .catch((err) => { + console.log(err); + }); + }, [videoUrl]); + + return ( + + + ); +}; + +export default VideoBlock; diff --git a/projects/app/src/components/Markdown/codeBlock/iframe-html.tsx b/projects/app/src/components/Markdown/codeBlock/iframe-html.tsx index 4bf8d29e8..d8d81bbb4 100644 --- a/projects/app/src/components/Markdown/codeBlock/iframe-html.tsx +++ b/projects/app/src/components/Markdown/codeBlock/iframe-html.tsx @@ -16,7 +16,7 @@ import { useCopyData } from '@fastgpt/web/hooks/useCopyData'; import { useTranslation } from 'next-i18next'; import { useMarkdownWidth } from '../hooks'; import type { IconNameType } from '@fastgpt/web/components/common/Icon/type.d'; -import { codeLight } from '../CodeLight'; +import { codeLight } from './CodeLight'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; const StyledButton = ({ diff --git a/projects/app/src/components/Markdown/index.tsx b/projects/app/src/components/Markdown/index.tsx index 4e6dbeb31..f8ae9ecab 100644 --- a/projects/app/src/components/Markdown/index.tsx +++ b/projects/app/src/components/Markdown/index.tsx @@ -13,12 +13,14 @@ import dynamic from 'next/dynamic'; import { Box } from '@chakra-ui/react'; import { CodeClassNameEnum } from './utils'; -const CodeLight = dynamic(() => import('./CodeLight'), { ssr: false }); +const CodeLight = dynamic(() => import('./codeBlock/CodeLight'), { ssr: false }); const MermaidCodeBlock = dynamic(() => import('./img/MermaidCodeBlock'), { ssr: false }); const MdImage = dynamic(() => import('./img/Image'), { ssr: false }); const EChartsCodeBlock = dynamic(() => import('./img/EChartsCodeBlock'), { ssr: false }); const IframeCodeBlock = dynamic(() => import('./codeBlock/Iframe'), { ssr: false }); const IframeHtmlCodeBlock = dynamic(() => import('./codeBlock/iframe-html'), { ssr: false }); +const VideoBlock = dynamic(() => import('./codeBlock/Video'), { ssr: false }); +const AudioBlock = dynamic(() => import('./codeBlock/Audio'), { ssr: false }); const ChatGuide = dynamic(() => import('./chat/Guide'), { ssr: false }); const QuestionGuide = dynamic(() => import('./chat/QuestionGuide'), { ssr: false }); @@ -139,6 +141,12 @@ function Code(e: any) { ); } + if (codeType === CodeClassNameEnum.video) { + return ; + } + if (codeType === CodeClassNameEnum.audio) { + return ; + } return ( diff --git a/projects/app/src/components/Markdown/utils.ts b/projects/app/src/components/Markdown/utils.ts index 50204eb43..00992836f 100644 --- a/projects/app/src/components/Markdown/utils.ts +++ b/projects/app/src/components/Markdown/utils.ts @@ -7,7 +7,9 @@ export enum CodeClassNameEnum { files = 'files', latex = 'latex', iframe = 'iframe', - html = 'html' + html = 'html', + video = 'video', + audio = 'audio' } function htmlTableToLatex(html: string) { diff --git a/projects/app/src/components/core/ai/AISettingModal/index.tsx b/projects/app/src/components/core/ai/AISettingModal/index.tsx index 9f4c5ee58..65e385419 100644 --- a/projects/app/src/components/core/ai/AISettingModal/index.tsx +++ b/projects/app/src/components/core/ai/AISettingModal/index.tsx @@ -80,7 +80,9 @@ const AIChatSettingsModal = ({ const temperature = watch('temperature'); const useVision = watch('aiChatVision'); - const selectedModel = getWebLLMModel(model); + const selectedModel = useMemo(() => { + return getWebLLMModel(model); + }, [model]); const llmSupportVision = !!selectedModel?.vision; const tokenLimit = useMemo(() => { @@ -244,7 +246,7 @@ const AIChatSettingsModal = ({ { const { t } = useTranslation(); - const { llmModelList, defaultModels } = useSystemStore(); + const { llmModelList } = useSystemStore(); const model = defaultData.model; @@ -39,16 +39,19 @@ const SettingLLMModel = ({ }), [llmModelList, llmModelType] ); + const defaultModel = useMemo(() => { + return getWebDefaultModel(modelList).model; + }, [modelList]); // Set default model useEffect(() => { - if (!llmModelList.find((item) => item.model === model) && !!defaultModels.llm) { + if (!modelList.find((item) => item.model === model) && !!defaultModel) { onChange({ ...defaultData, - model: defaultModels.llm.model + model: defaultModel }); } - }, [model, defaultData, llmModelList, defaultModels.llm, onChange]); + }, [modelList, model, defaultModel, onChange]); const { isOpen: isOpenAIChatSetting, diff --git a/projects/app/src/components/core/app/DatasetParamsModal.tsx b/projects/app/src/components/core/app/DatasetParamsModal.tsx index f35f3368f..6bb846044 100644 --- a/projects/app/src/components/core/app/DatasetParamsModal.tsx +++ b/projects/app/src/components/core/app/DatasetParamsModal.tsx @@ -65,7 +65,7 @@ const DatasetParamsModal = ({ const theme = useTheme(); const { toast } = useToast(); const { teamPlanStatus } = useUserStore(); - const { reRankModelList, llmModelList } = useSystemStore(); + const { reRankModelList, llmModelList, defaultModels } = useSystemStore(); const [refresh, setRefresh] = useState(false); const [currentTabType, setCurrentTabType] = useState(SearchSettingTabEnum.searchMode); @@ -82,7 +82,7 @@ const DatasetParamsModal = ({ searchMode, usingReRank: !!usingReRank && teamPlanStatus?.standardConstants?.permissionReRank !== false, datasetSearchUsingExtensionQuery, - datasetSearchExtensionModel: datasetSearchExtensionModel || chatModelSelectList[0]?.value, + datasetSearchExtensionModel: datasetSearchExtensionModel || defaultModels.llm?.model, datasetSearchExtensionBg } }); diff --git a/projects/app/src/components/core/app/TTSSelect.tsx b/projects/app/src/components/core/app/TTSSelect.tsx index 6c2a12428..ff8650a17 100644 --- a/projects/app/src/components/core/app/TTSSelect.tsx +++ b/projects/app/src/components/core/app/TTSSelect.tsx @@ -1,6 +1,6 @@ import MyIcon from '@fastgpt/web/components/common/Icon'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; -import { Box, Button, Flex, ModalBody, useDisclosure, Image } from '@chakra-ui/react'; +import { Box, Button, Flex, ModalBody, useDisclosure, Image, HStack } from '@chakra-ui/react'; import React, { useCallback, useMemo } from 'react'; import { useTranslation } from 'next-i18next'; import { TTSTypeEnum } from '@/web/core/app/constants'; @@ -9,13 +9,15 @@ import { useAudioPlay } from '@/web/common/utils/voice'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import MyModal from '@fastgpt/web/components/common/MyModal'; import MySlider from '@/components/Slider'; -import MySelect from '@fastgpt/web/components/common/MySelect'; import { defaultTTSConfig } from '@fastgpt/global/core/app/constants'; import ChatFunctionTip from './Tip'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; import MyImage from '@fastgpt/web/components/common/Image/MyImage'; import { useContextSelector } from 'use-context-selector'; import { AppContext } from '@/pageComponents/app/detail/context'; +import Avatar from '@fastgpt/web/components/common/Avatar'; +import { getModelProvider } from '@fastgpt/global/core/ai/provider'; +import MultipleRowSelect from '@fastgpt/web/components/common/MySelect/MultipleRowSelect'; const TTSSelect = ({ value = defaultTTSConfig, @@ -30,28 +32,57 @@ const TTSSelect = ({ const appId = useContextSelector(AppContext, (v) => v.appId); - const list = useMemo( + const selectorList = useMemo( () => [ - { label: t('common:core.app.tts.Close'), value: TTSTypeEnum.none }, - { label: t('common:core.app.tts.Web'), value: TTSTypeEnum.web }, - ...ttsModelList.map((item) => item?.voices || []).flat() + { label: t('app:tts_close'), value: TTSTypeEnum.none, children: [] }, + { label: t('app:tts_browser'), value: TTSTypeEnum.web, children: [] }, + ...ttsModelList.map((model) => { + const providerData = getModelProvider(model.provider); + return { + label: ( + + + {t(providerData.name)} + + ), + value: model.model, + children: model.voices.map((voice) => ({ + label: voice.label, + value: voice.value + })) + }; + }) ], [ttsModelList, t] ); const formatValue = useMemo(() => { if (!value || !value.type) { - return TTSTypeEnum.none; + return [TTSTypeEnum.none, undefined]; } if (value.type === TTSTypeEnum.none || value.type === TTSTypeEnum.web) { - return value.type; + return [value.type, undefined]; } - return value.voice; + + return [value.model, value.voice]; }, [value]); - const formLabel = useMemo( - () => list.find((item) => item.value === formatValue)?.label || t('common:common.UnKnow'), - [formatValue, list, t] - ); + const formLabel = useMemo(() => { + const provider = selectorList.find((item) => item.value === formatValue[0]) || selectorList[0]; + const voice = provider.children.find((item) => item.value === formatValue[1]); + return ( + + {voice ? ( + + {provider.label} + - + {voice.label} + + ) : ( + provider.label + )} + + ); + }, [formatValue, selectorList, t]); const { playAudioByText, cancelAudio, audioLoading, audioPlaying } = useAudioPlay({ appId, @@ -59,21 +90,16 @@ const TTSSelect = ({ }); const onclickChange = useCallback( - (e: string) => { - if (e === TTSTypeEnum.none || e === TTSTypeEnum.web) { - onChange({ type: e as `${TTSTypeEnum}` }); + (e: string[]) => { + console.log(e, '-='); + if (e[0] === TTSTypeEnum.none || e[0] === TTSTypeEnum.web) { + onChange({ type: e[0] }); } else { - const audioModel = ttsModelList.find((item) => - item.voices?.find((voice) => voice.value === e) - ); - if (!audioModel) { - return; - } onChange({ ...value, type: TTSTypeEnum.model, - model: audioModel.model, - voice: e + model: e[0], + voice: e[1] }); } }, @@ -113,7 +139,13 @@ const TTSSelect = ({ {t('common:core.app.tts.Speech model')} - + {t('common:core.app.tts.Speech speed')} @@ -135,7 +167,7 @@ const TTSSelect = ({ }} /> - {formatValue !== TTSTypeEnum.none && ( + {formatValue[0] !== TTSTypeEnum.none && ( {audioPlaying ? ( diff --git a/projects/app/src/components/core/app/WelcomeTextConfig.tsx b/projects/app/src/components/core/app/WelcomeTextConfig.tsx index 67a3139ff..b1dfc4f47 100644 --- a/projects/app/src/components/core/app/WelcomeTextConfig.tsx +++ b/projects/app/src/components/core/app/WelcomeTextConfig.tsx @@ -25,7 +25,7 @@ const WelcomeTextConfig = (props: TextareaProps) => { mt={1.5} rows={6} fontSize={'sm'} - bg={'white'} + bg={'myGray.50'} minW={'384px'} placeholder={t('common:core.app.tip.welcomeTextTip')} autoHeight diff --git a/projects/app/src/components/support/wallet/QRCodePayModal.tsx b/projects/app/src/components/support/wallet/QRCodePayModal.tsx index 6b3fe5bd5..c2db2fd8e 100644 --- a/projects/app/src/components/support/wallet/QRCodePayModal.tsx +++ b/projects/app/src/components/support/wallet/QRCodePayModal.tsx @@ -1,14 +1,12 @@ import MyModal from '@fastgpt/web/components/common/MyModal'; -import React, { useCallback, useEffect, useRef } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'next-i18next'; import { Box, ModalBody } from '@chakra-ui/react'; import { checkBalancePayResult } from '@/web/support/wallet/bill/api'; import { useToast } from '@fastgpt/web/hooks/useToast'; -import { useRouter } from 'next/router'; import { getErrText } from '@fastgpt/global/common/error/utils'; import LightTip from '@fastgpt/web/components/common/LightTip'; -import Script from 'next/script'; -import { getWebReqUrl } from '@fastgpt/web/common/system/utils'; +import QRCode from 'qrcode'; export type QRPayProps = { readPrice: number; @@ -27,21 +25,35 @@ const QRCodePayModal = ({ }: QRPayProps & { tip?: string; onSuccess?: () => any }) => { const { t } = useTranslation(); const { toast } = useToast(); - const dom = useRef(null); + const canvasRef = useRef(null); const drawCode = useCallback(() => { - if (dom.current && window.QRCode && !dom.current.innerHTML) { - new window.QRCode(dom.current, { - text: codeUrl, - width: qrCodeSize, - height: qrCodeSize, - colorDark: '#000000', - colorLight: '#ffffff', - correctLevel: window.QRCode.CorrectLevel.H + const canvas = document.createElement('canvas'); + QRCode.toCanvas(canvas, codeUrl, { + width: qrCodeSize, + margin: 0, + color: { + dark: '#000000', + light: '#ffffff' + } + }) + .then(() => { + if (canvasRef.current) { + canvasRef.current.innerHTML = ''; + canvasRef.current.appendChild(canvas); + } else { + drawCode(); + } + }) + .catch((err) => { + console.error('QRCode generation error:', err); }); - } }, [codeUrl]); + useEffect(() => { + drawCode(); + }, [drawCode]); + useEffect(() => { let timer: NodeJS.Timeout; const check = async () => { @@ -54,7 +66,7 @@ const QRCodePayModal = ({ title: res, status: 'success' }); - return; + return clearTimeout(timer); } catch (error) { toast({ title: getErrText(error), @@ -63,9 +75,7 @@ const QRCodePayModal = ({ } } } catch (error) {} - - drawCode(); - + clearTimeout(timer); timer = setTimeout(check, 2000); }; @@ -75,23 +85,15 @@ const QRCodePayModal = ({ }, [billId, drawCode, onSuccess, toast]); return ( - <> - - - - - {tip && } - - - {t('common:pay.wechat', { price: readPrice })} - - - - + + + {tip && } + + + {t('common:pay.wechat', { price: readPrice })} + + + ); }; diff --git a/projects/app/src/pageComponents/account/model/ModelConfigTable.tsx b/projects/app/src/pageComponents/account/model/ModelConfigTable.tsx index 1ea52498c..980b2146d 100644 --- a/projects/app/src/pageComponents/account/model/ModelConfigTable.tsx +++ b/projects/app/src/pageComponents/account/model/ModelConfigTable.tsx @@ -33,6 +33,7 @@ import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { deleteSystemModel, getModelConfigJson, + getSystemModelDefaultConfig, getSystemModelDetail, getSystemModelList, getTestModel, @@ -56,6 +57,7 @@ import { putUpdateWithJson } from '@/web/core/ai/config'; import CopyBox from '@fastgpt/web/components/common/String/CopyBox'; import MyIcon from '@fastgpt/web/components/common/Icon'; import AIModelSelector from '@/components/Select/AIModelSelector'; +import { useRefresh } from '../../../../../../packages/web/hooks/useRefresh'; const MyModal = dynamic(() => import('@fastgpt/web/components/common/MyModal')); @@ -173,7 +175,7 @@ const ModelTable = ({ Tab }: { Tab: React.ReactNode }) => { priceLabel: ( - {item.charsPointsPrice} + {item.charsPointsPrice || 0} {` ${t('common:support.wallet.subscription.point')} / 60${t('common:unit.seconds')}`} @@ -526,9 +528,10 @@ const ModelEditModal = ({ const { t } = useTranslation(); const { feConfigs } = useSystemStore(); - const { register, getValues, setValue, handleSubmit, watch } = useForm({ - defaultValues: modelData - }); + const { register, getValues, setValue, handleSubmit, watch, reset } = + useForm({ + defaultValues: modelData + }); const isCustom = !!modelData.isCustom; const isLLMModel = modelData?.type === ModelTypeEnum.llm; @@ -575,6 +578,22 @@ const ModelEditModal = ({ } ); + const [key, setKey] = useState(0); + const { runAsync: loadDefaultConfig, loading: loadingDefaultConfig } = useRequest2( + getSystemModelDefaultConfig, + { + onSuccess(res) { + reset({ + ...getValues(), + ...res + }); + setTimeout(() => { + setKey((prev) => prev + 1); + }, 0); + } + } + ); + return ( - + @@ -1007,6 +1026,16 @@ const ModelEditModal = ({ + {!modelData.isCustom && ( + + )} diff --git a/projects/app/src/pageComponents/account/usage/UsageTable.tsx b/projects/app/src/pageComponents/account/usage/UsageTable.tsx index ed550d5d1..ccb4bf0b9 100644 --- a/projects/app/src/pageComponents/account/usage/UsageTable.tsx +++ b/projects/app/src/pageComponents/account/usage/UsageTable.tsx @@ -44,33 +44,10 @@ const UsageTableList = ({ const { dateRange, selectTmbIds, isSelectAllTmb, usageSources, isSelectAllSource, projectName } = filterParams; const requestParams = useMemo(() => { - const appNameMap = { - ['core.app.Question Guide']: t('common:core.app.Question Guide'), - ['common:support.wallet.usage.Audio Speech']: t('common:support.wallet.usage.Audio Speech'), - ['support.wallet.usage.Whisper']: t('common:support.wallet.usage.Whisper'), - ['support.wallet.moduleName.index']: t('common:support.wallet.moduleName.index'), - ['support.wallet.moduleName.qa']: t('common:support.wallet.moduleName.qa'), - ['core.dataset.training.Auto mode']: t('common:core.dataset.training.Auto mode'), - ['common:core.module.template.ai_chat']: t('common:core.module.template.ai_chat') - }; - - const sourcesMap = Object.fromEntries( - Object.entries(UsageSourceMap).map(([key, config]) => [ - key, - { - label: t(config.label as any) - } - ]) - ); - const title = t('account_usage:export_title'); - return { dateStart: dateRange.from || new Date(), dateEnd: addDays(dateRange.to || new Date(), 1), sources: isSelectAllSource ? undefined : usageSources, - sourcesMap, - appNameMap, - title, teamMemberIds: isSelectAllTmb ? undefined : selectTmbIds, projectName }; @@ -81,8 +58,7 @@ const UsageTableList = ({ isSelectAllTmb, projectName, selectTmbIds, - usageSources, - t + usageSources ]); const { @@ -103,7 +79,29 @@ const UsageTableList = ({ await downloadFetch({ url: `/api/proApi/support/wallet/usage/exportUsage`, filename: `usage.csv`, - body: requestParams + body: { + ...requestParams, + appNameMap: { + ['core.app.Question Guide']: t('common:core.app.Question Guide'), + ['common:support.wallet.usage.Audio Speech']: t( + 'common:support.wallet.usage.Audio Speech' + ), + ['support.wallet.usage.Whisper']: t('common:support.wallet.usage.Whisper'), + ['support.wallet.moduleName.index']: t('common:support.wallet.moduleName.index'), + ['support.wallet.moduleName.qa']: t('common:support.wallet.moduleName.qa'), + ['core.dataset.training.Auto mode']: t('common:core.dataset.training.Auto mode'), + ['common:core.module.template.ai_chat']: t('common:core.module.template.ai_chat') + }, + sourcesMap: Object.fromEntries( + Object.entries(UsageSourceMap).map(([key, config]) => [ + key, + { + label: t(config.label as any) + } + ]) + ), + title: t('account_usage:export_title') + } }); }, { diff --git a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectLLMModel.tsx b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectLLMModel.tsx index 870e57e5c..470b71faa 100644 --- a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectLLMModel.tsx +++ b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectLLMModel.tsx @@ -5,6 +5,7 @@ import { llmModelTypeFilterMap } from '@fastgpt/global/core/ai/constants'; import AIModelSelector from '@/components/Select/AIModelSelector'; import { useContextSelector } from 'use-context-selector'; import { WorkflowContext } from '@/pageComponents/app/detail/WorkflowComponents/context'; +import { getWebDefaultModel } from '@/web/common/system/utils'; const SelectAiModelRender = ({ item, nodeId }: RenderInputProps) => { const { llmModelList } = useSystemStore(); @@ -21,6 +22,9 @@ const SelectAiModelRender = ({ item, nodeId }: RenderInputProps) => { }), [llmModelList, item.llmModelType] ); + const defaultModel = useMemo(() => { + return getWebDefaultModel(modelList).model; + }, [modelList]); const onChangeModel = useCallback( (e: string) => { @@ -38,10 +42,10 @@ const SelectAiModelRender = ({ item, nodeId }: RenderInputProps) => { ); useEffect(() => { - if (!item.value && modelList.length > 0) { - onChangeModel(modelList[0].model); + if (!modelList.find((model) => model.model === item.value) && !!defaultModel) { + onChangeModel(defaultModel); } - }, []); + }, [defaultModel, item.value, modelList, onChangeModel]); const Render = useMemo(() => { return ( diff --git a/projects/app/src/pageComponents/dataset/detail/Test.tsx b/projects/app/src/pageComponents/dataset/detail/Test.tsx index 8d1c0529c..8a119afcd 100644 --- a/projects/app/src/pageComponents/dataset/detail/Test.tsx +++ b/projects/app/src/pageComponents/dataset/detail/Test.tsx @@ -69,7 +69,7 @@ const Test = ({ datasetId }: { datasetId: string }) => { usingReRank: false, limit: 5000, similarity: 0, - datasetSearchUsingExtensionQuery: true, + datasetSearchUsingExtensionQuery: false, datasetSearchExtensionModel: defaultModels.llm?.model, datasetSearchExtensionBg: '' } diff --git a/projects/app/src/pageComponents/dataset/list/CreateModal.tsx b/projects/app/src/pageComponents/dataset/list/CreateModal.tsx index e1145ab73..debf45fd5 100644 --- a/projects/app/src/pageComponents/dataset/list/CreateModal.tsx +++ b/projects/app/src/pageComponents/dataset/list/CreateModal.tsx @@ -21,6 +21,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon'; import { getDocPath } from '@/web/common/system/doc'; import { datasetTypeCourseMap } from '@/web/core/dataset/constants'; import ApiDatasetForm from '../ApiDatasetForm'; +import { getWebDefaultModel } from '@/web/common/system/utils'; export type CreateDatasetType = | DatasetTypeEnum.dataset @@ -79,7 +80,7 @@ const CreateModal = ({ name: '', intro: '', vectorModel: defaultModels.embedding?.model, - agentModel: defaultModels.llm?.model + agentModel: getWebDefaultModel(datasetModelList)?.model } }); const { register, setValue, handleSubmit, watch } = form; diff --git a/projects/app/src/pages/api/common/tracks/push.ts b/projects/app/src/pages/api/common/tracks/push.ts index daf63ea51..b64d8c003 100644 --- a/projects/app/src/pages/api/common/tracks/push.ts +++ b/projects/app/src/pages/api/common/tracks/push.ts @@ -38,7 +38,7 @@ async function handler( return TrackModel.create(data); } -export default NextAPI(useIPFrequencyLimit(1, 5), handler); +export default NextAPI(useIPFrequencyLimit({ id: 'push-tracks', seconds: 1, limit: 5 }), handler); export const config = { api: { diff --git a/projects/app/src/pages/api/core/ai/model/getDefaultConfig.ts b/projects/app/src/pages/api/core/ai/model/getDefaultConfig.ts new file mode 100644 index 000000000..5d24830af --- /dev/null +++ b/projects/app/src/pages/api/core/ai/model/getDefaultConfig.ts @@ -0,0 +1,22 @@ +import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next'; +import { NextAPI } from '@/service/middleware/entry'; +import { authSystemAdmin } from '@fastgpt/service/support/permission/user/auth'; +import { getSystemModelConfig } from '@fastgpt/service/core/ai/config/utils'; +import { SystemModelItemType } from '@fastgpt/service/core/ai/type'; + +export type getDefaultQuery = { model: string }; + +export type getDefaultBody = {}; + +async function handler( + req: ApiRequestProps, + res: ApiResponseType +): Promise { + await authSystemAdmin({ req }); + + const model = req.query.model; + + return getSystemModelConfig(model); +} + +export default NextAPI(handler); diff --git a/projects/app/src/pages/api/core/ai/model/test.ts b/projects/app/src/pages/api/core/ai/model/test.ts index 9895ac971..3900dcd2c 100644 --- a/projects/app/src/pages/api/core/ai/model/test.ts +++ b/projects/app/src/pages/api/core/ai/model/test.ts @@ -1,7 +1,7 @@ import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next'; import { NextAPI } from '@/service/middleware/entry'; import { authSystemAdmin } from '@fastgpt/service/support/permission/user/auth'; -import { findModelFromAlldata } from '@fastgpt/service/core/ai/model'; +import { findModelFromAlldata, getReRankModel } from '@fastgpt/service/core/ai/model'; import { EmbeddingModelItemType, LLMModelItemType, @@ -120,6 +120,7 @@ const testSTTModel = async (model: STTModelType) => { const testReRankModel = async (model: ReRankModelItemType) => { await reRankRecall({ + model, query: 'Hi', documents: [{ id: '1', text: 'Hi' }] }); diff --git a/projects/app/src/pages/api/core/ai/model/updateDefault.ts b/projects/app/src/pages/api/core/ai/model/updateDefault.ts index 00cdc33d2..cc34dafc2 100644 --- a/projects/app/src/pages/api/core/ai/model/updateDefault.ts +++ b/projects/app/src/pages/api/core/ai/model/updateDefault.ts @@ -5,6 +5,7 @@ import { MongoSystemModel } from '@fastgpt/service/core/ai/config/schema'; import { loadSystemModels } from '@fastgpt/service/core/ai/config/utils'; import { updateFastGPTConfigBuffer } from '@fastgpt/service/common/system/config/controller'; import { ModelTypeEnum } from '@fastgpt/global/core/ai/model'; +import { authSystemAdmin } from '@fastgpt/service/support/permission/user/auth'; export type updateDefaultQuery = {}; @@ -22,10 +23,12 @@ async function handler( req: ApiRequestProps, res: ApiResponseType ): Promise { + await authSystemAdmin({ req }); + const { llm, embedding, tts, stt, rerank } = req.body; await mongoSessionRun(async (session) => { - await MongoSystemModel.updateMany({}, { $set: { 'metadata.isDefault': false } }, { session }); + await MongoSystemModel.updateMany({}, { $unset: { 'metadata.isDefault': 1 } }, { session }); if (llm) { await MongoSystemModel.updateOne( diff --git a/projects/app/src/pages/api/core/dataset/searchTest.ts b/projects/app/src/pages/api/core/dataset/searchTest.ts index 0bb4260f9..d09666de0 100644 --- a/projects/app/src/pages/api/core/dataset/searchTest.ts +++ b/projects/app/src/pages/api/core/dataset/searchTest.ts @@ -100,4 +100,4 @@ async function handler(req: NextApiRequest) { }; } -export default NextAPI(useIPFrequencyLimit(1, 15), handler); +export default NextAPI(useIPFrequencyLimit({ id: 'search-test', seconds: 1, limit: 15 }), handler); diff --git a/projects/app/src/pages/api/support/user/account/loginByPassword.ts b/projects/app/src/pages/api/support/user/account/loginByPassword.ts index ffb5a1417..8c37ce0d2 100644 --- a/projects/app/src/pages/api/support/user/account/loginByPassword.ts +++ b/projects/app/src/pages/api/support/user/account/loginByPassword.ts @@ -70,4 +70,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { }; } -export default NextAPI(useIPFrequencyLimit(120, 10, true), handler); +export default NextAPI( + useIPFrequencyLimit({ id: 'login-by-password', seconds: 120, limit: 10, force: true }), + handler +); diff --git a/projects/app/src/pages/api/v1/audio/transcriptions.ts b/projects/app/src/pages/api/v1/audio/transcriptions.ts index 837d33ff4..5f8581595 100644 --- a/projects/app/src/pages/api/v1/audio/transcriptions.ts +++ b/projects/app/src/pages/api/v1/audio/transcriptions.ts @@ -90,7 +90,10 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { removeFilesByPaths(filePaths); } -export default NextAPI(useIPFrequencyLimit(1, 1), handler); +export default NextAPI( + useIPFrequencyLimit({ id: 'transcriptions', seconds: 1, limit: 1 }), + handler +); export const config = { api: { diff --git a/projects/app/src/web/common/system/utils.ts b/projects/app/src/web/common/system/utils.ts index 8f6e4484f..2c3f9f156 100644 --- a/projects/app/src/web/common/system/utils.ts +++ b/projects/app/src/web/common/system/utils.ts @@ -1,3 +1,4 @@ +import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d'; import { useSystemStore } from './useSystemStore'; export const downloadFetch = async ({ @@ -43,5 +44,15 @@ export const downloadFetch = async ({ export const getWebLLMModel = (model?: string) => { const list = useSystemStore.getState().llmModelList; - return list.find((item) => item.model === model || item.name === model) ?? list[0]; + const defaultModels = useSystemStore.getState().defaultModels; + + return list.find((item) => item.model === model || item.name === model) ?? defaultModels.llm!; +}; +export const getWebDefaultModel = (llmList: LLMModelItemType[] = []) => { + const list = llmList.length > 0 ? llmList : useSystemStore.getState().llmModelList; + const defaultModels = useSystemStore.getState().defaultModels; + + return defaultModels.llm && list.find((item) => item.model === defaultModels.llm?.model) + ? defaultModels.llm + : list[0]; }; diff --git a/projects/app/src/web/common/utils/voice.ts b/projects/app/src/web/common/utils/voice.ts index 9b06e2bcc..d912dba87 100644 --- a/projects/app/src/web/common/utils/voice.ts +++ b/projects/app/src/web/common/utils/voice.ts @@ -69,10 +69,6 @@ export const useAudioPlay = ( if (!response.body || !response.ok) { const data = await response.json(); - toast({ - status: 'error', - title: getErrText(data, t('common:core.chat.Audio Speech Error')) - }); return Promise.reject(data); } return response.body; diff --git a/projects/app/src/web/core/ai/config.ts b/projects/app/src/web/core/ai/config.ts index fa192701d..a8d330bd1 100644 --- a/projects/app/src/web/core/ai/config.ts +++ b/projects/app/src/web/core/ai/config.ts @@ -10,6 +10,9 @@ export const getSystemModelList = () => GET('/core/ai/model/list') export const getSystemModelDetail = (model: string) => GET('/core/ai/model/detail', { model }); +export const getSystemModelDefaultConfig = (model: string) => + GET('/core/ai/model/getDefaultConfig', { model }); + export const putSystemModel = (data: updateBody) => PUT('/core/ai/model/update', data); export const deleteSystemModel = (data: deleteQuery) => DELETE('/core/ai/model/delete', data);