From e7024786b23bf90900c332ba1d59095a049f7ac2 Mon Sep 17 00:00:00 2001 From: Hosisora_Ling <2374416274@qq.com> Date: Thu, 23 Apr 2026 16:45:53 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20Xiaomi=20?= =?UTF-8?q?=E5=92=8C=20Xiaomi=20Token=20Plan=20LLM=20=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E5=95=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 Xiaomi provider(OpenAI 兼容) - 新增 Xiaomi Token Plan provider(Anthropic 兼容) - 支持全模态(图片理解) - 内置 MiMo v2.5 系列模型 --- astrbot/core/config/default.py | 25 +++++++ astrbot/core/provider/manager.py | 6 ++ .../core/provider/sources/xiaomi_source.py | 70 +++++++++++++++++ .../sources/xiaomi_token_plan_source.py | 75 +++++++++++++++++++ dashboard/src/utils/providerUtils.js | 4 +- 5 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 astrbot/core/provider/sources/xiaomi_source.py create mode 100644 astrbot/core/provider/sources/xiaomi_token_plan_source.py diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 1cdd1d2e45..36593f1ef9 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -1250,6 +1250,31 @@ class ChatProviderTemplate(TypedDict): "custom_headers": {"User-Agent": "claude-code/0.1.0"}, "anth_thinking_config": {"type": "", "budget": 0, "effort": ""}, }, + "Xiaomi": { + "id": "xiaomi", + "provider": "xiaomi", + "type": "xiaomi_chat_completion", + "provider_type": "chat_completion", + "enable": True, + "key": [], + "api_base": "https://api.xiaomimimo.com/v1", + "timeout": 120, + "proxy": "", + "custom_headers": {}, + }, + "Xiaomi Token Plan": { + "id": "xiaomi-token-plan", + "provider": "xiaomi-token-plan", + "type": "xiaomi_token_plan", + "provider_type": "chat_completion", + "enable": True, + "key": [], + "api_base": "https://token-plan-cn.xiaomimimo.com/anthropic", + "timeout": 120, + "proxy": "", + "custom_headers": {"User-Agent": "claude-code/0.1.0"}, + "anth_thinking_config": {"type": "", "budget": 0, "effort": ""}, + }, "xAI": { "id": "xai", "provider": "xai", diff --git a/astrbot/core/provider/manager.py b/astrbot/core/provider/manager.py index 0dfdbdcf6d..80b6695c3e 100644 --- a/astrbot/core/provider/manager.py +++ b/astrbot/core/provider/manager.py @@ -367,6 +367,12 @@ def dynamic_import_provider(self, type: str) -> None: from .sources.minimax_token_plan_source import ( ProviderMiniMaxTokenPlan as ProviderMiniMaxTokenPlan, ) + case "xiaomi_chat_completion": + from .sources.xiaomi_source import ProviderXiaomi as ProviderXiaomi + case "xiaomi_token_plan": + from .sources.xiaomi_token_plan_source import ( + ProviderXiaomiTokenPlan as ProviderXiaomiTokenPlan, + ) case "zhipu_chat_completion": from .sources.zhipu_source import ProviderZhipu as ProviderZhipu case "groq_chat_completion": diff --git a/astrbot/core/provider/sources/xiaomi_source.py b/astrbot/core/provider/sources/xiaomi_source.py new file mode 100644 index 0000000000..21508c0b03 --- /dev/null +++ b/astrbot/core/provider/sources/xiaomi_source.py @@ -0,0 +1,70 @@ +from astrbot import logger +from astrbot.core.provider.sources.openai_source import ProviderOpenAIOfficial + +from ..register import register_provider_adapter + +XIAOMI_MODELS = [ + "mimo-v2.5-pro", + "mimo-v2.5", + "mimo-v2-pro", + "mimo-v2-omni", + "mimo-v2-flash", +] + + +@register_provider_adapter( + "xiaomi_chat_completion", + "Xiaomi API 提供商适配器 (OpenAI 兼容)", + default_config_tmpl={ + "id": "xiaomi", + "provider": "xiaomi", + "type": "xiaomi_chat_completion", + "provider_type": "chat_completion", + "enable": True, + "key": [], + "api_base": "https://api.xiaomimimo.com/v1", + "timeout": 120, + "proxy": "", + "custom_headers": {}, + "custom_extra_body": {"temperature": 1, "top_p": 0.95}, + }, +) +class ProviderXiaomi(ProviderOpenAIOfficial): + """Xiaomi provider using OpenAI-compatible API. + + Supports both standard API and multimodal capabilities. + See https://platform.xiaomimimo.com/docs/api/chat/openai-api + """ + + def __init__( + self, + provider_config, + provider_settings, + ) -> None: + # Ensure api_base is set to Xiaomi endpoint if not provided + if not provider_config.get("api_base"): + provider_config["api_base"] = "https://api.xiaomimimo.com/v1" + + super().__init__( + provider_config, + provider_settings, + ) + + configured_model = provider_config.get("model", "mimo-v2.5") + self.set_model(configured_model) + + logger.debug(f"Xiaomi provider initialized with model: {self.get_model()}") + + async def get_models(self) -> list[str]: + """Return the list of known Xiaomi models. + + Tries to fetch from API first, falls back to hard-coded list if unavailable. + """ + try: + models = await super().get_models() + if models: + return models + except Exception as e: + logger.debug(f"Failed to fetch models from Xiaomi API: {e}") + + return XIAOMI_MODELS.copy() diff --git a/astrbot/core/provider/sources/xiaomi_token_plan_source.py b/astrbot/core/provider/sources/xiaomi_token_plan_source.py new file mode 100644 index 0000000000..9231453207 --- /dev/null +++ b/astrbot/core/provider/sources/xiaomi_token_plan_source.py @@ -0,0 +1,75 @@ +from astrbot import logger +from astrbot.core.provider.sources.anthropic_source import ProviderAnthropic + +from ..register import register_provider_adapter + +XIAOMI_TOKEN_PLAN_MODELS = [ + "mimo-v2.5-pro", + "mimo-v2.5", + "mimo-v2-pro", + "mimo-v2-omni", + "mimo-v2-flash", +] + + +@register_provider_adapter( + "xiaomi_token_plan", + "Xiaomi Token Plan 提供商适配器", + default_config_tmpl={ + "id": "xiaomi-token-plan", + "provider": "xiaomi-token-plan", + "type": "xiaomi_token_plan", + "provider_type": "chat_completion", + "enable": True, + "key": [], + "api_base": "https://token-plan-cn.xiaomimimo.com/anthropic", + "timeout": 120, + "proxy": "", + "custom_headers": {"User-Agent": "claude-code/0.1.0"}, + "custom_extra_body": {"temperature": 1, "top_p": 0.95}, + "anth_thinking_config": {"type": "", "budget": 0, "effort": ""}, + }, +) +class ProviderXiaomiTokenPlan(ProviderAnthropic): + """Xiaomi Token Plan provider. + + The Token Plan API uses Anthropic-compatible endpoint with Bearer token auth. + See https://platform.xiaomimimo.com/docs/tokenplan/quick-access + """ + + def __init__( + self, + provider_config, + provider_settings, + ) -> None: + # Keep api_base fixed; Token Plan users do not need to configure it. + provider_config["api_base"] = "https://token-plan-cn.xiaomimimo.com/anthropic" + + # Xiaomi Token Plan requires the Authorization: Bearer header. + key = provider_config.get("key", "") + actual_key = key[0] if isinstance(key, list) else key + provider_config.setdefault("custom_headers", {})["Authorization"] = ( + f"Bearer {actual_key}" + ) + + super().__init__( + provider_config, + provider_settings, + ) + + configured_model = provider_config.get("model", "mimo-v2.5") + if configured_model not in XIAOMI_TOKEN_PLAN_MODELS: + logger.warning( + f"Configured model {configured_model!r} is not in the known " + f"Token Plan model list " + f"({', '.join(XIAOMI_TOKEN_PLAN_MODELS)}). " + f"The model may still work if your plan supports it. " + f"If you encounter errors, please check your plan's " + f"model availability." + ) + + self.set_model(configured_model) + + async def get_models(self) -> list[str]: + """Return the hard-coded known model list because Token Plan cannot fetch it dynamically.""" + return XIAOMI_TOKEN_PLAN_MODELS.copy() diff --git a/dashboard/src/utils/providerUtils.js b/dashboard/src/utils/providerUtils.js index dbf09b83a3..ee76fafa88 100644 --- a/dashboard/src/utils/providerUtils.js +++ b/dashboard/src/utils/providerUtils.js @@ -34,7 +34,9 @@ export function getProviderIcon(type) { 'fishaudio': 'https://cdn.jsdelivr.net/npm/@lobehub/icons-static-svg@latest/icons/fishaudio.svg', 'minimax': 'https://cdn.jsdelivr.net/npm/@lobehub/icons-static-svg@latest/icons/minimax.svg', 'minimax-token-plan': 'https://cdn.jsdelivr.net/npm/@lobehub/icons-static-svg@latest/icons/minimax.svg', - 'mimo': 'https://platform.xiaomimimo.com/favicon.874c9507.png', + 'mimo': 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/xiaomi.svg', + 'xiaomi': 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/xiaomi.svg', + 'xiaomi-token-plan': 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/xiaomi.svg', '302ai': 'https://cdn.jsdelivr.net/npm/@lobehub/icons-static-svg@1.53.0/icons/ai302-color.svg', 'microsoft': 'https://cdn.jsdelivr.net/npm/@lobehub/icons-static-svg@latest/icons/microsoft.svg', 'vllm': 'https://cdn.jsdelivr.net/npm/@lobehub/icons-static-svg@latest/icons/vllm.svg', From 3ffcb2c616c273b34527ded3fd89c028b2502278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E7=A9=BA=E5=87=8C?= <104693985+HosisoraLing@users.noreply.github.com> Date: Mon, 27 Apr 2026 08:57:16 +0800 Subject: [PATCH 2/2] Update astrbot/core/provider/sources/xiaomi_token_plan_source.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../core/provider/sources/xiaomi_token_plan_source.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/astrbot/core/provider/sources/xiaomi_token_plan_source.py b/astrbot/core/provider/sources/xiaomi_token_plan_source.py index 9231453207..a1ef20d670 100644 --- a/astrbot/core/provider/sources/xiaomi_token_plan_source.py +++ b/astrbot/core/provider/sources/xiaomi_token_plan_source.py @@ -46,11 +46,12 @@ def __init__( provider_config["api_base"] = "https://token-plan-cn.xiaomimimo.com/anthropic" # Xiaomi Token Plan requires the Authorization: Bearer header. - key = provider_config.get("key", "") - actual_key = key[0] if isinstance(key, list) else key - provider_config.setdefault("custom_headers", {})["Authorization"] = ( - f"Bearer {actual_key}" - ) + keys = provider_config.get("key", []) + actual_key = keys[0] if isinstance(keys, list) and keys else keys + if actual_key: + provider_config.setdefault("custom_headers", {})["Authorization"] = ( + f"Bearer {actual_key}" + ) super().__init__( provider_config,