From 1a678cb4d832fe47f5d04e614bb267907bbf2677 Mon Sep 17 00:00:00 2001 From: code-october <148516338+code-october@users.noreply.github.com> Date: Fri, 29 Nov 2024 15:47:28 +0000 Subject: [PATCH 1/4] fix model leak issue --- app/api/alibaba.ts | 4 ++-- app/api/anthropic.ts | 4 ++-- app/api/baidu.ts | 4 ++-- app/api/bytedance.ts | 4 ++-- app/api/common.ts | 15 +++++++-------- app/api/glm.ts | 4 ++-- app/api/iflytek.ts | 4 ++-- app/api/moonshot.ts | 4 ++-- app/api/xai.ts | 4 ++-- app/utils/model.ts | 24 ++++++++++++++++++++++++ 10 files changed, 47 insertions(+), 24 deletions(-) diff --git a/app/api/alibaba.ts b/app/api/alibaba.ts index 894b1ae4c04..20f6caefa8d 100644 --- a/app/api/alibaba.ts +++ b/app/api/alibaba.ts @@ -8,7 +8,7 @@ import { import { prettyObject } from "@/app/utils/format"; import { NextRequest, NextResponse } from "next/server"; import { auth } from "@/app/api/auth"; -import { isModelAvailableInServer } from "@/app/utils/model"; +import { isModelNotavailableInServer } from "@/app/utils/model"; const serverConfig = getServerSideConfig(); @@ -89,7 +89,7 @@ async function request(req: NextRequest) { // not undefined and is false if ( - isModelAvailableInServer( + isModelNotavailableInServer( serverConfig.customModels, jsonBody?.model as string, ServiceProvider.Alibaba as string, diff --git a/app/api/anthropic.ts b/app/api/anthropic.ts index 7a44443710f..b96637b2c8c 100644 --- a/app/api/anthropic.ts +++ b/app/api/anthropic.ts @@ -9,7 +9,7 @@ import { import { prettyObject } from "@/app/utils/format"; import { NextRequest, NextResponse } from "next/server"; import { auth } from "./auth"; -import { isModelAvailableInServer } from "@/app/utils/model"; +import { isModelNotavailableInServer } from "@/app/utils/model"; import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare"; const ALLOWD_PATH = new Set([Anthropic.ChatPath, Anthropic.ChatPath1]); @@ -122,7 +122,7 @@ async function request(req: NextRequest) { // not undefined and is false if ( - isModelAvailableInServer( + isModelNotavailableInServer( serverConfig.customModels, jsonBody?.model as string, ServiceProvider.Anthropic as string, diff --git a/app/api/baidu.ts b/app/api/baidu.ts index 0408b43c5bc..0f4e05ee86c 100644 --- a/app/api/baidu.ts +++ b/app/api/baidu.ts @@ -8,7 +8,7 @@ import { import { prettyObject } from "@/app/utils/format"; import { NextRequest, NextResponse } from "next/server"; import { auth } from "@/app/api/auth"; -import { isModelAvailableInServer } from "@/app/utils/model"; +import { isModelNotavailableInServer } from "@/app/utils/model"; import { getAccessToken } from "@/app/utils/baidu"; const serverConfig = getServerSideConfig(); @@ -104,7 +104,7 @@ async function request(req: NextRequest) { // not undefined and is false if ( - isModelAvailableInServer( + isModelNotavailableInServer( serverConfig.customModels, jsonBody?.model as string, ServiceProvider.Baidu as string, diff --git a/app/api/bytedance.ts b/app/api/bytedance.ts index cb65b106109..51b39ceb7cb 100644 --- a/app/api/bytedance.ts +++ b/app/api/bytedance.ts @@ -8,7 +8,7 @@ import { import { prettyObject } from "@/app/utils/format"; import { NextRequest, NextResponse } from "next/server"; import { auth } from "@/app/api/auth"; -import { isModelAvailableInServer } from "@/app/utils/model"; +import { isModelNotavailableInServer } from "@/app/utils/model"; const serverConfig = getServerSideConfig(); @@ -88,7 +88,7 @@ async function request(req: NextRequest) { // not undefined and is false if ( - isModelAvailableInServer( + isModelNotavailableInServer( serverConfig.customModels, jsonBody?.model as string, ServiceProvider.ByteDance as string, diff --git a/app/api/common.ts b/app/api/common.ts index 495a12ccdbb..8b75d4aedf6 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from "next/server"; import { getServerSideConfig } from "../config/server"; import { OPENAI_BASE_URL, ServiceProvider } from "../constant"; import { cloudflareAIGatewayUrl } from "../utils/cloudflare"; -import { getModelProvider, isModelAvailableInServer } from "../utils/model"; +import { getModelProvider, isModelNotavailableInServer } from "../utils/model"; const serverConfig = getServerSideConfig(); @@ -118,15 +118,14 @@ export async function requestOpenai(req: NextRequest) { // not undefined and is false if ( - isModelAvailableInServer( + isModelNotavailableInServer( serverConfig.customModels, jsonBody?.model as string, - ServiceProvider.OpenAI as string, - ) || - isModelAvailableInServer( - serverConfig.customModels, - jsonBody?.model as string, - ServiceProvider.Azure as string, + [ + ServiceProvider.OpenAI, + ServiceProvider.Azure, + jsonBody?.model as string, // support provider-unspecified model + ], ) ) { return NextResponse.json( diff --git a/app/api/glm.ts b/app/api/glm.ts index 3625b9f7bf9..8431c5db5b0 100644 --- a/app/api/glm.ts +++ b/app/api/glm.ts @@ -8,7 +8,7 @@ import { import { prettyObject } from "@/app/utils/format"; import { NextRequest, NextResponse } from "next/server"; import { auth } from "@/app/api/auth"; -import { isModelAvailableInServer } from "@/app/utils/model"; +import { isModelNotavailableInServer } from "@/app/utils/model"; const serverConfig = getServerSideConfig(); @@ -89,7 +89,7 @@ async function request(req: NextRequest) { // not undefined and is false if ( - isModelAvailableInServer( + isModelNotavailableInServer( serverConfig.customModels, jsonBody?.model as string, ServiceProvider.ChatGLM as string, diff --git a/app/api/iflytek.ts b/app/api/iflytek.ts index 8b8227dce1f..6624f74e9ab 100644 --- a/app/api/iflytek.ts +++ b/app/api/iflytek.ts @@ -8,7 +8,7 @@ import { import { prettyObject } from "@/app/utils/format"; import { NextRequest, NextResponse } from "next/server"; import { auth } from "@/app/api/auth"; -import { isModelAvailableInServer } from "@/app/utils/model"; +import { isModelNotavailableInServer } from "@/app/utils/model"; // iflytek const serverConfig = getServerSideConfig(); @@ -89,7 +89,7 @@ async function request(req: NextRequest) { // not undefined and is false if ( - isModelAvailableInServer( + isModelNotavailableInServer( serverConfig.customModels, jsonBody?.model as string, ServiceProvider.Iflytek as string, diff --git a/app/api/moonshot.ts b/app/api/moonshot.ts index 5bf4807e3e6..792d14d3334 100644 --- a/app/api/moonshot.ts +++ b/app/api/moonshot.ts @@ -8,7 +8,7 @@ import { import { prettyObject } from "@/app/utils/format"; import { NextRequest, NextResponse } from "next/server"; import { auth } from "@/app/api/auth"; -import { isModelAvailableInServer } from "@/app/utils/model"; +import { isModelNotavailableInServer } from "@/app/utils/model"; const serverConfig = getServerSideConfig(); @@ -88,7 +88,7 @@ async function request(req: NextRequest) { // not undefined and is false if ( - isModelAvailableInServer( + isModelNotavailableInServer( serverConfig.customModels, jsonBody?.model as string, ServiceProvider.Moonshot as string, diff --git a/app/api/xai.ts b/app/api/xai.ts index a4ee8b39731..4aad5e5fb3e 100644 --- a/app/api/xai.ts +++ b/app/api/xai.ts @@ -8,7 +8,7 @@ import { import { prettyObject } from "@/app/utils/format"; import { NextRequest, NextResponse } from "next/server"; import { auth } from "@/app/api/auth"; -import { isModelAvailableInServer } from "@/app/utils/model"; +import { isModelNotavailableInServer } from "@/app/utils/model"; const serverConfig = getServerSideConfig(); @@ -88,7 +88,7 @@ async function request(req: NextRequest) { // not undefined and is false if ( - isModelAvailableInServer( + isModelNotavailableInServer( serverConfig.customModels, jsonBody?.model as string, ServiceProvider.XAI as string, diff --git a/app/utils/model.ts b/app/utils/model.ts index a1b7df1b61e..32021d5fac2 100644 --- a/app/utils/model.ts +++ b/app/utils/model.ts @@ -202,3 +202,27 @@ export function isModelAvailableInServer( const modelTable = collectModelTable(DEFAULT_MODELS, customModels); return modelTable[fullName]?.available === false; } + +/** + * Checks if a model is not available on any of the specified providers in the server. + * + * @param {string} customModels - A string of custom models, comma-separated. + * @param {string} modelName - The name of the model to check. + * @param {string|string[]} providerNames - A string or array of provider names to check against. + * + * @returns {boolean} True if the model is not available on any of the specified providers, false otherwise. + */ +export function isModelNotavailableInServer( + customModels: string, + modelName: string, + providerNames: string | string[], +) { + const modelTable = collectModelTable(DEFAULT_MODELS, customModels); + const providerNamesArray = Array.isArray(providerNames) ? providerNames : [providerNames]; + for (const providerName of providerNamesArray){ + const fullName = `${modelName}@${providerName.toLowerCase()}`; + if (modelTable[fullName]?.available === true) + return false; + } + return true; +} From e1ac0538b8143f93074c1c248a5739358b3ddfd1 Mon Sep 17 00:00:00 2001 From: code-october <148516338+code-october@users.noreply.github.com> Date: Sat, 30 Nov 2024 07:22:24 +0000 Subject: [PATCH 2/4] add unit test --- test/model-available.test.ts | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 test/model-available.test.ts diff --git a/test/model-available.test.ts b/test/model-available.test.ts new file mode 100644 index 00000000000..09a7143e2f4 --- /dev/null +++ b/test/model-available.test.ts @@ -0,0 +1,43 @@ +import { isModelNotavailableInServer } from "../app/utils/model"; + +describe("isModelNotavailableInServer", () => { + test("test model will return false, which means the model is available", () => { + const customModels = ""; + const modelName = "gpt-4"; + const providerNames = "OpenAI"; + const result = isModelNotavailableInServer(customModels, modelName, providerNames); + expect(result).toBe(false); + }); + + test("test model will return false, which means the model is not available", () => { + const customModels = "-all,gpt-4o-mini"; + const modelName = "gpt-4"; + const providerNames = "OpenAI"; + const result = isModelNotavailableInServer(customModels, modelName, providerNames); + expect(result).toBe(true); + }); + + test("support passing multiple providers, model unavailable on one of the providers will return true", () => { + const customModels = "-all,gpt-4@Google"; + const modelName = "gpt-4"; + const providerNames = ["OpenAI", "Azure"]; + const result = isModelNotavailableInServer(customModels, modelName, providerNames); + expect(result).toBe(true); + }); + + test("support passing multiple providers, model available on one of the providers will return false", () => { + const customModels = "-all,gpt-4@Google"; + const modelName = "gpt-4"; + const providerNames = ["OpenAI", "Google"]; + const result = isModelNotavailableInServer(customModels, modelName, providerNames); + expect(result).toBe(false); + }); + + test("test custom model without setting provider", () => { + const customModels = "-all,mistral-large"; + const modelName = "mistral-large"; + const providerNames = modelName; + const result = isModelNotavailableInServer(customModels, modelName, providerNames); + expect(result).toBe(false); + }); +}) \ No newline at end of file From 54f6feb2d74b9ac81fa5f826f24f73929c7cb238 Mon Sep 17 00:00:00 2001 From: code-october <148516338+code-october@users.noreply.github.com> Date: Sat, 30 Nov 2024 07:28:38 +0000 Subject: [PATCH 3/4] update unit test --- test/model-available.test.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/model-available.test.ts b/test/model-available.test.ts index 09a7143e2f4..2d222e05259 100644 --- a/test/model-available.test.ts +++ b/test/model-available.test.ts @@ -9,14 +9,24 @@ describe("isModelNotavailableInServer", () => { expect(result).toBe(false); }); - test("test model will return false, which means the model is not available", () => { + test("test model will return true when model is not available in custom models", () => { const customModels = "-all,gpt-4o-mini"; const modelName = "gpt-4"; const providerNames = "OpenAI"; const result = isModelNotavailableInServer(customModels, modelName, providerNames); expect(result).toBe(true); }); + test("should respect DISABLE_GPT4 setting", () => { + process.env.DISABLE_GPT4 = "1"; + const result = isModelNotavailableInServer("", "gpt-4", "OpenAI"); + expect(result).toBe(true); + }); + test("should handle empty provider names", () => { + const result = isModelNotavailableInServer("-all,gpt-4", "gpt-4", ""); + expect(result).toBe(true); + }); + test("support passing multiple providers, model unavailable on one of the providers will return true", () => { const customModels = "-all,gpt-4@Google"; const modelName = "gpt-4"; From cc5e16b0454481fab48b1115eda9b8fb11ce0054 Mon Sep 17 00:00:00 2001 From: code-october <148516338+code-october@users.noreply.github.com> Date: Sat, 30 Nov 2024 07:30:52 +0000 Subject: [PATCH 4/4] update unit test --- test/model-available.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/model-available.test.ts b/test/model-available.test.ts index 2d222e05259..2ceda56f037 100644 --- a/test/model-available.test.ts +++ b/test/model-available.test.ts @@ -16,6 +16,7 @@ describe("isModelNotavailableInServer", () => { const result = isModelNotavailableInServer(customModels, modelName, providerNames); expect(result).toBe(true); }); + test("should respect DISABLE_GPT4 setting", () => { process.env.DISABLE_GPT4 = "1"; const result = isModelNotavailableInServer("", "gpt-4", "OpenAI"); @@ -27,6 +28,11 @@ describe("isModelNotavailableInServer", () => { expect(result).toBe(true); }); + test("should be case insensitive for model names", () => { + const result = isModelNotavailableInServer("-all,GPT-4", "gpt-4", "OpenAI"); + expect(result).toBe(true); + }); + test("support passing multiple providers, model unavailable on one of the providers will return true", () => { const customModels = "-all,gpt-4@Google"; const modelName = "gpt-4";