| """anuma.ai ModelRegistry:模型目录(探测自 GET portal.anuma.ai/api/v1/curated-models)。 |
| |
| 字段:id(catalog id,即上游 curated-models 的 id 如 ``kimi/kimi-k3``)/ |
| name / owner(provider)/ upstream_id(Fireworks 格式 ``accounts/fireworks/models/<短名>``)。 |
| |
| ⚠️ 列表为 2026-08-01 探测快照;上游增删模型时用 scripts/probe_catalog.py 重新生成。 |
| """ |
| from __future__ import annotations |
|
|
| import re |
| from typing import Any |
|
|
| from app.upstream.base import ModelRegistry |
|
|
| __all__ = [ |
| "DEFAULT_MODEL", "MODEL_CATALOG", "IMAGE_MODEL_CATALOG", |
| "normalize_image_model", "DefaultModelRegistry", |
| ] |
|
|
| DEFAULT_MODEL = "openai/gpt-5.6-luna" |
|
|
| |
| |
| |
| IMAGE_MODEL_CATALOG: list[dict[str, Any]] = [ |
| {"id": "gpt-image-2", "name": "GPT Image 2"}, |
| {"id": "flux-2-pro", "name": "Flux 2 Pro"}, |
| {"id": "flux-2-klein-4b", "name": "Flux 2 Klein 4B"}, |
| {"id": "grok-imagine", "name": "Grok Imagine"}, |
| {"id": "nano-banana", "name": "Nano Banana"}, |
| {"id": "nano-banana-pro", "name": "Nano Banana Pro"}, |
| {"id": "nano-banana-2", "name": "Nano Banana 2"}, |
| {"id": "anuma-flash", "name": "Anuma Flash (tier alias)"}, |
| {"id": "anuma-pro", "name": "Anuma Pro (tier alias)"}, |
| {"id": "anuma-flash-private", "name": "Anuma Flash Private (tier alias)"}, |
| {"id": "anuma-pro-private", "name": "Anuma Pro Private (tier alias)"}, |
| ] |
|
|
| _IMAGE_BY_KEY: dict[str, dict[str, Any]] = {} |
| for _im in IMAGE_MODEL_CATALOG: |
| _IMAGE_BY_KEY[_im["id"]] = _im |
| _IMAGE_BY_KEY[_im["name"].lower()] = _im |
|
|
|
|
| def normalize_image_model(model: str | None) -> str | None: |
| """客户端传入的 gen 图片模型 → 上游 tool 参数值;空/未知 → None(由客户端容错)。""" |
| if not model: |
| return None |
| if model in _IMAGE_BY_KEY: |
| return _IMAGE_BY_KEY[model]["id"] |
| low = model.lower() |
| if low in _IMAGE_BY_KEY: |
| return _IMAGE_BY_KEY[low]["id"] |
| norm = re.sub(r"[^a-z0-9]", "", low) |
| for m in IMAGE_MODEL_CATALOG: |
| if re.sub(r"[^a-z0-9]", "", m["id"]) == norm: |
| return m["id"] |
| return None |
|
|
| |
| MODEL_CATALOG: list[dict[str, Any]] = [ |
| {"id": "inclusionai/ling-2.6-flash", "name": "Ling 2.6 Flash", "owner": "InclusionAI", "upstream_id": "accounts/fireworks/models/ling-2.6-flash"}, |
| {"id": "kimi/kimi-k3", "name": "Kimi K3", "owner": "Kimi", "upstream_id": "accounts/fireworks/models/kimi-k3"}, |
| {"id": "kimi/kimi-k2.7-code", "name": "Kimi K2.7 Code", "owner": "Kimi", "upstream_id": "accounts/fireworks/models/kimi-k2.7-code"}, |
| {"id": "kimi/kimi-k2.6", "name": "Kimi 2.6", "owner": "Kimi", "upstream_id": "accounts/fireworks/models/kimi-k2.6"}, |
| {"id": "openai/gpt-5.6-sol", "name": "GPT 5.6 Sol", "owner": "OpenAI", "upstream_id": "accounts/fireworks/models/gpt-5.6-sol"}, |
| {"id": "openai/gpt-5.6-terra", "name": "GPT 5.6 Terra", "owner": "OpenAI", "upstream_id": "accounts/fireworks/models/gpt-5.6-terra"}, |
| {"id": "openai/gpt-5.6-luna", "name": "GPT 5.6 Luna", "owner": "OpenAI", "upstream_id": "accounts/fireworks/models/gpt-5.6-luna"}, |
| {"id": "anthropic/claude-sonnet-5", "name": "Claude Sonnet 5", "owner": "Anthropic", "upstream_id": "accounts/fireworks/models/claude-sonnet-5"}, |
| {"id": "anthropic/claude-opus-5", "name": "Claude Opus 5", "owner": "Anthropic", "upstream_id": "accounts/fireworks/models/claude-opus-5"}, |
| {"id": "openai/gpt-5.5", "name": "GPT 5.5", "owner": "OpenAI", "upstream_id": "accounts/fireworks/models/gpt-5.5"}, |
| {"id": "qwen/qwen-3.7-plus", "name": "Qwen 3.7 Plus", "owner": "Qwen", "upstream_id": "accounts/fireworks/models/qwen-3.7-plus"}, |
| {"id": "qwen/qwen-3.6-plus", "name": "Qwen 3.6 Plus", "owner": "Qwen", "upstream_id": "accounts/fireworks/models/qwen-3.6-plus"}, |
| {"id": "glm/glm-5.2", "name": "GLM 5.2", "owner": "Zhipu", "upstream_id": "accounts/fireworks/models/glm-5.2"}, |
| {"id": "minimax/minimax-m3", "name": "MiniMax M3", "owner": "MiniMax", "upstream_id": "accounts/fireworks/models/minimax-m3"}, |
| {"id": "minimax/minimax-m2.7", "name": "Minimax 2.7", "owner": "MiniMax", "upstream_id": "accounts/fireworks/models/minimax-m2.7"}, |
| ] |
|
|
| _BY_KEY: dict[str, dict[str, Any]] = {} |
| for _m in MODEL_CATALOG: |
| _BY_KEY[_m["id"]] = _m |
| _BY_KEY[_m["name"].lower()] = _m |
|
|
|
|
| class DefaultModelRegistry(ModelRegistry): |
| def catalog(self) -> list[dict[str, Any]]: |
| return list(MODEL_CATALOG) |
|
|
| def normalize(self, model: str | None) -> str: |
| """客户端传入的 model → catalog id;空或未知 → 默认。匹配:精确 id > 显示名(小写) > 模糊。""" |
| if not model: |
| return DEFAULT_MODEL |
| if model in _BY_KEY: |
| return _BY_KEY[model]["id"] |
| low = model.lower() |
| if low in _BY_KEY: |
| return _BY_KEY[low]["id"] |
| norm = re.sub(r"[^a-z0-9]", "", low) |
| for m in MODEL_CATALOG: |
| if (re.sub(r"[^a-z0-9]", "", m["id"]) == norm |
| or re.sub(r"[^a-z0-9]", "", m["name"].lower()) == norm): |
| return m["id"] |
| return DEFAULT_MODEL |
|
|
| def upstream_id_for(self, model_id: str) -> str | None: |
| m = _BY_KEY.get(model_id) |
| return m["upstream_id"] if m else None |
|
|