From 1109bf3896f0397d687fae274a343bb22ab5234b Mon Sep 17 00:00:00 2001 From: XiaoBoAI Date: Tue, 8 Jul 2025 01:48:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=B8=AD=E8=BD=AC=E6=B8=A0?= =?UTF-8?q?=E9=81=93=E6=94=AF=E6=8C=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新config.py配置文件,添加中转渠道相关配置项 - 修改bridge_all.py和bridge_chatgpt.py以支持中转渠道 - 更新key_pattern_manager.py处理中转渠道密钥模式 --- config.py | 52 +++++++++++++++++++++++++++-- request_llms/bridge_all.py | 28 ++++++++++++++-- request_llms/bridge_chatgpt.py | 30 ++++++++++++++--- shared_utils/key_pattern_manager.py | 29 ++++++++++++++-- 4 files changed, 127 insertions(+), 12 deletions(-) diff --git a/config.py b/config.py index 4af8ffd33..559579310 100644 --- a/config.py +++ b/config.py @@ -8,6 +8,9 @@ """ # [step 1-1]>> ( 接入OpenAI模型家族 ) API_KEY = "sk-123456789xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx123456789"。极少数情况下,还需要填写组织(格式如org-123456789abcdefghijklmno的),请向下翻,找 API_ORG 设置项 +from pickle import TRUE + + API_KEY = "在此处填写APIKEY" # 可同时填写多个API-KEY,用英文逗号分割,例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey3,azure-apikey4" # [step 1-2]>> ( 强烈推荐!接入通义家族 & 大模型服务平台百炼 ) 接入通义千问在线大模型,api-key获取地址 https://dashscope.console.aliyun.com/ @@ -16,6 +19,36 @@ # [step 1-3]>> ( 接入 deepseek-reasoner, 即 deepseek-r1 ) 深度求索(DeepSeek) API KEY,默认请求地址为"https://api.deepseek.com/v1/chat/completions" DEEPSEEK_API_KEY = "" +# [step 1-4]>> ( 接入中转渠道 ) 中转渠道配置,支持采用OpenAI接口模式的中转渠道商 +ZHONGZHUAN_ENABLE = TRUE # 是否启用中转渠道,默认关闭 +ZHONGZHUAN_ENDPOINT = "https://test.com/v1/chat/completions" # 中转渠道的完整API端点 +ZHONGZHUAN_API_KEY = "sk-xxxxxxxxxxxxxxx" # 中转渠道的API KEY,如果为空则使用API_KEY +ZHONGZHUAN_MODELS = [ + # 中转渠道支持的模型列表,使用原始模型名称 + "o3-mini-all", + "gpt-4.1", + "gpt-4o", + "gpt-4o-mini", + "claude-sonnet-4-20250514-thinking", + "claude-sonnet-4-20250514", + "gemini-2.5-pro-preview-03-25", + # 可以添加更多模型... +] +# 配置说明: +# 1. 将ZHONGZHUAN_ENABLE设置为True启用中转渠道 +# 2. 将ZHONGZHUAN_ENDPOINT设置为你的中转渠道商提供的完整API端点(包含/chat/completions) +# 3. 将ZHONGZHUAN_API_KEY设置为你的中转渠道商提供的API KEY(可选) +# 4. 在ZHONGZHUAN_MODELS中配置你想要使用的模型,使用原始模型名称 +# 5. 系统将自动把ZHONGZHUAN_MODELS中的模型添加到AVAIL_LLM_MODELS中,无需重复配置 +# 6. 对于同时在两个列表中的模型,将自动使用中转渠道访问 +# +# 示例配置: +# ZHONGZHUAN_ENABLE = True +# ZHONGZHUAN_ENDPOINT = "https://api.your-provider.com/v1/chat/completions" +# ZHONGZHUAN_API_KEY = "your-api-key-here" +# ZHONGZHUAN_MODELS = ["o3-mini-all", "gpt-4.1", "claude-sonnet-4-20250514"] +# 然后可以直接设置LLM_MODEL = "o3-mini-all"(将通过中转渠道访问) + # [step 2]>> 改为True应用代理。如果使用本地或无地域限制的大模型时,此处不修改;如果直接在海外服务器部署,此处不修改 USE_PROXY = False if USE_PROXY: @@ -49,6 +82,14 @@ "dashscope-qwen3-14b", "dashscope-qwen3-235b-a22b", "dashscope-qwen3-32b", ] +# 自动将中转渠道模型添加到可用模型列表中,避免用户重复配置 +# 对于同时在AVAIL_LLM_MODELS和ZHONGZHUAN_MODELS中的模型,将自动使用中转渠道 +if ZHONGZHUAN_ENABLE and ZHONGZHUAN_MODELS: + for model in ZHONGZHUAN_MODELS: + if model not in AVAIL_LLM_MODELS: + AVAIL_LLM_MODELS.append(model) + print(f"[中转渠道] 已启用,共{len(ZHONGZHUAN_MODELS)}个模型将通过中转渠道访问: {', '.join(ZHONGZHUAN_MODELS)}") + EMBEDDING_MODEL = "text-embedding-3-small" # --- --- --- --- @@ -158,7 +199,7 @@ DEFAULT_FN_GROUPS = ['对话', '编程', '学术', '智能体'] -# 定义界面上“询问多个GPT模型”插件应该使用哪些模型,请从AVAIL_LLM_MODELS中选择,并在不同模型之间用`&`间隔,例如"gpt-3.5-turbo&chatglm3&azure-gpt-4" +# 定义界面上"询问多个GPT模型"插件应该使用哪些模型,请从AVAIL_LLM_MODELS中选择,并在不同模型之间用`&`间隔,例如"gpt-3.5-turbo&chatglm3&azure-gpt-4" MULTI_QUERY_LLM_MODELS = "gpt-3.5-turbo&chatglm3" @@ -361,7 +402,7 @@ AUTO_CONTEXT_CLIP_TRIGGER_TOKEN_LEN = 30*1000 # 无条件丢弃x以上的轮数 AUTO_CONTEXT_MAX_ROUND = 64 -# 在裁剪上下文时,倒数第x次对话能“最多”保留的上下文token的比例占 AUTO_CONTEXT_CLIP_TRIGGER_TOKEN_LEN 的多少 +# 在裁剪上下文时,倒数第x次对话能"最多"保留的上下文token的比例占 AUTO_CONTEXT_CLIP_TRIGGER_TOKEN_LEN 的多少 AUTO_CONTEXT_MAX_CLIP_RATIO = [0.80, 0.60, 0.45, 0.25, 0.20, 0.18, 0.16, 0.14, 0.12, 0.10, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.02, 0.01] @@ -469,4 +510,11 @@ └── MATHPIX_APPKEY +"zhongzhuan-..." 中转渠道模型配置 + ├── ZHONGZHUAN_ENABLE + ├── ZHONGZHUAN_ENDPOINT + ├── ZHONGZHUAN_API_KEY + └── ZHONGZHUAN_MODELS + + """ diff --git a/request_llms/bridge_all.py b/request_llms/bridge_all.py index a37daae32..037a4034c 100644 --- a/request_llms/bridge_all.py +++ b/request_llms/bridge_all.py @@ -1,4 +1,3 @@ - """ 该文件中主要包含2个函数,是所有LLM的通用接口,它们会继续向下调用更底层的LLM模型,处理多模型并行等细节 @@ -115,6 +114,12 @@ def decode(self, *args, **kwargs): # 开始初始化模型 AVAIL_LLM_MODELS, LLM_MODEL = get_conf("AVAIL_LLM_MODELS", "LLM_MODEL") AVAIL_LLM_MODELS = AVAIL_LLM_MODELS + [LLM_MODEL] + +# 获取中转渠道配置 +ZHONGZHUAN_ENABLE, ZHONGZHUAN_ENDPOINT, ZHONGZHUAN_API_KEY, ZHONGZHUAN_MODELS = get_conf( + "ZHONGZHUAN_ENABLE", "ZHONGZHUAN_ENDPOINT", "ZHONGZHUAN_API_KEY", "ZHONGZHUAN_MODELS" +) + # -=-=-=-=-=-=- 以下这部分是最早加入的最稳定的模型 -=-=-=-=-=-=- model_info = { # openai @@ -1415,6 +1420,23 @@ def decode(self, *args, **kwargs): }, }) +# -=-=-=-=-=-=- 中转渠道模型对齐支持 -=-=-=-=-=-=- +# 为中转渠道模型创建统一的model_info配置 +if ZHONGZHUAN_ENABLE and ZHONGZHUAN_MODELS: + # 为每个中转渠道模型创建统一的model_info配置 + # 注意:模型列表的合并已在config.py中处理 + for model in ZHONGZHUAN_MODELS: + model_info.update({ + model: { + "fn_with_ui": chatgpt_ui, + "fn_without_ui": chatgpt_noui, + "endpoint": ZHONGZHUAN_ENDPOINT, + "has_multimodal_capacity": True, + "max_token": 12800000, + "tokenizer": tokenizer_gpt4, + "token_cnt": get_token_num_gpt4, + } + }) # -=-=-=-=-=-=--=-=-=-=-=-=--=-=-=-=-=-=--=-=-=-=-=-=-=-= # -=-=-=-=-=-=-=-=-=- ☝️ 以上是模型路由 -=-=-=-=-=-=-=-=-= @@ -1459,11 +1481,11 @@ def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list, sys model = llm_kwargs['llm_model'] n_model = 1 if '&' not in model: - # 如果只询问“一个”大语言模型(多数情况): + # 如果只询问"一个"大语言模型(多数情况): method = model_info[model]["fn_without_ui"] return method(inputs, llm_kwargs, history, sys_prompt, observe_window, console_silence) else: - # 如果同时询问“多个”大语言模型,这个稍微啰嗦一点,但思路相同,您不必读这个else分支 + # 如果同时询问"多个"大语言模型,这个稍微啰嗦一点,但思路相同,您不必读这个else分支 executor = ThreadPoolExecutor(max_workers=4) models = model.split('&') n_model = len(models) diff --git a/request_llms/bridge_chatgpt.py b/request_llms/bridge_chatgpt.py index b1eddb9e0..206e309d2 100644 --- a/request_llms/bridge_chatgpt.py +++ b/request_llms/bridge_chatgpt.py @@ -241,9 +241,19 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith yield from update_ui(chatbot=chatbot, history=history, msg="api_key已导入") # 刷新界面 return elif not is_any_api_key(chatbot._cookies['api_key']): - chatbot.append((inputs, "缺少api_key。\n\n1. 临时解决方案:直接在输入区键入api_key,然后回车提交。\n\n2. 长效解决方案:在config.py中配置。")) - yield from update_ui(chatbot=chatbot, history=history, msg="缺少api_key") # 刷新界面 - return + # 对于中转渠道模型,额外检查中转渠道API key + is_zhongzhuan_valid = False + try: + ZHONGZHUAN_ENABLE, ZHONGZHUAN_MODELS, ZHONGZHUAN_API_KEY = get_conf("ZHONGZHUAN_ENABLE", "ZHONGZHUAN_MODELS", "ZHONGZHUAN_API_KEY") + if ZHONGZHUAN_ENABLE and llm_kwargs['llm_model'] in ZHONGZHUAN_MODELS and ZHONGZHUAN_API_KEY: + is_zhongzhuan_valid = is_any_api_key(ZHONGZHUAN_API_KEY) + except Exception: + pass + + if not is_zhongzhuan_valid: + chatbot.append((inputs, "缺少api_key。\n\n1. 临时解决方案:直接在输入区键入api_key,然后回车提交。\n\n2. 长效解决方案:在config.py中配置。")) + yield from update_ui(chatbot=chatbot, history=history, msg="缺少api_key") # 刷新界面 + return user_input = inputs if additional_fn is not None: @@ -269,12 +279,22 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith # check mis-behavior if is_the_upload_folder(user_input): - chatbot[-1] = (inputs, f"[Local Message] 检测到操作错误!当您上传文档之后,需点击“**函数插件区**”按钮进行处理,请勿点击“提交”按钮或者“基础功能区”按钮。") + chatbot[-1] = (inputs, f"[Local Message] 检测到操作错误!当您上传文档之后,需点击\"**函数插件区**\"按钮进行处理,请勿点击\"提交\"按钮或者\"基础功能区\"按钮。") yield from update_ui(chatbot=chatbot, history=history, msg="正常") # 刷新界面 time.sleep(2) try: - headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt, image_base64_array, has_multimodal_capacity, stream) + # 对于中转渠道模型,需要确保使用正确的API key + llm_kwargs_modified = llm_kwargs.copy() + try: + ZHONGZHUAN_ENABLE, ZHONGZHUAN_MODELS, ZHONGZHUAN_API_KEY = get_conf("ZHONGZHUAN_ENABLE", "ZHONGZHUAN_MODELS", "ZHONGZHUAN_API_KEY") + if ZHONGZHUAN_ENABLE and llm_kwargs['llm_model'] in ZHONGZHUAN_MODELS and ZHONGZHUAN_API_KEY: + # 确保中转渠道模型使用正确的API key + llm_kwargs_modified['api_key'] = ZHONGZHUAN_API_KEY + except Exception: + pass + + headers, payload = generate_payload(inputs, llm_kwargs_modified, history, system_prompt, image_base64_array, has_multimodal_capacity, stream) except RuntimeError as e: chatbot[-1] = (inputs, f"您提供的api-key不满足要求,不包含任何可用于{llm_kwargs['llm_model']}的api-key。您可能选择了错误的模型或请求源。") yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面 diff --git a/shared_utils/key_pattern_manager.py b/shared_utils/key_pattern_manager.py index 8ea200165..4926c442a 100644 --- a/shared_utils/key_pattern_manager.py +++ b/shared_utils/key_pattern_manager.py @@ -45,8 +45,17 @@ def is_cohere_api_key(key): def is_any_api_key(key): - # key 一般只包含字母、数字、下划线、逗号、中划线 - if not re.match(r"^[a-zA-Z0-9_\-,]+$", key): + # 首先检查是否为中转渠道API KEY + try: + ZHONGZHUAN_ENABLE, ZHONGZHUAN_API_KEY = get_conf("ZHONGZHUAN_ENABLE", "ZHONGZHUAN_API_KEY") + if ZHONGZHUAN_ENABLE and ZHONGZHUAN_API_KEY and key == ZHONGZHUAN_API_KEY: + return True + except Exception: + pass + + # key 一般只包含字母、数字、下划线、逗号、中划线,但为了支持更多中转渠道,适当放宽限制 + # 允许点号(.),用于支持某些中转渠道的特殊格式 + if not re.match(r"^[a-zA-Z0-9_\-,\.]+$", key): # 如果配置了 CUSTOM_API_KEY_PATTERN,再检查以下以免误杀 if CUSTOM_API_KEY_PATTERN := get_conf('CUSTOM_API_KEY_PATTERN'): return bool(re.match(CUSTOM_API_KEY_PATTERN, key)) @@ -93,6 +102,22 @@ def select_api_key(keys, llm_model): avail_key_list = [] key_list = keys.split(',') + # 中转渠道API KEY处理 + try: + ZHONGZHUAN_ENABLE, ZHONGZHUAN_MODELS, ZHONGZHUAN_API_KEY = get_conf("ZHONGZHUAN_ENABLE", "ZHONGZHUAN_MODELS", "ZHONGZHUAN_API_KEY") + if ZHONGZHUAN_ENABLE and llm_model in ZHONGZHUAN_MODELS: + # 如果模型在中转渠道列表中,优先使用中转渠道的API KEY + if ZHONGZHUAN_API_KEY: + return ZHONGZHUAN_API_KEY + # 如果没有设置专门的中转渠道API KEY,则使用OpenAI格式的key(中转渠道一般采用OpenAI接口格式) + for k in key_list: + if is_openai_api_key(k): avail_key_list.append(k) + if len(avail_key_list) > 0: + return random.choice(avail_key_list) + except Exception: + # 如果获取中转渠道配置失败,继续使用原有逻辑 + pass + if llm_model.startswith('gpt-') or llm_model.startswith('chatgpt-') or \ llm_model.startswith('one-api-') or is_o_family_for_openai(llm_model): for k in key_list: