From 9cd6d2e81fc19aad3fa3f8c0c0e4637aa8c15787 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Mon, 21 Apr 2025 14:44:34 +0800 Subject: [PATCH] perf: init model (#4610) * fix: model config undefined value * perf: init model --- .../zh-cn/docs/development/upgrading/497.md | 2 +- packages/service/common/system/log.ts | 6 ++ packages/service/core/ai/config.ts | 5 +- packages/service/core/ai/config/utils.ts | 100 +++++++++--------- packages/service/core/ai/model.ts | 3 +- .../common/Input/NumberInput/index.tsx | 9 +- packages/web/i18n/en/account_model.json | 2 +- packages/web/i18n/zh-CN/account_model.json | 2 +- packages/web/i18n/zh-Hant/account_model.json | 2 +- .../account/model/AddModelBox.tsx | 8 +- .../app/src/pages/api/core/ai/model/test.ts | 1 + 11 files changed, 80 insertions(+), 60 deletions(-) diff --git a/docSite/content/zh-cn/docs/development/upgrading/497.md b/docSite/content/zh-cn/docs/development/upgrading/497.md index 29d40c47a..8b63e89d4 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/497.md +++ b/docSite/content/zh-cn/docs/development/upgrading/497.md @@ -20,5 +20,5 @@ weight: 793 1. 文件上传分块大小限制,避免超出 MongoDB 限制。 2. 使用记录仪表盘,无法获取指定成员的使用统计。 3. 仪表盘接口,因未考虑时区问题,统计异常。 -4. LLM 模型测试接口,无法测试未启用的 LLM。 +4. LLM 模型测试接口,无法测试未启用的 LLM。同时修复,模型测试接口会把模型自定义请求地址去除问题。 diff --git a/packages/service/common/system/log.ts b/packages/service/common/system/log.ts index 7efc64f08..80be8f69b 100644 --- a/packages/service/common/system/log.ts +++ b/packages/service/common/system/log.ts @@ -4,6 +4,12 @@ import { LogLevelEnum } from './log/constant'; import { connectionMongo } from '../mongo/index'; import { getMongoLog } from './log/schema'; +export enum EventTypeEnum { + outLinkBot = '[Outlink bot]', + feishuBot = '[Feishu bot]', + wxOffiaccount = '[Offiaccount bot]' +} + const logMap = { [LogLevelEnum.debug]: { levelLog: chalk.green('[Debug]') diff --git a/packages/service/core/ai/config.ts b/packages/service/core/ai/config.ts index da99ef155..e1af8b173 100644 --- a/packages/service/core/ai/config.ts +++ b/packages/service/core/ai/config.ts @@ -45,11 +45,13 @@ export const getAxiosConfig = (props?: { userKey?: OpenaiAccountType }) => { }; export const createChatCompletion = async ({ + modelData, body, userKey, timeout, options }: { + modelData?: LLMModelItemType; body: ChatCompletionCreateParamsNonStreaming | ChatCompletionCreateParamsStreaming; userKey?: OpenaiAccountType; timeout?: number; @@ -70,10 +72,11 @@ export const createChatCompletion = async ({ > => { try { // Rewrite model - const modelConstantsData = getLLMModel(body.model); + const modelConstantsData = modelData || getLLMModel(body.model); if (!modelConstantsData) { return Promise.reject(`${body.model} not found`); } + body.model = modelConstantsData.model; const formatTimeout = timeout ? timeout : body.stream ? 60000 : 600000; const ai = getAIApi({ diff --git a/packages/service/core/ai/config/utils.ts b/packages/service/core/ai/config/utils.ts index 31f0619da..35b1209fb 100644 --- a/packages/service/core/ai/config/utils.ts +++ b/packages/service/core/ai/config/utils.ts @@ -23,64 +23,65 @@ import { } from '../../../common/system/config/controller'; import { delay } from '@fastgpt/global/common/system/utils'; +const getModelConfigBaseUrl = () => { + const currentFileUrl = new URL(import.meta.url); + const filePath = decodeURIComponent( + process.platform === 'win32' + ? currentFileUrl.pathname.substring(1) // Remove leading slash on Windows + : currentFileUrl.pathname + ); + const modelsPath = path.join(path.dirname(filePath), 'provider'); + return modelsPath; +}; + /* TODO: 分优先级读取: 1. 有外部挂载目录,则读取外部的 2. 没有外部挂载目录,则读取本地的。然后试图拉取云端的进行覆盖。 */ export const loadSystemModels = async (init = false) => { - const getProviderList = () => { - const currentFileUrl = new URL(import.meta.url); - const filePath = decodeURIComponent( - process.platform === 'win32' - ? currentFileUrl.pathname.substring(1) // Remove leading slash on Windows - : currentFileUrl.pathname - ); - const modelsPath = path.join(path.dirname(filePath), 'provider'); - - return fs.readdirSync(modelsPath) as string[]; - }; const pushModel = (model: SystemModelItemType) => { global.systemModelList.push(model); if (model.isActive) { global.systemActiveModelList.push(model); - } - if (model.type === ModelTypeEnum.llm) { - global.llmModelMap.set(model.model, model); - global.llmModelMap.set(model.name, model); - if (model.isDefault) { - global.systemDefaultModel.llm = model; - } - if (model.isDefaultDatasetTextModel) { - global.systemDefaultModel.datasetTextLLM = model; - } - if (model.isDefaultDatasetImageModel) { - global.systemDefaultModel.datasetImageLLM = model; - } - } else if (model.type === ModelTypeEnum.embedding) { - global.embeddingModelMap.set(model.model, model); - global.embeddingModelMap.set(model.name, model); - if (model.isDefault) { - global.systemDefaultModel.embedding = model; - } - } else if (model.type === ModelTypeEnum.tts) { - global.ttsModelMap.set(model.model, model); - global.ttsModelMap.set(model.name, model); - if (model.isDefault) { - global.systemDefaultModel.tts = model; - } - } else if (model.type === ModelTypeEnum.stt) { - global.sttModelMap.set(model.model, model); - global.sttModelMap.set(model.name, model); - if (model.isDefault) { - global.systemDefaultModel.stt = model; - } - } else if (model.type === ModelTypeEnum.rerank) { - global.reRankModelMap.set(model.model, model); - global.reRankModelMap.set(model.name, model); - if (model.isDefault) { - global.systemDefaultModel.rerank = model; + + if (model.type === ModelTypeEnum.llm) { + global.llmModelMap.set(model.model, model); + global.llmModelMap.set(model.name, model); + if (model.isDefault) { + global.systemDefaultModel.llm = model; + } + if (model.isDefaultDatasetTextModel) { + global.systemDefaultModel.datasetTextLLM = model; + } + if (model.isDefaultDatasetImageModel) { + global.systemDefaultModel.datasetImageLLM = model; + } + } else if (model.type === ModelTypeEnum.embedding) { + global.embeddingModelMap.set(model.model, model); + global.embeddingModelMap.set(model.name, model); + if (model.isDefault) { + global.systemDefaultModel.embedding = model; + } + } else if (model.type === ModelTypeEnum.tts) { + global.ttsModelMap.set(model.model, model); + global.ttsModelMap.set(model.name, model); + if (model.isDefault) { + global.systemDefaultModel.tts = model; + } + } else if (model.type === ModelTypeEnum.stt) { + global.sttModelMap.set(model.model, model); + global.sttModelMap.set(model.name, model); + if (model.isDefault) { + global.systemDefaultModel.stt = model; + } + } else if (model.type === ModelTypeEnum.rerank) { + global.reRankModelMap.set(model.model, model); + global.reRankModelMap.set(model.name, model); + if (model.isDefault) { + global.systemDefaultModel.rerank = model; + } } } }; @@ -99,9 +100,10 @@ export const loadSystemModels = async (init = false) => { try { const dbModels = await MongoSystemModel.find({}).lean(); - const providerList = getProviderList(); - // System model + // Load system model from local + const modelsPath = getModelConfigBaseUrl(); + const providerList = fs.readdirSync(modelsPath) as string[]; await Promise.all( providerList.map(async (name) => { const fileContent = (await import(`./provider/${name}`))?.default as { diff --git a/packages/service/core/ai/model.ts b/packages/service/core/ai/model.ts index 68a8e62cf..15f7c5612 100644 --- a/packages/service/core/ai/model.ts +++ b/packages/service/core/ai/model.ts @@ -1,3 +1,4 @@ +import { cloneDeep } from 'lodash'; import { SystemModelItemType } from './type'; export const getDefaultLLMModel = () => global?.systemDefaultModel.llm!; @@ -53,5 +54,5 @@ export const findAIModel = (model: string): SystemModelItemType | undefined => { ); }; export const findModelFromAlldata = (model: string) => { - return global.systemModelList.find((item) => item.model === model); + return cloneDeep(global.systemModelList.find((item) => item.model === model)); }; diff --git a/packages/web/components/common/Input/NumberInput/index.tsx b/packages/web/components/common/Input/NumberInput/index.tsx index cde19e69c..61f75ed20 100644 --- a/packages/web/components/common/Input/NumberInput/index.tsx +++ b/packages/web/components/common/Input/NumberInput/index.tsx @@ -26,9 +26,9 @@ const MyNumberInput = (props: Props) => { { - const numE = Number(e.target.value); + const numE = e.target.value === '' ? '' : Number(e.target.value); if (onBlur) { - if (isNaN(numE)) { + if (numE === '') { // @ts-ignore onBlur(''); } else { @@ -46,9 +46,9 @@ const MyNumberInput = (props: Props) => { } }} onChange={(e) => { - const numE = Number(e); + const numE = e === '' ? '' : Number(e); if (onChange) { - if (isNaN(numE)) { + if (numE === '') { // @ts-ignore onChange(''); } else { @@ -62,6 +62,7 @@ const MyNumberInput = (props: Props) => { value: numE } }; + register(name).onChange(event); } }} diff --git a/packages/web/i18n/en/account_model.json b/packages/web/i18n/en/account_model.json index f531787f4..a09ddb92e 100644 --- a/packages/web/i18n/en/account_model.json +++ b/packages/web/i18n/en/account_model.json @@ -30,7 +30,7 @@ "log_status": "Status", "mapping": "Model Mapping", "mapping_tip": "A valid Json is required. \nThe model can be mapped when sending a request to the actual address. \nFor example:\n{\n \n \"gpt-4o\": \"gpt-4o-test\"\n\n}\n\nWhen FastGPT requests the gpt-4o model, the gpt-4o-test model is sent to the actual address, instead of gpt-4o.", - "maxToken_tip": "The model max_tokens parameter, if left blank, means that the model does not support it.", + "maxToken_tip": "Model max_tokens parameter", "max_temperature_tip": "If the model temperature parameter is not filled in, it means that the model does not support the temperature parameter.", "model": "Model", "model_name": "Model name", diff --git a/packages/web/i18n/zh-CN/account_model.json b/packages/web/i18n/zh-CN/account_model.json index e41a61ef1..aa9585d9d 100644 --- a/packages/web/i18n/zh-CN/account_model.json +++ b/packages/web/i18n/zh-CN/account_model.json @@ -30,7 +30,7 @@ "log_status": "状态", "mapping": "模型映射", "mapping_tip": "需填写一个有效 Json。可在向实际地址发送请求时,对模型进行映射。例如:\n{\n \"gpt-4o\": \"gpt-4o-test\"\n}\n当 FastGPT 请求 gpt-4o 模型时,会向实际地址发送 gpt-4o-test 的模型,而不是 gpt-4o。", - "maxToken_tip": "模型 max_tokens 参数,如果留空,则代表模型不支持该参数。", + "maxToken_tip": "模型 max_tokens 参数", "max_temperature_tip": "模型 temperature 参数,不填则代表模型不支持 temperature 参数。", "model": "模型", "model_name": "模型名", diff --git a/packages/web/i18n/zh-Hant/account_model.json b/packages/web/i18n/zh-Hant/account_model.json index b521f6019..103f4b660 100644 --- a/packages/web/i18n/zh-Hant/account_model.json +++ b/packages/web/i18n/zh-Hant/account_model.json @@ -28,7 +28,7 @@ "log_status": "狀態", "mapping": "模型對映", "mapping_tip": "需填寫一個有效 Json。\n可在向實際地址傳送請求時,對模型進行對映。\n例如:\n{\n \n \"gpt-4o\": \"gpt-4o-test\"\n\n}\n\n當 FastGPT 請求 gpt-4o 模型時,會向實際地址傳送 gpt-4o-test 的模型,而不是 gpt-4o。", - "maxToken_tip": "模型 max_tokens 參數,如果留空,則代表模型不支援該參數。", + "maxToken_tip": "模型 max_tokens 參數", "max_temperature_tip": "模型 temperature 參數,不填則代表模型不支援 temperature 參數。", "model": "模型", "model_name": "模型名", diff --git a/projects/app/src/pageComponents/account/model/AddModelBox.tsx b/projects/app/src/pageComponents/account/model/AddModelBox.tsx index 0caef71b1..38bd47091 100644 --- a/projects/app/src/pageComponents/account/model/AddModelBox.tsx +++ b/projects/app/src/pageComponents/account/model/AddModelBox.tsx @@ -356,7 +356,12 @@ export const ModelEditModal = ({ - + @@ -372,6 +377,7 @@ export const ModelEditModal = ({ 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 2731f5cf5..beea912ad 100644 --- a/projects/app/src/pages/api/core/ai/model/test.ts +++ b/projects/app/src/pages/api/core/ai/model/test.ts @@ -79,6 +79,7 @@ const testLLMModel = async (model: LLMModelItemType, headers: Record