diff --git a/src/_locales/de/main.json b/src/_locales/de/main.json index 9e5df2a55..ad4a25d91 100644 --- a/src/_locales/de/main.json +++ b/src/_locales/de/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-Turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-Turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Benutzerdefiniertes Modell", @@ -132,7 +134,8 @@ "Generating...": "Generieren...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "Moonshot-Token erforderlich, bitte zuerst bei https://kimi.com anmelden und dann auf die Schaltfläche Wiederholen klicken", "Hide context menu of this extension": "Kontextmenü dieser Erweiterung ausblenden", - "Custom Claude API Url": "Benutzerdefinierte Claude-API-URL", + "Custom Anthropic API Url": "Benutzerdefinierte Anthropic-API-URL", + "Anthropic API Key": "Anthropic-API-Schlüssel", "Cancel": "Abbrechen", "Name is required": "Name ist erforderlich", "Prompt template should include {{selection}}": "Die Vorlage sollte {{selection}} enthalten", @@ -158,5 +161,41 @@ "Gemini (Web)": "Gemini (Web)", "Type": "Typ", "Mode": "Modus", - "Custom": "Benutzerdefiniert" + "Custom": "Benutzerdefiniert", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/en/main.json b/src/_locales/en/main.json index 44981fbcb..0bc75df81 100644 --- a/src/_locales/en/main.json +++ b/src/_locales/en/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Custom Model", @@ -132,7 +134,8 @@ "Generating...": "Generating...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "moonshot token required, please login at https://kimi.com first, and then click the retry button", "Hide context menu of this extension": "Hide context menu of this extension", - "Custom Claude API Url": "Custom Claude API Url", + "Custom Anthropic API Url": "Custom Anthropic API Url", + "Anthropic API Key": "Anthropic API Key", "Cancel": "Cancel", "Name is required": "Name is required", "Prompt template should include {{selection}}": "Prompt template should include {{selection}}", @@ -159,5 +162,41 @@ "Type": "Type", "Mode": "Mode", "Custom": "Custom", - "Crop Text to ensure the input tokens do not exceed the model's limit": "Crop Text to ensure the input tokens do not exceed the model's limit" + "Crop Text to ensure the input tokens do not exceed the model's limit": "Crop Text to ensure the input tokens do not exceed the model's limit", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/es/main.json b/src/_locales/es/main.json index f44525355..4ea2c2081 100644 --- a/src/_locales/es/main.json +++ b/src/_locales/es/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Modelo personalizado", @@ -132,7 +134,8 @@ "Generating...": "Generando...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "se requiere un token de moonshot, por favor inicie sesión en https://kimi.com primero, y luego haga clic en el botón Reintentar", "Hide context menu of this extension": "Ocultar menú contextual de esta extensión", - "Custom Claude API Url": "URL personalizada de la API de Claude", + "Custom Anthropic API Url": "URL personalizada de la API de Anthropic", + "Anthropic API Key": "Clave API de Anthropic", "Cancel": "Cancelar", "Name is required": "Se requiere un nombre", "Prompt template should include {{selection}}": "La plantilla de sugerencias debe incluir {{selection}}", @@ -158,5 +161,41 @@ "Gemini (Web)": "Gemini (Web)", "Type": "Tipo", "Mode": "Modo", - "Custom": "Personalizado" + "Custom": "Personalizado", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/fr/main.json b/src/_locales/fr/main.json index 7fbc4ecb0..e718e2a71 100644 --- a/src/_locales/fr/main.json +++ b/src/_locales/fr/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Modèle personnalisé", @@ -132,7 +134,8 @@ "Generating...": "Génération...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "jeton moonshot requis, veuillez vous connecter d'abord sur https://kimi.com, puis cliquez sur le bouton Réessayer", "Hide context menu of this extension": "Masquer le menu contextuel de cette extension", - "Custom Claude API Url": "URL API Claude personnalisée", + "Custom Anthropic API Url": "URL API Anthropic personnalisée", + "Anthropic API Key": "Clé API Anthropic", "Cancel": "Annuler", "Name is required": "Le nom est requis", "Prompt template should include {{selection}}": "Le modèle de suggestion doit inclure {{selection}}", @@ -158,5 +161,41 @@ "Gemini (Web)": "Gemini (Web)", "Type": "Type", "Mode": "Mode", - "Custom": "Personnalisé" + "Custom": "Personnalisé", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/in/main.json b/src/_locales/in/main.json index 69bc49bd3..0e19c9f09 100644 --- a/src/_locales/in/main.json +++ b/src/_locales/in/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Model Kustom", @@ -132,7 +134,8 @@ "Generating...": "Menghasilkan...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "diperlukan token moonshot, silakan masuk di https://kimi.com terlebih dahulu, lalu klik tombol coba lagi", "Hide context menu of this extension": "Sembunyikan menu konteks ekstensi ini", - "Custom Claude API Url": "URL API Claude Kustom", + "Custom Anthropic API Url": "URL API Anthropic Kustom", + "Anthropic API Key": "Kunci API Anthropic", "Cancel": "Batal", "Name is required": "Nama diperlukan", "Prompt template should include {{selection}}": "Template prompt harus mencakup {{selection}}", @@ -158,5 +161,41 @@ "Gemini (Web)": "Gemini (Web)", "Type": "Jenis", "Mode": "Mode", - "Custom": "Kustom" + "Custom": "Kustom", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/it/main.json b/src/_locales/it/main.json index 1b81c251e..60cf3f6db 100644 --- a/src/_locales/it/main.json +++ b/src/_locales/it/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Modello personalizzato", @@ -132,7 +134,8 @@ "Generating...": "Generazione...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "richiesto token moonshot, effettua il login su https://kimi.com prima, quindi fai clic sul pulsante Riprova", "Hide context menu of this extension": "Nascondi il menu contestuale di questa estensione", - "Custom Claude API Url": "URL API Claude personalizzato", + "Custom Anthropic API Url": "URL API Anthropic personalizzato", + "Anthropic API Key": "Chiave API Anthropic", "Cancel": "Annulla", "Name is required": "Il nome è obbligatorio", "Prompt template should include {{selection}}": "Il modello di prompt dovrebbe includere {{selection}}", @@ -158,5 +161,41 @@ "Gemini (Web)": "Gemini (Web)", "Type": "Tipo", "Mode": "Modalità", - "Custom": "Personalizzato" + "Custom": "Personalizzato", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/ja/main.json b/src/_locales/ja/main.json index 92d6c62fc..75010c900 100644 --- a/src/_locales/ja/main.json +++ b/src/_locales/ja/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "カスタムモデル", @@ -132,7 +134,8 @@ "Generating...": "生成中...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "moonshotトークンが必要です。最初に https://kimi.com にログインしてから、再試行ボタンをクリックしてください", "Hide context menu of this extension": "この拡張機能のコンテキストメニューを非表示", - "Custom Claude API Url": "カスタムClaude APIのURL", + "Custom Anthropic API Url": "カスタムAnthropic APIのURL", + "Anthropic API Key": "Anthropic API キー", "Cancel": "キャンセル", "Name is required": "名前は必須です", "Prompt template should include {{selection}}": "プロンプトテンプレートには {{selection}} を含める必要があります", @@ -158,5 +161,41 @@ "Gemini (Web)": "Gemini (Web)", "Type": "タイプ", "Mode": "モード", - "Custom": "カスタム" + "Custom": "カスタム", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/ko/main.json b/src/_locales/ko/main.json index 3f01a2d67..856614e48 100644 --- a/src/_locales/ko/main.json +++ b/src/_locales/ko/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "사용자 정의 모델", @@ -132,7 +134,8 @@ "Generating...": "생성 중...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "moonshot 토큰이 필요합니다. https://kimi.com 에서 로그인한 다음 재시도 버튼을 클릭하세요.", "Hide context menu of this extension": "이 확장 프로그램의 컨텍스트 메뉴 숨기기", - "Custom Claude API Url": "사용자 정의 Claude API URL", + "Custom Anthropic API Url": "사용자 정의 Anthropic API URL", + "Anthropic API Key": "Anthropic API 키", "Cancel": "취소", "Name is required": "이름은 필수입니다", "Prompt template should include {{selection}}": "프롬프트 템플릿에는 {{selection}} 이 포함되어야 합니다", @@ -158,5 +161,41 @@ "Gemini (Web)": "Gemini (웹)", "Type": "유형", "Mode": "모드", - "Custom": "사용자 정의" + "Custom": "사용자 정의", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/pt/main.json b/src/_locales/pt/main.json index 3cfc84274..c71da47b5 100644 --- a/src/_locales/pt/main.json +++ b/src/_locales/pt/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Modelo Personalizado", @@ -132,7 +134,8 @@ "Generating...": "Gerando...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "token moonshot necessário, faça login em https://kimi.com primeiro e depois clique no botão de tentar novamente", "Hide context menu of this extension": "Ocultar menu de contexto desta extensão", - "Custom Claude API Url": "URL da API Personalizada do Claude", + "Custom Anthropic API Url": "URL da API Personalizada do Anthropic", + "Anthropic API Key": "Chave API Anthropic", "Cancel": "Cancelar", "Name is required": "Nome é obrigatório", "Prompt template should include {{selection}}": "O modelo de prompt deve incluir {{selection}}", @@ -158,5 +161,41 @@ "Gemini (Web)": "Gemini (Web)", "Type": "Tipo", "Mode": "Modo", - "Custom": "Personalizado" + "Custom": "Personalizado", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/ru/main.json b/src/_locales/ru/main.json index 6e0ff84fe..45f233a50 100644 --- a/src/_locales/ru/main.json +++ b/src/_locales/ru/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (Веб, GPT-4)", "Bing (Web, GPT-4)": "Bing (Веб, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-турбо)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-турбо)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8к)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8к)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32к)", "GPT-3.5": "GPT-3.5", "Custom Model": "Пользовательская модель", @@ -132,7 +134,8 @@ "Generating...": "Генерация...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "требуется токен moonshot, пожалуйста, сначала войдите на https://kimi.com, а затем нажмите кнопку повтора", "Hide context menu of this extension": "Скрыть контекстное меню этого расширения", - "Custom Claude API Url": "Пользовательский URL API Claude", + "Custom Anthropic API Url": "Пользовательский URL API Anthropic", + "Anthropic API Key": "Ключ API Anthropic", "Cancel": "Отмена", "Name is required": "Имя обязательно", "Prompt template should include {{selection}}": "Шаблон запроса должен включать {{selection}}", @@ -158,5 +161,41 @@ "Gemini (Web)": "Gemini (Веб)", "Type": "Тип", "Mode": "Режим", - "Custom": "Пользовательский" + "Custom": "Пользовательский", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/tr/main.json b/src/_locales/tr/main.json index 99e1b3641..042879bc4 100644 --- a/src/_locales/tr/main.json +++ b/src/_locales/tr/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (Web, GPT-4)", "Bing (Web, GPT-4)": "Bing (Web, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "Özel Model", @@ -132,7 +134,8 @@ "Generating...": "Üretiliyor...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "moonshot jetonu gereklidir, lütfen önce https://kimi.com adresinde oturum açın ve ardından yeniden dene düğmesine tıklayın", "Hide context menu of this extension": "Bu uzantının bağlam menüsünü gizle", - "Custom Claude API Url": "Özel Claude API Url'si", + "Custom Anthropic API Url": "Özel Anthropic API Url'si", + "Anthropic API Key": "Anthropic API Anahtarı", "Cancel": "İptal", "Name is required": "İsim gereklidir", "Prompt template should include {{selection}}": "Prompt şablonu {{selection}} içermelidir", @@ -158,5 +161,41 @@ "Gemini (Web)": "Gemini (Web)", "Type": "Tür", "Mode": "Mod", - "Custom": "Özel" + "Custom": "Özel", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/zh-hans/main.json b/src/_locales/zh-hans/main.json index fd3263fb9..55d2446e4 100644 --- a/src/_locales/zh-hans/main.json +++ b/src/_locales/zh-hans/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (网页版, GPT-4)", "Bing (Web, GPT-4)": "Bing (网页版, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "自定义模型", @@ -132,7 +134,8 @@ "Generating...": "正在生成...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "请先登录Kimi: https://kimi.com, 然后点击重试按钮", "Hide context menu of this extension": "隐藏此扩展的右键菜单", - "Custom Claude API Url": "自定义的Claude API地址", + "Custom Anthropic API Url": "自定义的Anthropic API地址", + "Anthropic API Key": "Anthropic API 密钥", "Cancel": "取消", "Name is required": "名称是必须的", "Prompt template should include {{selection}}": "提示模板应该包含 {{selection}}", @@ -165,5 +168,41 @@ "ChatGLM (Emohaa)": "ChatGLM (Emohaa, 专业情绪咨询)", "ChatGLM (CharGLM-3)": "ChatGLM (CharGLM-3, 角色扮演)", "Crop Text to ensure the input tokens do not exceed the model's limit": "裁剪文本以确保输入token不超过模型限制", - "Thinking Content": "思考内容" + "Thinking Content": "思考内容", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/_locales/zh-hant/main.json b/src/_locales/zh-hant/main.json index 87b41242a..e1c7c603a 100644 --- a/src/_locales/zh-hant/main.json +++ b/src/_locales/zh-hant/main.json @@ -73,7 +73,9 @@ "ChatGPT (Web, GPT-4)": "ChatGPT (網頁版, GPT-4)", "Bing (Web, GPT-4)": "Bing (網頁版, GPT-4)", "ChatGPT (GPT-3.5-turbo)": "ChatGPT (GPT-3.5-turbo)", + "OpenAI (GPT-3.5-turbo)": "OpenAI (GPT-3.5-turbo)", "ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)", + "OpenAI (GPT-4-8k)": "OpenAI (GPT-4-8k)", "ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)", "GPT-3.5": "GPT-3.5", "Custom Model": "自訂模型", @@ -132,7 +134,8 @@ "Generating...": "產生中...", "moonshot token required, please login at https://kimi.com first, and then click the retry button": "需要 moonshot token,請先在 https://kimi.com 登入,然後點擊重試按鈕", "Hide context menu of this extension": "隱藏此擴充功能的右鍵選單", - "Custom Claude API Url": "自訂 Claude API 網址", + "Custom Anthropic API Url": "自訂 Anthropic API 網址", + "Anthropic API Key": "Anthropic API 金鑰", "Cancel": "取消", "Name is required": "名稱是必填的", "Prompt template should include {{selection}}": "提示範本應該包含 {{selection}}", @@ -160,5 +163,41 @@ "Mode": "模式", "Custom": "自訂", "Crop Text to ensure the input tokens do not exceed the model's limit": "裁剪文本以確保輸入token不超過模型限制", - "Thinking Content": "思考內容" + "Thinking Content": "思考內容", + "OpenAI (API)": "OpenAI (API)", + "Anthropic (API)": "Anthropic (API)", + "Azure OpenAI (API)": "Azure OpenAI (API)", + "OpenAI (GPT-3.5-turbo-16k)": "OpenAI (GPT-3.5-turbo-16k)", + "OpenAI (GPT-4o, 128k)": "OpenAI (GPT-4o, 128k)", + "OpenAI (GPT-4o mini)": "OpenAI (GPT-4o mini)", + "OpenAI (GPT-4-Turbo 128k)": "OpenAI (GPT-4-Turbo 128k)", + "OpenAI (GPT-4-Turbo 128k Preview)": "OpenAI (GPT-4-Turbo 128k Preview)", + "OpenAI (GPT-4-Turbo 128k 1106 Preview)": "OpenAI (GPT-4-Turbo 128k 1106 Preview)", + "OpenAI (GPT-4-Turbo 128k 0125 Preview)": "OpenAI (GPT-4-Turbo 128k 0125 Preview)", + "OpenAI (GPT-5 latest)": "OpenAI (GPT-5 latest)", + "OpenAI (GPT-5.1 latest)": "OpenAI (GPT-5.1 latest)", + "OpenAI (GPT-4.1)": "OpenAI (GPT-4.1)", + "OpenAI (GPT-4.1 mini)": "OpenAI (GPT-4.1 mini)", + "OpenAI (GPT-4.1 nano)": "OpenAI (GPT-4.1 nano)", + "Anthropic (Claude 3 Haiku)": "Anthropic (Claude 3 Haiku)", + "Anthropic (Claude 3.5 Haiku)": "Anthropic (Claude 3.5 Haiku)", + "Anthropic (Claude 3.7 Sonnet)": "Anthropic (Claude 3.7 Sonnet)", + "Anthropic (Claude Opus 4)": "Anthropic (Claude Opus 4)", + "Anthropic (Claude Opus 4.1)": "Anthropic (Claude Opus 4.1)", + "Anthropic (Claude Opus 4.5)": "Anthropic (Claude Opus 4.5)", + "Anthropic (Claude Opus 4.6)": "Anthropic (Claude Opus 4.6)", + "Anthropic (Claude Sonnet 4)": "Anthropic (Claude Sonnet 4)", + "Anthropic (Claude Sonnet 4.5)": "Anthropic (Claude Sonnet 4.5)", + "Anthropic (Claude Haiku 4.5)": "Anthropic (Claude Haiku 4.5)", + "OpenAI (GPT-3.5-turbo 1106)": "OpenAI (GPT-3.5-turbo 1106)", + "OpenAI (GPT-3.5-turbo 0125)": "OpenAI (GPT-3.5-turbo 0125)", + "OpenAI (GPT-4-8k 0613)": "OpenAI (GPT-4-8k 0613)", + "Azure OpenAI": "Azure OpenAI", + "OpenAI (GPT-5)": "OpenAI (GPT-5)", + "OpenAI (GPT-5.1)": "OpenAI (GPT-5.1)", + "OpenAI (GPT-5.2 latest)": "OpenAI (GPT-5.2 latest)", + "OpenAI (GPT-5.2)": "OpenAI (GPT-5.2)", + "OpenAI (GPT-5.3 latest)": "OpenAI (GPT-5.3 latest)", + "OpenAI (GPT-5.4)": "OpenAI (GPT-5.4)", + "Anthropic (Claude Sonnet 4.6)": "Anthropic (Claude Sonnet 4.6)" } diff --git a/src/background/index.mjs b/src/background/index.mjs index ec5092fde..7fcaa4286 100644 --- a/src/background/index.mjs +++ b/src/background/index.mjs @@ -6,7 +6,7 @@ import { } from '../services/apis/chatgpt-web' import { generateAnswersWithBingWebApi } from '../services/apis/bing-web.mjs' import { - generateAnswersWithChatgptApi, + generateAnswersWithOpenAiApi, generateAnswersWithGptCompletionApi, } from '../services/apis/openai-api' import { generateAnswersWithCustomApi } from '../services/apis/custom-api.mjs' @@ -64,7 +64,6 @@ const RECONNECT_CONFIG = { BACKOFF_MULTIPLIER: 2, // Multiplier for exponential backoff STABLE_CONNECT_RESET_DELAY_MS: 3000, // Reset retries only after connection stays stable } - function setPortProxy(port, proxyTabId) { try { console.debug(`[background] Attempting to connect to proxy tab: ${proxyTabId}`) @@ -509,10 +508,10 @@ async function executeApi(session, port, config) { const cookies = await getBardCookies() await generateAnswersWithBardWebApi(port, session.question, session, cookies) } else if (isUsingChatgptApiModel(session)) { - console.debug('[background] Using ChatGPT API Model') - await generateAnswersWithChatgptApi(port, session.question, session, config.apiKey) + console.debug('[background] Using OpenAI API Model') + await generateAnswersWithOpenAiApi(port, session.question, session, config.apiKey) } else if (isUsingClaudeApiModel(session)) { - console.debug('[background] Using Claude API Model') + console.debug('[background] Using Anthropic API Model') await generateAnswersWithClaudeApi(port, session.question, session) } else if (isUsingMoonshotApiModel(session)) { console.debug('[background] Using Moonshot API Model') diff --git a/src/config/index.mjs b/src/config/index.mjs index 42366aa2f..d425b78bf 100644 --- a/src/config/index.mjs +++ b/src/config/index.mjs @@ -166,11 +166,11 @@ export const ModelGroups = { chatgptApiModelKeys: { value: chatgptApiModelKeys, - desc: 'ChatGPT (API)', + desc: 'OpenAI (API)', }, claudeApiModelKeys: { value: claudeApiModelKeys, - desc: 'Claude.ai (API)', + desc: 'Anthropic (API)', }, moonshotApiModelKeys: { value: moonshotApiModelKeys, @@ -186,7 +186,7 @@ export const ModelGroups = { }, azureOpenAiApiModelKeys: { value: azureOpenAiApiModelKeys, - desc: 'ChatGPT (Azure API)', + desc: 'Azure OpenAI (API)', }, gptApiModelKeys: { value: gptApiModelKeys, @@ -230,85 +230,85 @@ export const Models = { chatgptPlus4: { value: 'gpt-4', desc: 'ChatGPT (Web, GPT-4)' }, chatgptPlus4Browsing: { value: 'gpt-4', desc: 'ChatGPT (Web, GPT-4)' }, // for compatibility - chatgptApi35: { value: 'gpt-3.5-turbo', desc: 'ChatGPT (GPT-3.5-turbo)' }, - chatgptApi35_16k: { value: 'gpt-3.5-turbo-16k', desc: 'ChatGPT (GPT-3.5-turbo-16k)' }, + chatgptApi35: { value: 'gpt-3.5-turbo', desc: 'OpenAI (GPT-3.5-turbo)' }, + chatgptApi35_16k: { value: 'gpt-3.5-turbo-16k', desc: 'OpenAI (GPT-3.5-turbo-16k)' }, - chatgptApi4o_128k: { value: 'gpt-4o', desc: 'ChatGPT (GPT-4o, 128k)' }, - chatgptApi4oMini: { value: 'gpt-4o-mini', desc: 'ChatGPT (GPT-4o mini)' }, - chatgptApi4_8k: { value: 'gpt-4', desc: 'ChatGPT (GPT-4-8k)' }, + chatgptApi4o_128k: { value: 'gpt-4o', desc: 'OpenAI (GPT-4o, 128k)' }, + chatgptApi4oMini: { value: 'gpt-4o-mini', desc: 'OpenAI (GPT-4o mini)' }, + chatgptApi4_8k: { value: 'gpt-4', desc: 'OpenAI (GPT-4-8k)' }, chatgptApi4_128k: { value: 'gpt-4-turbo', - desc: 'ChatGPT (GPT-4-Turbo 128k)', + desc: 'OpenAI (GPT-4-Turbo 128k)', }, chatgptApi4_128k_preview: { value: 'gpt-4-turbo-preview', - desc: 'ChatGPT (GPT-4-Turbo 128k Preview)', + desc: 'OpenAI (GPT-4-Turbo 128k Preview)', }, chatgptApi4_128k_1106_preview: { value: 'gpt-4-1106-preview', - desc: 'ChatGPT (GPT-4-Turbo 128k 1106 Preview)', + desc: 'OpenAI (GPT-4-Turbo 128k 1106 Preview)', }, chatgptApi4_128k_0125_preview: { value: 'gpt-4-0125-preview', - desc: 'ChatGPT (GPT-4-Turbo 128k 0125 Preview)', + desc: 'OpenAI (GPT-4-Turbo 128k 0125 Preview)', }, - chatgptApi5Latest: { value: 'gpt-5-chat-latest', desc: 'ChatGPT (ChatGPT-5 latest)' }, - chatgptApi5: { value: 'gpt-5', desc: 'ChatGPT (GPT-5)' }, - chatgptApi5_1Latest: { value: 'gpt-5.1-chat-latest', desc: 'ChatGPT (ChatGPT-5.1 latest)' }, - chatgptApi5_1: { value: 'gpt-5.1', desc: 'ChatGPT (GPT-5.1)' }, - chatgptApi5_2Latest: { value: 'gpt-5.2-chat-latest', desc: 'ChatGPT (ChatGPT-5.2 latest)' }, - chatgptApi5_2: { value: 'gpt-5.2', desc: 'ChatGPT (GPT-5.2)' }, - chatgptApi5_3Latest: { value: 'gpt-5.3-chat-latest', desc: 'ChatGPT (ChatGPT-5.3 latest)' }, - chatgptApi5_4: { value: 'gpt-5.4', desc: 'ChatGPT (GPT-5.4)' }, + chatgptApi5Latest: { value: 'gpt-5-chat-latest', desc: 'OpenAI (GPT-5 latest)' }, + chatgptApi5: { value: 'gpt-5', desc: 'OpenAI (GPT-5)' }, + chatgptApi5_1Latest: { value: 'gpt-5.1-chat-latest', desc: 'OpenAI (GPT-5.1 latest)' }, + chatgptApi5_1: { value: 'gpt-5.1', desc: 'OpenAI (GPT-5.1)' }, + chatgptApi5_2Latest: { value: 'gpt-5.2-chat-latest', desc: 'OpenAI (GPT-5.2 latest)' }, + chatgptApi5_2: { value: 'gpt-5.2', desc: 'OpenAI (GPT-5.2)' }, + chatgptApi5_3Latest: { value: 'gpt-5.3-chat-latest', desc: 'OpenAI (GPT-5.3 latest)' }, + chatgptApi5_4: { value: 'gpt-5.4', desc: 'OpenAI (GPT-5.4)' }, - chatgptApi4_1: { value: 'gpt-4.1', desc: 'ChatGPT (GPT-4.1)' }, - chatgptApi4_1_mini: { value: 'gpt-4.1-mini', desc: 'ChatGPT (GPT-4.1 mini)' }, - chatgptApi4_1_nano: { value: 'gpt-4.1-nano', desc: 'ChatGPT (GPT-4.1 nano)' }, + chatgptApi4_1: { value: 'gpt-4.1', desc: 'OpenAI (GPT-4.1)' }, + chatgptApi4_1_mini: { value: 'gpt-4.1-mini', desc: 'OpenAI (GPT-4.1 mini)' }, + chatgptApi4_1_nano: { value: 'gpt-4.1-nano', desc: 'OpenAI (GPT-4.1 nano)' }, claude2WebFree: { value: '', desc: 'Claude.ai (Web)' }, claude3HaikuApi: { value: 'claude-3-haiku-20240307', - desc: 'Claude.ai (API, Claude 3 Haiku)', + desc: 'Anthropic (Claude 3 Haiku)', }, claude35HaikuApi: { value: 'claude-3-5-haiku-20241022', - desc: 'Claude.ai (API, Claude 3.5 Haiku)', + desc: 'Anthropic (Claude 3.5 Haiku)', }, claude37SonnetApi: { value: 'claude-3-7-sonnet-20250219', - desc: 'Claude.ai (API, Claude 3.7 Sonnet)', + desc: 'Anthropic (Claude 3.7 Sonnet)', }, claudeOpus4Api: { value: 'claude-opus-4-20250514', - desc: 'Claude.ai (API, Claude Opus 4)', + desc: 'Anthropic (Claude Opus 4)', }, claudeOpus41Api: { value: 'claude-opus-4-1-20250805', - desc: 'Claude.ai (API, Claude Opus 4.1)', + desc: 'Anthropic (Claude Opus 4.1)', }, claudeOpus45Api: { value: 'claude-opus-4-5', - desc: 'Claude.ai (API, Claude Opus 4.5)', + desc: 'Anthropic (Claude Opus 4.5)', }, claudeOpus46Api: { value: 'claude-opus-4-6', - desc: 'Claude.ai (API, Claude Opus 4.6)', + desc: 'Anthropic (Claude Opus 4.6)', }, claudeSonnet4Api: { value: 'claude-sonnet-4-20250514', - desc: 'Claude.ai (API, Claude Sonnet 4)', + desc: 'Anthropic (Claude Sonnet 4)', }, claudeSonnet45Api: { value: 'claude-sonnet-4-5-20250929', - desc: 'Claude.ai (API, Claude Sonnet 4.5)', + desc: 'Anthropic (Claude Sonnet 4.5)', }, claudeSonnet46Api: { value: 'claude-sonnet-4-6', - desc: 'Claude.ai (API, Claude Sonnet 4.6)', + desc: 'Anthropic (Claude Sonnet 4.6)', }, claudeHaiku45Api: { value: 'claude-haiku-4-5-20251001', - desc: 'Claude.ai (API, Claude Haiku 4.5)', + desc: 'Anthropic (Claude Haiku 4.5)', }, bingFree4: { value: '', desc: 'Bing (Web, GPT-4)' }, @@ -331,15 +331,15 @@ export const Models = { chatgptFree35Mobile: { value: 'text-davinci-002-render-sha-mobile', desc: 'ChatGPT (Mobile)' }, chatgptPlus4Mobile: { value: 'gpt-4-mobile', desc: 'ChatGPT (Mobile, GPT-4)' }, - chatgptApi35_1106: { value: 'gpt-3.5-turbo-1106', desc: 'ChatGPT (GPT-3.5-turbo 1106)' }, - chatgptApi35_0125: { value: 'gpt-3.5-turbo-0125', desc: 'ChatGPT (GPT-3.5-turbo 0125)' }, - chatgptApi4_8k_0613: { value: 'gpt-4', desc: 'ChatGPT (GPT-4-8k 0613)' }, + chatgptApi35_1106: { value: 'gpt-3.5-turbo-1106', desc: 'OpenAI (GPT-3.5-turbo 1106)' }, + chatgptApi35_0125: { value: 'gpt-3.5-turbo-0125', desc: 'OpenAI (GPT-3.5-turbo 0125)' }, + chatgptApi4_8k_0613: { value: 'gpt-4', desc: 'OpenAI (GPT-4-8k 0613)' }, gptApiInstruct: { value: 'gpt-3.5-turbo-instruct', desc: 'GPT-3.5-turbo Instruct' }, customModel: { value: '', desc: 'Custom Model' }, ollamaModel: { value: '', desc: 'Ollama API' }, - azureOpenAi: { value: '', desc: 'ChatGPT (Azure)' }, + azureOpenAi: { value: '', desc: 'Azure OpenAI' }, waylaidwandererApi: { value: '', desc: 'Waylaidwanderer API (Github)' }, poeAiWebSage: { value: 'Assistant', desc: 'Poe AI (Web, Assistant)' }, @@ -513,7 +513,7 @@ export const defaultConfig = { poeCustomBotName: '', - claudeApiKey: '', + anthropicApiKey: '', chatglmApiKey: '', moonshotApiKey: '', deepSeekApiKey: '', @@ -543,7 +543,7 @@ export const defaultConfig = { customChatGptWebApiUrl: 'https://chatgpt.com', customChatGptWebApiPath: '/backend-api/conversation', customOpenAiApiUrl: 'https://api.openai.com', - customClaudeApiUrl: 'https://api.anthropic.com', + customAnthropicApiUrl: 'https://api.anthropic.com', disableWebModeHistory: true, hideContextMenu: false, cropText: true, @@ -759,9 +759,45 @@ export async function getPreferredLanguageKey() { * @returns {Promise} */ export async function getUserConfig() { - const options = await Browser.storage.local.get(Object.keys(defaultConfig)) + // Also fetch old keys for migration + const options = await Browser.storage.local.get([ + ...Object.keys(defaultConfig), + 'claudeApiKey', + 'customClaudeApiUrl', + ]) if (options.customChatGptWebApiUrl === 'https://chat.openai.com') options.customChatGptWebApiUrl = 'https://chatgpt.com' + + // Migrate legacy Claude-named keys to Anthropic-named keys. + // If both old/new keys coexist (for example after a partial migration), + // keep the Anthropic-named keys and clean up the legacy Claude-named keys. + if (options.claudeApiKey !== undefined) { + if (options.anthropicApiKey === undefined) { + options.anthropicApiKey = options.claudeApiKey + try { + await Browser.storage.local.set({ anthropicApiKey: options.claudeApiKey }) + await Browser.storage.local.remove('claudeApiKey') + } catch { + // Retry the legacy-key cleanup on the next config read. + } + } else { + await Browser.storage.local.remove('claudeApiKey').catch(() => {}) + } + } + if (options.customClaudeApiUrl !== undefined) { + if (options.customAnthropicApiUrl === undefined) { + options.customAnthropicApiUrl = options.customClaudeApiUrl + try { + await Browser.storage.local.set({ customAnthropicApiUrl: options.customClaudeApiUrl }) + await Browser.storage.local.remove('customClaudeApiUrl') + } catch { + // Retry the legacy-key cleanup on the next config read. + } + } else { + await Browser.storage.local.remove('customClaudeApiUrl').catch(() => {}) + } + } + return defaults(options, defaultConfig) } diff --git a/src/popup/sections/AdvancedPart.jsx b/src/popup/sections/AdvancedPart.jsx index 4149528bf..bfd211504 100644 --- a/src/popup/sections/AdvancedPart.jsx +++ b/src/popup/sections/AdvancedPart.jsx @@ -104,13 +104,13 @@ function ApiUrl({ config, updateConfig }) { /> diff --git a/src/popup/sections/GeneralPart.jsx b/src/popup/sections/GeneralPart.jsx index 30e6c20a4..11e72a408 100644 --- a/src/popup/sections/GeneralPart.jsx +++ b/src/popup/sections/GeneralPart.jsx @@ -30,6 +30,7 @@ import { languageList } from '../../config/language.mjs' import PropTypes from 'prop-types' import { config as menuConfig } from '../../content-script/menu-tools' import { PencilIcon } from '@primer/octicons-react' +import { importDataIntoStorage } from './import-data-cleanup.mjs' GeneralPart.propTypes = { config: PropTypes.object.isRequired, @@ -212,11 +213,11 @@ export function GeneralPart({ config, updateConfig, setTabIndex }) { { const apiKey = e.target.value - updateConfig({ claudeApiKey: apiKey }) + updateConfig({ anthropicApiKey: apiKey }) }} /> )} @@ -572,7 +573,7 @@ export function GeneralPart({ config, updateConfig, setTabIndex }) { reader.onload = (e) => resolve(JSON.parse(e.target.result)) reader.readAsText(file) }) - await Browser.storage.local.set(data) + await importDataIntoStorage(Browser.storage.local, data) window.location.reload() }} > diff --git a/src/popup/sections/import-data-cleanup.mjs b/src/popup/sections/import-data-cleanup.mjs new file mode 100644 index 000000000..19fbea4b6 --- /dev/null +++ b/src/popup/sections/import-data-cleanup.mjs @@ -0,0 +1,34 @@ +const conflictingKeyPairs = [ + ['claudeApiKey', 'anthropicApiKey'], + ['customClaudeApiUrl', 'customAnthropicApiUrl'], +] + +export function prepareImportData(data) { + const normalizedData = { ...data } + const keysToRemove = [] + + for (const [legacyKey, anthropicKey] of conflictingKeyPairs) { + const hasLegacyKey = Object.hasOwn(data, legacyKey) + const hasAnthropicKey = Object.hasOwn(data, anthropicKey) + + if (hasLegacyKey && !hasAnthropicKey) { + normalizedData[anthropicKey] = data[legacyKey] + keysToRemove.push(legacyKey) + } else if (hasAnthropicKey && !hasLegacyKey) { + normalizedData[legacyKey] = data[anthropicKey] + keysToRemove.push(legacyKey) + } + } + + return { normalizedData, keysToRemove } +} + +export async function importDataIntoStorage(storageArea, data) { + const { normalizedData, keysToRemove } = prepareImportData(data) + + await storageArea.set(normalizedData) + + if (keysToRemove.length > 0) { + await storageArea.remove(keysToRemove) + } +} diff --git a/src/services/apis/aiml-api.mjs b/src/services/apis/aiml-api.mjs index b1699052b..fb10be47b 100644 --- a/src/services/apis/aiml-api.mjs +++ b/src/services/apis/aiml-api.mjs @@ -1,4 +1,4 @@ -import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs' +import { generateAnswersWithOpenAiApiCompat } from './openai-api.mjs' /** * @param {Browser.Runtime.Port} port @@ -8,5 +8,5 @@ import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs' */ export async function generateAnswersWithAimlApi(port, question, session, apiKey) { const baseUrl = 'https://api.aimlapi.com/v1' - return generateAnswersWithChatgptApiCompat(baseUrl, port, question, session, apiKey) + return generateAnswersWithOpenAiApiCompat(baseUrl, port, question, session, apiKey) } diff --git a/src/services/apis/chatglm-api.mjs b/src/services/apis/chatglm-api.mjs index 8307c3c51..fa6899abe 100644 --- a/src/services/apis/chatglm-api.mjs +++ b/src/services/apis/chatglm-api.mjs @@ -1,6 +1,6 @@ import { getUserConfig } from '../../config/index.mjs' // import { getToken } from '../../utils/jwt-token-generator.mjs' -import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs' +import { generateAnswersWithOpenAiApiCompat } from './openai-api.mjs' /** * @param {Runtime.Port} port @@ -10,5 +10,5 @@ import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs' export async function generateAnswersWithChatGLMApi(port, question, session) { const baseUrl = 'https://open.bigmodel.cn/api/paas/v4' const config = await getUserConfig() - return generateAnswersWithChatgptApiCompat(baseUrl, port, question, session, config.chatglmApiKey) + return generateAnswersWithOpenAiApiCompat(baseUrl, port, question, session, config.chatglmApiKey) } diff --git a/src/services/apis/claude-api.mjs b/src/services/apis/claude-api.mjs index 9931e4e75..04a87fe2a 100644 --- a/src/services/apis/claude-api.mjs +++ b/src/services/apis/claude-api.mjs @@ -13,7 +13,7 @@ import { getModelValue } from '../../utils/model-name-convert.mjs' export async function generateAnswersWithClaudeApi(port, question, session) { const { controller, messageListener, disconnectListener } = setAbortController(port) const config = await getUserConfig() - const apiUrl = config.customClaudeApiUrl + const apiUrl = config.customAnthropicApiUrl const model = getModelValue(session) const prompt = getConversationPairs( @@ -29,7 +29,7 @@ export async function generateAnswersWithClaudeApi(port, question, session) { headers: { 'Content-Type': 'application/json', 'anthropic-version': '2023-06-01', - 'x-api-key': config.claudeApiKey, + 'x-api-key': config.anthropicApiKey, 'anthropic-dangerous-direct-browser-access': true, }, body: JSON.stringify({ diff --git a/src/services/apis/deepseek-api.mjs b/src/services/apis/deepseek-api.mjs index d0538ea15..9e91b97a8 100644 --- a/src/services/apis/deepseek-api.mjs +++ b/src/services/apis/deepseek-api.mjs @@ -1,4 +1,4 @@ -import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs' +import { generateAnswersWithOpenAiApiCompat } from './openai-api.mjs' /** * @param {Browser.Runtime.Port} port @@ -8,5 +8,5 @@ import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs' */ export async function generateAnswersWithDeepSeekApi(port, question, session, apiKey) { const baseUrl = 'https://api.deepseek.com' - return generateAnswersWithChatgptApiCompat(baseUrl, port, question, session, apiKey) + return generateAnswersWithOpenAiApiCompat(baseUrl, port, question, session, apiKey) } diff --git a/src/services/apis/moonshot-api.mjs b/src/services/apis/moonshot-api.mjs index c3cc187b3..157c3ecd4 100644 --- a/src/services/apis/moonshot-api.mjs +++ b/src/services/apis/moonshot-api.mjs @@ -1,4 +1,4 @@ -import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs' +import { generateAnswersWithOpenAiApiCompat } from './openai-api.mjs' /** * @param {Browser.Runtime.Port} port @@ -8,5 +8,5 @@ import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs' */ export async function generateAnswersWithMoonshotCompletionApi(port, question, session, apiKey) { const baseUrl = 'https://api.moonshot.cn/v1' - return generateAnswersWithChatgptApiCompat(baseUrl, port, question, session, apiKey) + return generateAnswersWithOpenAiApiCompat(baseUrl, port, question, session, apiKey) } diff --git a/src/services/apis/ollama-api.mjs b/src/services/apis/ollama-api.mjs index 2bf5753e6..01634fc64 100644 --- a/src/services/apis/ollama-api.mjs +++ b/src/services/apis/ollama-api.mjs @@ -1,5 +1,5 @@ import { getUserConfig } from '../../config/index.mjs' -import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs' +import { generateAnswersWithOpenAiApiCompat } from './openai-api.mjs' import { getModelValue } from '../../utils/model-name-convert.mjs' /** @@ -10,7 +10,7 @@ import { getModelValue } from '../../utils/model-name-convert.mjs' export async function generateAnswersWithOllamaApi(port, question, session) { const config = await getUserConfig() const model = getModelValue(session) - return generateAnswersWithChatgptApiCompat( + return generateAnswersWithOpenAiApiCompat( config.ollamaEndpoint + '/v1', port, question, diff --git a/src/services/apis/openai-api.mjs b/src/services/apis/openai-api.mjs index 752a2a21c..0131d8f7d 100644 --- a/src/services/apis/openai-api.mjs +++ b/src/services/apis/openai-api.mjs @@ -96,9 +96,9 @@ export async function generateAnswersWithGptCompletionApi(port, question, sessio * @param {Session} session * @param {string} apiKey */ -export async function generateAnswersWithChatgptApi(port, question, session, apiKey) { +export async function generateAnswersWithOpenAiApi(port, question, session, apiKey) { const config = await getUserConfig() - return generateAnswersWithChatgptApiCompat( + return generateAnswersWithOpenAiApiCompat( config.customOpenAiApiUrl + '/v1', port, question, @@ -109,7 +109,7 @@ export async function generateAnswersWithChatgptApi(port, question, session, api ) } -export async function generateAnswersWithChatgptApiCompat( +export async function generateAnswersWithOpenAiApiCompat( baseUrl, port, question, diff --git a/src/services/apis/openrouter-api.mjs b/src/services/apis/openrouter-api.mjs index 1fe9c8ad7..f514e1e29 100644 --- a/src/services/apis/openrouter-api.mjs +++ b/src/services/apis/openrouter-api.mjs @@ -1,4 +1,4 @@ -import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs' +import { generateAnswersWithOpenAiApiCompat } from './openai-api.mjs' /** * @param {Browser.Runtime.Port} port @@ -8,5 +8,5 @@ import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs' */ export async function generateAnswersWithOpenRouterApi(port, question, session, apiKey) { const baseUrl = 'https://openrouter.ai/api/v1' - return generateAnswersWithChatgptApiCompat(baseUrl, port, question, session, apiKey) + return generateAnswersWithOpenAiApiCompat(baseUrl, port, question, session, apiKey) } diff --git a/src/utils/model-name-convert.mjs b/src/utils/model-name-convert.mjs index 3f2062326..04eeb4226 100644 --- a/src/utils/model-name-convert.mjs +++ b/src/utils/model-name-convert.mjs @@ -18,7 +18,11 @@ export function modelNameToDesc(modelName, t, extraCustomModelName = '') { desc = `${t(Models[presetPart].desc)} (${t(ModelMode[customPart])})` else desc = `${t(Models[presetPart].desc)} (${customPart})` } else if (presetPart in ModelGroups) { - desc = `${t(ModelGroups[presetPart].desc)} (${customPart})` + const baseDesc = + presetPart === 'azureOpenAiApiModelKeys' + ? Models.azureOpenAi.desc + : ModelGroups[presetPart].desc + desc = `${t(baseDesc)} (${customPart})` } } return desc diff --git a/tests/setup/browser-shim.mjs b/tests/setup/browser-shim.mjs index 2685d46de..cd6d5380c 100644 --- a/tests/setup/browser-shim.mjs +++ b/tests/setup/browser-shim.mjs @@ -76,6 +76,17 @@ const storageLocal = { } return Promise.resolve() }, + remove(keys, callback) { + const keyList = Array.isArray(keys) ? keys : [keys] + for (const key of keyList) { + delete storageState[key] + } + if (typeof callback === 'function') { + queueMicrotask(() => callback()) + return + } + return Promise.resolve() + }, clear(callback) { storageState = createStorageState() if (typeof callback === 'function') { diff --git a/tests/unit/config/user-config.test.mjs b/tests/unit/config/user-config.test.mjs index 95a6b06b2..f22d73609 100644 --- a/tests/unit/config/user-config.test.mjs +++ b/tests/unit/config/user-config.test.mjs @@ -1,5 +1,6 @@ import assert from 'node:assert/strict' import { beforeEach, test } from 'node:test' +import Browser from 'webextension-polyfill' import { clearOldAccessToken, getUserConfig, setAccessToken } from '../../../src/config/index.mjs' const THIRTY_DAYS_MS = 30 * 24 * 3600 * 1000 @@ -28,6 +29,118 @@ test('getUserConfig keeps modern chatgpt.com URL unchanged', async () => { assert.equal(config.customChatGptWebApiUrl, 'https://chatgpt.com') }) +test('getUserConfig migrates legacy Claude keys to Anthropic keys and removes old keys', async () => { + globalThis.__TEST_BROWSER_SHIM__.replaceStorage({ + claudeApiKey: 'legacy-key', + customClaudeApiUrl: 'https://legacy.anthropic.example', + }) + + const config = await getUserConfig() + const storage = globalThis.__TEST_BROWSER_SHIM__.getStorage() + + assert.equal(config.anthropicApiKey, 'legacy-key') + assert.equal(config.customAnthropicApiUrl, 'https://legacy.anthropic.example') + assert.equal(storage.anthropicApiKey, 'legacy-key') + assert.equal(storage.customAnthropicApiUrl, 'https://legacy.anthropic.example') + assert.equal(Object.hasOwn(storage, 'claudeApiKey'), false) + assert.equal(Object.hasOwn(storage, 'customClaudeApiUrl'), false) +}) + +test('getUserConfig prefers Anthropic keys when both legacy and Anthropic keys exist', async () => { + globalThis.__TEST_BROWSER_SHIM__.replaceStorage({ + anthropicApiKey: 'new-key', + claudeApiKey: 'legacy-key', + customAnthropicApiUrl: 'https://new.anthropic.example', + customClaudeApiUrl: 'https://legacy.anthropic.example', + }) + + const config = await getUserConfig() + const storage = globalThis.__TEST_BROWSER_SHIM__.getStorage() + + assert.equal(config.anthropicApiKey, 'new-key') + assert.equal(config.customAnthropicApiUrl, 'https://new.anthropic.example') + assert.equal(storage.anthropicApiKey, 'new-key') + assert.equal(storage.customAnthropicApiUrl, 'https://new.anthropic.example') + assert.equal(Object.hasOwn(storage, 'claudeApiKey'), false) + assert.equal(Object.hasOwn(storage, 'customClaudeApiUrl'), false) +}) + +test('getUserConfig keeps Anthropic keys unchanged when legacy Claude keys are absent', async () => { + globalThis.__TEST_BROWSER_SHIM__.replaceStorage({ + anthropicApiKey: 'new-key', + customAnthropicApiUrl: 'https://new.anthropic.example', + }) + + const config = await getUserConfig() + const storage = globalThis.__TEST_BROWSER_SHIM__.getStorage() + + assert.equal(config.anthropicApiKey, 'new-key') + assert.equal(config.customAnthropicApiUrl, 'https://new.anthropic.example') + assert.equal(storage.anthropicApiKey, 'new-key') + assert.equal(storage.customAnthropicApiUrl, 'https://new.anthropic.example') + assert.equal(Object.hasOwn(storage, 'claudeApiKey'), false) + assert.equal(Object.hasOwn(storage, 'customClaudeApiUrl'), false) +}) + +test('getUserConfig returns migrated Anthropic values when storage.set fails', async (t) => { + globalThis.__TEST_BROWSER_SHIM__.replaceStorage({ + claudeApiKey: 'legacy-key', + customClaudeApiUrl: 'https://legacy.anthropic.example', + }) + + const removeCalls = [] + t.mock.method(Browser.storage.local, 'set', async () => { + throw new Error('quota exceeded') + }) + t.mock.method(Browser.storage.local, 'remove', async (key) => { + removeCalls.push(key) + }) + + const config = await getUserConfig() + const storage = globalThis.__TEST_BROWSER_SHIM__.getStorage() + + assert.equal(config.anthropicApiKey, 'legacy-key') + assert.equal(config.customAnthropicApiUrl, 'https://legacy.anthropic.example') + assert.equal(Object.hasOwn(storage, 'anthropicApiKey'), false) + assert.equal(Object.hasOwn(storage, 'customAnthropicApiUrl'), false) + assert.equal(storage.claudeApiKey, 'legacy-key') + assert.equal(storage.customClaudeApiUrl, 'https://legacy.anthropic.example') + assert.deepEqual(removeCalls, []) +}) + +test('getUserConfig returns migrated Anthropic values when storage.remove fails', async (t) => { + globalThis.__TEST_BROWSER_SHIM__.replaceStorage({ + claudeApiKey: 'legacy-key', + customClaudeApiUrl: 'https://legacy.anthropic.example', + }) + + const originalRemove = Browser.storage.local.remove + let removeCalls = 0 + t.mock.method(Browser.storage.local, 'remove', async (key) => { + removeCalls += 1 + if (removeCalls === 1) throw new Error('remove failed') + return originalRemove.call(Browser.storage.local, key) + }) + + const config = await getUserConfig() + let storage = globalThis.__TEST_BROWSER_SHIM__.getStorage() + + assert.equal(config.anthropicApiKey, 'legacy-key') + assert.equal(config.customAnthropicApiUrl, 'https://legacy.anthropic.example') + assert.equal(storage.anthropicApiKey, 'legacy-key') + assert.equal(storage.customAnthropicApiUrl, 'https://legacy.anthropic.example') + assert.equal(storage.claudeApiKey, 'legacy-key') + assert.equal(Object.hasOwn(storage, 'customClaudeApiUrl'), false) + + const nextConfig = await getUserConfig() + storage = globalThis.__TEST_BROWSER_SHIM__.getStorage() + + assert.equal(nextConfig.anthropicApiKey, 'legacy-key') + assert.equal(nextConfig.customAnthropicApiUrl, 'https://legacy.anthropic.example') + assert.equal(Object.hasOwn(storage, 'claudeApiKey'), false) + assert.equal(Object.hasOwn(storage, 'customClaudeApiUrl'), false) +}) + test('clearOldAccessToken clears expired token older than 30 days', async (t) => { const now = 1_700_000_000_000 t.mock.method(Date, 'now', () => now) diff --git a/tests/unit/popup/import-data-cleanup.test.mjs b/tests/unit/popup/import-data-cleanup.test.mjs new file mode 100644 index 000000000..d21639726 --- /dev/null +++ b/tests/unit/popup/import-data-cleanup.test.mjs @@ -0,0 +1,138 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import { + importDataIntoStorage, + prepareImportData, +} from '../../../src/popup/sections/import-data-cleanup.mjs' + +test('prepareImportData normalizes a legacy-only backup to Anthropic keys and removes legacy keys later', () => { + const { normalizedData, keysToRemove } = prepareImportData({ + claudeApiKey: 'legacy-key', + customClaudeApiUrl: 'https://legacy.anthropic.example', + }) + + assert.deepEqual(normalizedData, { + claudeApiKey: 'legacy-key', + anthropicApiKey: 'legacy-key', + customClaudeApiUrl: 'https://legacy.anthropic.example', + customAnthropicApiUrl: 'https://legacy.anthropic.example', + }) + assert.deepEqual(keysToRemove, ['claudeApiKey', 'customClaudeApiUrl']) +}) + +test('prepareImportData normalizes an Anthropic-only backup and still removes legacy keys later', () => { + const { normalizedData, keysToRemove } = prepareImportData({ + anthropicApiKey: 'new-key', + customAnthropicApiUrl: 'https://new.anthropic.example', + }) + + assert.deepEqual(normalizedData, { + claudeApiKey: 'new-key', + anthropicApiKey: 'new-key', + customClaudeApiUrl: 'https://new.anthropic.example', + customAnthropicApiUrl: 'https://new.anthropic.example', + }) + assert.deepEqual(keysToRemove, ['claudeApiKey', 'customClaudeApiUrl']) +}) + +test('prepareImportData resolves each conflicting field pair independently', () => { + const { normalizedData, keysToRemove } = prepareImportData({ + anthropicApiKey: 'new-key', + customClaudeApiUrl: 'https://legacy.anthropic.example', + }) + + assert.deepEqual(normalizedData, { + claudeApiKey: 'new-key', + anthropicApiKey: 'new-key', + customClaudeApiUrl: 'https://legacy.anthropic.example', + customAnthropicApiUrl: 'https://legacy.anthropic.example', + }) + assert.deepEqual(keysToRemove, ['claudeApiKey', 'customClaudeApiUrl']) +}) + +test('prepareImportData keeps imported values unchanged when both key families are already present', () => { + const input = { + anthropicApiKey: 'new-key', + claudeApiKey: 'legacy-key', + customAnthropicApiUrl: 'https://new.anthropic.example', + customClaudeApiUrl: 'https://legacy.anthropic.example', + } + const { normalizedData, keysToRemove } = prepareImportData(input) + + assert.deepEqual(normalizedData, input) + assert.deepEqual(keysToRemove, []) +}) + +test('prepareImportData leaves unrelated imports untouched', () => { + const { normalizedData, keysToRemove } = prepareImportData({ + apiKey: 'openai-key', + }) + + assert.deepEqual(normalizedData, { apiKey: 'openai-key' }) + assert.deepEqual(keysToRemove, []) +}) + +test('importDataIntoStorage writes normalized data before removing legacy keys', async () => { + const calls = [] + const storageArea = { + async set(data) { + calls.push(['set', data]) + }, + async remove(keys) { + calls.push(['remove', keys]) + }, + } + + await importDataIntoStorage(storageArea, { + claudeApiKey: 'legacy-key', + }) + + assert.deepEqual(calls, [ + ['set', { claudeApiKey: 'legacy-key', anthropicApiKey: 'legacy-key' }], + ['remove', ['claudeApiKey']], + ]) +}) + +test('importDataIntoStorage does not remove existing keys when set fails', async () => { + const calls = [] + const storageArea = { + async set() { + calls.push(['set']) + throw new Error('quota exceeded') + }, + async remove(keys) { + calls.push(['remove', keys]) + }, + } + + await assert.rejects(async () => { + await importDataIntoStorage(storageArea, { + claudeApiKey: 'legacy-key', + }) + }, /quota exceeded/) + + assert.deepEqual(calls, [['set']]) +}) + +test('importDataIntoStorage leaves normalized values in storage when remove fails after set', async () => { + const storageState = {} + const storageArea = { + async set(data) { + Object.assign(storageState, data) + }, + async remove() { + throw new Error('remove failed') + }, + } + + await assert.rejects(async () => { + await importDataIntoStorage(storageArea, { + anthropicApiKey: 'new-key', + }) + }, /remove failed/) + + assert.deepEqual(storageState, { + claudeApiKey: 'new-key', + anthropicApiKey: 'new-key', + }) +}) diff --git a/tests/unit/services/apis/openai-api-compat.test.mjs b/tests/unit/services/apis/openai-api-compat.test.mjs index 87834819a..89292f1b7 100644 --- a/tests/unit/services/apis/openai-api-compat.test.mjs +++ b/tests/unit/services/apis/openai-api-compat.test.mjs @@ -1,8 +1,8 @@ import assert from 'node:assert/strict' import { beforeEach, test } from 'node:test' import { - generateAnswersWithChatgptApi, - generateAnswersWithChatgptApiCompat, + generateAnswersWithOpenAiApi, + generateAnswersWithOpenAiApiCompat, generateAnswersWithGptCompletionApi, } from '../../../../src/services/apis/openai-api.mjs' import { createFakePort } from '../../helpers/port.mjs' @@ -29,7 +29,7 @@ beforeEach(() => { globalThis.__TEST_BROWSER_SHIM__.clearStorage() }) -test('generateAnswersWithChatgptApiCompat sends expected request and aggregates SSE deltas', async (t) => { +test('generateAnswersWithOpenAiApiCompat sends expected request and aggregates SSE deltas', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 3, @@ -55,7 +55,7 @@ test('generateAnswersWithChatgptApiCompat sends expected request and aggregates ]) }) - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', @@ -93,7 +93,7 @@ test('generateAnswersWithChatgptApiCompat sends expected request and aggregates assert.deepEqual(session.conversationRecords.at(-1), { question: 'CurrentQ', answer: 'Hello' }) }) -test('generateAnswersWithChatgptApiCompat uses max_completion_tokens for OpenAI latest gpt-5 compat models', async (t) => { +test('generateAnswersWithOpenAiApiCompat uses max_completion_tokens for OpenAI latest gpt-5 compat models', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 3, @@ -117,7 +117,7 @@ test('generateAnswersWithChatgptApiCompat uses max_completion_tokens for OpenAI } const port = createFakePort() - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', @@ -133,7 +133,7 @@ test('generateAnswersWithChatgptApiCompat uses max_completion_tokens for OpenAI } }) -test('generateAnswersWithChatgptApiCompat uses latest mapped gpt-5 API model values', async (t) => { +test('generateAnswersWithOpenAiApiCompat uses latest mapped gpt-5 API model values', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 3, @@ -157,7 +157,7 @@ test('generateAnswersWithChatgptApiCompat uses latest mapped gpt-5 API model val } const port = createFakePort() - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', @@ -174,7 +174,7 @@ test('generateAnswersWithChatgptApiCompat uses latest mapped gpt-5 API model val } }) -test('generateAnswersWithChatgptApi uses OpenAI token params for a latest mapped gpt-5 model', async (t) => { +test('generateAnswersWithOpenAiApi uses OpenAI token params for a latest mapped gpt-5 model', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ customOpenAiApiUrl: 'https://api.openai.example.com', @@ -200,7 +200,7 @@ test('generateAnswersWithChatgptApi uses OpenAI token params for a latest mapped ]) }) - await generateAnswersWithChatgptApi(port, 'CurrentQ', session, 'sk-test') + await generateAnswersWithOpenAiApi(port, 'CurrentQ', session, 'sk-test') const body = JSON.parse(capturedInit.body) assert.equal(capturedInput, 'https://api.openai.example.com/v1/chat/completions') @@ -209,7 +209,7 @@ test('generateAnswersWithChatgptApi uses OpenAI token params for a latest mapped assert.equal(Object.hasOwn(body, 'max_tokens'), false) }) -test('generateAnswersWithChatgptApiCompat keeps max_tokens for latest mapped gpt-5 models in compat provider', async (t) => { +test('generateAnswersWithOpenAiApiCompat keeps max_tokens for latest mapped gpt-5 models in compat provider', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 3, @@ -233,7 +233,7 @@ test('generateAnswersWithChatgptApiCompat keeps max_tokens for latest mapped gpt } const port = createFakePort() - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', @@ -250,7 +250,7 @@ test('generateAnswersWithChatgptApiCompat keeps max_tokens for latest mapped gpt } }) -test('generateAnswersWithChatgptApiCompat removes conflicting token key from extraBody', async (t) => { +test('generateAnswersWithOpenAiApiCompat removes conflicting token key from extraBody', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 3, @@ -273,7 +273,7 @@ test('generateAnswersWithChatgptApiCompat removes conflicting token key from ext ]) }) - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', @@ -291,7 +291,7 @@ test('generateAnswersWithChatgptApiCompat removes conflicting token key from ext assert.equal(body.top_p, 0.9) }) -test('generateAnswersWithChatgptApiCompat removes max_tokens from extraBody for OpenAI gpt-5 models', async (t) => { +test('generateAnswersWithOpenAiApiCompat removes max_tokens from extraBody for OpenAI gpt-5 models', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 3, @@ -315,7 +315,7 @@ test('generateAnswersWithChatgptApiCompat removes max_tokens from extraBody for } const port = createFakePort() - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', @@ -335,7 +335,7 @@ test('generateAnswersWithChatgptApiCompat removes max_tokens from extraBody for } }) -test('generateAnswersWithChatgptApiCompat allows max_tokens override for compat provider', async (t) => { +test('generateAnswersWithOpenAiApiCompat allows max_tokens override for compat provider', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 3, @@ -358,7 +358,7 @@ test('generateAnswersWithChatgptApiCompat allows max_tokens override for compat ]) }) - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', @@ -376,7 +376,7 @@ test('generateAnswersWithChatgptApiCompat allows max_tokens override for compat assert.equal(body.top_p, 0.75) }) -test('generateAnswersWithChatgptApiCompat allows max_completion_tokens override for OpenAI gpt-5 models', async (t) => { +test('generateAnswersWithOpenAiApiCompat allows max_completion_tokens override for OpenAI gpt-5 models', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 3, @@ -400,7 +400,7 @@ test('generateAnswersWithChatgptApiCompat allows max_completion_tokens override } const port = createFakePort() - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', @@ -420,7 +420,7 @@ test('generateAnswersWithChatgptApiCompat allows max_completion_tokens override } }) -test('generateAnswersWithChatgptApiCompat throws on non-ok response with JSON error body', async (t) => { +test('generateAnswersWithOpenAiApiCompat throws on non-ok response with JSON error body', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 3, @@ -445,7 +445,7 @@ test('generateAnswersWithChatgptApiCompat throws on non-ok response with JSON er ) await assert.rejects(async () => { - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', @@ -457,7 +457,7 @@ test('generateAnswersWithChatgptApiCompat throws on non-ok response with JSON er assert.deepEqual(port.listenerCounts(), { onMessage: 0, onDisconnect: 0 }) }) -test('generateAnswersWithChatgptApiCompat throws on network error', async (t) => { +test('generateAnswersWithOpenAiApiCompat throws on network error', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 3, @@ -477,7 +477,7 @@ test('generateAnswersWithChatgptApiCompat throws on network error', async (t) => }) await assert.rejects(async () => { - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', @@ -489,7 +489,7 @@ test('generateAnswersWithChatgptApiCompat throws on network error', async (t) => assert.deepEqual(port.listenerCounts(), { onMessage: 0, onDisconnect: 0 }) }) -test('generateAnswersWithChatgptApiCompat falls back to status text when JSON error parsing fails', async (t) => { +test('generateAnswersWithOpenAiApiCompat falls back to status text when JSON error parsing fails', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 3, @@ -516,7 +516,7 @@ test('generateAnswersWithChatgptApiCompat falls back to status text when JSON er ) await assert.rejects(async () => { - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', @@ -528,7 +528,7 @@ test('generateAnswersWithChatgptApiCompat falls back to status text when JSON er assert.deepEqual(port.listenerCounts(), { onMessage: 0, onDisconnect: 0 }) }) -test('generateAnswersWithChatgptApiCompat supports message.content fallback', async (t) => { +test('generateAnswersWithOpenAiApiCompat supports message.content fallback', async (t) => { t.mock.method(console, 'debug', () => {}) setStorage({ maxConversationContextLength: 2, @@ -549,7 +549,7 @@ test('generateAnswersWithChatgptApiCompat supports message.content fallback', as ]), ) - await generateAnswersWithChatgptApiCompat( + await generateAnswersWithOpenAiApiCompat( 'https://api.example.com/v1', port, 'CurrentQ', diff --git a/tests/unit/utils/model-name-convert.test.mjs b/tests/unit/utils/model-name-convert.test.mjs index 8601418a3..73e00dbf0 100644 --- a/tests/unit/utils/model-name-convert.test.mjs +++ b/tests/unit/utils/model-name-convert.test.mjs @@ -119,10 +119,10 @@ test('modelNameToDesc returns desc for a known model name without t function', ( }) test('modelNameToDesc returns desc for GPT-5 stable presets', () => { - assert.equal(modelNameToDesc('chatgptApi5'), 'ChatGPT (GPT-5)') - assert.equal(modelNameToDesc('chatgptApi5_1'), 'ChatGPT (GPT-5.1)') - assert.equal(modelNameToDesc('chatgptApi5_2'), 'ChatGPT (GPT-5.2)') - assert.equal(modelNameToDesc('chatgptApi5_4'), 'ChatGPT (GPT-5.4)') + assert.equal(modelNameToDesc('chatgptApi5'), 'OpenAI (GPT-5)') + assert.equal(modelNameToDesc('chatgptApi5_1'), 'OpenAI (GPT-5.1)') + assert.equal(modelNameToDesc('chatgptApi5_2'), 'OpenAI (GPT-5.2)') + assert.equal(modelNameToDesc('chatgptApi5_4'), 'OpenAI (GPT-5.4)') }) test('modelNameToDesc appends extraCustomModelName for customModel', () => { @@ -145,6 +145,15 @@ test('modelNameToDesc handles custom model with presetPart in ModelGroups', () = assert.equal(desc, 'Bing (Web) (customVariant)') }) +test('modelNameToDesc shows Azure OpenAI deployment without duplicate API label', () => { + const desc = modelNameToDesc('azureOpenAiApiModelKeys-deployment-a') + assert.equal(desc, 'Azure OpenAI (deployment-a)') +}) + +test('Azure OpenAI group label remains unchanged', () => { + assert.equal(ModelGroups.azureOpenAiApiModelKeys.desc, 'Azure OpenAI (API)') +}) + test('modelNameToCustomPart returns modelName when not custom', () => { assert.equal(modelNameToCustomPart('chatgptFree35'), 'chatgptFree35') })