From e7b16bfbc09ff1167292485db6fba7dee372171d Mon Sep 17 00:00:00 2001 From: lloydzhou Date: Thu, 4 Jul 2024 15:30:24 +0800 Subject: [PATCH 1/9] add function to check model is available --- app/api/anthropic/[...path]/route.ts | 8 ++------ app/api/common.ts | 30 ++++++++++++---------------- app/utils/model.ts | 6 ++++++ 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/app/api/anthropic/[...path]/route.ts b/app/api/anthropic/[...path]/route.ts index 4264893d93ee..274d7d7c496b 100644 --- a/app/api/anthropic/[...path]/route.ts +++ b/app/api/anthropic/[...path]/route.ts @@ -9,7 +9,7 @@ import { import { prettyObject } from "@/app/utils/format"; import { NextRequest, NextResponse } from "next/server"; import { auth } from "../../auth"; -import { collectModelTable } from "@/app/utils/model"; +import { isModelAvailableInServer } from "@/app/utils/model"; const ALLOWD_PATH = new Set([Anthropic.ChatPath, Anthropic.ChatPath1]); @@ -136,17 +136,13 @@ async function request(req: NextRequest) { // #1815 try to refuse some request to some models if (serverConfig.customModels && req.body) { try { - const modelTable = collectModelTable( - DEFAULT_MODELS, - serverConfig.customModels, - ); const clonedBody = await req.text(); fetchOptions.body = clonedBody; const jsonBody = JSON.parse(clonedBody) as { model?: string }; // not undefined and is false - if (modelTable[jsonBody?.model ?? ""].available === false) { + if (isModelAvailableInServer(jsonBody?.model ?? "")) { return NextResponse.json( { error: true, diff --git a/app/api/common.ts b/app/api/common.ts index a75f2de5cfae..3e0156569883 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -1,7 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { getServerSideConfig } from "../config/server"; import { DEFAULT_MODELS, OPENAI_BASE_URL, GEMINI_BASE_URL } from "../constant"; -import { collectModelTable } from "../utils/model"; +import { isModelAvailableInServer } from "../utils/model"; import { makeAzurePath } from "../azure"; const serverConfig = getServerSideConfig(); @@ -83,17 +83,15 @@ export async function requestOpenai(req: NextRequest) { // #1815 try to refuse gpt4 request if (serverConfig.customModels && req.body) { try { - const modelTable = collectModelTable( - DEFAULT_MODELS, - serverConfig.customModels, - ); const clonedBody = await req.text(); fetchOptions.body = clonedBody; const jsonBody = JSON.parse(clonedBody) as { model?: string }; // not undefined and is false - if (modelTable[jsonBody?.model ?? ""].available === false) { + if ( + isModelAvailableInServer(serverConfig.customModels, jsonBody?.model) + ) { return NextResponse.json( { error: true, @@ -112,16 +110,16 @@ export async function requestOpenai(req: NextRequest) { try { const res = await fetch(fetchUrl, fetchOptions); - // Extract the OpenAI-Organization header from the response - const openaiOrganizationHeader = res.headers.get("OpenAI-Organization"); + // Extract the OpenAI-Organization header from the response + const openaiOrganizationHeader = res.headers.get("OpenAI-Organization"); - // Check if serverConfig.openaiOrgId is defined and not an empty string - if (serverConfig.openaiOrgId && serverConfig.openaiOrgId.trim() !== "") { - // If openaiOrganizationHeader is present, log it; otherwise, log that the header is not present - console.log("[Org ID]", openaiOrganizationHeader); - } else { - console.log("[Org ID] is not set up."); - } + // Check if serverConfig.openaiOrgId is defined and not an empty string + if (serverConfig.openaiOrgId && serverConfig.openaiOrgId.trim() !== "") { + // If openaiOrganizationHeader is present, log it; otherwise, log that the header is not present + console.log("[Org ID]", openaiOrganizationHeader); + } else { + console.log("[Org ID] is not set up."); + } // to prevent browser prompt for credentials const newHeaders = new Headers(res.headers); @@ -129,7 +127,6 @@ export async function requestOpenai(req: NextRequest) { // to disable nginx buffering newHeaders.set("X-Accel-Buffering", "no"); - // Conditionally delete the OpenAI-Organization header from the response if [Org ID] is undefined or empty (not setup in ENV) // Also, this is to prevent the header from being sent to the client if (!serverConfig.openaiOrgId || serverConfig.openaiOrgId.trim() === "") { @@ -142,7 +139,6 @@ export async function requestOpenai(req: NextRequest) { // The browser will try to decode the response with brotli and fail newHeaders.delete("content-encoding"); - return new Response(res.body, { status: res.status, statusText: res.statusText, diff --git a/app/utils/model.ts b/app/utils/model.ts index 056fff2e98d9..970c4ea1ce4c 100644 --- a/app/utils/model.ts +++ b/app/utils/model.ts @@ -1,3 +1,4 @@ +import { DEFAULT_MODELS } from "../constant"; import { LLMModel } from "../client/api"; const customProvider = (modelName: string) => ({ @@ -100,3 +101,8 @@ export function collectModelsWithDefaultModel( const allModels = Object.values(modelTable); return allModels; } + +export function isModelAvailableInServer(customModels, modelName) { + const modelTable = collectModelTable(DEFAULT_MODELS, customModels); + return modelTable[modelName ?? ""].available === false; +} From 14f2a8f3700c920b6f4680b3e547e0f94790326e Mon Sep 17 00:00:00 2001 From: lloydzhou Date: Thu, 4 Jul 2024 15:32:08 +0800 Subject: [PATCH 2/9] merge model with modelName and providerName --- app/store/config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/store/config.ts b/app/store/config.ts index 94cfcd8ecaaa..85929d900a64 100644 --- a/app/store/config.ts +++ b/app/store/config.ts @@ -116,12 +116,12 @@ export const useAppConfig = createPersistStore( for (const model of oldModels) { model.available = false; - modelMap[model.name] = model; + modelMap[`${model.name}@${model.provider.name}`] = model; } for (const model of newModels) { model.available = true; - modelMap[model.name] = model; + modelMap[`${model.name}@${model.provider.name}`] = model; } set(() => ({ From b9ffd509925f1475e28ddd4b1a9e688e08fc39c0 Mon Sep 17 00:00:00 2001 From: lloydzhou Date: Thu, 4 Jul 2024 15:44:36 +0800 Subject: [PATCH 3/9] using @ as fullName in modelTable --- app/utils/model.ts | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/app/utils/model.ts b/app/utils/model.ts index 970c4ea1ce4c..cd3a90611c4c 100644 --- a/app/utils/model.ts +++ b/app/utils/model.ts @@ -24,7 +24,8 @@ export function collectModelTable( // default models models.forEach((m) => { - modelTable[m.name] = { + // using @ as fullName + modelTable[`${m.name}@${m?.provider?.name}`] = { ...m, displayName: m.name, // 'provider' is copied over if it exists }; @@ -46,12 +47,27 @@ export function collectModelTable( (model) => (model.available = available), ); } else { - modelTable[name] = { - name, - displayName: displayName || name, - available, - provider: modelTable[name]?.provider ?? customProvider(name), // Use optional chaining - }; + // 1. find model by name(), and set available value + let count = 0; + for (const fullName in modelTable) { + if (fullName.includes(name)) { + count += 1; + modelTable[fullName]["available"] = available; + if (displayName) { + modelTable[fullName]["displayName"] = displayName; + } + } + } + // 2. if model not exists, create new model with available value + if (count === 0) { + const provider = customProvider(name); + modelTable[`${name}@${provider.name}`] = { + name, + displayName: displayName || name, + available, + provider, // Use optional chaining + }; + } } }); From 7a5596b9091d056d8bbce9cccf3684c4ee625325 Mon Sep 17 00:00:00 2001 From: lloydzhou Date: Thu, 4 Jul 2024 15:48:48 +0800 Subject: [PATCH 4/9] hotfix --- app/api/anthropic/[...path]/route.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/api/anthropic/[...path]/route.ts b/app/api/anthropic/[...path]/route.ts index 274d7d7c496b..f50730fa963c 100644 --- a/app/api/anthropic/[...path]/route.ts +++ b/app/api/anthropic/[...path]/route.ts @@ -142,7 +142,9 @@ async function request(req: NextRequest) { const jsonBody = JSON.parse(clonedBody) as { model?: string }; // not undefined and is false - if (isModelAvailableInServer(jsonBody?.model ?? "")) { + if ( + isModelAvailableInServer(serverConfig.customModels, jsonBody?.model) + ) { return NextResponse.json( { error: true, From aa081834395ac11a7d2f037914f5ffb36e9aee02 Mon Sep 17 00:00:00 2001 From: lloydzhou Date: Thu, 4 Jul 2024 16:03:35 +0800 Subject: [PATCH 5/9] hotfix --- app/api/anthropic/[...path]/route.ts | 7 ++++++- app/api/common.ts | 18 ++++++++++++++++-- app/store/config.ts | 4 ++-- app/utils/model.ts | 9 +++++++-- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/app/api/anthropic/[...path]/route.ts b/app/api/anthropic/[...path]/route.ts index f50730fa963c..495002b8facc 100644 --- a/app/api/anthropic/[...path]/route.ts +++ b/app/api/anthropic/[...path]/route.ts @@ -4,6 +4,7 @@ import { Anthropic, ApiPath, DEFAULT_MODELS, + ServiceProvider, ModelProvider, } from "@/app/constant"; import { prettyObject } from "@/app/utils/format"; @@ -143,7 +144,11 @@ async function request(req: NextRequest) { // not undefined and is false if ( - isModelAvailableInServer(serverConfig.customModels, jsonBody?.model) + isModelAvailableInServer( + serverConfig.customModels, + jsonBody?.model, + ServiceProvider.Anthropic, + ) ) { return NextResponse.json( { diff --git a/app/api/common.ts b/app/api/common.ts index 3e0156569883..c2dfed4ab012 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -1,6 +1,11 @@ import { NextRequest, NextResponse } from "next/server"; import { getServerSideConfig } from "../config/server"; -import { DEFAULT_MODELS, OPENAI_BASE_URL, GEMINI_BASE_URL } from "../constant"; +import { + DEFAULT_MODELS, + OPENAI_BASE_URL, + GEMINI_BASE_URL, + ServiceProvider, +} from "../constant"; import { isModelAvailableInServer } from "../utils/model"; import { makeAzurePath } from "../azure"; @@ -90,7 +95,16 @@ export async function requestOpenai(req: NextRequest) { // not undefined and is false if ( - isModelAvailableInServer(serverConfig.customModels, jsonBody?.model) + isModelAvailableInServer( + serverConfig.customModels, + jsonBody?.model, + ServiceProvider.OpenAI, + ) || + isModelAvailableInServer( + serverConfig.customModels, + jsonBody?.model, + ServiceProvider.Azure, + ) ) { return NextResponse.json( { diff --git a/app/store/config.ts b/app/store/config.ts index 85929d900a64..96d6d91258f2 100644 --- a/app/store/config.ts +++ b/app/store/config.ts @@ -116,12 +116,12 @@ export const useAppConfig = createPersistStore( for (const model of oldModels) { model.available = false; - modelMap[`${model.name}@${model.provider.name}`] = model; + modelMap[`${model.name}@${model?.provider?.name}`] = model; } for (const model of newModels) { model.available = true; - modelMap[`${model.name}@${model.provider.name}`] = model; + modelMap[`${model.name}@${model?.provider?.name}`] = model; } set(() => ({ diff --git a/app/utils/model.ts b/app/utils/model.ts index cd3a90611c4c..9bd6ea673e97 100644 --- a/app/utils/model.ts +++ b/app/utils/model.ts @@ -118,7 +118,12 @@ export function collectModelsWithDefaultModel( return allModels; } -export function isModelAvailableInServer(customModels, modelName) { +export function isModelAvailableInServer( + customModels, + modelName, + providerName, +) { + const fullName = `${modelName}@${providerName}`; const modelTable = collectModelTable(DEFAULT_MODELS, customModels); - return modelTable[modelName ?? ""].available === false; + return modelTable[fullName]?.available === false; } From a68341eae64b4d8bf14afd80299d99928a92364e Mon Sep 17 00:00:00 2001 From: lloydzhou Date: Thu, 4 Jul 2024 16:11:37 +0800 Subject: [PATCH 6/9] include providerId in fullName --- app/store/config.ts | 4 ++-- app/utils/model.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/store/config.ts b/app/store/config.ts index 96d6d91258f2..0e7f43ee6a67 100644 --- a/app/store/config.ts +++ b/app/store/config.ts @@ -116,12 +116,12 @@ export const useAppConfig = createPersistStore( for (const model of oldModels) { model.available = false; - modelMap[`${model.name}@${model?.provider?.name}`] = model; + modelMap[`${model.name}@${model?.provider?.id}`] = model; } for (const model of newModels) { model.available = true; - modelMap[`${model.name}@${model?.provider?.name}`] = model; + modelMap[`${model.name}@${model?.provider?.id}`] = model; } set(() => ({ diff --git a/app/utils/model.ts b/app/utils/model.ts index 9bd6ea673e97..741971b003e9 100644 --- a/app/utils/model.ts +++ b/app/utils/model.ts @@ -24,8 +24,8 @@ export function collectModelTable( // default models models.forEach((m) => { - // using @ as fullName - modelTable[`${m.name}@${m?.provider?.name}`] = { + // using @ as fullName + modelTable[`${m.name}@${m?.provider?.id}`] = { ...m, displayName: m.name, // 'provider' is copied over if it exists }; @@ -61,7 +61,7 @@ export function collectModelTable( // 2. if model not exists, create new model with available value if (count === 0) { const provider = customProvider(name); - modelTable[`${name}@${provider.name}`] = { + modelTable[`${name}@${provider?.id}`] = { name, displayName: displayName || name, available, From 97aa72ec5bbc0e48587bb621d0f2d247b3f8d76a Mon Sep 17 00:00:00 2001 From: lloydzhou Date: Thu, 4 Jul 2024 08:36:25 +0000 Subject: [PATCH 7/9] hotfix ts --- app/api/anthropic/[...path]/route.ts | 4 ++-- app/api/common.ts | 8 ++++---- app/utils/model.ts | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/api/anthropic/[...path]/route.ts b/app/api/anthropic/[...path]/route.ts index 495002b8facc..78106efa76c7 100644 --- a/app/api/anthropic/[...path]/route.ts +++ b/app/api/anthropic/[...path]/route.ts @@ -146,8 +146,8 @@ async function request(req: NextRequest) { if ( isModelAvailableInServer( serverConfig.customModels, - jsonBody?.model, - ServiceProvider.Anthropic, + jsonBody?.model as string, + ServiceProvider.Anthropic as string, ) ) { return NextResponse.json( diff --git a/app/api/common.ts b/app/api/common.ts index c2dfed4ab012..1454fde2ed13 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -97,13 +97,13 @@ export async function requestOpenai(req: NextRequest) { if ( isModelAvailableInServer( serverConfig.customModels, - jsonBody?.model, - ServiceProvider.OpenAI, + jsonBody?.model as string, + ServiceProvider.OpenAI as string, ) || isModelAvailableInServer( serverConfig.customModels, - jsonBody?.model, - ServiceProvider.Azure, + jsonBody?.model as string, + ServiceProvider.Azure as string, ) ) { return NextResponse.json( diff --git a/app/utils/model.ts b/app/utils/model.ts index 741971b003e9..6b5173a5977a 100644 --- a/app/utils/model.ts +++ b/app/utils/model.ts @@ -119,9 +119,9 @@ export function collectModelsWithDefaultModel( } export function isModelAvailableInServer( - customModels, - modelName, - providerName, + customModels: string, + modelName: string, + providerName: string, ) { const fullName = `${modelName}@${providerName}`; const modelTable = collectModelTable(DEFAULT_MODELS, customModels); From 8cb204e22ea3b5c0a29b99b8ec486f9346e798b9 Mon Sep 17 00:00:00 2001 From: Lloyd Zhou Date: Thu, 4 Jul 2024 17:18:42 +0800 Subject: [PATCH 8/9] refactor: get language (#4922) * refactor: get language --- app/locales/index.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/app/locales/index.ts b/app/locales/index.ts index 6e8088a98944..acdb3e878a1a 100644 --- a/app/locales/index.ts +++ b/app/locales/index.ts @@ -97,7 +97,17 @@ function setItem(key: string, value: string) { function getLanguage() { try { - return navigator.language.toLowerCase(); + const locale = new Intl.Locale(navigator.language).maximize(); + const region = locale?.region?.toLowerCase(); + // 1. check region code in ALL_LANGS + if (AllLangs.includes(region as Lang)) { + return region as Lang; + } + // 2. check language code in ALL_LANGS + if (AllLangs.includes(locale.language as Lang)) { + return locale.language as Lang; + } + return DEFAULT_LANG; } catch { return DEFAULT_LANG; } @@ -110,15 +120,7 @@ export function getLang(): Lang { return savedLang as Lang; } - const lang = getLanguage(); - - for (const option of AllLangs) { - if (lang.includes(option)) { - return option; - } - } - - return DEFAULT_LANG; + return getLanguage(); } export function changeLang(lang: Lang) { From 31d94442644232e272ecca36c8f16e4399997633 Mon Sep 17 00:00:00 2001 From: lloydzhou Date: Thu, 4 Jul 2024 19:38:26 +0800 Subject: [PATCH 9/9] hotfix --- app/utils/model.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/utils/model.ts b/app/utils/model.ts index 6b5173a5977a..249987726ad2 100644 --- a/app/utils/model.ts +++ b/app/utils/model.ts @@ -3,7 +3,7 @@ import { LLMModel } from "../client/api"; const customProvider = (modelName: string) => ({ id: modelName, - providerName: "", + providerName: "Custom", providerType: "custom", }); @@ -50,7 +50,7 @@ export function collectModelTable( // 1. find model by name(), and set available value let count = 0; for (const fullName in modelTable) { - if (fullName.includes(name)) { + if (fullName.split("@").shift() == name) { count += 1; modelTable[fullName]["available"] = available; if (displayName) {