Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web
This commit is contained in:
commit
ca8e84702b
|
@ -11,6 +11,7 @@ import { prettyObject } from "@/app/utils/format";
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { auth } from "../../auth";
|
import { auth } from "../../auth";
|
||||||
import { isModelAvailableInServer } from "@/app/utils/model";
|
import { isModelAvailableInServer } from "@/app/utils/model";
|
||||||
|
import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare";
|
||||||
|
|
||||||
const ALLOWD_PATH = new Set([Anthropic.ChatPath, Anthropic.ChatPath1]);
|
const ALLOWD_PATH = new Set([Anthropic.ChatPath, Anthropic.ChatPath1]);
|
||||||
|
|
||||||
|
@ -114,7 +115,8 @@ async function request(req: NextRequest) {
|
||||||
10 * 60 * 1000,
|
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 = {
|
const fetchOptions: RequestInit = {
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -164,17 +166,17 @@ async function request(req: NextRequest) {
|
||||||
console.error(`[Anthropic] filter`, e);
|
console.error(`[Anthropic] filter`, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("[Anthropic request]", fetchOptions.headers, req.method);
|
// console.log("[Anthropic request]", fetchOptions.headers, req.method);
|
||||||
try {
|
try {
|
||||||
const res = await fetch(fetchUrl, fetchOptions);
|
const res = await fetch(fetchUrl, fetchOptions);
|
||||||
|
|
||||||
console.log(
|
// console.log(
|
||||||
"[Anthropic response]",
|
// "[Anthropic response]",
|
||||||
res.status,
|
// res.status,
|
||||||
" ",
|
// " ",
|
||||||
res.headers,
|
// res.headers,
|
||||||
res.url,
|
// res.url,
|
||||||
);
|
// );
|
||||||
// to prevent browser prompt for credentials
|
// to prevent browser prompt for credentials
|
||||||
const newHeaders = new Headers(res.headers);
|
const newHeaders = new Headers(res.headers);
|
||||||
newHeaders.delete("www-authenticate");
|
newHeaders.delete("www-authenticate");
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
ServiceProvider,
|
ServiceProvider,
|
||||||
} from "../constant";
|
} from "../constant";
|
||||||
import { isModelAvailableInServer } from "../utils/model";
|
import { isModelAvailableInServer } from "../utils/model";
|
||||||
|
import { cloudflareAIGatewayUrl } from "../utils/cloudflare";
|
||||||
|
|
||||||
const serverConfig = getServerSideConfig();
|
const serverConfig = getServerSideConfig();
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ export async function requestOpenai(req: NextRequest) {
|
||||||
);
|
);
|
||||||
|
|
||||||
let baseUrl =
|
let baseUrl =
|
||||||
serverConfig.azureUrl || serverConfig.baseUrl || OPENAI_BASE_URL;
|
(isAzure ? serverConfig.azureUrl : serverConfig.baseUrl) || OPENAI_BASE_URL;
|
||||||
|
|
||||||
if (!baseUrl.startsWith("http")) {
|
if (!baseUrl.startsWith("http")) {
|
||||||
baseUrl = `https://${baseUrl}`;
|
baseUrl = `https://${baseUrl}`;
|
||||||
|
@ -95,7 +96,8 @@ export async function requestOpenai(req: NextRequest) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchUrl = `${baseUrl}/${path}`;
|
const fetchUrl = cloudflareAIGatewayUrl(`${baseUrl}/${path}`);
|
||||||
|
console.log("fetchUrl", fetchUrl);
|
||||||
const fetchOptions: RequestInit = {
|
const fetchOptions: RequestInit = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ACCESS_CODE_PREFIX, Anthropic, ApiPath } from "@/app/constant";
|
import { ACCESS_CODE_PREFIX, Anthropic, ApiPath } from "@/app/constant";
|
||||||
import { ChatOptions, getHeaders, LLMApi, MultimodalContent, } from "../api";
|
import { ChatOptions, getHeaders, LLMApi, MultimodalContent } from "../api";
|
||||||
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
|
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
|
||||||
import { getClientConfig } from "@/app/config/client";
|
import { getClientConfig } from "@/app/config/client";
|
||||||
import { DEFAULT_API_HOST } from "@/app/constant";
|
import { DEFAULT_API_HOST } from "@/app/constant";
|
||||||
|
@ -12,6 +12,7 @@ import {
|
||||||
import Locale from "../../locales";
|
import Locale from "../../locales";
|
||||||
import { prettyObject } from "@/app/utils/format";
|
import { prettyObject } from "@/app/utils/format";
|
||||||
import { getMessageTextContent, isVisionModel } from "@/app/utils";
|
import { getMessageTextContent, isVisionModel } from "@/app/utils";
|
||||||
|
import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare";
|
||||||
|
|
||||||
export type MultiBlockContent = {
|
export type MultiBlockContent = {
|
||||||
type: "image" | "text";
|
type: "image" | "text";
|
||||||
|
@ -375,7 +376,8 @@ export class ClaudeApi implements LLMApi {
|
||||||
|
|
||||||
baseUrl = trimEnd(baseUrl, "/");
|
baseUrl = trimEnd(baseUrl, "/");
|
||||||
|
|
||||||
return `${baseUrl}/${path}`;
|
// try rebuild url, when using cloudflare ai gateway in client
|
||||||
|
return cloudflareAIGatewayUrl(`${baseUrl}/${path}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,16 +122,13 @@ export class GeminiProApi implements LLMApi {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
options.onController?.(controller);
|
options.onController?.(controller);
|
||||||
try {
|
try {
|
||||||
// let baseUrl = accessStore.googleUrl;
|
if (!baseUrl && isApp) {
|
||||||
|
baseUrl = DEFAULT_API_HOST + "/api/proxy/google/";
|
||||||
if (!baseUrl) {
|
|
||||||
baseUrl = isApp
|
|
||||||
? DEFAULT_API_HOST +
|
|
||||||
"/api/proxy/google/" +
|
|
||||||
Google.ChatPath(modelConfig.model)
|
|
||||||
: this.path(Google.ChatPath(modelConfig.model));
|
|
||||||
}
|
}
|
||||||
|
baseUrl = `${baseUrl}/${Google.ChatPath(modelConfig.model)}`.replaceAll(
|
||||||
|
"//",
|
||||||
|
"/",
|
||||||
|
);
|
||||||
if (isApp) {
|
if (isApp) {
|
||||||
baseUrl += `?key=${accessStore.googleApiKey}`;
|
baseUrl += `?key=${accessStore.googleApiKey}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
} from "@/app/constant";
|
} from "@/app/constant";
|
||||||
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
|
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
|
||||||
import { collectModelsWithDefaultModel } from "@/app/utils/model";
|
import { collectModelsWithDefaultModel } from "@/app/utils/model";
|
||||||
|
import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChatOptions,
|
ChatOptions,
|
||||||
|
@ -94,7 +95,8 @@ export class ChatGPTApi implements LLMApi {
|
||||||
|
|
||||||
console.log("[Proxy Endpoint] ", baseUrl, path);
|
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) {
|
extractMessage(res: any) {
|
||||||
|
|
|
@ -1195,8 +1195,7 @@ export function Settings() {
|
||||||
<ListItem
|
<ListItem
|
||||||
title={Locale.Settings.Access.Baidu.Endpoint.Title}
|
title={Locale.Settings.Access.Baidu.Endpoint.Title}
|
||||||
subTitle={
|
subTitle={
|
||||||
Locale.Settings.Access.Anthropic.Endpoint.SubTitle +
|
Locale.Settings.Access.Baidu.Endpoint.SubTitle
|
||||||
Baidu.ExampleEndpoint
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
|
|
@ -35,6 +35,7 @@ export enum ApiPath {
|
||||||
Azure = "/api/azure",
|
Azure = "/api/azure",
|
||||||
OpenAI = "/api/openai",
|
OpenAI = "/api/openai",
|
||||||
Anthropic = "/api/anthropic",
|
Anthropic = "/api/anthropic",
|
||||||
|
Google = "/api/google",
|
||||||
Baidu = "/api/baidu",
|
Baidu = "/api/baidu",
|
||||||
ByteDance = "/api/bytedance",
|
ByteDance = "/api/bytedance",
|
||||||
Alibaba = "/api/alibaba",
|
Alibaba = "/api/alibaba",
|
||||||
|
|
|
@ -349,18 +349,18 @@ const cn = {
|
||||||
},
|
},
|
||||||
Baidu: {
|
Baidu: {
|
||||||
ApiKey: {
|
ApiKey: {
|
||||||
Title: "接口密钥",
|
Title: "API Key",
|
||||||
SubTitle: "使用自定义 Baidu API Key",
|
SubTitle: "使用自定义 Baidu API Key",
|
||||||
Placeholder: "Baidu API Key",
|
Placeholder: "Baidu API Key",
|
||||||
},
|
},
|
||||||
SecretKey: {
|
SecretKey: {
|
||||||
Title: "接口密钥",
|
Title: "Secret Key",
|
||||||
SubTitle: "使用自定义 Baidu Secret Key",
|
SubTitle: "使用自定义 Baidu Secret Key",
|
||||||
Placeholder: "Baidu Secret Key",
|
Placeholder: "Baidu Secret Key",
|
||||||
},
|
},
|
||||||
Endpoint: {
|
Endpoint: {
|
||||||
Title: "接口地址",
|
Title: "接口地址",
|
||||||
SubTitle: "样例:",
|
SubTitle: "不支持自定义前往.env配置",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ByteDance: {
|
ByteDance: {
|
||||||
|
|
|
@ -347,7 +347,7 @@ const en: LocaleType = {
|
||||||
},
|
},
|
||||||
Endpoint: {
|
Endpoint: {
|
||||||
Title: "Endpoint Address",
|
Title: "Endpoint Address",
|
||||||
SubTitle: "Example:",
|
SubTitle: "not supported, configure in .env",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ByteDance: {
|
ByteDance: {
|
||||||
|
|
|
@ -4,11 +4,11 @@ import { SubmitKey } from "../store/config";
|
||||||
const isApp = !!getClientConfig()?.isApp;
|
const isApp = !!getClientConfig()?.isApp;
|
||||||
|
|
||||||
const tw = {
|
const tw = {
|
||||||
WIP: "該功能仍在開發中……",
|
WIP: "此功能仍在開發中……",
|
||||||
Error: {
|
Error: {
|
||||||
Unauthorized: isApp
|
Unauthorized: isApp
|
||||||
? "檢測到無效 API Key,請前往[設定](/#/settings)頁檢查 API Key 是否設定正確。"
|
? "偵測到無效的 API Key,請前往[設定](/#/settings)頁面檢查 API Key 是否設定正確。"
|
||||||
: "存取密碼不正確或未填寫,請前往[登入](/#/auth)頁輸入正確的存取密碼,或者在[設定](/#/settings)頁填入你自己的 OpenAI API Key。",
|
: "存取密碼不正確或尚未填寫,請前往[登入](/#/auth)頁面輸入正確的存取密碼,或者在[設定](/#/settings)頁面填入你自己的 OpenAI API Key。",
|
||||||
},
|
},
|
||||||
|
|
||||||
Auth: {
|
Auth: {
|
||||||
|
@ -159,7 +159,7 @@ const tw = {
|
||||||
},
|
},
|
||||||
InputTemplate: {
|
InputTemplate: {
|
||||||
Title: "使用者輸入預處理",
|
Title: "使用者輸入預處理",
|
||||||
SubTitle: "使用者最新的一條訊息會填充到此範本",
|
SubTitle: "使用者最新的一則訊息會填充到此範本",
|
||||||
},
|
},
|
||||||
|
|
||||||
Update: {
|
Update: {
|
||||||
|
@ -194,19 +194,19 @@ const tw = {
|
||||||
},
|
},
|
||||||
SyncType: {
|
SyncType: {
|
||||||
Title: "同步類型",
|
Title: "同步類型",
|
||||||
SubTitle: "選擇喜愛的同步伺服器",
|
SubTitle: "選擇偏好的同步伺服器",
|
||||||
},
|
},
|
||||||
Proxy: {
|
Proxy: {
|
||||||
Title: "啟用代理",
|
Title: "啟用代理伺服器",
|
||||||
SubTitle: "在瀏覽器中同步時,必須啟用代理以避免跨域限制",
|
SubTitle: "在瀏覽器中同步時,啟用代理伺服器以避免跨域限制",
|
||||||
},
|
},
|
||||||
ProxyUrl: {
|
ProxyUrl: {
|
||||||
Title: "代理地址",
|
Title: "代理伺服器位置",
|
||||||
SubTitle: "僅適用於本專案自帶的跨域代理",
|
SubTitle: "僅適用於本專案內建的跨域代理",
|
||||||
},
|
},
|
||||||
|
|
||||||
WebDav: {
|
WebDav: {
|
||||||
Endpoint: "WebDAV 地址",
|
Endpoint: "WebDAV 位置",
|
||||||
UserName: "使用者名稱",
|
UserName: "使用者名稱",
|
||||||
Password: "密碼",
|
Password: "密碼",
|
||||||
},
|
},
|
||||||
|
@ -218,9 +218,9 @@ const tw = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
LocalState: "本地資料",
|
LocalState: "本機資料",
|
||||||
Overview: (overview: any) => {
|
Overview: (overview: any) => {
|
||||||
return `${overview.chat} 次對話,${overview.message} 條訊息,${overview.prompt} 條提示詞,${overview.mask} 個角色範本`;
|
return `${overview.chat} 次對話,${overview.message} 則訊息,${overview.prompt} 條提示詞,${overview.mask} 個角色範本`;
|
||||||
},
|
},
|
||||||
ImportFailed: "匯入失敗",
|
ImportFailed: "匯入失敗",
|
||||||
},
|
},
|
||||||
|
@ -239,13 +239,13 @@ const tw = {
|
||||||
Title: "停用提示詞自動補齊",
|
Title: "停用提示詞自動補齊",
|
||||||
SubTitle: "在輸入框開頭輸入 / 即可觸發自動補齊",
|
SubTitle: "在輸入框開頭輸入 / 即可觸發自動補齊",
|
||||||
},
|
},
|
||||||
List: "自定義提示詞列表",
|
List: "自訂提示詞列表",
|
||||||
ListCount: (builtin: number, custom: number) =>
|
ListCount: (builtin: number, custom: number) =>
|
||||||
`內建 ${builtin} 條,使用者定義 ${custom} 條`,
|
`內建 ${builtin} 條,使用者自訂 ${custom} 條`,
|
||||||
Edit: "編輯",
|
Edit: "編輯",
|
||||||
Modal: {
|
Modal: {
|
||||||
Title: "提示詞列表",
|
Title: "提示詞列表",
|
||||||
Add: "新增一條",
|
Add: "新增一則",
|
||||||
Search: "搜尋提示詞",
|
Search: "搜尋提示詞",
|
||||||
},
|
},
|
||||||
EditModal: {
|
EditModal: {
|
||||||
|
@ -278,40 +278,40 @@ const tw = {
|
||||||
Placeholder: "請輸入存取密碼",
|
Placeholder: "請輸入存取密碼",
|
||||||
},
|
},
|
||||||
CustomEndpoint: {
|
CustomEndpoint: {
|
||||||
Title: "自定義介面 (Endpoint)",
|
Title: "自訂 API 端點 (Endpoint)",
|
||||||
SubTitle: "是否使用自定義 Azure 或 OpenAI 服務",
|
SubTitle: "是否使用自訂 Azure 或 OpenAI 服務",
|
||||||
},
|
},
|
||||||
Provider: {
|
Provider: {
|
||||||
Title: "模型服務商",
|
Title: "模型供應商",
|
||||||
SubTitle: "切換不同的服務商",
|
SubTitle: "切換不同的服務供應商",
|
||||||
},
|
},
|
||||||
OpenAI: {
|
OpenAI: {
|
||||||
ApiKey: {
|
ApiKey: {
|
||||||
Title: "API Key",
|
Title: "API Key",
|
||||||
SubTitle: "使用自定義 OpenAI Key 繞過密碼存取限制",
|
SubTitle: "使用自訂 OpenAI Key 繞過密碼存取限制",
|
||||||
Placeholder: "OpenAI API Key",
|
Placeholder: "OpenAI API Key",
|
||||||
},
|
},
|
||||||
|
|
||||||
Endpoint: {
|
Endpoint: {
|
||||||
Title: "介面(Endpoint) 地址",
|
Title: "API 端點 (Endpoint) 位址",
|
||||||
SubTitle: "除預設地址外,必須包含 http(s)://",
|
SubTitle: "除預設位址外,必須包含 http(s)://",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Azure: {
|
Azure: {
|
||||||
ApiKey: {
|
ApiKey: {
|
||||||
Title: "介面金鑰",
|
Title: "API 金鑰",
|
||||||
SubTitle: "使用自定義 Azure Key 繞過密碼存取限制",
|
SubTitle: "使用自訂 Azure Key 繞過密碼存取限制",
|
||||||
Placeholder: "Azure API Key",
|
Placeholder: "Azure API Key",
|
||||||
},
|
},
|
||||||
|
|
||||||
Endpoint: {
|
Endpoint: {
|
||||||
Title: "介面(Endpoint) 地址",
|
Title: "API 端點 (Endpoint) 位址",
|
||||||
SubTitle: "樣例:",
|
SubTitle: "範例:",
|
||||||
},
|
},
|
||||||
|
|
||||||
ApiVerion: {
|
ApiVerion: {
|
||||||
Title: "介面版本 (azure api version)",
|
Title: "API 版本 (azure api version)",
|
||||||
SubTitle: "選擇指定的部分版本",
|
SubTitle: "指定一個特定的 API 版本",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Anthropic: {
|
Anthropic: {
|
||||||
|
@ -322,13 +322,13 @@ const tw = {
|
||||||
},
|
},
|
||||||
|
|
||||||
Endpoint: {
|
Endpoint: {
|
||||||
Title: "終端地址",
|
Title: "端點位址",
|
||||||
SubTitle: "範例:",
|
SubTitle: "範例:",
|
||||||
},
|
},
|
||||||
|
|
||||||
ApiVerion: {
|
ApiVerion: {
|
||||||
Title: "API 版本 (claude api version)",
|
Title: "API 版本 (claude api version)",
|
||||||
SubTitle: "選擇一個特定的 API 版本輸入",
|
SubTitle: "指定一個特定的 API 版本",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Google: {
|
Google: {
|
||||||
|
@ -339,7 +339,7 @@ const tw = {
|
||||||
},
|
},
|
||||||
|
|
||||||
Endpoint: {
|
Endpoint: {
|
||||||
Title: "終端地址",
|
Title: "端點位址",
|
||||||
SubTitle: "範例:",
|
SubTitle: "範例:",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -349,8 +349,8 @@ const tw = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CustomModel: {
|
CustomModel: {
|
||||||
Title: "自定義模型名",
|
Title: "自訂模型名稱",
|
||||||
SubTitle: "增加自定義模型可選項,使用英文逗號隔開",
|
SubTitle: "增加自訂模型可選擇項目,使用英文逗號隔開",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -400,7 +400,7 @@ const tw = {
|
||||||
Context: {
|
Context: {
|
||||||
Toast: (x: any) => `已設定 ${x} 條前置上下文`,
|
Toast: (x: any) => `已設定 ${x} 條前置上下文`,
|
||||||
Edit: "前置上下文和歷史記憶",
|
Edit: "前置上下文和歷史記憶",
|
||||||
Add: "新增一條",
|
Add: "新增一則",
|
||||||
Clear: "上下文已清除",
|
Clear: "上下文已清除",
|
||||||
Revert: "恢復上下文",
|
Revert: "恢復上下文",
|
||||||
},
|
},
|
||||||
|
@ -425,16 +425,16 @@ const tw = {
|
||||||
EditModal: {
|
EditModal: {
|
||||||
Title: (readonly: boolean) =>
|
Title: (readonly: boolean) =>
|
||||||
`編輯預設角色範本 ${readonly ? "(唯讀)" : ""}`,
|
`編輯預設角色範本 ${readonly ? "(唯讀)" : ""}`,
|
||||||
Download: "下載預設",
|
Download: "下載預設值",
|
||||||
Clone: "複製預設",
|
Clone: "以此預設值建立副本",
|
||||||
},
|
},
|
||||||
Config: {
|
Config: {
|
||||||
Avatar: "角色頭像",
|
Avatar: "角色頭像",
|
||||||
Name: "角色名稱",
|
Name: "角色名稱",
|
||||||
Sync: {
|
Sync: {
|
||||||
Title: "使用全域性設定",
|
Title: "使用全域設定",
|
||||||
SubTitle: "目前對話是否使用全域性模型設定",
|
SubTitle: "目前對話是否使用全域模型設定",
|
||||||
Confirm: "目前對話的自定義設定將會被自動覆蓋,確認啟用全域性設定?",
|
Confirm: "目前對話的自訂設定將會被自動覆蓋,確認啟用全域設定?",
|
||||||
},
|
},
|
||||||
HideContext: {
|
HideContext: {
|
||||||
Title: "隱藏預設對話",
|
Title: "隱藏預設對話",
|
||||||
|
@ -450,15 +450,15 @@ const tw = {
|
||||||
NewChat: {
|
NewChat: {
|
||||||
Return: "返回",
|
Return: "返回",
|
||||||
Skip: "跳過",
|
Skip: "跳過",
|
||||||
NotShow: "不再呈現",
|
NotShow: "不再顯示",
|
||||||
ConfirmNoShow: "確認停用?停用後可以隨時在設定中重新啟用。",
|
ConfirmNoShow: "確認停用?停用後可以隨時在設定中重新啟用。",
|
||||||
Title: "挑選一個角色範本",
|
Title: "挑選一個角色範本",
|
||||||
SubTitle: "現在開始,與角色範本背後的靈魂思維碰撞",
|
SubTitle: "現在開始,與角色範本背後的靈魂思維碰撞",
|
||||||
More: "搜尋更多",
|
More: "搜尋更多",
|
||||||
},
|
},
|
||||||
URLCommand: {
|
URLCommand: {
|
||||||
Code: "檢測到連結中已經包含存取密碼,是否自動填入?",
|
Code: "偵測到連結中已經包含存取密碼,是否自動填入?",
|
||||||
Settings: "檢測到連結中包含了預設設定,是否自動填入?",
|
Settings: "偵測到連結中包含了預設設定,是否自動填入?",
|
||||||
},
|
},
|
||||||
UI: {
|
UI: {
|
||||||
Confirm: "確認",
|
Confirm: "確認",
|
||||||
|
|
|
@ -12,15 +12,33 @@ import { DEFAULT_CONFIG } from "./config";
|
||||||
|
|
||||||
let fetchState = 0; // 0 not fetch, 1 fetching, 2 done
|
let fetchState = 0; // 0 not fetch, 1 fetching, 2 done
|
||||||
|
|
||||||
const DEFAULT_OPENAI_URL =
|
const isApp = getClientConfig()?.buildMode === "export";
|
||||||
getClientConfig()?.buildMode === "export"
|
|
||||||
|
const DEFAULT_OPENAI_URL = isApp
|
||||||
? DEFAULT_API_HOST + "/api/proxy/openai"
|
? DEFAULT_API_HOST + "/api/proxy/openai"
|
||||||
: ApiPath.OpenAI;
|
: ApiPath.OpenAI;
|
||||||
|
|
||||||
const DEFAULT_AZURE_URL =
|
const DEFAULT_GOOGLE_URL = isApp
|
||||||
getClientConfig()?.buildMode === "export"
|
? DEFAULT_API_HOST + "/api/proxy/google"
|
||||||
? DEFAULT_API_HOST + "/api/proxy/azure/{resource_name}"
|
: ApiPath.Google;
|
||||||
: ApiPath.Azure;
|
|
||||||
|
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 = {
|
const DEFAULT_ACCESS_STATE = {
|
||||||
accessCode: "",
|
accessCode: "",
|
||||||
|
@ -33,31 +51,31 @@ const DEFAULT_ACCESS_STATE = {
|
||||||
openaiApiKey: "",
|
openaiApiKey: "",
|
||||||
|
|
||||||
// azure
|
// azure
|
||||||
azureUrl: DEFAULT_AZURE_URL,
|
azureUrl: "",
|
||||||
azureApiKey: "",
|
azureApiKey: "",
|
||||||
azureApiVersion: "2023-08-01-preview",
|
azureApiVersion: "2023-08-01-preview",
|
||||||
|
|
||||||
// google ai studio
|
// google ai studio
|
||||||
googleUrl: "",
|
googleUrl: DEFAULT_GOOGLE_URL,
|
||||||
googleApiKey: "",
|
googleApiKey: "",
|
||||||
googleApiVersion: "v1",
|
googleApiVersion: "v1",
|
||||||
|
|
||||||
// anthropic
|
// anthropic
|
||||||
|
anthropicUrl: DEFAULT_ANTHROPIC_URL,
|
||||||
anthropicApiKey: "",
|
anthropicApiKey: "",
|
||||||
anthropicApiVersion: "2023-06-01",
|
anthropicApiVersion: "2023-06-01",
|
||||||
anthropicUrl: "",
|
|
||||||
|
|
||||||
// baidu
|
// baidu
|
||||||
baiduUrl: "",
|
baiduUrl: DEFAULT_BAIDU_URL,
|
||||||
baiduApiKey: "",
|
baiduApiKey: "",
|
||||||
baiduSecretKey: "",
|
baiduSecretKey: "",
|
||||||
|
|
||||||
// bytedance
|
// bytedance
|
||||||
|
bytedanceUrl: DEFAULT_BYTEDANCE_URL,
|
||||||
bytedanceApiKey: "",
|
bytedanceApiKey: "",
|
||||||
bytedanceUrl: "",
|
|
||||||
|
|
||||||
// alibaba
|
// alibaba
|
||||||
alibabaUrl: "",
|
alibabaUrl: DEFAULT_ALIBABA_URL,
|
||||||
alibabaApiKey: "",
|
alibabaApiKey: "",
|
||||||
|
|
||||||
// server config
|
// server config
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
import { DEFAULT_MODELS } from "../constant";
|
import { DEFAULT_MODELS } from "../constant";
|
||||||
import { LLMModel } from "../client/api";
|
import { LLMModel } from "../client/api";
|
||||||
|
|
||||||
const customProvider = (modelName: string) => ({
|
const customProvider = (providerName: string) => ({
|
||||||
id: modelName,
|
id: providerName.toLowerCase(),
|
||||||
providerName: "Custom",
|
providerName: providerName,
|
||||||
providerType: "custom",
|
providerType: "custom",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -71,10 +71,17 @@ export function collectModelTable(
|
||||||
}
|
}
|
||||||
// 2. if model not exists, create new model with available value
|
// 2. if model not exists, create new model with available value
|
||||||
if (count === 0) {
|
if (count === 0) {
|
||||||
const provider = customProvider(name);
|
let [customModelName, customProviderName] = name.split("@");
|
||||||
modelTable[`${name}@${provider?.id}`] = {
|
const provider = customProvider(
|
||||||
name,
|
customProviderName || customModelName,
|
||||||
displayName: displayName || name,
|
);
|
||||||
|
// 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,
|
available,
|
||||||
provider, // Use optional chaining
|
provider, // Use optional chaining
|
||||||
};
|
};
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue