From f653483eeab868bf71ae932c1925c87d17a223e0 Mon Sep 17 00:00:00 2001 From: jimmyzhuu Date: Wed, 29 Apr 2026 16:32:53 +0800 Subject: [PATCH] feat: expose qianfan in configuration surfaces --- channel/web/web_channel.py | 14 ++++++++++++-- plugins/godcmd/godcmd.py | 4 ++-- plugins/role/role.py | 2 +- tests/test_qianfan_provider.py | 29 +++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/channel/web/web_channel.py b/channel/web/web_channel.py index 4d70defe..62d7c96a 100644 --- a/channel/web/web_channel.py +++ b/channel/web/web_channel.py @@ -771,6 +771,7 @@ class ConfigHandler: _RECOMMENDED_MODELS = [ const.DEEPSEEK_V4_FLASH, const.DEEPSEEK_V4_PRO, const.DEEPSEEK_CHAT, const.DEEPSEEK_REASONER, + const.ERNIE_45_TURBO_128K, const.ERNIE_45_TURBO_32K, const.ERNIE_X1_TURBO_32K, const.MINIMAX_M2_7_HIGHSPEED, const.MINIMAX_M2_7, const.MINIMAX_M2_5, const.MINIMAX_M2_1, const.MINIMAX_M2_1_LIGHTNING, const.CLAUDE_4_6_SONNET, const.CLAUDE_4_7_OPUS, const.CLAUDE_4_6_OPUS, const.CLAUDE_4_5_SONNET, const.GEMINI_31_FLASH_LITE_PRE, const.GEMINI_31_PRO_PRE, const.GEMINI_3_FLASH_PRE, @@ -787,6 +788,7 @@ class ConfigHandler: # never looks like a real default a user might paste verbatim — and we # never auto-rewrite anything on the server side. _PLACEHOLDER_V1 = "https://...../v1" + _PLACEHOLDER_QIANFAN = "https://...../v2" _PLACEHOLDER_ZHIPU = "https://...../api/paas/v4" _PLACEHOLDER_DOUBAO = "https://...../api/v3" _PLACEHOLDER_GEMINI = "https://....." @@ -800,6 +802,14 @@ class ConfigHandler: "api_base_placeholder": _PLACEHOLDER_V1, "models": [const.DEEPSEEK_V4_FLASH, const.DEEPSEEK_V4_PRO, const.DEEPSEEK_CHAT, const.DEEPSEEK_REASONER], }), + ("qianfan", { + "label": "百度千帆", + "api_key_field": "qianfan_api_key", + "api_base_key": "qianfan_api_base", + "api_base_default": "https://qianfan.baidubce.com/v2", + "api_base_placeholder": _PLACEHOLDER_QIANFAN, + "models": [const.ERNIE_45_TURBO_128K, const.ERNIE_45_TURBO_32K, const.ERNIE_X1_TURBO_32K], + }), ("minimax", { "label": "MiniMax", "api_key_field": "minimax_api_key", @@ -892,9 +902,9 @@ class ConfigHandler: EDITABLE_KEYS = { "model", "bot_type", "use_linkai", - "open_ai_api_base", "deepseek_api_base", "claude_api_base", "gemini_api_base", + "open_ai_api_base", "deepseek_api_base", "qianfan_api_base", "claude_api_base", "gemini_api_base", "zhipu_ai_api_base", "moonshot_base_url", "ark_base_url", "custom_api_base", - "open_ai_api_key", "deepseek_api_key", "claude_api_key", "gemini_api_key", + "open_ai_api_key", "deepseek_api_key", "qianfan_api_key", "claude_api_key", "gemini_api_key", "zhipu_ai_api_key", "dashscope_api_key", "moonshot_api_key", "ark_api_key", "minimax_api_key", "linkai_api_key", "custom_api_key", "agent_max_context_tokens", "agent_max_context_turns", "agent_max_steps", diff --git a/plugins/godcmd/godcmd.py b/plugins/godcmd/godcmd.py index 6439411d..efd445f2 100644 --- a/plugins/godcmd/godcmd.py +++ b/plugins/godcmd/godcmd.py @@ -315,7 +315,7 @@ class Godcmd(Plugin): except Exception as e: ok, result = False, "你没有设置私有GPT模型" elif cmd == "reset": - if bottype in [const.OPEN_AI, const.OPENAI, const.CHATGPT, const.CHATGPTONAZURE, const.LINKAI, const.BAIDU, const.XUNFEI, const.QWEN, const.QWEN_DASHSCOPE, const.GEMINI, const.ZHIPU_AI, const.CLAUDEAPI]: + if bottype in [const.OPEN_AI, const.OPENAI, const.CHATGPT, const.CHATGPTONAZURE, const.LINKAI, const.BAIDU, const.QIANFAN, const.XUNFEI, const.QWEN, const.QWEN_DASHSCOPE, const.GEMINI, const.ZHIPU_AI, const.CLAUDEAPI]: bot.sessions.clear_session(session_id) if Bridge().chat_bots.get(bottype): Bridge().chat_bots.get(bottype).sessions.clear_session(session_id) @@ -341,7 +341,7 @@ class Godcmd(Plugin): ok, result = True, "配置已重载" elif cmd == "resetall": if bottype in [const.OPEN_AI, const.OPENAI, const.CHATGPT, const.CHATGPTONAZURE, const.LINKAI, - const.BAIDU, const.XUNFEI, const.QWEN, const.QWEN_DASHSCOPE, const.GEMINI, const.ZHIPU_AI, const.MOONSHOT, + const.BAIDU, const.QIANFAN, const.XUNFEI, const.QWEN, const.QWEN_DASHSCOPE, const.GEMINI, const.ZHIPU_AI, const.MOONSHOT, const.MODELSCOPE]: channel.cancel_all_session() bot.sessions.clear_all_session() diff --git a/plugins/role/role.py b/plugins/role/role.py index adec6c82..e23ff361 100644 --- a/plugins/role/role.py +++ b/plugins/role/role.py @@ -99,7 +99,7 @@ class Role(Plugin): if e_context["context"].type != ContextType.TEXT: return btype = Bridge().get_bot_type("chat") - if btype not in [const.OPEN_AI, const.OPENAI, const.CHATGPT, const.CHATGPTONAZURE, const.QWEN_DASHSCOPE, const.XUNFEI, const.BAIDU, const.ZHIPU_AI, const.MOONSHOT, const.MiniMax, const.LINKAI, const.MODELSCOPE]: + if btype not in [const.OPEN_AI, const.OPENAI, const.CHATGPT, const.CHATGPTONAZURE, const.QWEN_DASHSCOPE, const.XUNFEI, const.BAIDU, const.QIANFAN, const.ZHIPU_AI, const.MOONSHOT, const.MiniMax, const.LINKAI, const.MODELSCOPE]: logger.debug(f'不支持的bot: {btype}') return bot = Bridge().get_bot("chat") diff --git a/tests/test_qianfan_provider.py b/tests/test_qianfan_provider.py index 115e7159..ac574330 100644 --- a/tests/test_qianfan_provider.py +++ b/tests/test_qianfan_provider.py @@ -214,5 +214,34 @@ class TestQianfanBot(unittest.TestCase): post.assert_called_once() +class TestQianfanSurfaces(unittest.TestCase): + def _read(self, relative_path): + root = os.path.join(os.path.dirname(__file__), "..") + with open(os.path.join(root, relative_path), encoding="utf-8") as f: + return f.read() + + def test_web_console_registers_qianfan_provider(self): + source = self._read("channel/web/web_channel.py") + + self.assertIn('("qianfan", {', source) + self.assertIn('"label": "百度千帆"', source) + self.assertIn('"api_key_field": "qianfan_api_key"', source) + self.assertIn('"api_base_key": "qianfan_api_base"', source) + self.assertIn('"api_base_default": "https://qianfan.baidubce.com/v2"', source) + + def test_web_console_allows_qianfan_config_edits(self): + source = self._read("channel/web/web_channel.py") + + self.assertIn('"qianfan_api_base"', source) + self.assertIn('"qianfan_api_key"', source) + + def test_session_plugins_allow_qianfan(self): + role_source = self._read("plugins/role/role.py") + godcmd_source = self._read("plugins/godcmd/godcmd.py") + + self.assertIn("const.QIANFAN", role_source) + self.assertIn("const.QIANFAN", godcmd_source) + + if __name__ == "__main__": unittest.main()