From 75cd63aa393a3cf1e284a18f57adcd4c1951a718 Mon Sep 17 00:00:00 2001 From: wyw <1006629314@qq.com> Date: Tue, 4 Jun 2024 11:38:56 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=20feat:=20Support=20Qwen=20as=20ne?= =?UTF-8?q?w=20model=20provider=20(#2715)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: mingholy.lmh --- .env.example | 4 + Dockerfile | 3 + README.md | 1 + README.zh-CN.md | 1 + docs/self-hosting/advanced/upstream-sync.mdx | 2 +- .../environment-variables/model-provider.mdx | 11 +- .../model-provider.zh-CN.mdx | 9 + docs/usage/features/multi-ai-providers.mdx | 1 + .../features/multi-ai-providers.zh-CN.mdx | 1 + locales/ar/error.json | 4 +- locales/ar/modelProvider.json | 12 + locales/bg-BG/error.json | 2 + locales/bg-BG/modelProvider.json | 12 + locales/de-DE/error.json | 2 + locales/de-DE/modelProvider.json | 12 + locales/en-US/error.json | 2 + locales/en-US/modelProvider.json | 12 + locales/es-ES/error.json | 2 + locales/es-ES/modelProvider.json | 12 + locales/fr-FR/error.json | 2 + locales/fr-FR/modelProvider.json | 12 + locales/it-IT/error.json | 2 + locales/it-IT/modelProvider.json | 12 + locales/ja-JP/error.json | 2 + locales/ja-JP/modelProvider.json | 12 + locales/ko-KR/error.json | 2 + locales/ko-KR/modelProvider.json | 12 + locales/nl-NL/error.json | 2 + locales/nl-NL/modelProvider.json | 12 + locales/pl-PL/error.json | 2 + locales/pl-PL/modelProvider.json | 12 + locales/pt-BR/error.json | 2 + locales/pt-BR/modelProvider.json | 12 + locales/ru-RU/error.json | 2 + locales/ru-RU/modelProvider.json | 12 + locales/tr-TR/error.json | 2 + locales/tr-TR/modelProvider.json | 12 + locales/vi-VN/error.json | 2 + locales/vi-VN/modelProvider.json | 12 + locales/zh-CN/error.json | 2 + locales/zh-CN/modelProvider.json | 12 + locales/zh-TW/error.json | 2 + locales/zh-TW/modelProvider.json | 12 + src/app/(main)/settings/llm/Qwen/index.tsx | 21 ++ src/app/(main)/settings/llm/index.tsx | 2 + src/app/api/chat/agentRuntime.test.ts | 17 ++ src/app/api/chat/agentRuntime.ts | 7 + src/app/api/errorResponse.test.ts | 6 + src/app/api/errorResponse.ts | 3 + src/components/ModelProviderIcon/index.tsx | 5 + src/config/llm.ts | 6 + src/config/modelProviders/index.ts | 4 + src/config/modelProviders/qwen.ts | 32 +++ src/const/settings/llm.ts | 5 + .../Error/APIKeyForm/ProviderAvatar.tsx | 5 + .../Conversation/Error/APIKeyForm/index.tsx | 4 + src/features/Conversation/Error/index.tsx | 1 + src/libs/agent-runtime/AgentRuntime.ts | 9 +- src/libs/agent-runtime/error.ts | 3 + src/libs/agent-runtime/index.ts | 1 + src/libs/agent-runtime/qwen/index.test.ts | 251 ++++++++++++++++++ src/libs/agent-runtime/qwen/index.ts | 33 +++ src/libs/agent-runtime/types/type.ts | 2 +- src/server/globalConfig/index.ts | 2 + src/services/__tests__/chat.test.ts | 16 ++ src/services/chat.ts | 3 + src/types/user/settings/keyVaults.ts | 1 + 67 files changed, 707 insertions(+), 5 deletions(-) create mode 100644 src/app/(main)/settings/llm/Qwen/index.tsx create mode 100644 src/config/modelProviders/qwen.ts create mode 100644 src/libs/agent-runtime/qwen/index.test.ts create mode 100644 src/libs/agent-runtime/qwen/index.ts diff --git a/.env.example b/.env.example index 14f902edaa..3f4b777f29 100644 --- a/.env.example +++ b/.env.example @@ -108,6 +108,10 @@ OPENAI_API_KEY=sk-xxxxxxxxx # DEEPSEEK_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx +### Qwen AI #### + +# QWEN_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + ######################################## ############ Market Service ############ ######################################## diff --git a/Dockerfile b/Dockerfile index c604543b6a..6ace0247d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -132,4 +132,7 @@ ENV MINIMAX_API_KEY "" # DeepSeek ENV DEEPSEEK_API_KEY "" +# Qwen +ENV QWEN_API_KEY "" + CMD ["node", "server.js"] diff --git a/README.md b/README.md index 272c548bcb..cb4c29eea3 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,7 @@ We have implemented support for the following model service providers: - **Moonshot AI (Dark Side of the Moon)**: Integrated with the Moonshot series models, an innovative AI startup from China, aiming to provide deeper conversation understanding. [Learn more](https://www.moonshot.cn/) - **Minimax**: Integrated the Minimax models, including the MoE model **abab6**, offers a broader range of choices. [Learn more](https://www.minimaxi.com/) - **DeepSeek**: Integrated with the DeepSeek series models, an innovative AI startup from China, The product has been designed to provide a model that balances performance with price. [Learn more](https://www.deepseek.com/) +- **Qwen**: Integrated the Qwen series models, including the latest **qwen-turbo**, **qwen-plus** and **qwen-max**. [Lean more](https://help.aliyun.com/zh/dashscope/developer-reference/model-introduction) At the same time, we are also planning to support more model service providers, such as Replicate and Perplexity, to further enrich our service provider library. If you would like LobeChat to support your favorite service provider, feel free to join our [community discussion](https://github.com/lobehub/lobe-chat/discussions/1284). diff --git a/README.zh-CN.md b/README.zh-CN.md index 4675766124..5fc18c8db4 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -130,6 +130,7 @@ - **OpenRouter**:其支持包括 **Claude 3**,**Gemma**,**Mistral**,**Llama2**和**Cohere**等模型路由,支持智能路由优化,提升使用效率,开放且灵活。[了解更多](https://openrouter.ai/) - **Minimax**: 接入了 Minimax 的 AI 模型,包括 MoE 模型 **abab6**,提供了更多的选择空间。[了解更多](https://www.minimaxi.com/) - **DeepSeek**: 接入了 DeepSeek 的 AI 模型,包括最新的 **DeepSeek-V2**,提供兼顾性能与价格的模型。[了解更多](https://www.deepseek.com/) +- **Qwen**: 接入了 Qwen 的 AI 模型,包括最新的 **qwen-turbo**,**qwen-plus** 和 **qwen-max** 等模型。[了解更多](https://help.aliyun.com/zh/dashscope/developer-reference/model-introduction) 同时,我们也在计划支持更多的模型服务商,如 Replicate 和 Perplexity 等,以进一步丰富我们的服务商库。如果你希望让 LobeChat 支持你喜爱的服务商,欢迎加入我们的[社区讨论](https://github.com/lobehub/lobe-chat/discussions/1284)。 diff --git a/docs/self-hosting/advanced/upstream-sync.mdx b/docs/self-hosting/advanced/upstream-sync.mdx index 3f000383c7..5324ea0eb9 100644 --- a/docs/self-hosting/advanced/upstream-sync.mdx +++ b/docs/self-hosting/advanced/upstream-sync.mdx @@ -158,4 +158,4 @@ The following command configures Crontab to execute scripts every 5 minutes, or */5 * * * * /path/to/auto-update-lobe-chat.sh >> /path/to/auto-update-lobe-chat.log 2>&1 ``` - \ No newline at end of file + diff --git a/docs/self-hosting/environment-variables/model-provider.mdx b/docs/self-hosting/environment-variables/model-provider.mdx index 6786fdfe93..515b6d6b72 100644 --- a/docs/self-hosting/environment-variables/model-provider.mdx +++ b/docs/self-hosting/environment-variables/model-provider.mdx @@ -285,6 +285,15 @@ If you need to use Azure OpenAI to provide model services, you can refer to the - Type: Required - Description: This is the API key you applied for in the 01.AI service - Default: - -- 示例:`xxxxxx...xxxxxx` +- Example:`xxxxxx...xxxxxx` + +## Qwen + +### `QWEN_API_KEY` + +- Type: Required +- Description: This is the DashScope API key you can obtain from Alibaba Cloud +- Default: - +- Example:`sk-xxxxx...xxxxx` [model-list]: /docs/self-hosting/advanced/model-list diff --git a/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx b/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx index 59618813ab..bf84641ecc 100644 --- a/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +++ b/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx @@ -286,3 +286,12 @@ LobeChat 在部署时提供了丰富的模型服务商相关的环境变量, - 示例:`xxxxxx...xxxxxx` [model-list]: /docs/self-hosting/advanced/model-list + +## 通义千问 + +### `QWEN_API_KEY` + +- 类型:必选 +- 描述:这是你在阿里云百炼平台上获取的 DashScope API 密钥 +- 默认值:- +- 示例:`sk-xxxxx...xxxxx` diff --git a/docs/usage/features/multi-ai-providers.mdx b/docs/usage/features/multi-ai-providers.mdx index e2939cc944..f249a48719 100644 --- a/docs/usage/features/multi-ai-providers.mdx +++ b/docs/usage/features/multi-ai-providers.mdx @@ -46,6 +46,7 @@ We have implemented support for the following model service providers: - **Together.ai**: Over 100 leading open-source Chat, Language, Image, Code, and Embedding models are available through the Together Inference API. For these models you pay just for what you use. [Learn more](https://www.together.ai/) - **Minimax**: Integrated the Minimax models, including the MoE model **abab6**, offers a broader range of choices. [Learn more](https://www.minimaxi.com/) - **DeepSeek**: Integrated with the DeepSeek series models, an innovative AI startup from China, The product has been designed to provide a model that balances performance with price. [Learn more](https://www.deepseek.com/) +- **Qwen**: Integrated with the Qwen series models, including the latest **qwen-turbo**, **qwen-plus** and **qwen-max**. [Learn more](https://help.aliyun.com/zh/dashscope/developer-reference/model-introduction) At the same time, we are also planning to support more model service providers, such as Replicate and Perplexity, to further enrich our service provider library. If you would like LobeChat to support your favorite service provider, feel free to join our [community discussion](https://github.com/lobehub/lobe-chat/discussions/1284). diff --git a/docs/usage/features/multi-ai-providers.zh-CN.mdx b/docs/usage/features/multi-ai-providers.zh-CN.mdx index c6b1433477..7a9d3872e0 100644 --- a/docs/usage/features/multi-ai-providers.zh-CN.mdx +++ b/docs/usage/features/multi-ai-providers.zh-CN.mdx @@ -46,6 +46,7 @@ tags: - **OpenRouter**:其支持包括 **Claude 3**,**Gemma**,**Mistral**,**Llama2**和**Cohere**等模型路由,支持智能路由优化,提升使用效率,开放且灵活。[了解更多](https://openrouter.ai/) - **Minimax**: 接入了 Minimax 的 AI 模型,包括 MoE 模型 **abab6**,提供了更多的选择空间。[了解更多](https://www.minimaxi.com/) - **DeepSeek**: 接入了 DeepSeek 的 AI 模型,包括最新的 **DeepSeek-V2**,提供兼顾性能与价格的模型。[了解更多](https://www.deepseek.com/) +- **Qwen (通义千问)**: 接入了 Qwen 的 AI 模型,包括最新的 **qwen-turbo**,**qwen-plus** 和 **qwen-max** 等模型。[了解更多](https://help.aliyun.com/zh/dashscope/developer-reference/model-introduction) 同时,我们也在计划支持更多的模型服务商,如 Replicate 和 Perplexity 等,以进一步丰富我们的服务商库。如果你希望让 LobeChat 支持你喜爱的服务商,欢迎加入我们的[社区讨论](https://github.com/lobehub/lobe-chat/discussions/1284)。 diff --git a/locales/ar/error.json b/locales/ar/error.json index f55786750e..41c76e0912 100644 --- a/locales/ar/error.json +++ b/locales/ar/error.json @@ -77,6 +77,7 @@ "InvalidTogetherAIAPIKey": "مفتاح TogetherAI API غير صحيح أو فارغ، يرجى التحقق من مفتاح TogetherAI API وإعادة المحاولة", "InvalidZeroOneAPIKey": "مفتاح ZeroOne API غير صحيح أو فارغ، يرجى التحقق من مفتاح ZeroOne API وإعادة المحاولة", "InvalidZhipuAPIKey": "مفتاح Zhipu API غير صحيح أو فارغ، يرجى التحقق من مفتاح Zhipu API وإعادة المحاولة", + "InvalidQwenAPIKey": "مفتاح Qwen API غير صحيح أو فارغ، يرجى التحقق من مفتاح Qwen API وإعادة المحاولة", "LocationNotSupportError": "عذرًا، لا يدعم موقعك الحالي خدمة هذا النموذج، قد يكون ذلك بسبب قيود المنطقة أو عدم توفر الخدمة. يرجى التحقق مما إذا كان الموقع الحالي يدعم استخدام هذه الخدمة، أو محاولة استخدام معلومات الموقع الأخرى.", "MinimaxBizError": "حدث خطأ في طلب خدمة Minimax، يرجى التحقق من المعلومات التالية أو إعادة المحاولة", "MistralBizError": "طلب خدمة Mistral AI خاطئ، يرجى التحقق من المعلومات التالية أو إعادة المحاولة", @@ -101,7 +102,8 @@ "PluginSettingsInvalid": "تحتاج هذه الإضافة إلى تكوين صحيح قبل الاستخدام، يرجى التحقق من صحة تكوينك", "TogetherAIBizError": "خطأ في طلب خدمة TogetherAI AI، يرجى التحقق من المعلومات التالية أو إعادة المحاولة", "ZeroOneBizError": "طلب خدمة ZeroOneBiz خطأ، يرجى التحقق من المعلومات أدناه أو إعادة المحاولة", - "ZhipuBizError": "حدث خطأ في طلب خدمة Zhipu، يرجى التحقق من المعلومات التالية أو إعادة المحاولة" + "ZhipuBizError": "حدث خطأ في طلب خدمة Zhipu، يرجى التحقق من المعلومات التالية أو إعادة المحاولة", + "QwenBizError": "حدث خطأ في طلب خدمة Qwen، يرجى التحقق من المعلومات التالية أو إعادة المحاولة" }, "stt": { "responseError": "فشل طلب الخدمة، يرجى التحقق من الإعدادات أو إعادة المحاولة" diff --git a/locales/ar/modelProvider.json b/locales/ar/modelProvider.json index 2f5983287d..82452e967c 100644 --- a/locales/ar/modelProvider.json +++ b/locales/ar/modelProvider.json @@ -217,6 +217,18 @@ "title": "استخدام مفتاح API الخاص بـ Perplexity المخصص" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "أدخل مفتاح API الخاص بـ Qwen", + "placeholder": "Qwen API Key", + "title": "مفتاح API" + }, + "unlock": { + "description": "أدخل مفتاح API الخاص بك في Qwen لبدء الجلسة. لن يتم تسجيل مفتاح الخاص بك من قبل التطبيق", + "title": "استخدام مفتاح API الخاص بـ Qwen المخصص" + } + }, "togetherai": { "checker": { "desc": "اختبر ما إذا تم إدخال عنوان الوكيل بشكل صحيح" diff --git a/locales/bg-BG/error.json b/locales/bg-BG/error.json index 0b0da74ade..3ebd91f911 100644 --- a/locales/bg-BG/error.json +++ b/locales/bg-BG/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Невалидна конфигурация на Ollama, моля, проверете конфигурацията на Ollama и опитайте отново", "InvalidOpenRouterAPIKey": "Невалиден или празен API ключ на OpenRouter. Моля, проверете вашия API ключ на OpenRouter и опитайте отново.", "InvalidPerplexityAPIKey": "API ключът на Perplexity е неправилен или празен. Моля, проверете API ключа на Perplexity и опитайте отново.", + "InvalidQwenAPIKey": "API ключът на Qwen е неправилен или празен. Моля, проверете API ключа на Qwen и опитайте отново.", "InvalidTogetherAIAPIKey": "TogetherAI API ключът е неправилен или липсва, моля, проверете TogetherAI API ключа и опитайте отново", "InvalidZeroOneAPIKey": "API ключът на 01-AI е неправилен или празен. Моля, проверете API ключа на 01-AI и опитайте отново.", "InvalidZhipuAPIKey": "API ключът на Zhipu е неправилен или празен. Моля, проверете API ключа на Zhipu и опитайте отново.", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "Съжаляваме, клиентът на OpenAPI не успя да се инициализира. Моля, проверете дали информацията за конфигурацията на OpenAPI е правилна.", "PluginServerError": "Заявката към сървъра на плъгина върна грешка. Моля, проверете файла на манифеста на плъгина, конфигурацията на плъгина или изпълнението на сървъра въз основа на информацията за грешката по-долу", "PluginSettingsInvalid": "Този плъгин трябва да бъде конфигуриран правилно, преди да може да се използва. Моля, проверете дали конфигурацията ви е правилна", + "QwenBizError": "Грешка при заявка към услугата Qwen. Моля, отстранете неизправностите или опитайте отново въз основа на следната информация.", "TogetherAIBizError": "Възникна грешка при заявка към TogetherAI AI услугата, моля, проверете следната информация или опитайте отново", "ZeroOneBizError": "Грешка при заявка към услугата 01-AI. Моля, отстранете неизправностите или опитайте отново въз основа на следната информация.", "ZhipuBizError": "Грешка при заявка към услугата Zhipu. Моля, отстранете неизправностите или опитайте отново въз основа на следната информация." diff --git a/locales/bg-BG/modelProvider.json b/locales/bg-BG/modelProvider.json index 14506b038b..03bcc70bcc 100644 --- a/locales/bg-BG/modelProvider.json +++ b/locales/bg-BG/modelProvider.json @@ -217,6 +217,18 @@ "title": "Използване на персонализиран Perplexity API ключ" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Въведете API Key, получен от Интелигентен албум", + "placeholder": "Qwen API Key", + "title": "API ключ" + }, + "unlock": { + "description": "Въведете вашия Qwen API ключ, за да започнете сесия. Приложението няма да запази вашия API ключ", + "title": "Използване на персонализиран Qwen API ключ" + } + }, "togetherai": { "checker": { "desc": "Тестване дали адресът на прокси е попълнен правилно" diff --git a/locales/de-DE/error.json b/locales/de-DE/error.json index c78df3da9a..7ce0e38aef 100644 --- a/locales/de-DE/error.json +++ b/locales/de-DE/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Ollama-Konfiguration ist ungültig. Bitte überprüfen Sie die Ollama-Konfiguration und versuchen Sie es erneut.", "InvalidOpenRouterAPIKey": "OpenRouter API-Schlüssel ungültig oder leer. Bitte überprüfen Sie den OpenRouter API-Schlüssel und versuchen Sie es erneut.", "InvalidPerplexityAPIKey": "Perplexity API Key ist ungültig oder leer. Bitte überprüfen Sie den Perplexity API Key und versuchen Sie es erneut.", + "InvalidQwenAPIKey": "Der Qwen API-Schlüssel ist ungültig oder leer. Bitte überprüfen Sie den Qwen API-Schlüssel und versuchen Sie es erneut.", "InvalidTogetherAIAPIKey": "TogetherAI API-Schlüssel ungültig oder leer. Bitte überprüfen Sie den TogetherAI API-Schlüssel und versuchen Sie es erneut.", "InvalidZeroOneAPIKey": "Ungültiger oder leerer ZeroOne-API-Schlüssel. Bitte überprüfen Sie den ZeroOne-API-Schlüssel und versuchen Sie es erneut.", "InvalidZhipuAPIKey": "Der Zhipu API-Schlüssel ist ungültig oder leer. Bitte überprüfen Sie den Zhipu API-Schlüssel und versuchen Sie es erneut.", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "Entschuldigung, die Initialisierung des OpenAPI-Clients ist fehlgeschlagen. Bitte überprüfen Sie die Konfigurationsinformationen des OpenAPI auf Richtigkeit", "PluginServerError": "Fehler bei der Serveranfrage des Plugins. Bitte überprüfen Sie die Fehlerinformationen unten in Ihrer Plugin-Beschreibungsdatei, Plugin-Konfiguration oder Serverimplementierung", "PluginSettingsInvalid": "Das Plugin muss korrekt konfiguriert werden, um verwendet werden zu können. Bitte überprüfen Sie Ihre Konfiguration auf Richtigkeit", + "QwenBizError": "Es ist ein Fehler bei der Anforderung des Qwen-Dienstes aufgetreten. Bitte überprüfen Sie die folgenden Informationen oder versuchen Sie es erneut.", "TogetherAIBizError": "Fehler bei der Anforderung des TogetherAI AI-Dienstes. Bitte überprüfen Sie die folgenden Informationen oder versuchen Sie es erneut.", "ZeroOneBizError": "Anfrage an ZeroOneBiz-Dienst fehlgeschlagen. Bitte überprüfen Sie die folgenden Informationen oder versuchen Sie es erneut.", "ZhipuBizError": "Es ist ein Fehler bei der Anforderung des Zhipu-Dienstes aufgetreten. Bitte überprüfen Sie die folgenden Informationen oder versuchen Sie es erneut." diff --git a/locales/de-DE/modelProvider.json b/locales/de-DE/modelProvider.json index ac8f891dd3..2ecf5539e6 100644 --- a/locales/de-DE/modelProvider.json +++ b/locales/de-DE/modelProvider.json @@ -217,6 +217,18 @@ "title": "Verwenden Sie einen individuellen Perplexity-API-Schlüssel" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Geben Sie Ihren API-Key von Qwen ein", + "placeholder": "Qwen API Key", + "title": "API Key" + }, + "unlock": { + "description": "Geben Sie Ihren individuellen Qwen-API-Schlüssel ein, um das Gespräch zu beginnen. Die App speichert Ihren API-Schlüssel nicht.", + "title": "Verwenden Sie einen individuellen Qwen-API-Schlüssel" + } + }, "togetherai": { "checker": { "desc": "Testen Sie, ob die Proxy-Adresse korrekt eingetragen wurde" diff --git a/locales/en-US/error.json b/locales/en-US/error.json index e8dcabaab5..eab610fe9f 100644 --- a/locales/en-US/error.json +++ b/locales/en-US/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Invalid Ollama configuration, please check Ollama configuration and try again", "InvalidOpenRouterAPIKey": "Invalid or empty OpenRouter API Key. Please check your OpenRouter API Key and try again.", "InvalidPerplexityAPIKey": "Perplexity API Key is incorrect or empty. Please check the Perplexity API Key and retry.", + "InvalidQwenAPIKey": "Qwen API Key is incorrect or empty. Please check the Qwen API Key and retry.", "InvalidTogetherAIAPIKey": "Invalid or empty TogetherAI API Key. Please check your TogetherAI API Key and try again.", "InvalidZeroOneAPIKey": "01-AI API Key is incorrect or empty. Please check the 01-AI API Key and retry.", "InvalidZhipuAPIKey": "Zhipu API Key is incorrect or empty. Please check the Zhipu API Key and retry.", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "Sorry, the OpenAPI client failed to initialize. Please check if the OpenAPI configuration information is correct.", "PluginServerError": "Plugin server request returned an error. Please check your plugin manifest file, plugin configuration, or server implementation based on the error information below", "PluginSettingsInvalid": "This plugin needs to be correctly configured before it can be used. Please check if your configuration is correct", + "QwenBizError": "Error requesting Qwen service. Please troubleshoot or retry based on the following information.", "TogetherAIBizError": "Error requesting TogetherAI AI service. Please troubleshoot or retry based on the following information.", "ZeroOneBizError": "Error requesting 01-AI service. Please troubleshoot or retry based on the following information.", "ZhipuBizError": "Error requesting Zhipu service. Please troubleshoot or retry based on the following information." diff --git a/locales/en-US/modelProvider.json b/locales/en-US/modelProvider.json index 6bfe4bb685..0a4aa32786 100644 --- a/locales/en-US/modelProvider.json +++ b/locales/en-US/modelProvider.json @@ -217,6 +217,18 @@ "title": "Use custom Perplexity API Key" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Enter the API Key from Qwen", + "placeholder": "Qwen API Key", + "title": "API Key" + }, + "unlock": { + "description": "Enter your Qwen API Key to start the session. The app will not store your API Key.", + "title": "Use Custom Qwen API Key" + } + }, "togetherai": { "checker": { "desc": "Test if the proxy address is correctly filled in" diff --git a/locales/es-ES/error.json b/locales/es-ES/error.json index 93d13989c5..5f20c11c85 100644 --- a/locales/es-ES/error.json +++ b/locales/es-ES/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "La configuración de Ollama no es válida, por favor revisa la configuración de Ollama e inténtalo de nuevo", "InvalidOpenRouterAPIKey": "La clave de API de OpenRouter es incorrecta o está vacía. Por favor, revisa la clave de API de OpenRouter e inténtalo de nuevo", "InvalidPerplexityAPIKey": "La clave de API de Perplexity es inválida o está vacía. Por favor, verifica la clave de API de Perplexity e inténtalo de nuevo", + "InvalidQwenAPIKey": "La clave de API de Qwen es incorrecta o está vacía, por favor, verifica la clave de API de Qwen e inténtalo de nuevo", "InvalidTogetherAIAPIKey": "La clave de API de TogetherAI es incorrecta o está vacía. Por favor, revisa la clave de API de TogetherAI e inténtalo de nuevo", "InvalidZeroOneAPIKey": "La clave de API de ZeroOneBiz es incorrecta o está vacía. Por favor, revise la clave de API de ZeroOneBiz e inténtelo de nuevo.", "InvalidZhipuAPIKey": "La clave de API de Zhipu es incorrecta o está vacía, por favor, verifica la clave de API de Zhipu e inténtalo de nuevo", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "Lo sentimos, la inicialización del cliente OpenAPI ha fallado. Verifique si la información de configuración de OpenAPI es correcta", "PluginServerError": "Error al recibir la respuesta del servidor del complemento. Verifique el archivo de descripción del complemento, la configuración del complemento o la implementación del servidor según la información de error a continuación", "PluginSettingsInvalid": "Este complemento necesita una configuración correcta antes de poder usarse. Verifique si su configuración es correcta", + "QwenBizError": "Se produjo un error al solicitar el servicio Qwen, por favor, verifica la siguiente información o inténtalo de nuevo", "TogetherAIBizError": "Error al solicitar el servicio de IA de TogetherAI. Por favor, revisa la siguiente información o inténtalo de nuevo", "ZeroOneBizError": "Se produjo un error al solicitar el servicio ZeroOneBiz. Por favor, revise la siguiente información o inténtelo de nuevo.", "ZhipuBizError": "Se produjo un error al solicitar el servicio Zhipu, por favor, verifica la siguiente información o inténtalo de nuevo" diff --git a/locales/es-ES/modelProvider.json b/locales/es-ES/modelProvider.json index f4df5100b3..267523250a 100644 --- a/locales/es-ES/modelProvider.json +++ b/locales/es-ES/modelProvider.json @@ -217,6 +217,18 @@ "title": "Usar clave de API de Perplexity personalizada" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Introduce la clave API proporcionada por Qwen", + "placeholder": "Clave API de Qwen", + "title": "Clave API" + }, + "unlock": { + "description": "Introduce tu clave de API de Qwen personalizada para comenzar la sesión. La aplicación no guardará tu clave de API.", + "title": "Usar clave de API de Zhipu personalizada" + } + }, "togetherai": { "checker": { "desc": "Prueba si la dirección del proxy de la interfaz se ha introducido correctamente" diff --git a/locales/fr-FR/error.json b/locales/fr-FR/error.json index 0169d84dbb..8ed80a2853 100644 --- a/locales/fr-FR/error.json +++ b/locales/fr-FR/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "La configuration d'Ollama n'est pas valide, veuillez vérifier la configuration d'Ollama et réessayer", "InvalidOpenRouterAPIKey": "La clé d'API OpenRouter est incorrecte ou manquante. Veuillez vérifier la clé d'API OpenRouter et réessayer.", "InvalidPerplexityAPIKey": "La clé API Perplexity est incorrecte ou vide. Veuillez vérifier la clé API Perplexity et réessayer.", + "InvalidQwenAPIKey": "Clé API Qwen incorrecte ou vide, veuillez vérifier la clé API Zhipu et réessayer", "InvalidTogetherAIAPIKey": "La clé d'API TogetherAI est incorrecte ou manquante. Veuillez vérifier la clé d'API TogetherAI et réessayer.", "InvalidZeroOneAPIKey": "La clé d'API ZeroOne est incorrecte ou vide, veuillez vérifier la clé d'API ZeroOne et réessayer", "InvalidZhipuAPIKey": "Clé API Zhipu incorrecte ou vide, veuillez vérifier la clé API Zhipu et réessayer", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "Désolé, l'initialisation du client OpenAPI a échoué. Veuillez vérifier les informations de configuration d'OpenAPI.", "PluginServerError": "Erreur de réponse du serveur du plugin. Veuillez vérifier le fichier de description du plugin, la configuration du plugin ou la mise en œuvre côté serveur en fonction des informations d'erreur ci-dessous", "PluginSettingsInvalid": "Ce plugin doit être correctement configuré avant de pouvoir être utilisé. Veuillez vérifier votre configuration", + "QwenBizError": "Erreur lors de la demande de service Qwen, veuillez vérifier les informations ci-dessous ou réessayer", "TogetherAIBizError": "Erreur commerciale lors de la demande de service TogetherAI AI. Veuillez vérifier les informations ci-dessous ou réessayer.", "ZeroOneBizError": "请求零一万物服务出错,请根据以下信息排查或重试", "ZhipuBizError": "Erreur lors de la demande de service Zhipu, veuillez vérifier les informations ci-dessous ou réessayer" diff --git a/locales/fr-FR/modelProvider.json b/locales/fr-FR/modelProvider.json index 33363e9b89..d392d84376 100644 --- a/locales/fr-FR/modelProvider.json +++ b/locales/fr-FR/modelProvider.json @@ -217,6 +217,18 @@ "title": "Use custom Perplexity API Key" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Entrez la clé API de Qwen", + "placeholder": "Clé API Qwen", + "title": "Clé API" + }, + "unlock": { + "description": "Entrez votre clé API Qwen pour commencer la session. L'application ne stockera pas votre clé API.", + "title": "Utiliser une clé API Qwen personnalisée" + } + }, "togetherai": { "checker": { "desc": "Test if the proxy address is correctly filled in" diff --git a/locales/it-IT/error.json b/locales/it-IT/error.json index 1febf4e515..1c9712847f 100644 --- a/locales/it-IT/error.json +++ b/locales/it-IT/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Configurazione Ollama non valida, controllare la configurazione di Ollama e riprovare", "InvalidOpenRouterAPIKey": "La chiave API di OpenRouter non è valida o è vuota. Si prega di controllare la chiave API di OpenRouter e riprovare.", "InvalidPerplexityAPIKey": "Chiave API Perplexity non valida o vuota, controlla la chiave API Perplexity e riprova", + "InvalidQwenAPIKey": "Chiave API Qwen non corretta o vuota, controlla la chiave API Qwen e riprova", "InvalidTogetherAIAPIKey": "La chiave API di TogetherAI non è valida o è vuota. Si prega di controllare la chiave API di TogetherAI e riprovare.", "InvalidZeroOneAPIKey": "La chiave API ZeroOne non è corretta o è vuota, si prega di controllare la chiave API ZeroOne e riprovare", "InvalidZhipuAPIKey": "Chiave API Zhipu non corretta o vuota, controlla la chiave API Zhipu e riprova", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "Spiacenti, inizializzazione fallita del client OpenAPI. Verifica che le informazioni di configurazione di OpenAPI siano corrette", "PluginServerError": "Errore nella risposta del server del plugin. Verifica il file descrittivo del plugin, la configurazione del plugin o l'implementazione del server", "PluginSettingsInvalid": "Il plugin deve essere configurato correttamente prima di poter essere utilizzato. Verifica che la tua configurazione sia corretta", + "QwenBizError": "Errore nella richiesta del servizio Qwen, controlla le informazioni seguenti o riprova", "TogetherAIBizError": "Errore di richiesta del servizio TogetherAI AI. Si prega di controllare le informazioni seguenti o riprovare.", "ZeroOneBizError": "Si è verificato un errore nel servizio ZeroOneBiz, si prega di controllare le informazioni seguenti o riprovare", "ZhipuBizError": "Errore nella richiesta del servizio Zhipu, controlla le informazioni seguenti o riprova" diff --git a/locales/it-IT/modelProvider.json b/locales/it-IT/modelProvider.json index 77e1875ec0..613af68055 100644 --- a/locales/it-IT/modelProvider.json +++ b/locales/it-IT/modelProvider.json @@ -217,6 +217,18 @@ "title": "Usa una chiave API personalizzata da Perplexity" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Inserisci la tua chiave API da Qwen", + "placeholder": "Chiave API Qwen", + "title": "Chiave API" + }, + "unlock": { + "description": "Inserisci la tua chiave API da Qwen per iniziare la sessione. L'applicazione non memorizzerà la tua chiave API", + "title": "Usa una chiave API personalizzata da Qwen" + } + }, "togetherai": { "checker": { "desc": "Verifica se l'indirizzo del proxy è stato compilato correttamente" diff --git a/locales/ja-JP/error.json b/locales/ja-JP/error.json index 9f4ae2b04d..cff1f0f410 100644 --- a/locales/ja-JP/error.json +++ b/locales/ja-JP/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Ollamaの設定が正しくありません。Ollamaの設定を確認してからもう一度お試しください", "InvalidOpenRouterAPIKey": "OpenRouter API キーが正しくないか空です。OpenRouter API キーを確認してもう一度お試しください。", "InvalidPerplexityAPIKey": "Perplexity APIキーが正しくないか空です。Perplexity APIキーを確認してもう一度お試しください", + "InvalidQwenAPIKey": "Qwen APIキーが正しくないか空です。Qwen APIキーを確認してから再試行してください。", "InvalidTogetherAIAPIKey": "TogetherAI API キーが正しくないか空です。TogetherAI API キーを確認してもう一度お試しください。", "InvalidZeroOneAPIKey": "ZeroOne APIキーが正しくないか空です。ZeroOne APIキーを確認して再試行してください。", "InvalidZhipuAPIKey": "Zhipu APIキーが正しくないか空です。Zhipu APIキーを確認してから再試行してください。", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "申し訳ありませんが、OpenAPIクライアントの初期化に失敗しました。OpenAPIの設定情報を確認してください。", "PluginServerError": "プラグインサーバーのリクエストエラーが発生しました。以下のエラーメッセージを参考に、プラグインのマニフェストファイル、設定、サーバー実装を確認してください", "PluginSettingsInvalid": "このプラグインを使用するには、正しい設定が必要です。設定が正しいかどうか確認してください", + "QwenBizError": "Qwenサービスのリクエストでエラーが発生しました。以下の情報に基づいてトラブルシューティングを行うか、再試行してください。", "TogetherAIBizError": "TogetherAI AI サービスのリクエスト中にエラーが発生しました。以下の情報に基づいてトラブルシューティングを行うか、もう一度お試しください。", "ZeroOneBizError": "リクエストがZeroOneサービスでエラーが発生しました。以下の情報を確認して再試行してください。", "ZhipuBizError": "Zhipuサービスのリクエストでエラーが発生しました。以下の情報に基づいてトラブルシューティングを行うか、再試行してください。" diff --git a/locales/ja-JP/modelProvider.json b/locales/ja-JP/modelProvider.json index 865eee2edf..279f614853 100644 --- a/locales/ja-JP/modelProvider.json +++ b/locales/ja-JP/modelProvider.json @@ -217,6 +217,18 @@ "title": "カスタムPerplexity APIキーを使用する" } }, + "qwen": { + "title": "通义千问", + "token": { + "desc": "通义千问からのAPIキーを入力してください", + "placeholder": "Qwen API Key", + "title": "APIキー" + }, + "unlock": { + "description": "あなたのQwen APIキーを入力すると、セッションを開始できます。アプリはあなたのAPIキーを記録しません。", + "title": "カスタムQwen APIキーを使用する" + } + }, "togetherai": { "checker": { "desc": "プロキシアドレスが正しく入力されているかをテストします" diff --git a/locales/ko-KR/error.json b/locales/ko-KR/error.json index 27f57859c1..219bd62d96 100644 --- a/locales/ko-KR/error.json +++ b/locales/ko-KR/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Ollama 구성이 잘못되었습니다. Ollama 구성을 확인한 후 다시 시도하십시오.", "InvalidOpenRouterAPIKey": "OpenRouter API 키가 잘못되었거나 비어 있습니다. OpenRouter API 키를 확인한 후 다시 시도하십시오.", "InvalidPerplexityAPIKey": "Perplexity API 키가 잘못되었거나 비어 있습니다. Perplexity API 키를 확인한 후 다시 시도하십시오.", + "InvalidQwenAPIKey": "잘못된 또는 비어 있는 Qwen API Key입니다. Qwen API Key를 확인한 후 다시 시도하십시오.", "InvalidTogetherAIAPIKey": "TogetherAI API 키가 잘못되었거나 비어 있습니다. TogetherAI API 키를 확인한 후 다시 시도하십시오.", "InvalidZeroOneAPIKey": "잘못된 또는 빈 제로원물 API 키입니다. 제로원물 API 키를 확인하고 다시 시도해주세요.", "InvalidZhipuAPIKey": "잘못된 또는 비어 있는 Zhipu API Key입니다. Zhipu API Key를 확인한 후 다시 시도하십시오.", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "죄송합니다. OpenAPI 클라이언트 초기화에 실패했습니다. OpenAPI 구성 정보를 확인해주세요.", "PluginServerError": "플러그인 서버 요청이 오류로 반환되었습니다. 플러그인 설명 파일, 플러그인 구성 또는 서버 구현을 확인해주세요.", "PluginSettingsInvalid": "플러그인을 사용하려면 올바른 구성이 필요합니다. 구성이 올바른지 확인해주세요.", + "QwenBizError": "Qwen 서비스 요청 중 오류가 발생했습니다. 아래 정보를 확인하고 다시 시도하십시오.", "TogetherAIBizError": "TogetherAI AI 서비스 요청 중 오류가 발생했습니다. 다음 정보를 확인하고 다시 시도하십시오.", "ZeroOneBizError": "제로원물 서비스 요청 중 오류가 발생했습니다. 아래 정보를 확인하고 다시 시도해주세요.", "ZhipuBizError": "Zhipu 서비스 요청 중 오류가 발생했습니다. 아래 정보를 확인하고 다시 시도하십시오." diff --git a/locales/ko-KR/modelProvider.json b/locales/ko-KR/modelProvider.json index 87f36cf35a..054ce07b66 100644 --- a/locales/ko-KR/modelProvider.json +++ b/locales/ko-KR/modelProvider.json @@ -217,6 +217,18 @@ "title": "사용자 정의 Perplexity API 키 사용" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Qwen의 API 키를 입력하세요", + "placeholder": "Qwen API 키", + "title": "API 키" + }, + "unlock": { + "description": "귀하의 Qwen API 키를 입력하면 세션을 시작할 수 있습니다. 애플리케이션은 귀하의 API 키를 기록하지 않습니다", + "title": "사용자 정의 Qwen API 키 사용" + } + }, "togetherai": { "checker": { "desc": "프록시 주소가 올바르게 입력되었는지 테스트합니다" diff --git a/locales/nl-NL/error.json b/locales/nl-NL/error.json index 2130b6b0c5..454513f467 100644 --- a/locales/nl-NL/error.json +++ b/locales/nl-NL/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Ollama-configuratie is onjuist, controleer de Ollama-configuratie en probeer het opnieuw", "InvalidOpenRouterAPIKey": "OpenRouter API Key is onjuist of leeg. Controleer de OpenRouter API Key en probeer het opnieuw.", "InvalidPerplexityAPIKey": "Perplexity API Key is onjuist of leeg. Controleer de Perplexity API Key en probeer het opnieuw.", + "InvalidQwenAPIKey": "Incorrect or empty Qwen API Key, please check the Qwen API Key and retry", "InvalidTogetherAIAPIKey": "TogetherAI API Key is onjuist of leeg. Controleer de TogetherAI API Key en probeer het opnieuw.", "InvalidZeroOneAPIKey": "Ongeldige ZeroOneAPI-sleutel of leeg, controleer de ZeroOneAPI-sleutel en probeer het opnieuw", "InvalidZhipuAPIKey": "Incorrect or empty Zhipu API Key, please check the Zhipu API Key and retry", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "Sorry, initialisatie van de OpenAPI-client is mislukt. Controleer of de configuratie van OpenAPI juist is", "PluginServerError": "Fout bij serverrespons voor plug-in. Controleer de foutinformatie hieronder voor uw plug-inbeschrijvingsbestand, plug-inconfiguratie of serverimplementatie", "PluginSettingsInvalid": "Deze plug-in moet correct geconfigureerd zijn voordat deze kan worden gebruikt. Controleer of uw configuratie juist is", + "QwenBizError": "Error requesting Qwen service, please troubleshoot or retry based on the following information", "TogetherAIBizError": "Fout bij het aanvragen van TogetherAI AI-service. Controleer de onderstaande informatie en probeer opnieuw.", "ZeroOneBizError": "请求零一万物服务出错,请根据以下信息排查或重试", "ZhipuBizError": "Error requesting Zhipu service, please troubleshoot or retry based on the following information" diff --git a/locales/nl-NL/modelProvider.json b/locales/nl-NL/modelProvider.json index 3fa11a39bf..6cfb61b116 100644 --- a/locales/nl-NL/modelProvider.json +++ b/locales/nl-NL/modelProvider.json @@ -217,6 +217,18 @@ "title": "Gebruik aangepaste Perplexity API-sleutel" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Voer de API Key van Qwen in", + "placeholder": "Qwen API Key", + "title": "API Key" + }, + "unlock": { + "description": "Voer uw Qwen API-sleutel in om een sessie te starten. De app zal uw API-sleutel niet opslaan", + "title": "Gebruik aangepaste Qwen API-sleutel" + } + }, "togetherai": { "checker": { "desc": "Test of het proxyadres correct is ingevuld" diff --git a/locales/pl-PL/error.json b/locales/pl-PL/error.json index 1468471d07..0dde05dd02 100644 --- a/locales/pl-PL/error.json +++ b/locales/pl-PL/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Nieprawidłowa konfiguracja Ollama, sprawdź konfigurację Ollama i spróbuj ponownie", "InvalidOpenRouterAPIKey": "OpenRouter API Key jest nieprawidłowy lub pusty. Sprawdź klucz API OpenRouter i spróbuj ponownie.", "InvalidPerplexityAPIKey": "Klucz API Perplexity jest nieprawidłowy lub pusty. Sprawdź klucz API Perplexity i spróbuj ponownie.", + "InvalidQwenAPIKey": "Nieprawidłowy lub pusty klucz API Qwen, prosimy sprawdzić klucz API Qwen i spróbować ponownie.", "InvalidTogetherAIAPIKey": "TogetherAI API Key jest nieprawidłowy lub pusty. Sprawdź klucz API TogetherAI i spróbuj ponownie.", "InvalidZeroOneAPIKey": "Klucz API Zero One nieprawidłowy lub pusty, sprawdź poprawność klucza API Zero One i spróbuj ponownie", "InvalidZhipuAPIKey": "Nieprawidłowy lub pusty klucz API Zhipu, prosimy sprawdzić klucz API Zhipu i spróbować ponownie.", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "Przepraszamy, inicjalizacja klienta OpenAPI nie powiodła się. Proszę sprawdź, czy informacje konfiguracyjne OpenAPI są poprawne", "PluginServerError": "Błąd zwrócony przez serwer wtyczki. Proszę sprawdź plik opisowy wtyczki, konfigurację wtyczki lub implementację serwera zgodnie z poniższymi informacjami o błędzie", "PluginSettingsInvalid": "Ta wtyczka wymaga poprawnej konfiguracji przed użyciem. Proszę sprawdź, czy Twoja konfiguracja jest poprawna", + "QwenBizError": "Wystąpił błąd żądania usługi Qwen, prosimy o sprawdzenie poniższych informacji lub ponowne próbowanie.", "TogetherAIBizError": "Wystąpił błąd biznesowy podczas żądania usługi TogetherAI AI. Sprawdź poniższe informacje lub spróbuj ponownie.", "ZeroOneBizError": "请求零一万物服务出错,请根据以下信息排查或重试", "ZhipuBizError": "Wystąpił błąd żądania usługi Zhipu, prosimy o sprawdzenie poniższych informacji lub ponowne próbowanie." diff --git a/locales/pl-PL/modelProvider.json b/locales/pl-PL/modelProvider.json index 5219db1e27..ae2b533f91 100644 --- a/locales/pl-PL/modelProvider.json +++ b/locales/pl-PL/modelProvider.json @@ -217,6 +217,18 @@ "title": "Użyj niestandardowego klucza API Perplexity" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Wprowadź klucz API uzyskany od Qwen", + "placeholder": "Qwen API Key", + "title": "Klucz API" + }, + "unlock": { + "description": "Wprowadź swój klucz API Qwen, aby rozpocząć sesję. Aplikacja nie będzie przechowywać Twojego klucza API", + "title": "Użyj niestandardowego klucza API Qwen" + } + }, "togetherai": { "checker": { "desc": "Test czy adres proxy jest poprawnie wypełniony" diff --git a/locales/pt-BR/error.json b/locales/pt-BR/error.json index 7f44bedfe0..084ecd5cae 100644 --- a/locales/pt-BR/error.json +++ b/locales/pt-BR/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Configuração Ollama inválida, verifique a configuração do Ollama e tente novamente", "InvalidOpenRouterAPIKey": "Chave da API do OpenRouter inválida ou em branco. Por favor, verifique a chave da API do OpenRouter e tente novamente.", "InvalidPerplexityAPIKey": "Chave da API Perplexity inválida ou em branco, verifique a chave da API Perplexity e tente novamente", + "InvalidQwenAPIKey": "Chave de API Qwen incorreta ou vazia, por favor, verifique a chave de API Qwen e tente novamente", "InvalidTogetherAIAPIKey": "Chave da API do TogetherAI inválida ou em branco. Por favor, verifique a chave da API do TogetherAI e tente novamente.", "InvalidZeroOneAPIKey": "Chave de API ZeroOne inválida ou vazia, verifique a chave de API ZeroOne e tente novamente", "InvalidZhipuAPIKey": "Chave de API Zhipu incorreta ou vazia, por favor, verifique a chave de API Zhipu e tente novamente", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "Desculpe, a inicialização do cliente OpenAPI falhou. Verifique se as informações de configuração do OpenAPI estão corretas", "PluginServerError": "Erro na resposta do servidor do plugin. Verifique o arquivo de descrição do plugin, a configuração do plugin ou a implementação do servidor de acordo com as informações de erro abaixo", "PluginSettingsInvalid": "Este plugin precisa ser configurado corretamente antes de ser usado. Verifique se sua configuração está correta", + "QwenBizError": "Erro ao solicitar o serviço Qwen, por favor, verifique as informações abaixo ou tente novamente", "TogetherAIBizError": "Erro de negócios ao solicitar o serviço de IA do TogetherAI. Por favor, verifique as informações abaixo ou tente novamente.", "ZeroOneBizError": "Erro no serviço ZeroOneBiz, verifique as informações abaixo e tente novamente", "ZhipuBizError": "Erro ao solicitar o serviço Zhipu, por favor, verifique as informações abaixo ou tente novamente" diff --git a/locales/pt-BR/modelProvider.json b/locales/pt-BR/modelProvider.json index 04e49aec24..d67c953e0d 100644 --- a/locales/pt-BR/modelProvider.json +++ b/locales/pt-BR/modelProvider.json @@ -217,6 +217,18 @@ "title": "Usar chave de API Perplexity personalizada" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Insira sua API Key fornecida pela Qwen", + "placeholder": "Qwen API Key", + "title": "API Key" + }, + "unlock": { + "description": "Digite sua chave de API Qwen para iniciar a sessão. O aplicativo não irá armazenar sua chave de API", + "title": "Usar chave de API Qwen personalizada" + } + }, "togetherai": { "checker": { "desc": "Teste se o endereço do proxy está corretamente preenchido" diff --git a/locales/ru-RU/error.json b/locales/ru-RU/error.json index 69baae32b8..a2311b7d01 100644 --- a/locales/ru-RU/error.json +++ b/locales/ru-RU/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Неверная конфигурация Ollama, пожалуйста, проверьте конфигурацию Ollama и повторите попытку", "InvalidOpenRouterAPIKey": "OpenRouter API Key недействителен или отсутствует. Пожалуйста, проверьте правильность OpenRouter API Key и повторите попытку", "InvalidPerplexityAPIKey": "Неверный или пустой ключ API Perplexity. Пожалуйста, проверьте ключ API Perplexity и повторите попытку", + "InvalidQwenAPIKey": "Неверный или пустой ключ API Qwen, пожалуйста, проверьте ключ API Qwen и повторите попытку", "InvalidTogetherAIAPIKey": "TogetherAI API Key недействителен или отсутствует. Пожалуйста, проверьте правильность TogetherAI API Key и повторите попытку", "InvalidZeroOneAPIKey": "Неверный или пустой ключ API ZeroOne. Пожалуйста, проверьте ключ API ZeroOne и повторите попытку", "InvalidZhipuAPIKey": "Неверный или пустой ключ API Zhipu, пожалуйста, проверьте ключ API Zhipu и повторите попытку", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "Извините, не удалось инициализировать клиент OpenAPI. Пожалуйста, проверьте правильность информации конфигурации OpenAPI.", "PluginServerError": "Запрос сервера плагина возвратил ошибку. Проверьте файл манифеста плагина, конфигурацию плагина или реализацию сервера на основе информации об ошибке ниже", "PluginSettingsInvalid": "Этот плагин необходимо правильно настроить, прежде чем его можно будет использовать. Пожалуйста, проверьте правильность вашей конфигурации", + "QwenBizError": "Ошибка запроса службы Qwen, пожалуйста, проверьте и повторите попытку в соответствии с предоставленной информацией", "TogetherAIBizError": "Ошибка запроса к сервису TogetherAI AI. Пожалуйста, проверьте информацию ниже или повторите попытку", "ZeroOneBizError": "Ошибка обслуживания запроса к сервису ZeroOneBiz. Пожалуйста, проверьте следующую информацию и повторите попытку", "ZhipuBizError": "Ошибка запроса службы Zhipu, пожалуйста, проверьте и повторите попытку в соответствии с предоставленной информацией" diff --git a/locales/ru-RU/modelProvider.json b/locales/ru-RU/modelProvider.json index 05673bb60d..5569ab9d28 100644 --- a/locales/ru-RU/modelProvider.json +++ b/locales/ru-RU/modelProvider.json @@ -217,6 +217,18 @@ "title": "Использовать пользовательский ключ API Perplexity" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Введите свой API Key от Qwen", + "placeholder": "Qwen API Key", + "title": "API Key" + }, + "unlock": { + "description": "Введите свой ключ API Qwen, чтобы начать сеанс. Приложение не будет сохранять ваш ключ API", + "title": "Использовать пользовательский ключ API Qwen" + } + }, "togetherai": { "checker": { "desc": "Проверить правильность адреса прокси" diff --git a/locales/tr-TR/error.json b/locales/tr-TR/error.json index a0726785dd..62c5769e38 100644 --- a/locales/tr-TR/error.json +++ b/locales/tr-TR/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Ollama yapılandırması yanlış, lütfen Ollama yapılandırmasını kontrol edip tekrar deneyin", "InvalidOpenRouterAPIKey": "OpenRouter API Anahtarı geçersiz veya boş, lütfen OpenRouter API Anahtarınızı kontrol edip tekrar deneyin", "InvalidPerplexityAPIKey": "Perplexity API Key geçersiz veya boş, lütfen Perplexity API Key'inizi kontrol edip tekrar deneyin", + "InvalidQwenAPIKey": "Qwen API Anahtarı yanlış veya boş, lütfen Qwen API Anahtarınızı kontrol edip tekrar deneyin", "InvalidTogetherAIAPIKey": "TogetherAI API Anahtarı geçersiz veya boş, lütfen TogetherAI API Anahtarınızı kontrol edip tekrar deneyin", "InvalidZeroOneAPIKey": "SıfırBirIoT API Anahtarı geçersiz veya boş. Lütfen SıfırBirIoT API Anahtarınızı kontrol edip tekrar deneyin", "InvalidZhipuAPIKey": "Zhipu API Anahtarı yanlış veya boş, lütfen Zhipu API Anahtarınızı kontrol edip tekrar deneyin", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "Üzgünüz, OpenAPI istemci başlatma hatası, lütfen OpenAPI yapılandırma bilgilerini kontrol edin", "PluginServerError": "Eklenti sunucusu isteği bir hata ile döndü. Lütfen aşağıdaki hata bilgilerine dayanarak eklenti bildirim dosyanızı, eklenti yapılandırmanızı veya sunucu uygulamanızı kontrol edin", "PluginSettingsInvalid": "Bu eklenti, kullanılmadan önce doğru şekilde yapılandırılmalıdır. Lütfen yapılandırmanızın doğru olup olmadığını kontrol edin", + "QwenBizError": "Qwen servisi isteği hatası, lütfen aşağıdaki bilgilere göre sorunu gidermeye çalışın veya tekrar deneyin", "TogetherAIBizError": "TogetherAI AI hizmetine yönelik istek hatası, lütfen aşağıdaki bilgilere göre sorunu gidermeye çalışın veya tekrar deneyin", "ZeroOneBizError": "SıfırBirIoT hizmetine yapılan istekte bir hata oluştu. Lütfen aşağıdaki bilgilere göre sorunu gidermeye çalışın veya tekrar deneyin", "ZhipuBizError": "Zhipu servisi isteği hatası, lütfen aşağıdaki bilgilere göre sorunu gidermeye çalışın veya tekrar deneyin" diff --git a/locales/tr-TR/modelProvider.json b/locales/tr-TR/modelProvider.json index 051f33904a..7c46b6f0f1 100644 --- a/locales/tr-TR/modelProvider.json +++ b/locales/tr-TR/modelProvider.json @@ -1,4 +1,16 @@ { + "Qwen": { + "title": "Qwen", + "token": { + "desc": "Qwen'dan gelen API Key'i girin", + "placeholder": "Qwen API Key", + "title": "API Key" + }, + "unlock": { + "description": "Qwen API Anahtarınızı girerek oturumu başlatabilirsiniz. Uygulama API Anahtarınızı kaydetmez.", + "title": "Özel Qwen API Anahtarı Kullan" + } + }, "anthropic": { "title": "Anthropic", "token": { diff --git a/locales/vi-VN/error.json b/locales/vi-VN/error.json index 7eb871ada2..16bb9d587f 100644 --- a/locales/vi-VN/error.json +++ b/locales/vi-VN/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Cấu hình Ollama không hợp lệ, vui lòng kiểm tra lại cấu hình Ollama và thử lại", "InvalidOpenRouterAPIKey": "OpenRouter API Key không hợp lệ hoặc trống, vui lòng kiểm tra lại và thử lại", "InvalidPerplexityAPIKey": "Khóa API Perplexity không hợp lệ hoặc trống, vui lòng kiểm tra lại và thử lại sau", + "InvalidQwenAPIKey": "Khóa API Qwen không chính xác hoặc trống, vui lòng kiểm tra lại Khóa API Qwen và thử lại", "InvalidTogetherAIAPIKey": "TogetherAI API Key không hợp lệ hoặc trống, vui lòng kiểm tra lại và thử lại", "InvalidZeroOneAPIKey": "Khóa API ZeroOne không hợp lệ hoặc trống, vui lòng kiểm tra lại khóa API ZeroOne và thử lại", "InvalidZhipuAPIKey": "Khóa API Zhipu không chính xác hoặc trống, vui lòng kiểm tra lại Khóa API Zhipu và thử lại", @@ -88,6 +89,7 @@ "OpenRouterBizError": "Yêu cầu dịch vụ OpenRouter AI gặp lỗi, vui lòng kiểm tra thông tin dưới đây hoặc thử lại", "PerplexityBizError": "Yêu cầu dịch vụ AI Perplexity gặp lỗi, vui lòng kiểm tra thông tin dưới đây hoặc thử lại sau", "PluginApiNotFound": "Xin lỗi, không có API nào trong tệp mô tả plugin, vui lòng kiểm tra phương thức yêu cầu của bạn có khớp với API mô tả plugin không", + "QwenBizError": "Yêu cầu dịch vụ Qwen gặp lỗi, vui lòng kiểm tra thông tin dưới đây hoặc thử lại sau", "PluginApiParamsError": "Xin lỗi, kiểm tra tham số đầu vào yêu cầu của plugin không thông qua, vui lòng kiểm tra tham số đầu vào có khớp với thông tin mô tả API không", "PluginGatewayError": "Xin lỗi, cổng plugin gặp lỗi, vui lòng kiểm tra cấu hình cổng plugin có đúng không", "PluginManifestInvalid": "Xin lỗi, kiểm tra mô tả plugin không thông qua, vui lòng kiểm tra định dạng mô tả có đúng không", diff --git a/locales/vi-VN/modelProvider.json b/locales/vi-VN/modelProvider.json index 9fa98660bd..b70dbf3229 100644 --- a/locales/vi-VN/modelProvider.json +++ b/locales/vi-VN/modelProvider.json @@ -217,6 +217,18 @@ "title": "Sử dụng Khóa API Perplexity tùy chỉnh" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "Nhập API Key từ Qwen", + "placeholder": "Qwen API Key", + "title": "API Key" + }, + "unlock": { + "description": "Nhập Khóa API Qwen của bạn để bắt đầu phiên làm việc. Ứng dụng sẽ không lưu trữ Khóa API của bạn", + "title": "Sử dụng Khóa API Qwen tùy chỉnh" + } + }, "togetherai": { "checker": { "desc": "Kiểm tra địa chỉ proxy có được nhập chính xác không" diff --git a/locales/zh-CN/error.json b/locales/zh-CN/error.json index d2b14fbdc4..ebd6fa412a 100644 --- a/locales/zh-CN/error.json +++ b/locales/zh-CN/error.json @@ -101,6 +101,8 @@ "OllamaServiceUnavailable": "Ollama 服务连接失败,请检查 Ollama 是否运行正常,或是否正确设置 Ollama 的跨域配置", "MinimaxBizError": "请求 Minimax 服务出错,请根据以下信息排查或重试", "InvalidMinimaxAPIKey": "Minimax API Key 不正确或为空,请检查 Minimax API Key 后重试", + "QwenBizError": "请求 Qwen 服务出错,请根据以下信息排查或重试", + "InvalidQwenAPIKey": "Qwen API Key 不正确或为空,请检查 Qwen API Key 后重试", "AgentRuntimeError": "Lobe AI Runtime 执行出错,请根据以下信息排查或重试" }, "stt": { diff --git a/locales/zh-CN/modelProvider.json b/locales/zh-CN/modelProvider.json index 3c13da0cc1..dd98f0b3ab 100644 --- a/locales/zh-CN/modelProvider.json +++ b/locales/zh-CN/modelProvider.json @@ -217,6 +217,18 @@ "title": "使用自定义 Perplexity API Key" } }, + "qwen": { + "title": "Qwen", + "token": { + "desc": "填入来自 DashScope 的 Qwen API Key", + "placeholder": "Qwen API Key", + "title": "Qwen API Key" + }, + "unlock": { + "description": "输入你的 Qwen API Key 即可开始会话。应用不会记录你的 API Key", + "title": "使用自定义 Qwen API Key" + } + }, "togetherai": { "checker": { "desc": "测试代理地址是否正确填写" diff --git a/locales/zh-TW/error.json b/locales/zh-TW/error.json index 3eee5e5974..cda2a05861 100644 --- a/locales/zh-TW/error.json +++ b/locales/zh-TW/error.json @@ -74,6 +74,7 @@ "InvalidOllamaArgs": "Ollama 配置不正確,請檢查 Ollama 配置後重試", "InvalidOpenRouterAPIKey": "OpenRouter API 金鑰不正確或為空,請檢查 OpenRouter API 金鑰後重試", "InvalidPerplexityAPIKey": "Perplexity API Key 不正確或為空,請檢查 Perplexity API Key 後重試", + "InvalidQwenAPIKey": "Qwen API Key 不正確或為空,請檢查 Qwen API Key 後重試", "InvalidTogetherAIAPIKey": "TogetherAI API 金鑰不正確或為空,請檢查 TogetherAI API 金鑰後重試", "InvalidZeroOneAPIKey": "零一萬物 API Key 不正確或為空,請檢查零一萬物 API Key 後重試", "InvalidZhipuAPIKey": "Zhipu API Key 不正確或為空,請檢查 Zhipu API Key 後重試", @@ -99,6 +100,7 @@ "PluginOpenApiInitError": "很抱歉,OpenAPI 客戶端初始化失敗,請檢查 OpenAPI 的配置信息是否正確", "PluginServerError": "外掛伺服器請求回傳錯誤。請根據下面的錯誤資訊檢查您的外掛描述檔案、外掛設定或伺服器實作", "PluginSettingsInvalid": "該外掛需要正確設定後才可以使用。請檢查您的設定是否正確", + "QwenBizError": "請求通義千問服務出錯,請根據以下信息排查或重試", "TogetherAIBizError": "請求 TogetherAI AI 服務出錯,請根據以下信息排查或重試", "ZeroOneBizError": "請求零一萬物服務出錯,請根據以下信息排查或重試", "ZhipuBizError": "請求智譜服務出錯,請根據以下信息排查或重試" diff --git a/locales/zh-TW/modelProvider.json b/locales/zh-TW/modelProvider.json index 0a8f7185f7..117aa18115 100644 --- a/locales/zh-TW/modelProvider.json +++ b/locales/zh-TW/modelProvider.json @@ -217,6 +217,18 @@ "title": "使用自定義 Perplexity API 金鑰" } }, + "qwen": { + "title": "通義千問", + "token": { + "desc": "填入來自通義千問的 API 金鑰", + "placeholder": "通義千問 API 金鑰", + "title": "API 金鑰" + }, + "unlock": { + "description": "輸入你的 通義千問 API 金鑰即可開始會話。應用不會記錄你的 API 金鑰", + "title": "使用自定義 通義千問 API 金鑰" + } + }, "togetherai": { "checker": { "desc": "測試代理地址是否正確填寫" diff --git a/src/app/(main)/settings/llm/Qwen/index.tsx b/src/app/(main)/settings/llm/Qwen/index.tsx new file mode 100644 index 0000000000..09d0423c46 --- /dev/null +++ b/src/app/(main)/settings/llm/Qwen/index.tsx @@ -0,0 +1,21 @@ +'use client'; + +import { Tongyi } from '@lobehub/icons'; +import { memo } from 'react'; + +import { ModelProvider } from '@/libs/agent-runtime'; + +import ProviderConfig from '../components/ProviderConfig'; + +const QwenProvider = memo(() => { + return ( + } + /> + ); +}); + +export default QwenProvider; diff --git a/src/app/(main)/settings/llm/index.tsx b/src/app/(main)/settings/llm/index.tsx index 68cc4f6401..2ac5707338 100644 --- a/src/app/(main)/settings/llm/index.tsx +++ b/src/app/(main)/settings/llm/index.tsx @@ -15,6 +15,7 @@ import Ollama from './Ollama'; import OpenAI from './OpenAI'; import OpenRouter from './OpenRouter'; import Perplexity from './Perplexity'; +import Qwen from './Qwen'; import TogetherAI from './TogetherAI'; import ZeroOne from './ZeroOne'; import Zhipu from './Zhipu'; @@ -34,6 +35,7 @@ const Page = () => { + diff --git a/src/app/api/chat/agentRuntime.test.ts b/src/app/api/chat/agentRuntime.test.ts index 6b6be9731c..20d8bd3364 100644 --- a/src/app/api/chat/agentRuntime.test.ts +++ b/src/app/api/chat/agentRuntime.test.ts @@ -16,6 +16,7 @@ import { LobeOpenAI, LobeOpenRouterAI, LobePerplexityAI, + LobeQwenAI, LobeRuntimeAI, LobeTogetherAI, LobeZeroOneAI, @@ -49,6 +50,7 @@ vi.mock('@/config/llm', () => ({ MISTRAL_API_KEY: 'test-mistral-key', OPENROUTER_API_KEY: 'test-openrouter-key', TOGETHERAI_API_KEY: 'test-togetherai-key', + QWEN_API_KEY: 'test-qwen-key', })), })); @@ -101,6 +103,13 @@ describe('initAgentRuntimeWithUserPayload method', () => { expect(runtime['_runtime']).toBeInstanceOf(LobeMoonshotAI); }); + it('Qwen AI provider: with apikey', async () => { + const jwtPayload: JWTPayload = { apiKey: 'user-qwen-key' }; + const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Qwen, jwtPayload); + expect(runtime).toBeInstanceOf(AgentRuntime); + expect(runtime['_runtime']).toBeInstanceOf(LobeQwenAI); + }); + it('Bedrock AI provider: with apikey, awsAccessKeyId, awsSecretAccessKey, awsRegion', async () => { const jwtPayload: JWTPayload = { apiKey: 'user-bedrock-key', @@ -232,6 +241,14 @@ describe('initAgentRuntimeWithUserPayload method', () => { expect(runtime['_runtime']).toBeInstanceOf(LobeMoonshotAI); }); + it('Qwen AI provider: without apikey', async () => { + const jwtPayload: JWTPayload = {}; + const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Qwen, jwtPayload); + + // 假设 LobeQwenAI 是 Qwen 提供者的实现类 + expect(runtime['_runtime']).toBeInstanceOf(LobeQwenAI); + }); + it('Bedrock AI provider: without apikey', async () => { const jwtPayload = {}; const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Bedrock, jwtPayload); diff --git a/src/app/api/chat/agentRuntime.ts b/src/app/api/chat/agentRuntime.ts index 554a810a14..a21210ae2e 100644 --- a/src/app/api/chat/agentRuntime.ts +++ b/src/app/api/chat/agentRuntime.ts @@ -156,6 +156,13 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => { const apiKey = apiKeyManager.pick(payload?.apiKey || ZEROONE_API_KEY); + return { apiKey }; + } + case ModelProvider.Qwen: { + const { QWEN_API_KEY } = getLLMConfig(); + + const apiKey = apiKeyManager.pick(payload?.apiKey || QWEN_API_KEY); + return { apiKey }; } } diff --git a/src/app/api/errorResponse.test.ts b/src/app/api/errorResponse.test.ts index 1bf2c7a379..3503bcebb9 100644 --- a/src/app/api/errorResponse.test.ts +++ b/src/app/api/errorResponse.test.ts @@ -138,6 +138,12 @@ describe('createErrorResponse', () => { const response = createErrorResponse(errorType); expect(response.status).toBe(486); }); + + it('returns a 487 status for QwenBizError error type', () => { + const errorType = AgentRuntimeErrorType.QwenBizError; + const response = createErrorResponse(errorType); + expect(response.status).toBe(487); + }); }); // 测试状态码不在200-599范围内的情况 diff --git a/src/app/api/errorResponse.ts b/src/app/api/errorResponse.ts index 880241f48e..90ad625ef2 100644 --- a/src/app/api/errorResponse.ts +++ b/src/app/api/errorResponse.ts @@ -68,6 +68,9 @@ const getStatus = (errorType: ILobeAgentRuntimeErrorType | ErrorType) => { case AgentRuntimeErrorType.DeepSeekBizError: { return 486; } + case AgentRuntimeErrorType.QwenBizError: { + return 487; + } } return errorType as number; }; diff --git a/src/components/ModelProviderIcon/index.tsx b/src/components/ModelProviderIcon/index.tsx index 3738e973d3..0dfd8c98c3 100644 --- a/src/components/ModelProviderIcon/index.tsx +++ b/src/components/ModelProviderIcon/index.tsx @@ -14,6 +14,7 @@ import { OpenRouter, Perplexity, Together, + Tongyi, ZeroOne, Zhipu, } from '@lobehub/icons'; @@ -104,6 +105,10 @@ const ModelProviderIcon = memo(({ provider }) => { return ; } + case ModelProvider.Qwen: { + return ; + } + default: { return null; } diff --git a/src/config/llm.ts b/src/config/llm.ts index 506d0123ba..f4bd3ed7cb 100644 --- a/src/config/llm.ts +++ b/src/config/llm.ts @@ -114,6 +114,9 @@ export const getLLMConfig = () => { ENABLED_OLLAMA: z.boolean(), OLLAMA_PROXY_URL: z.string().optional(), OLLAMA_MODEL_LIST: z.string().optional(), + + ENABLED_QWEN: z.boolean(), + QWEN_API_KEY: z.string().optional(), }, runtimeEnv: { API_KEY_SELECT_MODE: process.env.API_KEY_SELECT_MODE, @@ -182,6 +185,9 @@ export const getLLMConfig = () => { ENABLED_OLLAMA: process.env.ENABLED_OLLAMA !== '0', OLLAMA_PROXY_URL: process.env.OLLAMA_PROXY_URL || '', OLLAMA_MODEL_LIST: process.env.OLLAMA_MODEL_LIST || process.env.OLLAMA_CUSTOM_MODELS, + + ENABLED_QWEN: !!process.env.QWEN_API_KEY, + QWEN_API_KEY: process.env.QWEN_API_KEY, }, }); }; diff --git a/src/config/modelProviders/index.ts b/src/config/modelProviders/index.ts index 20f9793880..12150c36f7 100644 --- a/src/config/modelProviders/index.ts +++ b/src/config/modelProviders/index.ts @@ -13,12 +13,14 @@ import OllamaProvider from './ollama'; import OpenAIProvider from './openai'; import OpenRouterProvider from './openrouter'; import PerplexityProvider from './perplexity'; +import QwenProvider from './qwen'; import TogetherAIProvider from './togetherai'; import ZeroOneProvider from './zeroone'; import ZhiPuProvider from './zhipu'; export const LOBE_DEFAULT_MODEL_LIST: ChatModelCard[] = [ OpenAIProvider.chatModels, + QwenProvider.chatModels, ZhiPuProvider.chatModels, BedrockProvider.chatModels, DeepSeekProvider.chatModels, @@ -38,6 +40,7 @@ export const LOBE_DEFAULT_MODEL_LIST: ChatModelCard[] = [ export const DEFAULT_MODEL_PROVIDER_LIST = [ OpenAIProvider, { ...AzureProvider, chatModels: [] }, + QwenProvider, OllamaProvider, AnthropicProvider, DeepSeekProvider, @@ -71,6 +74,7 @@ export { default as OllamaProviderCard } from './ollama'; export { default as OpenAIProviderCard } from './openai'; export { default as OpenRouterProviderCard } from './openrouter'; export { default as PerplexityProviderCard } from './perplexity'; +export { default as QwenProviderCard } from './qwen'; export { default as TogetherAIProviderCard } from './togetherai'; export { default as ZeroOneProviderCard } from './zeroone'; export { default as ZhiPuProviderCard } from './zhipu'; diff --git a/src/config/modelProviders/qwen.ts b/src/config/modelProviders/qwen.ts new file mode 100644 index 0000000000..7e39da7221 --- /dev/null +++ b/src/config/modelProviders/qwen.ts @@ -0,0 +1,32 @@ +import { ModelProviderCard } from '@/types/llm'; + +// ref https://help.aliyun.com/zh/dashscope/developer-reference/api-details +const Qwen: ModelProviderCard = { + chatModels: [ + { + description: '通义千问超大规模语言模型,支持中文、英文等不同语言输入。', + displayName: 'Qwen Turbo', + enabled: true, + id: 'qwen-turbo', + tokens: 8192, + }, + { + description: '通义千问超大规模语言模型增强版,支持中文、英文等不同语言输入。', + displayName: 'Qwen Plus', + enabled: true, + id: 'qwen-plus', + tokens: 30_720, + }, + { + description: + '通义千问千亿级别超大规模语言模型,支持中文、英文等不同语言输入,当前通义千问2.5产品版本背后的API模型。', + displayName: 'Qwen Max', + enabled: true, + id: 'qwen-max', + tokens: 8192, + }, + ], + id: 'qwen', +}; + +export default Qwen; diff --git a/src/const/settings/llm.ts b/src/const/settings/llm.ts index aa95640c43..0e251af724 100644 --- a/src/const/settings/llm.ts +++ b/src/const/settings/llm.ts @@ -11,6 +11,7 @@ import { OpenAIProviderCard, OpenRouterProviderCard, PerplexityProviderCard, + QwenProviderCard, TogetherAIProviderCard, ZeroOneProviderCard, ZhiPuProviderCard, @@ -72,6 +73,10 @@ export const DEFAULT_LLM_CONFIG: UserModelProviderConfig = { enabled: false, enabledModels: filterEnabledModels(PerplexityProviderCard), }, + qwen: { + enabled: false, + enabledModels: filterEnabledModels(QwenProviderCard), + }, togetherai: { enabled: false, enabledModels: filterEnabledModels(TogetherAIProviderCard), diff --git a/src/features/Conversation/Error/APIKeyForm/ProviderAvatar.tsx b/src/features/Conversation/Error/APIKeyForm/ProviderAvatar.tsx index d332f54a0e..e937422d29 100644 --- a/src/features/Conversation/Error/APIKeyForm/ProviderAvatar.tsx +++ b/src/features/Conversation/Error/APIKeyForm/ProviderAvatar.tsx @@ -10,6 +10,7 @@ import { OpenRouter, Perplexity, Together, + Tongyi, ZeroOne, Zhipu, } from '@lobehub/icons'; @@ -66,6 +67,10 @@ const ProviderAvatar = memo(({ provider }) => { return ; } + case ModelProvider.Qwen: { + return ; + } + case ModelProvider.TogetherAI: { return ; } diff --git a/src/features/Conversation/Error/APIKeyForm/index.tsx b/src/features/Conversation/Error/APIKeyForm/index.tsx index d18501b77f..832f3b4c91 100644 --- a/src/features/Conversation/Error/APIKeyForm/index.tsx +++ b/src/features/Conversation/Error/APIKeyForm/index.tsx @@ -47,6 +47,10 @@ const APIKeyForm = memo(({ id, provider }) => { return 'sk_******************************'; } + case ModelProvider.Qwen: { + return 'sk-********************************'; + } + default: { return '*********************************'; } diff --git a/src/features/Conversation/Error/index.tsx b/src/features/Conversation/Error/index.tsx index 4a926e4ca3..2cce1a66cb 100644 --- a/src/features/Conversation/Error/index.tsx +++ b/src/features/Conversation/Error/index.tsx @@ -88,6 +88,7 @@ const ErrorMessageExtra = memo<{ data: ChatMessage }>(({ data }) => { case AgentRuntimeErrorType.InvalidAnthropicAPIKey: case AgentRuntimeErrorType.InvalidGroqAPIKey: case AgentRuntimeErrorType.InvalidOpenRouterAPIKey: + case AgentRuntimeErrorType.InvalidQwenAPIKey: case AgentRuntimeErrorType.InvalidTogetherAIAPIKey: case AgentRuntimeErrorType.InvalidZeroOneAPIKey: case AgentRuntimeErrorType.NoOpenAIAPIKey: { diff --git a/src/libs/agent-runtime/AgentRuntime.ts b/src/libs/agent-runtime/AgentRuntime.ts index bec176eb5c..ef07480ac6 100644 --- a/src/libs/agent-runtime/AgentRuntime.ts +++ b/src/libs/agent-runtime/AgentRuntime.ts @@ -16,6 +16,7 @@ import { LobeOllamaAI } from './ollama'; import { LobeOpenAI } from './openai'; import { LobeOpenRouterAI } from './openrouter'; import { LobePerplexityAI } from './perplexity'; +import { LobeQwenAI } from './qwen'; import { LobeTogetherAI } from './togetherai'; import { ChatCompetitionOptions, @@ -112,6 +113,7 @@ class AgentRuntime { openai: Partial; openrouter: Partial; perplexity: Partial; + qwen: Partial; togetherai: Partial; zeroone: Partial; zhipu: Partial; @@ -175,7 +177,7 @@ class AgentRuntime { runtimeModel = new LobeDeepSeekAI(params.deepseek ?? {}); break; } - + case ModelProvider.Minimax: { runtimeModel = new LobeMinimaxAI(params.minimax ?? {}); break; @@ -205,6 +207,11 @@ class AgentRuntime { runtimeModel = new LobeZeroOneAI(params.zeroone ?? {}); break; } + + case ModelProvider.Qwen: { + runtimeModel = new LobeQwenAI(params.qwen ?? {}); + break; + } } return new AgentRuntime(runtimeModel); diff --git a/src/libs/agent-runtime/error.ts b/src/libs/agent-runtime/error.ts index cef141d40f..4f5306c6e5 100644 --- a/src/libs/agent-runtime/error.ts +++ b/src/libs/agent-runtime/error.ts @@ -52,6 +52,9 @@ export const AgentRuntimeErrorType = { InvalidDeepSeekAPIKey: 'InvalidDeepSeekAPIKey', DeepSeekBizError: 'DeepSeekBizError', + + InvalidQwenAPIKey: 'InvalidQwenAPIKey', + QwenBizError: 'QwenBizError', } as const; export type ILobeAgentRuntimeErrorType = diff --git a/src/libs/agent-runtime/index.ts b/src/libs/agent-runtime/index.ts index 7431cbbd54..308cd40ca4 100644 --- a/src/libs/agent-runtime/index.ts +++ b/src/libs/agent-runtime/index.ts @@ -14,6 +14,7 @@ export { LobeOllamaAI } from './ollama'; export { LobeOpenAI } from './openai'; export { LobeOpenRouterAI } from './openrouter'; export { LobePerplexityAI } from './perplexity'; +export { LobeQwenAI } from './qwen'; export { LobeTogetherAI } from './togetherai'; export * from './types'; export { AgentRuntimeError } from './utils/createError'; diff --git a/src/libs/agent-runtime/qwen/index.test.ts b/src/libs/agent-runtime/qwen/index.test.ts new file mode 100644 index 0000000000..b1ec2f6fcf --- /dev/null +++ b/src/libs/agent-runtime/qwen/index.test.ts @@ -0,0 +1,251 @@ +// @vitest-environment node +import OpenAI from 'openai'; +import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { LobeOpenAICompatibleRuntime } from '@/libs/agent-runtime'; +import { ModelProvider } from '@/libs/agent-runtime'; +import { AgentRuntimeErrorType } from '@/libs/agent-runtime'; + +import * as debugStreamModule from '../utils/debugStream'; +import { LobeQwenAI } from './index'; + +const provider = ModelProvider.Qwen; +const defaultBaseURL = 'https://dashscope.aliyuncs.com/compatible-mode/v1'; +const bizErrorType = AgentRuntimeErrorType.QwenBizError; +const invalidErrorType = AgentRuntimeErrorType.InvalidQwenAPIKey; + +// Mock the console.error to avoid polluting test output +vi.spyOn(console, 'error').mockImplementation(() => {}); + +let instance: LobeOpenAICompatibleRuntime; + +beforeEach(() => { + instance = new LobeQwenAI({ apiKey: 'test' }); + + // 使用 vi.spyOn 来模拟 chat.completions.create 方法 + vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue( + new ReadableStream() as any, + ); +}); + +afterEach(() => { + vi.clearAllMocks(); +}); + +describe('LobeQwenAI', () => { + describe('init', () => { + it('should correctly initialize with an API key', async () => { + const instance = new LobeQwenAI({ apiKey: 'test_api_key' }); + expect(instance).toBeInstanceOf(LobeQwenAI); + expect(instance.baseURL).toEqual(defaultBaseURL); + }); + }); + + describe('chat', () => { + describe('Error', () => { + it('should return QwenBizError with an openai error response when OpenAI.APIError is thrown', async () => { + // Arrange + const apiError = new OpenAI.APIError( + 400, + { + status: 400, + error: { + message: 'Bad Request', + }, + }, + 'Error message', + {}, + ); + + vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError); + + // Act + try { + await instance.chat({ + messages: [{ content: 'Hello', role: 'user' }], + model: 'qwen-turbo', + temperature: 0.999, + }); + } catch (e) { + expect(e).toEqual({ + endpoint: defaultBaseURL, + error: { + error: { message: 'Bad Request' }, + status: 400, + }, + errorType: bizErrorType, + provider, + }); + } + }); + + it('should throw AgentRuntimeError with InvalidQwenAPIKey if no apiKey is provided', async () => { + try { + new LobeQwenAI({}); + } catch (e) { + expect(e).toEqual({ errorType: invalidErrorType }); + } + }); + + it('should return QwenBizError with the cause when OpenAI.APIError is thrown with cause', async () => { + // Arrange + const errorInfo = { + stack: 'abc', + cause: { + message: 'api is undefined', + }, + }; + const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {}); + + vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError); + + // Act + try { + await instance.chat({ + messages: [{ content: 'Hello', role: 'user' }], + model: 'qwen-turbo', + temperature: 0.999, + }); + } catch (e) { + expect(e).toEqual({ + endpoint: defaultBaseURL, + error: { + cause: { message: 'api is undefined' }, + stack: 'abc', + }, + errorType: bizErrorType, + provider, + }); + } + }); + + it('should return QwenBizError with an cause response with desensitize Url', async () => { + // Arrange + const errorInfo = { + stack: 'abc', + cause: { message: 'api is undefined' }, + }; + const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {}); + + instance = new LobeQwenAI({ + apiKey: 'test', + + baseURL: 'https://api.abc.com/v1', + }); + + vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError); + + // Act + try { + await instance.chat({ + messages: [{ content: 'Hello', role: 'user' }], + model: 'qwen-turbo', + temperature: 0.999, + }); + } catch (e) { + expect(e).toEqual({ + endpoint: 'https://api.***.com/v1', + error: { + cause: { message: 'api is undefined' }, + stack: 'abc', + }, + errorType: bizErrorType, + provider, + }); + } + }); + + it('should throw an InvalidQwenAPIKey error type on 401 status code', async () => { + // Mock the API call to simulate a 401 error + const error = new Error('InvalidApiKey') as any; + error.status = 401; + vi.mocked(instance['client'].chat.completions.create).mockRejectedValue(error); + + try { + await instance.chat({ + messages: [{ content: 'Hello', role: 'user' }], + model: 'qwen-turbo', + temperature: 0.999, + }); + } catch (e) { + expect(e).toEqual({ + endpoint: defaultBaseURL, + error: new Error('InvalidApiKey'), + errorType: invalidErrorType, + provider, + }); + } + }); + + it('should return AgentRuntimeError for non-OpenAI errors', async () => { + // Arrange + const genericError = new Error('Generic Error'); + + vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(genericError); + + // Act + try { + await instance.chat({ + messages: [{ content: 'Hello', role: 'user' }], + model: 'qwen-turbo', + temperature: 0.999, + }); + } catch (e) { + expect(e).toEqual({ + endpoint: defaultBaseURL, + errorType: 'AgentRuntimeError', + provider, + error: { + name: genericError.name, + cause: genericError.cause, + message: genericError.message, + stack: genericError.stack, + }, + }); + } + }); + }); + + describe('DEBUG', () => { + it('should call debugStream and return StreamingTextResponse when DEBUG_QWEN_CHAT_COMPLETION is 1', async () => { + // Arrange + const mockProdStream = new ReadableStream() as any; // 模拟的 prod 流 + const mockDebugStream = new ReadableStream({ + start(controller) { + controller.enqueue('Debug stream content'); + controller.close(); + }, + }) as any; + mockDebugStream.toReadableStream = () => mockDebugStream; // 添加 toReadableStream 方法 + + // 模拟 chat.completions.create 返回值,包括模拟的 tee 方法 + (instance['client'].chat.completions.create as Mock).mockResolvedValue({ + tee: () => [mockProdStream, { toReadableStream: () => mockDebugStream }], + }); + + // 保存原始环境变量值 + const originalDebugValue = process.env.DEBUG_QWEN_CHAT_COMPLETION; + + // 模拟环境变量 + process.env.DEBUG_QWEN_CHAT_COMPLETION = '1'; + vi.spyOn(debugStreamModule, 'debugStream').mockImplementation(() => Promise.resolve()); + + // 执行测试 + // 运行你的测试函数,确保它会在条件满足时调用 debugStream + // 假设的测试函数调用,你可能需要根据实际情况调整 + await instance.chat({ + messages: [{ content: 'Hello', role: 'user' }], + model: 'qwen-turbo', + stream: true, + temperature: 0.999, + }); + + // 验证 debugStream 被调用 + expect(debugStreamModule.debugStream).toHaveBeenCalled(); + + // 恢复原始环境变量值 + process.env.DEBUG_QWEN_CHAT_COMPLETION = originalDebugValue; + }); + }); + }); +}); diff --git a/src/libs/agent-runtime/qwen/index.ts b/src/libs/agent-runtime/qwen/index.ts new file mode 100644 index 0000000000..2e150d5196 --- /dev/null +++ b/src/libs/agent-runtime/qwen/index.ts @@ -0,0 +1,33 @@ +import OpenAI from 'openai'; + +import { AgentRuntimeErrorType } from '../error'; +import { ModelProvider } from '../types'; +import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory'; + +export const LobeQwenAI = LobeOpenAICompatibleFactory({ + baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1', + chatCompletion: { + handlePayload: (payload) => { + const top_p = payload.top_p; + return { + ...payload, + stream: payload.stream ?? true, + top_p: top_p && top_p >= 1 ? 0.9999 : top_p, + } as OpenAI.ChatCompletionCreateParamsStreaming; + }, + }, + constructorOptions: { + defaultHeaders: { + 'Content-Type': 'application/json', + }, + }, + debug: { + chatCompletion: () => process.env.DEBUG_QWEN_CHAT_COMPLETION === '1', + }, + errorType: { + bizError: AgentRuntimeErrorType.QwenBizError, + invalidAPIKey: AgentRuntimeErrorType.InvalidQwenAPIKey, + }, + + provider: ModelProvider.Qwen, +}); diff --git a/src/libs/agent-runtime/types/type.ts b/src/libs/agent-runtime/types/type.ts index ce6459be33..3bcadf5176 100644 --- a/src/libs/agent-runtime/types/type.ts +++ b/src/libs/agent-runtime/types/type.ts @@ -35,8 +35,8 @@ export enum ModelProvider { OpenAI = 'openai', OpenRouter = 'openrouter', Perplexity = 'perplexity', + Qwen = 'qwen', TogetherAI = 'togetherai', - // Tongyi = 'tongyi', ZeroOne = 'zeroone', ZhiPu = 'zhipu', } diff --git a/src/server/globalConfig/index.ts b/src/server/globalConfig/index.ts index 20038cc7dc..7a0a79cf60 100644 --- a/src/server/globalConfig/index.ts +++ b/src/server/globalConfig/index.ts @@ -32,6 +32,7 @@ export const getServerGlobalConfig = () => { ENABLED_ANTHROPIC, ENABLED_MINIMAX, ENABLED_MISTRAL, + ENABLED_QWEN, ENABLED_AZURE_OPENAI, AZURE_MODEL_LIST, @@ -101,6 +102,7 @@ export const getServerGlobalConfig = () => { }), }, perplexity: { enabled: ENABLED_PERPLEXITY }, + qwen: { enabled: ENABLED_QWEN }, togetherai: { enabled: ENABLED_TOGETHERAI, diff --git a/src/services/__tests__/chat.test.ts b/src/services/__tests__/chat.test.ts index ab345eac07..e687befd5d 100644 --- a/src/services/__tests__/chat.test.ts +++ b/src/services/__tests__/chat.test.ts @@ -17,6 +17,7 @@ import { LobeOpenAI, LobeOpenRouterAI, LobePerplexityAI, + LobeQwenAI, LobeTogetherAI, LobeZeroOneAI, LobeZhipuAI, @@ -892,6 +893,21 @@ describe('AgentRuntimeOnClient', () => { expect(runtime['_runtime']).toBeInstanceOf(LobeDeepSeekAI); }); + it('Qwen provider: with apiKey', async () => { + merge(initialSettingsState, { + settings: { + keyVaults: { + qwen: { + apiKey: 'user-qwen-key', + }, + }, + }, + } as UserSettingsState) as unknown as UserStore; + const runtime = await initializeWithClientStore(ModelProvider.Qwen, {}); + expect(runtime).toBeInstanceOf(AgentRuntime); + expect(runtime['_runtime']).toBeInstanceOf(LobeQwenAI); + }); + /** * Should not have a unknown provider in client, but has * similar cases in server side diff --git a/src/services/chat.ts b/src/services/chat.ts index b5ba0fdf02..3eb78b3000 100644 --- a/src/services/chat.ts +++ b/src/services/chat.ts @@ -127,6 +127,9 @@ export function initializeWithClientStore(provider: string, payload: any) { case ModelProvider.Perplexity: { break; } + case ModelProvider.Qwen: { + break; + } case ModelProvider.Anthropic: { providerOptions = { baseURL: providerAuthPayload?.endpoint, diff --git a/src/types/user/settings/keyVaults.ts b/src/types/user/settings/keyVaults.ts index 8f07bdb4c8..55696044ea 100644 --- a/src/types/user/settings/keyVaults.ts +++ b/src/types/user/settings/keyVaults.ts @@ -30,6 +30,7 @@ export interface UserKeyVaults { openrouter?: OpenAICompatibleKeyVault; password?: string; perplexity?: OpenAICompatibleKeyVault; + qwen?: OpenAICompatibleKeyVault; togetherai?: OpenAICompatibleKeyVault; zeroone?: OpenAICompatibleKeyVault; zhipu?: OpenAICompatibleKeyVault;