From 2875f8f02e079d1dfcb6e8a796b54aaef14293f8 Mon Sep 17 00:00:00 2001 From: Bryan Lee <38807139+liby@users.noreply.github.com> Date: Wed, 4 Dec 2024 17:53:57 +0800 Subject: [PATCH] feat!: refactor service provider configuration BREAKING CHANGES: - Remove `deploymentName` and `apiVersion` options - Add `serviceProvider` option to support different service providers - Change API URL format requirements for different providers - Improve configuration validation for each provider Documentation: - Update configuration manuals with new options and examples - Add links to service provider documentation - Improve formatting and readability --- README.md | 41 ++++--- docs/README_EN.md | 40 ++++--- docs/configuration_manual_CN.md | 96 +++++++++++----- docs/configuration_manual_EN.md | 95 +++++++++++----- public/info.json | 48 ++++---- src/main.ts | 194 ++++++++++++++++++-------------- src/types.ts | 4 +- 7 files changed, 329 insertions(+), 189 deletions(-) diff --git a/README.md b/README.md index a1b9480..c96f679 100644 --- a/README.md +++ b/README.md @@ -24,25 +24,24 @@ > > 重要更新:非 macOS 用户可以使用我开发的基于 OpenAI API 的划词翻译浏览器插件 [openai-translator](https://github.com/yetone/openai-translator) 以解燃眉之急。 -## 演示 - -![](https://user-images.githubusercontent.com/1206493/221086195-f1ed941d-4dfa-4aa0-9d47-56c258a8f854.gif) - ## 简介 ChatGPT 向我们展示了 GPT 模型的伟大之处,所以我使用 OpenAI 的 API 实现了这个 Bob 的翻译 + 润色 + 语法修改插件,效果拔群! -### 润色功能 +
-此插件已支持使用 OpenAI API 对句子进行润色和语法修改,只需要把目标语言设置为与源语言一样即可,全面替代 Grammarly!而且理论上任何语言都可以润色,不仅仅是英语。 +演示 👀 -如果你不喜欢将翻译功能和文本润色功能放在一起,这里单独拆分出了一个专门用来文本润色和语法纠错的插件: [bob-plugin-openai-polisher](https://github.com/yetone/bob-plugin-openai-polisher),这个润色插件具有更高级的润色功能,比如解释修改原因等。 +![演示](https://user-images.githubusercontent.com/1206493/221086195-f1ed941d-4dfa-4aa0-9d47-56c258a8f854.gif) -### 语言模型 +
-要使用 ChatGPT 的 API 需要在 Bob 的设置页面把此插件的模型改为 `gpt-3.5-turbo-0301` 或者 `gpt-3.5-turbo`: -![how to use OpenAI API](https://user-images.githubusercontent.com/1206493/222339607-d8f05042-4b65-495c-af58-849891de7434.png) +### 润色功能 + +此插件已支持使用 OpenAI API 对句子进行润色和语法修改,只需要把目标语言设置为与源语言一样即可,全面替代 Grammarly!而且理论上任何语言都可以润色,不仅仅是英语。 + +如果你不喜欢将翻译功能和文本润色功能放在一起,这里单独拆分出了一个专门用来文本润色和语法纠错的插件: [bob-plugin-openai-polisher](https://github.com/openai-translator/bob-plugin-openai-polisher),这个润色插件具有更高级的润色功能,比如解释修改原因等。 ## 使用方法 @@ -50,21 +49,35 @@ ChatGPT 向我们展示了 GPT 模型的伟大之处,所以我使用 OpenAI 2. 下载此插件: [openai-translator.bobplugin](https://github.com/openai-translator/bob-plugin-openai-translator/releases/latest) -3. 安装此插件: +3.
+ + 安装此插件 👀 ![安装步骤](https://user-images.githubusercontent.com/1206493/219937302-6be8d362-1520-4906-b8d6-284d01012837.gif) +
+ 4. 去 [OpenAI](https://platform.openai.com/account/api-keys) 获取你的 API KEY 5. 把 API KEY 填入 Bob 偏好设置 > 服务 > 此插件配置界面的 API KEY 的输入框中 - 如果你想了解关于其他设置的更多信息,请查看[配置手册](./docs/configuration_manual_CN.md) - ![设置步骤](https://user-images.githubusercontent.com/1206493/219937398-8e5bb8d2-7dc8-404a-96e7-a937e08c939f.gif) +
+ + 演示 👀 + + ![设置步骤](https://user-images.githubusercontent.com/1206493/219937398-8e5bb8d2-7dc8-404a-96e7-a937e08c939f.gif) + +
+ + +6.
-6. 安装 [PopClip](https://bobtranslate.com/guide/integration/popclip.html) 实现划词后鼠标附近出现悬浮图标 + 安装 PopClip 实现划词后鼠标附近出现悬浮图标 👀 - ![PopClip](https://user-images.githubusercontent.com/1206493/219933584-d0c2b6cf-8fa0-40a6-858f-8f4bf05f38ef.gif) + [![PopClip](https://user-images.githubusercontent.com/1206493/219933584-d0c2b6cf-8fa0-40a6-858f-8f4bf05f38ef.gif)](https://bobtranslate.com/guide/integration/popclip.html) +
## 贡献 diff --git a/docs/README_EN.md b/docs/README_EN.md index f7cfb88..3c655b3 100644 --- a/docs/README_EN.md +++ b/docs/README_EN.md @@ -24,15 +24,17 @@ > > Important update: Non-macOS users can use my browser extension based on OpenAI API for word translation [openai-translator](https://github.com/yetone/openai-translator) to solve urgent needs. +## Introduction -## Demonstration +ChatGPT showcases the greatness of GPT models, so I have implemented the Bob translation + polishing + grammar modification plugin using OpenAI's API, with outstanding results! -![demo](https://user-images.githubusercontent.com/1206493/221086195-f1ed941d-4dfa-4aa0-9d47-56c258a8f854.gif) +
-""" -## Introduction +Demonstration 👀 -ChatGPT showcases the greatness of GPT models, so I have implemented the Bob translation + polishing + grammar modification plugin using OpenAI's API, with outstanding results! +![demo](https://user-images.githubusercontent.com/1206493/219937398-8e5bb8d2-7dc8-404a-96e7-a937e08c939f.gif) + +
### Polishing Feature @@ -40,33 +42,41 @@ This plugin supports polishing sentences and modifying grammar using the OpenAI If you don't like combining translation functionality and text polishing, a separate plugin specifically for text polishing and grammar correction is available: [bob-plugin-openai-polisher](https://github.com/yetone/bob-plugin-openai-polisher). This polishing plugin has more advanced polishing features, such as explaining the modification reasons, etc. -### Language Model - -To use the OpenAI API, go to Bob's settings page and change the plugin model to `gpt-3.5-turbo-0301` or `gpt-3.5-turbo`: - -![how to use OpenAI API](https://user-images.githubusercontent.com/1206493/222339607-d8f05042-4b65-495c-af58-849891de7434.png) - ## Usage 1. Install [Bob](https://bobtranslate.com/guide/#%E5%AE%89%E8%A3%85) (version >= 0.50), a macOS translation and OCR software 2. Download this plugin: [openai-translator.bobplugin](https://github.com/openai-translator/bob-plugin-openai-translator/releases/latest) -3. Install this plugin: +3.
- ![Installation Steps](https://user-images.githubusercontent.com/1206493/219937302-6be8d362-1520-4906-b8d6-284d01012837.gif) + Install this plugin 👀 + + ![Installation Steps](https://user-images.githubusercontent.com/1206493/219937302-6be8d362-1520-4906-b8d6-284d01012837.gif) + +
4. Get your API KEY from [OpenAI](https://platform.openai.com/account/api-keys) 5. Enter the API KEY in Bob Preferences > Services > This plugin configuration interface's API KEY input box: - If you would like to learn more about other settings, please refer to the [Configuration Manual](./docs/configuration_manual_EN.md) +
+ + Settings Steps 👀 + ![Settings Steps](https://user-images.githubusercontent.com/1206493/219937398-8e5bb8d2-7dc8-404a-96e7-a937e08c939f.gif) +
+ +6.
+ + Install PopClip for highlighted text mouse proximity floating icon 👀 + + [![PopClip](https://user-images.githubusercontent.com/1206493/219933584-d0c2b6cf-8fa0-40a6-858f-8f4bf05f38ef.gif)](https://bobtranslate.com/guide/integration/popclip.html) -6. Install [PopClip](https://bobtranslate.com/guide/integration/popclip.html) for highlighted text mouse proximity floating icon: +
- ![PopClip](https://user-images.githubusercontent.com/1206493/219933584-d0c2b6cf-8fa0-40a6-858f-8f4bf05f38ef.gif) ## Contributing diff --git a/docs/configuration_manual_CN.md b/docs/configuration_manual_CN.md index 38c9582..0a69755 100644 --- a/docs/configuration_manual_CN.md +++ b/docs/configuration_manual_CN.md @@ -1,80 +1,122 @@ ## 配置手册 -### 服务名称 +### 服务提供商 -- 可选项 -- 默认值: OpenAl Translator +- 必选项 -### API URL +- 默认值: OpenAI -- 可选项 -- 默认值: `https://api.openai.com` - 说明 - - 自定义 API URL 可以解决服务不稳定以及 IP 被封禁的问题,切换到反向代理服务来提高稳定性,并保护我们的 IP 地址不被 OpenAI 封禁 - - 或者是使用一些云服务商提供的 API 网关服务,比如 Cloudflare AI Gateway,除了可以代理 OpenAI 的 API 请求外,还额外增加了缓存、调用分析以及日志管理等功能 - - 将 API URL 设置为 `https://gateway.ai.cloudflare.com/v1/${ACCOUNT_TAG}/${GATEWAY}/openai` 即可体验 - - 更多信息请参阅 [Cloudflare AI Gateway 官方文档](https://developers.cloudflare.com/ai-gateway/) -### Dep. Name + - OpenAI: 使用 OpenAI 官方服务 -- 可选项 -- 默认值: 无 -- 说明 - - 当使用 Azure OpenAI Service 服务时,需要填写此项,具体步骤可参阅 [Azure OpenAI 翻译设置](https://bobtranslate.com/service/translate/azureopenai.html) - - [🔗 Azure OpenAI Service 官方文档](https://learn.microsoft.com/zh-cn/azure/cognitive-services/openai/chatgpt-quickstart?tabs=command-line&pivots=rest-api) + - Azure OpenAI: 使用 [Azure OpenAI Service](https://learn.microsoft.com/zh-cn/azure/ai-services/Translator/quickstart-text-rest-api) -### API Version + - Custom: 使用自定义服务,如 [Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/) 或者 [Ollama](https://ollama.com/blog/openai-compatibility) 等服务商 + + +### API URL + +- 可选项(OpenAI)/ 必填项(Azure OpenAI 和 Custom) -- 可选项 - 默认值: 无 + - 说明 - - 当使用 Azure OpenAI Service 服务时,需要填写此项,具体步骤可参阅 [Azure OpenAI 翻译设置](https://bobtranslate.com/service/translate/azureopenai.html) - - [🔗 Azure OpenAI Service 官方文档](https://learn.microsoft.com/zh-cn/azure/cognitive-services/openai/chatgpt-quickstart?tabs=command-line&pivots=rest-api) + + - OpenAI: 可选,默认为: `https://api.openai.com` + + - Azure OpenAI: 必填,完整的 API URL,格式为: + + ``` + https://YOUR_RESOURCE_NAME.openai.azure.com/openai/deployments/YOUR_DEPLOYMENT_NAME/chat/completions?api-version=API_VERSION + ``` + + - Custom: 必填,值为完整的 API URL,例如使用 Cloudflare AI Gateway 时,需填入: + + ``` + https://gateway.ai.cloudflare.com/v1/${CLOUDFLARE_ACCOUNT_ID}/${GATEWAY_ID}/openai/chat/completions + ``` ### API KEY - 必填项 + - 默认值: 无 + - 说明 + - 可使用英文逗号分割多个账号下不同的 API KEY 以实现额度加倍及负载均衡 ### 模型 - 必选项 -- 默认值: `gpt-3.5-turbo-1106` + +- 默认值: `gpt-3.5-turbo` + - 说明 + - 选择 `custom` 时,需要设置 `自定义模型` 配置项 ### 自定义模型 - 可选项 + - 默认值: `gpt-3.5-turbo` + - 说明 + - 联动项,当 `模型` 配置选择 `custom` 时,会读取此配置项设置的模型 ### 系统指令 - 可选项 + - 默认值: `You are a translation engine that can only translate text and cannot interpret it.` + - 说明 + - 自定义 System Prompt,填写则会覆盖默认的 System Prompt + - 自定义 Prompt可使用以下变量: - 1. `$text`:需要翻译的文本,即翻译窗口输入框内的文本 - 2. `$sourceLang`:-原文语言, 即翻译窗口输入框内文本的语言,比如「简体中文」 - 3. `$targetLang`:目标语言,即需要翻译成的语言,可以在翻译窗口中手动选择或自动检测,比如「English」 + + 1. `$text`:需要翻译的文本,即翻译窗口输入框内的文本 + + 2. `$sourceLang`:原文语言,即翻译窗口输入框内文本的语言,比如「简体中文」 + + 3. `$targetLang`:目标语言,即需要翻译成的语言,可以在翻译窗口中手动选择或自动检测,比如「English」 ### 用户指令 - 可选项 -- 默认值: `translate from $sourceLang to $targetLang:/n/n $text` + +- 默认值: `translate from $sourceLang to $targetLang:\n\n$text` + - 说明 + - 自定义 User Prompt,填写则会覆盖默认的 User Prompt + - 可以使用与系统指令中相同的变量 +### 流式输出 + +- 可选项 + +- 默认值: `Enable` + +- 说明 + + - 启用后翻译结果会实时显示 + + - 禁用后会等待翻译完成后一次性显示 + ### 温度 - 可选项 + - 默认值: `0.2` + - 说明 - - 温度值越高,生成的文本越随机,更有创意。 - - 翻译任务建议设置在 `0.2` 左右,润色任务可以适当调高,如果需要严谨性,可以设置为 `0`。 + + - 温度值越高,生成的文本越随机,更有创意 + + - 翻译任务建议设置在 `0.2` 左右,润色任务可以适当调高,如果需要严谨性,可以设置为 `0` diff --git a/docs/configuration_manual_EN.md b/docs/configuration_manual_EN.md index f2df3ce..0ff3fc8 100644 --- a/docs/configuration_manual_EN.md +++ b/docs/configuration_manual_EN.md @@ -1,80 +1,123 @@ ## Configuration Manual -### Service Name +### Service Provider -- Optional -- Default value: OpenAI Translator +- Required -### API URL +- Default value: OpenAI -- Optional -- Default value: `https://api.openai.com` - Description - - Customizing the API URL can address issues of service instability and IP bans by switching to a reverse proxy service to enhance stability and protect our IP address from being banned by OpenAI. - - Alternatively, using API gateway services provided by cloud vendors, such as Cloudflare AI Gateway, not only proxies OpenAI API requests but also adds extra features like caching, call analytics, and log management. - - Set the API URL to `https://gateway.ai.cloudflare.com/v1/${ACCOUNT_TAG}/${GATEWAY}/openai` to experience it. - - For more information, please refer to [Cloudflare AI Gateway Official Documentation](https://developers.cloudflare.com/ai-gateway/). -### Dep. Name + - OpenAI: Use official OpenAI service -- Optional -- Default value: None -- Description - - This field must be filled in when using the Azure OpenAI Service, for specific steps, please refer to [Azure OpenAI Translation Settings](https://bobtranslate.com/service/translate/azureopenai.html) - - [🔗 Official Azure OpenAI Service Documentation](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/chatgpt-quickstart?tabs=command-line&pivots=rest-api) + - Azure OpenAI: Use [Azure OpenAI Service](https://learn.microsoft.com/zh-cn/azure/ai-services/Translator/quickstart-text-rest-api) -### API Version + - Custom: Use custom service, such as [Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/) or [Ollama](https://ollama.com/blog/openai-compatibility) + +### API URL + +- Optional (OpenAI) / Required (Azure OpenAI and Custom) -- Optional - Default value: None + - Description - - This field must be filled in when using the Azure OpenAI Service, for specific steps, please refer to [Azure OpenAI Translation Settings](https://bobtranslate.com/service/translate/azureopenai.html) - - [🔗 Official Azure OpenAI Service Documentation](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/chatgpt-quickstart?tabs=command-line&pivots=rest-api) + + - OpenAI: Optional, default value: `https://api.openai.com` + + - Azure OpenAI: Required, complete API URL in format: + + ``` + https://RESOURCE_NAME.openai.azure.com/openai/deployments/DEPLOYMENT_NAME/chat/completions?api-version=API_VERSION + ``` + + - For more information, please refer to [Cloudflare AI Gateway Official Documentation](https://developers.cloudflare.com/ai-gateway/). + + - Custom: Required, complete API URL, for example when using Cloudflare AI Gateway: + + ``` + https://gateway.ai.cloudflare.com/v1/${CLOUDFLARE_ACCOUNT_ID}/${GATEWAY_ID}/openai/chat/completions + ``` ### API KEY -- Mandatory +- Required + - Default value: None + - Description + - Multiple API KEYS under different accounts can be separated by commas to achieve quota doubling and load balancing ### Model -- Mandatory -- Default value: `gpt-3.5-turbo-1106` +- Required + +- Default value: `gpt-3.5-turbo` + - Description + - When selecting `custom`, the `Custom Model` configuration item needs to be set ### Custom Model - Optional + - Default value: `gpt-3.5-turbo` + - Description + - A linked item, when the `Model` configuration selects `custom`, this configuration item's model will be read ### System Prompt - Optional + - Default value: `You are a translation engine that can only translate text and cannot interpret it.` + - Description + - Customize System Prompt, filling this will override the default System Prompt + - Custom Prompt can use the following variables: + 1. `$text`: the text to be translated, i.e., the text in the translation window input box + 2. `$sourceLang`: the source language, i.e., the language of the text in the translation window input box, such as "Simplified Chinese" + 3. `$targetLang`: the target language, i.e., the language into which the text is to be translated, which can be manually selected or automatically detected in the translation window, such as "English" ### User Prompt - Optional -- Default value: `translate from $sourceLang to $targetLang:/n/n $text` + +- Default value: `translate from $sourceLang to $targetLang:\n\n$text` + - Description + - Customize User Prompt, filling this will override the default User Prompt + - Can use the same variables as in the system command +### Stream Output + +- Optional + +- Default value: Enable + +- Description + + - When enabled, translation results will be displayed in real-time + + - When disabled, results will be displayed all at once after translation is complete + ### Temperature - Optional + - Default value: `0.2` + - Description - - The higher the temperature value, the more random and creative the generated text will be. - - For translation tasks, it is recommended to set around `0.2`; for polishing tasks, it can be appropriately increased. If accuracy is highly required, it can be set to `0`. + + - The higher the temperature value, the more random and creative the generated text will be + + - For translation tasks, it is recommended to set around `0.2`; for polishing tasks, it can be appropriately increased. If accuracy is highly required, it can be set to `0` diff --git a/public/info.json b/public/info.json index 1f40095..23ca06c 100644 --- a/public/info.json +++ b/public/info.json @@ -10,36 +10,36 @@ "appcast": "https://raw.githubusercontent.com/openai-translator/bob-plugin-openai-translator/main/appcast.json", "minBobVersion": "1.8.0", "options": [ + { + "identifier": "serviceProvider", + "type": "menu", + "title": "Service Provider", + "defaultValue": "openai", + "menuValues": [ + { + "title": "OpenAI", + "value": "openai" + }, + { + "title": "Azure OpenAI", + "value": "azure-openai" + }, + { + "title": "Custom", + "value": "custom" + } + ] + }, { "identifier": "apiUrl", "type": "text", "title": "API URL", - "defaultValue": "https://api.openai.com", - "desc": "可选项。如果您的网络环境需要代理才能访问 OpenAI API, 可在这里修改为反代 API 的地址", + "desc": "OpenAI: https://api.openai.com\n\nAzure OpenAI: https://RESOURCE_NAME.openai.azure.com/openai/deployments/DEPLOYMENT_NAME/chat/completions?api-version=API_VERSION\n\nCustom: 您的完整 API 地址,例如:https://gateway.ai.cloudflare.com/v1/CF_ACCOUNT_ID/GATEWAY_ID/openai/chat/completions", "textConfig": { "type": "visible", "placeholderText": "https://api.openai.com" } }, - { - "identifier": "deploymentName", - "type": "text", - "title": "Dep. Name", - "desc": "可选项。此值为在部署 Azure 模型时为部署选择的自定义名称,可在 Azure 门户中的 “资源管理”>“部署” 下查看", - "textConfig": { - "type": "visible" - } - }, - { - "identifier": "apiVersion", - "type": "text", - "title": "API Version", - "desc": "可选项。此值为在使用 Azure 模型时采用的 Chat completions API 版本,不支持 2023-03-15-preview 之前的版本", - "textConfig": { - "type": "visible", - "placeholderText": "2023-03-15-preview" - } - }, { "identifier": "apiKeys", "type": "text", @@ -135,15 +135,15 @@ "identifier": "stream", "type": "menu", "title": "流式输出", - "defaultValue": "1", + "defaultValue": "enable", "menuValues": [ { "title": "Enable", - "value": "1" + "value": "enable" }, { "title": "Disable", - "value": "" + "value": "disable" } ] }, diff --git a/src/main.ts b/src/main.ts index 4d8b504..956b535 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,6 @@ import { SYSTEM_PROMPT } from "./const"; import { langMap, supportLanguageList } from "./lang"; -import type { ChatCompletion, ModelList } from "./types"; +import type { ChatCompletion, ModelList, ServiceProvider } from "./types"; import type { HttpResponse, PluginValidate, @@ -17,6 +17,83 @@ import { replacePromptKeywords } from "./utils"; +function validateConfig( + serviceProvider: ServiceProvider, + apiKeys?: string, + apiUrl?: string, + model?: string, + customModel?: string +): ServiceError | null { + + if (serviceProvider !== 'openai' && !apiUrl) { + return { + type: "param", + message: "配置错误 - 请填写 API URL", + addition: "请在插件配置中填写完整的 API URL" + }; + } + + if (serviceProvider === 'azure-openai' && apiUrl) { + const parts = { + domain: /^https:\/\/[^\/]+\.openai\.azure\.com/, + path: /\/openai\/deployments\/[^\/]+\/chat\/completions/, + version: /\?api-version=\d{4}-\d{2}-\d{2}(?:-preview)?$/ + }; + + const isValidUrl = Object.values(parts).every(pattern => pattern.test(apiUrl)); + if (!isValidUrl) { + return { + type: "param", + message: "配置错误 - API URL 格式不正确", + addition: "Azure OpenAI 的 API URL 格式应为:https://YOUR_RESOURCE_NAME.openai.azure.com/openai/deployments/YOUR_DEPLOYMENT_NAME/chat/completions?api-version=API_VERSION", + troubleshootingLink: "https://bobtranslate.com/service/translate/azureopenai.html" + }; + } + } + + if (!apiKeys) { + return { + type: "secretKey", + message: "配置错误 - 请确保您在插件配置中填入了正确的 API Keys", + addition: "请在插件配置中填写 API Keys", + }; + } + + if (model === "custom" && !customModel) { + return { + type: "param", + message: "配置错误 - 请确保您在插件配置中填入了正确的自定义模型名称", + addition: "请在插件配置中填写自定义模型名称", + }; + } + + return null; +} + +function getServiceConfig(serviceProvider: ServiceProvider, apiUrl?: string) { + switch (serviceProvider) { + case 'azure-openai': + return { + chatCompletionsUrl: apiUrl!, + isAzureOpenAi: true, + validateUrl: apiUrl!, + }; + case 'custom': + return { + chatCompletionsUrl: apiUrl!, + isAzureOpenAi: false, + validateUrl: apiUrl!.replace(/\/chat\/completions$/, '/models'), + }; + default: // openai + const baseUrl = ensureHttpsAndNoTrailingSlash(apiUrl || "https://api.openai.com"); + return { + chatCompletionsUrl: `${baseUrl}/v1/chat/completions`, + isAzureOpenAi: false, + validateUrl: `${baseUrl}/v1/models`, + }; + } +} + const isServiceError = (error: unknown): error is ServiceError => { return ( typeof error === 'object' && @@ -182,73 +259,36 @@ const handleGeneralResponse = ( } const translate: TextTranslate = (query) => { - if (!langMap.get(query.detectTo)) { - handleGeneralError(query, { - type: "unsupportedLanguage", - message: "不支持该语种", - addition: "不支持该语种", - }); - } + const { apiKeys, apiUrl, customModel, model, serviceProvider, stream } = $option; - const { + const error = validateConfig( + serviceProvider as ServiceProvider, apiKeys, apiUrl, - apiVersion, - customModel, - deploymentName, model, - stream, - } = $option; - - const isCustomModelRequired = model === "custom"; - if (isCustomModelRequired && !customModel) { - handleGeneralError(query, { - type: "param", - message: "配置错误 - 请确保您在插件配置中填入了正确的自定义模型名称", - addition: "请在插件配置中填写自定义模型名称", - }); - } + customModel + ); - if (!apiKeys) { - handleGeneralError(query, { - type: "secretKey", - message: "配置错误 - 请确保您在插件配置中填入了正确的 API Keys", - addition: "请在插件配置中填写 API Keys", - }); + if (error) { + handleGeneralError(query, error); + return; } - const modelValue = isCustomModelRequired ? customModel : model; - - const apiKey = getApiKey($option.apiKeys); - - const baseUrl = ensureHttpsAndNoTrailingSlash(apiUrl || "https://api.openai.com"); - let apiUrlPath = baseUrl.includes("gateway.ai.cloudflare.com") ? "/chat/completions" : "/v1/chat/completions"; - const apiVersionQuery = apiVersion ? `?api-version=${apiVersion}` : "?api-version=2023-03-15-preview"; - - const isAzureServiceProvider = baseUrl.includes("openai.azure.com"); - if (isAzureServiceProvider) { - if (deploymentName) { - apiUrlPath = `/openai/deployments/${deploymentName}/chat/completions${apiVersionQuery}`; - } else { - handleGeneralError(query, { - type: "secretKey", - message: "配置错误 - 未填写 Deployment Name", - addition: "请在插件配置中填写 Deployment Name", - troubleshootingLink: "https://bobtranslate.com/service/translate/azureopenai.html" - }); - } - } + const serviceConfig = getServiceConfig(serviceProvider as ServiceProvider, apiUrl); + const { chatCompletionsUrl, isAzureOpenAi } = serviceConfig; - const header = buildHeader(isAzureServiceProvider, apiKey); + const modelValue = model === "custom" ? customModel : model; + const apiKey = getApiKey(apiKeys); + const header = buildHeader(isAzureOpenAi, apiKey); const body = buildRequestBody(modelValue, query); let targetText = ""; // 初始化拼接结果变量 let buffer = ""; // 新增 buffer 变量 (async () => { - if (stream) { + if (stream === "enable") { await $http.streamRequest({ method: "POST", - url: baseUrl + apiUrlPath, + url: chatCompletionsUrl, header, body: { ...body, @@ -298,7 +338,7 @@ const translate: TextTranslate = (query) => { } else { const result = await $http.request({ method: "POST", - url: baseUrl + apiUrlPath, + url: chatCompletionsUrl, header, body, }); @@ -315,41 +355,31 @@ const translate: TextTranslate = (query) => { } const pluginValidate: PluginValidate = (completion) => { - const { apiKeys, apiUrl, deploymentName } = $option; - if (!apiKeys) { - handleValidateError(completion, { - type: "secretKey", - message: "配置错误 - 请确保您在插件配置中填入了正确的 API Keys", - addition: "请在插件配置中填写正确的 API Keys", - troubleshootingLink: "https://bobtranslate.com/service/translate/openai.html" - }); + const { apiKeys, apiUrl, customModel, model, serviceProvider } = $option; + + const error = validateConfig( + serviceProvider as ServiceProvider, + apiKeys, + apiUrl, + model, + customModel + ); + + if (error) { + handleValidateError(completion, error); return; } + const serviceConfig = getServiceConfig(serviceProvider as ServiceProvider, apiUrl); + const { isAzureOpenAi, validateUrl } = serviceConfig; const apiKey = getApiKey(apiKeys); - const baseUrl = ensureHttpsAndNoTrailingSlash(apiUrl || "https://api.openai.com"); - let apiUrlPath = baseUrl.includes("gateway.ai.cloudflare.com") ? "/models" : "/v1/models"; - - const isAzureServiceProvider = apiUrl.includes("openai.azure.com"); - if (isAzureServiceProvider) { - if (!deploymentName) { - handleValidateError(completion, { - type: "secretKey", - message: "配置错误 - 未填写 Deployment Name", - addition: "请在插件配置中填写 Deployment Name", - troubleshootingLink: "https://bobtranslate.com/service/translate/azureopenai.html" - }); - return; - } - apiUrlPath = `/openai/deployments/${deploymentName}/chat/completions?api-version=2023-05-15`; - } + const header = buildHeader(isAzureOpenAi, apiKey); - const header = buildHeader(isAzureServiceProvider, apiKey); (async () => { - if (isAzureServiceProvider) { + if (isAzureOpenAi) { $http.request({ method: "POST", - url: baseUrl + apiUrlPath, + url: validateUrl, header: header, body: { "messages": [{ @@ -385,7 +415,7 @@ const pluginValidate: PluginValidate = (completion) => { } else { $http.request({ method: "GET", - url: baseUrl + apiUrlPath, + url: validateUrl, header: header, handler: function (resp) { const data = resp.data as { diff --git a/src/types.ts b/src/types.ts index 3f3a4bb..653385f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -90,4 +90,6 @@ interface Model { export interface ModelList { object: string, data: Model[] -} \ No newline at end of file +} + +export type ServiceProvider = 'openai' | 'azure-openai' | 'custom';