diff --git a/.github/ISSUE_TEMPLATE/1_bug_report.yml b/.github/ISSUE_TEMPLATE/1_bug_report.yml new file mode 100644 index 000000000..b576629e3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_bug_report.yml @@ -0,0 +1,80 @@ +name: '🐛 Bug Report' +description: 'Report an bug' +title: '[Bug] ' +labels: ['bug'] +body: + - type: dropdown + attributes: + label: '📦 Deployment Method' + multiple: true + options: + - 'Official installation package' + - 'Vercel' + - 'Zeabur' + - 'Sealos' + - 'Netlify' + - 'Docker' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 Version' + validations: + required: true + + - type: dropdown + attributes: + label: '💻 Operating System' + multiple: true + options: + - 'Windows' + - 'macOS' + - 'Ubuntu' + - 'Other Linux' + - 'iOS' + - 'iPad OS' + - 'Android' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 System Version' + validations: + required: true + - type: dropdown + attributes: + label: '🌐 Browser' + multiple: true + options: + - 'Chrome' + - 'Edge' + - 'Safari' + - 'Firefox' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 Browser Version' + validations: + required: true + - type: textarea + attributes: + label: '🐛 Bug Description' + description: A clear and concise description of the bug, if the above option is `Other`, please also explain in detail. + validations: + required: true + - type: textarea + attributes: + label: '📷 Recurrence Steps' + description: A clear and concise description of how to recurrence. + - type: textarea + attributes: + label: '🚦 Expected Behavior' + description: A clear and concise description of what you expected to happen. + - type: textarea + attributes: + label: '📝 Additional Information' + description: If your problem needs further explanation, or if the issue you're seeing cannot be reproduced in a gist, please add more information here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/1_bug_report_cn.yml b/.github/ISSUE_TEMPLATE/1_bug_report_cn.yml new file mode 100644 index 000000000..1977237de --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_bug_report_cn.yml @@ -0,0 +1,80 @@ +name: '🐛 反馈缺陷' +description: '反馈一个问题/缺陷' +title: '[Bug] ' +labels: ['bug'] +body: + - type: dropdown + attributes: + label: '📦 部署方式' + multiple: true + options: + - '官方安装包' + - 'Vercel' + - 'Zeabur' + - 'Sealos' + - 'Netlify' + - 'Docker' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 软件版本' + validations: + required: true + + - type: dropdown + attributes: + label: '💻 系统环境' + multiple: true + options: + - 'Windows' + - 'macOS' + - 'Ubuntu' + - 'Other Linux' + - 'iOS' + - 'iPad OS' + - 'Android' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 系统版本' + validations: + required: true + - type: dropdown + attributes: + label: '🌐 浏览器' + multiple: true + options: + - 'Chrome' + - 'Edge' + - 'Safari' + - 'Firefox' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 浏览器版本' + validations: + required: true + - type: textarea + attributes: + label: '🐛 问题描述' + description: 请提供一个清晰且简洁的问题描述,若上述选项为`Other`,也请详细说明。 + validations: + required: true + - type: textarea + attributes: + label: '📷 复现步骤' + description: 请提供一个清晰且简洁的描述,说明如何复现问题。 + - type: textarea + attributes: + label: '🚦 期望结果' + description: 请提供一个清晰且简洁的描述,说明您期望发生什么。 + - type: textarea + attributes: + label: '📝 补充信息' + description: 如果您的问题需要进一步说明,或者您遇到的问题无法在一个简单的示例中复现,请在这里添加更多信息。 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/2_feature_request.yml b/.github/ISSUE_TEMPLATE/2_feature_request.yml new file mode 100644 index 000000000..8576e8a83 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_feature_request.yml @@ -0,0 +1,21 @@ +name: '🌠 Feature Request' +description: 'Suggest an idea' +title: '[Feature Request] ' +labels: ['enhancement'] +body: + - type: textarea + attributes: + label: '🥰 Feature Description' + description: Please add a clear and concise description of the problem you are seeking to solve with this feature request. + validations: + required: true + - type: textarea + attributes: + label: '🧐 Proposed Solution' + description: Describe the solution you'd like in a clear and concise manner. + validations: + required: true + - type: textarea + attributes: + label: '📝 Additional Information' + description: Add any other context about the problem here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/2_feature_request_cn.yml b/.github/ISSUE_TEMPLATE/2_feature_request_cn.yml new file mode 100644 index 000000000..c7a3cc370 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_feature_request_cn.yml @@ -0,0 +1,21 @@ +name: '🌠 功能需求' +description: '提出需求或建议' +title: '[Feature Request] ' +labels: ['enhancement'] +body: + - type: textarea + attributes: + label: '🥰 需求描述' + description: 请添加一个清晰且简洁的问题描述,阐述您希望通过这个功能需求解决的问题。 + validations: + required: true + - type: textarea + attributes: + label: '🧐 解决方案' + description: 请清晰且简洁地描述您想要的解决方案。 + validations: + required: true + - type: textarea + attributes: + label: '📝 补充信息' + description: 在这里添加关于问题的任何其他背景信息。 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index bdba257d2..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,146 +0,0 @@ -name: Bug report -description: Create a report to help us improve -title: "[Bug] " -labels: ["bug"] - -body: - - type: markdown - attributes: - value: "## Describe the bug" - - type: textarea - id: bug-description - attributes: - label: "Bug Description" - description: "A clear and concise description of what the bug is." - placeholder: "Explain the bug..." - validations: - required: true - - - type: markdown - attributes: - value: "## To Reproduce" - - type: textarea - id: steps-to-reproduce - attributes: - label: "Steps to Reproduce" - description: "Steps to reproduce the behavior:" - placeholder: | - 1. Go to '...' - 2. Click on '....' - 3. Scroll down to '....' - 4. See error - validations: - required: true - - - type: markdown - attributes: - value: "## Expected behavior" - - type: textarea - id: expected-behavior - attributes: - label: "Expected Behavior" - description: "A clear and concise description of what you expected to happen." - placeholder: "Describe what you expected to happen..." - validations: - required: true - - - type: markdown - attributes: - value: "## Screenshots" - - type: textarea - id: screenshots - attributes: - label: "Screenshots" - description: "If applicable, add screenshots to help explain your problem." - placeholder: "Paste your screenshots here or write 'N/A' if not applicable..." - validations: - required: false - - - type: markdown - attributes: - value: "## Deployment" - - type: checkboxes - id: deployment - attributes: - label: "Deployment Method" - description: "Please select the deployment method you are using." - options: - - label: "Docker" - - label: "Vercel" - - label: "Server" - - - type: markdown - attributes: - value: "## Desktop (please complete the following information):" - - type: input - id: desktop-os - attributes: - label: "Desktop OS" - description: "Your desktop operating system." - placeholder: "e.g., Windows 10" - validations: - required: false - - type: input - id: desktop-browser - attributes: - label: "Desktop Browser" - description: "Your desktop browser." - placeholder: "e.g., Chrome, Safari" - validations: - required: false - - type: input - id: desktop-version - attributes: - label: "Desktop Browser Version" - description: "Version of your desktop browser." - placeholder: "e.g., 89.0" - validations: - required: false - - - type: markdown - attributes: - value: "## Smartphone (please complete the following information):" - - type: input - id: smartphone-device - attributes: - label: "Smartphone Device" - description: "Your smartphone device." - placeholder: "e.g., iPhone X" - validations: - required: false - - type: input - id: smartphone-os - attributes: - label: "Smartphone OS" - description: "Your smartphone operating system." - placeholder: "e.g., iOS 14.4" - validations: - required: false - - type: input - id: smartphone-browser - attributes: - label: "Smartphone Browser" - description: "Your smartphone browser." - placeholder: "e.g., Safari" - validations: - required: false - - type: input - id: smartphone-version - attributes: - label: "Smartphone Browser Version" - description: "Version of your smartphone browser." - placeholder: "e.g., 14" - validations: - required: false - - - type: markdown - attributes: - value: "## Additional Logs" - - type: textarea - id: additional-logs - attributes: - label: "Additional Logs" - description: "Add any logs about the problem here." - placeholder: "Paste any relevant logs here..." - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index 499781330..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Feature request -description: Suggest an idea for this project -title: "[Feature Request]: " -labels: ["enhancement"] - -body: - - type: markdown - attributes: - value: "## Is your feature request related to a problem? Please describe." - - type: textarea - id: problem-description - attributes: - label: Problem Description - description: "A clear and concise description of what the problem is. Example: I'm always frustrated when [...]" - placeholder: "Explain the problem you are facing..." - validations: - required: true - - - type: markdown - attributes: - value: "## Describe the solution you'd like" - - type: textarea - id: desired-solution - attributes: - label: Solution Description - description: A clear and concise description of what you want to happen. - placeholder: "Describe the solution you'd like..." - validations: - required: true - - - type: markdown - attributes: - value: "## Describe alternatives you've considered" - - type: textarea - id: alternatives-considered - attributes: - label: Alternatives Considered - description: A clear and concise description of any alternative solutions or features you've considered. - placeholder: "Describe any alternative solutions or features you've considered..." - validations: - required: false - - - type: markdown - attributes: - value: "## Additional context" - - type: textarea - id: additional-context - attributes: - label: Additional Context - description: Add any other context or screenshots about the feature request here. - placeholder: "Add any other context or screenshots about the feature request here..." - validations: - required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..3c4c90803 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,28 @@ +#### 💻 变更类型 | Change Type + + + +- [ ] feat +- [ ] fix +- [ ] refactor +- [ ] perf +- [ ] style +- [ ] test +- [ ] docs +- [ ] ci +- [ ] chore +- [ ] build + +#### 🔀 变更说明 | Description of Change + + + +#### 📝 补充信息 | Additional Information + + diff --git a/app/api/anthropic/[...path]/route.ts b/app/api/anthropic/[...path]/route.ts index 4621f5783..daaeb45b7 100644 --- a/app/api/anthropic/[...path]/route.ts +++ b/app/api/anthropic/[...path]/route.ts @@ -11,6 +11,7 @@ import { prettyObject } from "@/app/utils/format"; import { NextRequest, NextResponse } from "next/server"; import { auth } from "../../auth"; import { isModelAvailableInServer } from "@/app/utils/model"; +import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare"; const ALLOWD_PATH = new Set([Anthropic.ChatPath, Anthropic.ChatPath1]); @@ -114,7 +115,8 @@ async function request(req: NextRequest) { 10 * 60 * 1000, ); - const fetchUrl = `${baseUrl}${path}`; + // try rebuild url, when using cloudflare ai gateway in server + const fetchUrl = cloudflareAIGatewayUrl(`${baseUrl}${path}`); const fetchOptions: RequestInit = { headers: { @@ -164,17 +166,17 @@ async function request(req: NextRequest) { console.error(`[Anthropic] filter`, e); } } - console.log("[Anthropic request]", fetchOptions.headers, req.method); + // console.log("[Anthropic request]", fetchOptions.headers, req.method); try { const res = await fetch(fetchUrl, fetchOptions); - console.log( - "[Anthropic response]", - res.status, - " ", - res.headers, - res.url, - ); + // console.log( + // "[Anthropic response]", + // res.status, + // " ", + // res.headers, + // res.url, + // ); // to prevent browser prompt for credentials const newHeaders = new Headers(res.headers); newHeaders.delete("www-authenticate"); diff --git a/app/api/common.ts b/app/api/common.ts index ddd0722fc..125a46fdc 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -14,6 +14,7 @@ import prisma from "@/lib/prisma"; import { getTokenLength } from "@/lib/utils"; import { isModelAvailableInServer } from "../utils/model"; +import { cloudflareAIGatewayUrl } from "../utils/cloudflare"; const serverConfig = getServerSideConfig(); @@ -109,8 +110,10 @@ export async function requestOpenai( } } - const fetchUrl = `${baseUrl}/${path}`; + // const fetchUrl = `${baseUrl}/${path}`; const jsonBody = await req.json(); + const fetchUrl = cloudflareAIGatewayUrl(`${baseUrl}/${path}`); + console.log("fetchUrl", fetchUrl); const fetchOptions: RequestInit = { headers: { "Content-Type": "application/json", diff --git a/app/client/platforms/anthropic.ts b/app/client/platforms/anthropic.ts index 460e8f0bc..bf8faf837 100644 --- a/app/client/platforms/anthropic.ts +++ b/app/client/platforms/anthropic.ts @@ -12,6 +12,7 @@ import { import Locale from "../../locales"; import { prettyObject } from "@/app/utils/format"; import { getMessageTextContent, isVisionModel } from "@/app/utils"; +import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare"; export type MultiBlockContent = { type: "image" | "text"; @@ -375,7 +376,8 @@ export class ClaudeApi implements LLMApi { baseUrl = trimEnd(baseUrl, "/"); - return `${baseUrl}/${path}`; + // try rebuild url, when using cloudflare ai gateway in client + return cloudflareAIGatewayUrl(`${baseUrl}/${path}`); } } diff --git a/app/client/platforms/google.ts b/app/client/platforms/google.ts index 828b28a0d..6054c7a47 100644 --- a/app/client/platforms/google.ts +++ b/app/client/platforms/google.ts @@ -122,16 +122,13 @@ export class GeminiProApi implements LLMApi { const controller = new AbortController(); options.onController?.(controller); try { - // let baseUrl = accessStore.googleUrl; - - if (!baseUrl) { - baseUrl = isApp - ? DEFAULT_API_HOST + - "/api/proxy/google/" + - Google.ChatPath(modelConfig.model) - : this.path(Google.ChatPath(modelConfig.model)); + if (!baseUrl && isApp) { + baseUrl = DEFAULT_API_HOST + "/api/proxy/google/"; } - + baseUrl = `${baseUrl}/${Google.ChatPath(modelConfig.model)}`.replaceAll( + "//", + "/", + ); if (isApp) { baseUrl += `?key=${accessStore.googleApiKey}`; } diff --git a/app/client/platforms/openai.ts b/app/client/platforms/openai.ts index c35ec7cc2..83ce5e235 100644 --- a/app/client/platforms/openai.ts +++ b/app/client/platforms/openai.ts @@ -12,6 +12,7 @@ import { } from "@/app/constant"; import { useAccessStore, useAppConfig, useChatStore } from "@/app/store"; import { collectModelsWithDefaultModel } from "@/app/utils/model"; +import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare"; import { ChatOptions, @@ -95,7 +96,8 @@ export class ChatGPTApi implements LLMApi { console.log("[Proxy Endpoint] ", baseUrl, path); - return [baseUrl, path].join("/"); + // try rebuild url, when using cloudflare ai gateway in client + return cloudflareAIGatewayUrl([baseUrl, path].join("/")); } extractMessage(res: any) { diff --git a/app/components/chat.tsx b/app/components/chat.tsx index a114ee5fe..3d5c0130a 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -257,11 +257,11 @@ function useSubmitHandler() { }; } -export type RenderPompt = Pick; +export type RenderPrompt = Pick; export function PromptHints(props: { - prompts: RenderPompt[]; - onPromptSelect: (prompt: RenderPompt) => void; + prompts: RenderPrompt[]; + onPromptSelect: (prompt: RenderPrompt) => void; }) { const noPrompts = props.prompts.length === 0; const [selectIndex, setSelectIndex] = useState(0); @@ -784,7 +784,7 @@ function _Chat() { // prompt hints const promptStore = usePromptStore(); - const [promptHints, setPromptHints] = useState([]); + const [promptHints, setPromptHints] = useState([]); const onSearch = useDebouncedCallback( (text: string) => { const matchedPrompts = promptStore.search(text); @@ -873,7 +873,7 @@ function _Chat() { setAutoScroll(true); }; - const onPromptSelect = (prompt: RenderPompt) => { + const onPromptSelect = (prompt: RenderPrompt) => { setTimeout(() => { setPromptHints([]); diff --git a/app/constant.ts b/app/constant.ts index 14ac36999..5cdd1fe4b 100644 --- a/app/constant.ts +++ b/app/constant.ts @@ -36,6 +36,7 @@ export enum ApiPath { Azure = "/api/azure", OpenAI = "/api/openai", Anthropic = "/api/anthropic", + Google = "/api/google", Baidu = "/api/baidu", ByteDance = "/api/bytedance", Alibaba = "/api/alibaba", diff --git a/app/locales/cn.ts b/app/locales/cn.ts index f4fc4408c..43422873c 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -389,18 +389,18 @@ const cn = { }, Baidu: { ApiKey: { - Title: "接口密钥", + Title: "API Key", SubTitle: "使用自定义 Baidu API Key", Placeholder: "Baidu API Key", }, SecretKey: { - Title: "接口密钥", + Title: "Secret Key", SubTitle: "使用自定义 Baidu Secret Key", Placeholder: "Baidu Secret Key", }, Endpoint: { Title: "接口地址", - SubTitle: "样例:", + SubTitle: "不支持自定义前往.env配置", }, }, ByteDance: { diff --git a/app/locales/en.ts b/app/locales/en.ts index c3152901d..1c8d7686f 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -366,7 +366,7 @@ const en: LocaleType = { Endpoint: { Title: "Endpoint Address", - SubTitle: "Example:", + SubTitle: "Example: ", }, ApiVerion: { @@ -387,7 +387,7 @@ const en: LocaleType = { }, Endpoint: { Title: "Endpoint Address", - SubTitle: "Example:", + SubTitle: "not supported, configure in .env", }, }, ByteDance: { @@ -398,7 +398,7 @@ const en: LocaleType = { }, Endpoint: { Title: "Endpoint Address", - SubTitle: "Example:", + SubTitle: "Example: ", }, }, Alibaba: { @@ -409,7 +409,7 @@ const en: LocaleType = { }, Endpoint: { Title: "Endpoint Address", - SubTitle: "Example:", + SubTitle: "Example: ", }, }, CustomModel: { @@ -425,7 +425,7 @@ const en: LocaleType = { Endpoint: { Title: "Endpoint Address", - SubTitle: "Example:", + SubTitle: "Example: ", }, ApiVersion: { diff --git a/app/store/access.ts b/app/store/access.ts index 61d154b4b..253d414b9 100644 --- a/app/store/access.ts +++ b/app/store/access.ts @@ -12,15 +12,33 @@ import { DEFAULT_CONFIG } from "./config"; let fetchState = 0; // 0 not fetch, 1 fetching, 2 done -const DEFAULT_OPENAI_URL = - getClientConfig()?.buildMode === "export" - ? DEFAULT_API_HOST + "/api/proxy/openai" - : ApiPath.OpenAI; +const isApp = getClientConfig()?.buildMode === "export"; -const DEFAULT_AZURE_URL = - getClientConfig()?.buildMode === "export" - ? DEFAULT_API_HOST + "/api/proxy/azure/{resource_name}" - : ApiPath.Azure; +const DEFAULT_OPENAI_URL = isApp + ? DEFAULT_API_HOST + "/api/proxy/openai" + : ApiPath.OpenAI; + +const DEFAULT_GOOGLE_URL = isApp + ? DEFAULT_API_HOST + "/api/proxy/google" + : ApiPath.Google; + +const DEFAULT_ANTHROPIC_URL = isApp + ? DEFAULT_API_HOST + "/api/proxy/anthropic" + : ApiPath.Anthropic; + +const DEFAULT_BAIDU_URL = isApp + ? DEFAULT_API_HOST + "/api/proxy/baidu" + : ApiPath.Baidu; + +const DEFAULT_BYTEDANCE_URL = isApp + ? DEFAULT_API_HOST + "/api/proxy/bytedance" + : ApiPath.ByteDance; + +const DEFAULT_ALIBABA_URL = isApp + ? DEFAULT_API_HOST + "/api/proxy/alibaba" + : ApiPath.Alibaba; + +// console.log("DEFAULT_ANTHROPIC_URL", DEFAULT_ANTHROPIC_URL); const DEFAULT_ACCESS_STATE = { accessCode: "", @@ -33,32 +51,32 @@ const DEFAULT_ACCESS_STATE = { openaiApiKey: "", // azure - azureUrl: DEFAULT_AZURE_URL, + azureUrl: "", azureApiKey: "", azureApiVersion: "2023-05-15", azureVoiceKey: "", // google ai studio - googleUrl: "", + googleUrl: DEFAULT_GOOGLE_URL, googleApiKey: "", googleApiVersion: "v1", // anthropic + anthropicUrl: DEFAULT_ANTHROPIC_URL, anthropicApiKey: "", anthropicApiVersion: "2023-06-01", - anthropicUrl: "", // baidu - baiduUrl: "", + baiduUrl: DEFAULT_BAIDU_URL, baiduApiKey: "", baiduSecretKey: "", // bytedance + bytedanceUrl: DEFAULT_BYTEDANCE_URL, bytedanceApiKey: "", - bytedanceUrl: "", // alibaba - alibabaUrl: "", + alibabaUrl: DEFAULT_ALIBABA_URL, alibabaApiKey: "", // server config diff --git a/app/utils/cloudflare.ts b/app/utils/cloudflare.ts new file mode 100644 index 000000000..5094640fc --- /dev/null +++ b/app/utils/cloudflare.ts @@ -0,0 +1,26 @@ +export function cloudflareAIGatewayUrl(fetchUrl: string) { + // rebuild fetchUrl, if using cloudflare ai gateway + // document: https://developers.cloudflare.com/ai-gateway/providers/openai/ + + const paths = fetchUrl.split("/"); + if ("gateway.ai.cloudflare.com" == paths[2]) { + // is cloudflare.com ai gateway + // https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/azure-openai/{resource_name}/{deployment_name}/chat/completions?api-version=2023-05-15' + if ("azure-openai" == paths[6]) { + // is azure gateway + return paths.slice(0, 8).concat(paths.slice(-3)).join("/"); // rebuild ai gateway azure_url + } + // https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/openai/chat/completions + if ("openai" == paths[6]) { + // is openai gateway + return paths.slice(0, 7).concat(paths.slice(-2)).join("/"); // rebuild ai gateway openai_url + } + // https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/anthropic/v1/messages \ + if ("anthropic" == paths[6]) { + // is anthropic gateway + return paths.slice(0, 7).concat(paths.slice(-2)).join("/"); // rebuild ai gateway anthropic_url + } + // TODO: Amazon Bedrock, Groq, HuggingFace... + } + return fetchUrl; +} diff --git a/app/utils/model.ts b/app/utils/model.ts index a0b6f6630..663b3c109 100644 --- a/app/utils/model.ts +++ b/app/utils/model.ts @@ -1,9 +1,9 @@ import { DEFAULT_MODELS } from "../constant"; import { LLMModel } from "../client/api"; -const customProvider = (modelName: string) => ({ - id: modelName, - providerName: "Custom", +const customProvider = (providerName: string) => ({ + id: providerName.toLowerCase(), + providerName: providerName, providerType: "custom", }); @@ -72,10 +72,17 @@ export function collectModelTable( } // 2. if model not exists, create new model with available value if (count === 0) { - const provider = customProvider(name); - modelTable[`${name}@${provider?.id}`] = { - name, - displayName: displayName || name, + let [customModelName, customProviderName] = name.split("@"); + const provider = customProvider( + customProviderName || customModelName, + ); + // swap name and displayName for bytedance + if (displayName && provider.providerName == "ByteDance") { + [customModelName, displayName] = [displayName, customModelName]; + } + modelTable[`${customModelName}@${provider?.id}`] = { + name: customModelName, + displayName: displayName || customModelName, available, describe: "", provider, // Use optional chaining diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns index 131a0810a..0967ef466 100644 Binary files a/src-tauri/icons/icon.icns and b/src-tauri/icons/icon.icns differ diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 6230ba41f..f20bfbb74 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -9,7 +9,7 @@ }, "package": { "productName": "NextChat", - "version": "2.12.4" + "version": "2.13.0" }, "tauri": { "allowlist": { @@ -112,4 +112,4 @@ } ] } -} \ No newline at end of file +}