"""生图可用模型的判定规则(与「对话可用模型」对称)。 ``/api/image/models`` 给出**全部能生图的模型**:账号池上游内置生图模型 (``gpt-image-2`` 及其 codex 变体)+ 第三方接入的生图模型。 候选判据复用 services/chat_model_service.py 的 ``supports_image_generation``: 优先看第三方的能力字段(``txt2img`` / ``img2img``),没有该字段的上游模型退回名字判定。 多模态模型(能力里同时有 ``chat`` 与 ``txt2img``)会同时出现在对话与生图两个列表里。 **默认全部启用。** 第三方生图模型能不能用,本来就由第三方生图配置(分组 / 模型开关、 计费、路由)决定;这里的开关只是**展示层过滤**,只影响模型是否出现在生图下拉里, 不改变计费、路由、额度与对外 API 的行为。所以升级后不会莫名其妙少模型, 管理员可以按需勾掉不想在列表里看到的。 """ from __future__ import annotations from typing import Any from services.chat_model_service import ( SOURCE_THIRD_PARTY, SOURCE_UPSTREAM, _clean, image_capabilities, model_source, supports_image_generation, ) # 生图列表里的来源标签:上游内置生图模型 / 第三方接入生图模型。 IMAGE_SOURCE_BUILTIN = "builtin" IMAGE_SOURCE_THIRD_PARTY = "third_party" def image_model_source(item: dict[str, Any]) -> str: """生图模型的来源:``builtin`` = 账号池上游内置,``third_party`` = 第三方接入。""" if model_source(item) == SOURCE_THIRD_PARTY: return IMAGE_SOURCE_THIRD_PARTY return IMAGE_SOURCE_BUILTIN def _clean_id_set(value: object) -> set[str]: if not isinstance(value, list): return set() return {_clean(item) for item in value if _clean(item)} def resolve_image_models( items: list[Any], overrides: dict[str, Any] | None = None, ) -> list[dict[str, Any]]: """筛出能生图的模型,并标注 ``image_enabled`` / ``image_default_enabled``。 只保留 ``supports_image_generation`` 为真的条目(对话模型不会混进来); 分不清能不能生图的模型一律不放进候选,避免生图下拉里出现选不了的模型。 """ source = overrides if isinstance(overrides, dict) else {} include = _clean_id_set(source.get("include")) exclude = _clean_id_set(source.get("exclude")) resolved: list[dict[str, Any]] = [] for item in items or []: if not isinstance(item, dict): continue model_id = _clean(item.get("id")) if not model_id or not supports_image_generation(item): continue if model_id in include: enabled = True elif model_id in exclude: enabled = False else: enabled = True resolved.append({ **item, "image_enabled": enabled, "image_default_enabled": True, "image_source": image_model_source(item), "image_capabilities": sorted(image_capabilities(item)), }) # 已启用的排前面;同组内上游内置模型优先,再按模型名排序。 resolved.sort(key=lambda entry: ( 0 if entry["image_enabled"] else 1, 0 if entry["image_source"] == IMAGE_SOURCE_BUILTIN else 1, str(entry.get("id") or ""), )) return resolved __all__ = [ "IMAGE_SOURCE_BUILTIN", "IMAGE_SOURCE_THIRD_PARTY", "image_model_source", "resolve_image_models", "SOURCE_THIRD_PARTY", "SOURCE_UPSTREAM", ]