Spaces:
Running
Running
| """模型配置构建器""" | |
| import json | |
| import time | |
| from typing import Any, cast | |
| from src.core import MODELS_CONFIG_FILE | |
| from ..utils.logger import get_logger | |
| from ..utils.string_utils import snake_to_camel | |
| # 初始化日志 | |
| logger = get_logger(__name__) | |
| class ModelConfigBuilder: | |
| """解析模型名称、处理后缀、构建生成配置""" | |
| _cached_map: dict[str, str] | None = None | |
| _last_load_time: float = 0 | |
| def __init__(self) -> None: | |
| # 只有在启动阶段打印 | |
| from src.utils.logger import get_request_id | |
| if not get_request_id(): | |
| logger.info("模型配置构建器初始化完成", extra={ | |
| "model_count": len(self._get_model_map()) | |
| }) | |
| def _get_model_map(self) -> dict[str, str]: | |
| # 简单缓存机制,每 60 秒检查一次文件更新 | |
| current_time = time.time() | |
| if ModelConfigBuilder._cached_map is not None and current_time - ModelConfigBuilder._last_load_time < 60: | |
| return ModelConfigBuilder._cached_map | |
| try: | |
| with open(MODELS_CONFIG_FILE, 'r', encoding='utf-8') as f: | |
| config = json.load(f) | |
| ModelConfigBuilder._cached_map = cast(dict[str, str], config.get('alias_map', {})) | |
| ModelConfigBuilder._last_load_time = current_time | |
| logger.debug("模型配置文件加载成功", extra={ | |
| "config_file": MODELS_CONFIG_FILE, | |
| "alias_count": len(ModelConfigBuilder._cached_map) | |
| }) | |
| except Exception as e: | |
| logger.warning(f"模型配置文件加载失败,使用空配置", extra={ | |
| "config_file": MODELS_CONFIG_FILE, | |
| "error": str(e) | |
| }) | |
| if ModelConfigBuilder._cached_map is None: | |
| ModelConfigBuilder._cached_map = {} | |
| return ModelConfigBuilder._cached_map or {} | |
| def parse_model_name(self, model: str) -> str: | |
| """ | |
| 解析模型名称,返回 backend_model | |
| """ | |
| return self._get_model_map().get(model, model) | |
| def build_generation_config( | |
| self, | |
| gen_config: dict[str, Any], | |
| gemini_payload: dict[str, Any] | None = None, | |
| **kwargs: Any | |
| ) -> dict[str, Any]: | |
| """构建生成配置""" | |
| # 防止修改原始配置对象 | |
| final_config = gen_config.copy() | |
| # 1. 直接合并用户提供的配置 | |
| if gemini_payload: | |
| user_gen_config_raw = gemini_payload.get('generationConfig', {}) or gemini_payload.get('generation_config', {}) | |
| if user_gen_config_raw: | |
| user_gen_config: dict[str, Any] = {} | |
| # 显式转换为 Dict (如果它是 Pydantic model) | |
| if hasattr(user_gen_config_raw, 'model_dump'): | |
| user_gen_config = user_gen_config_raw.model_dump(exclude_none=True) | |
| elif isinstance(user_gen_config_raw, dict): | |
| user_gen_config = cast(dict[str, Any], user_gen_config_raw) | |
| if user_gen_config: | |
| final_config.update(user_gen_config) | |
| # 1.5 合并 kwargs 中的生成配置参数 | |
| for k, v in kwargs.items(): | |
| # 直接添加所有 kwargs 参数,让转换函数处理驼峰转换 | |
| final_config[k] = v | |
| # 2. 统一转换为 camelCase (适配 Vcore AI API) | |
| return self._convert_to_gemini_format(final_config) | |
| def _convert_to_gemini_format(self, config: dict[str, Any]) -> dict[str, Any]: | |
| """将 snake_case 配置转换为 camelCase""" | |
| converted: dict[str, Any] = {} | |
| for k, v in config.items(): | |
| camel_key = snake_to_camel(k) | |
| # 特殊处理 thinkingConfig 中的 thinkingLevel 值 | |
| if camel_key == "thinkingConfig" and isinstance(v, dict): | |
| thinking_config: dict[str, Any] = self._camelize_nested(cast(dict[str, Any], v)) | |
| if "thinkingLevel" in thinking_config: | |
| # 将小写的 thinking level 转换为大写 | |
| level = thinking_config["thinkingLevel"] | |
| if isinstance(level, str): | |
| thinking_config["thinkingLevel"] = level.upper() | |
| converted[camel_key] = thinking_config | |
| elif camel_key in {"imageConfig", "speechConfig", "audioTimestamp", "routingConfig"} and isinstance(v, dict): | |
| converted[camel_key] = self._camelize_nested(cast(dict[str, Any], v)) | |
| elif camel_key == "topK" and isinstance(v, (int, float)): | |
| # topK 最大值为 63,防止 API 报错 | |
| converted[camel_key] = min(63, int(v)) | |
| else: | |
| converted[camel_key] = v | |
| return converted | |
| def _camelize_nested(self, value: Any) -> Any: | |
| """递归把 Gemini 配置中的 snake_case 转为 camelCase。""" | |
| if isinstance(value, dict): | |
| return {snake_to_camel(str(k)): self._camelize_nested(v) for k, v in value.items()} | |
| if isinstance(value, list): | |
| return [self._camelize_nested(item) for item in value] | |
| return value | |
| def build_safety_settings(self) -> list[dict[str, str]]: | |
| """构建安全设置""" | |
| return [ | |
| {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"}, | |
| {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"}, | |
| {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE"}, | |
| {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"}, | |
| {"category": "HARM_CATEGORY_CIVIC_INTEGRITY", "threshold": "BLOCK_NONE"} | |
| ] | |