feat: expose qianfan in configuration surfaces

This commit is contained in:
jimmyzhuu
2026-04-29 16:32:53 +08:00
parent 6b200fd36b
commit f653483eea
4 changed files with 44 additions and 5 deletions

View File

@@ -771,6 +771,7 @@ class ConfigHandler:
_RECOMMENDED_MODELS = [ _RECOMMENDED_MODELS = [
const.DEEPSEEK_V4_FLASH, const.DEEPSEEK_V4_PRO, const.DEEPSEEK_CHAT, const.DEEPSEEK_REASONER, 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.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.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, 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 looks like a real default a user might paste verbatim — and we
# never auto-rewrite anything on the server side. # never auto-rewrite anything on the server side.
_PLACEHOLDER_V1 = "https://...../v1" _PLACEHOLDER_V1 = "https://...../v1"
_PLACEHOLDER_QIANFAN = "https://...../v2"
_PLACEHOLDER_ZHIPU = "https://...../api/paas/v4" _PLACEHOLDER_ZHIPU = "https://...../api/paas/v4"
_PLACEHOLDER_DOUBAO = "https://...../api/v3" _PLACEHOLDER_DOUBAO = "https://...../api/v3"
_PLACEHOLDER_GEMINI = "https://....." _PLACEHOLDER_GEMINI = "https://....."
@@ -800,6 +802,14 @@ class ConfigHandler:
"api_base_placeholder": _PLACEHOLDER_V1, "api_base_placeholder": _PLACEHOLDER_V1,
"models": [const.DEEPSEEK_V4_FLASH, const.DEEPSEEK_V4_PRO, const.DEEPSEEK_CHAT, const.DEEPSEEK_REASONER], "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", { ("minimax", {
"label": "MiniMax", "label": "MiniMax",
"api_key_field": "minimax_api_key", "api_key_field": "minimax_api_key",
@@ -892,9 +902,9 @@ class ConfigHandler:
EDITABLE_KEYS = { EDITABLE_KEYS = {
"model", "bot_type", "use_linkai", "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", "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", "zhipu_ai_api_key", "dashscope_api_key", "moonshot_api_key",
"ark_api_key", "minimax_api_key", "linkai_api_key", "custom_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", "agent_max_context_tokens", "agent_max_context_turns", "agent_max_steps",

View File

@@ -315,7 +315,7 @@ class Godcmd(Plugin):
except Exception as e: except Exception as e:
ok, result = False, "你没有设置私有GPT模型" ok, result = False, "你没有设置私有GPT模型"
elif cmd == "reset": 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) bot.sessions.clear_session(session_id)
if Bridge().chat_bots.get(bottype): if Bridge().chat_bots.get(bottype):
Bridge().chat_bots.get(bottype).sessions.clear_session(session_id) Bridge().chat_bots.get(bottype).sessions.clear_session(session_id)
@@ -341,7 +341,7 @@ class Godcmd(Plugin):
ok, result = True, "配置已重载" ok, result = True, "配置已重载"
elif cmd == "resetall": elif cmd == "resetall":
if bottype in [const.OPEN_AI, const.OPENAI, const.CHATGPT, const.CHATGPTONAZURE, const.LINKAI, 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]: const.MODELSCOPE]:
channel.cancel_all_session() channel.cancel_all_session()
bot.sessions.clear_all_session() bot.sessions.clear_all_session()

View File

@@ -99,7 +99,7 @@ class Role(Plugin):
if e_context["context"].type != ContextType.TEXT: if e_context["context"].type != ContextType.TEXT:
return return
btype = Bridge().get_bot_type("chat") 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}') logger.debug(f'不支持的bot: {btype}')
return return
bot = Bridge().get_bot("chat") bot = Bridge().get_bot("chat")

View File

@@ -214,5 +214,34 @@ class TestQianfanBot(unittest.TestCase):
post.assert_called_once() 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__": if __name__ == "__main__":
unittest.main() unittest.main()