pythonise-exercice / app /models /catalog.py
wilenPxs
Politique de modeles multi-fournisseurs + retrait de Fable + durcissements
81836d8
Raw
History Blame Contribute Delete
4.95 kB
"""
catalog.py — catalogue des modèles candidats par rôle. SANS Fable
(claude-fable-5 retiré volontairement de toute liste utilisable — §7).
Chaque entrée décrit sa route DIRECTE fournisseur (api_format anthropic|openai,
base_url, api_key_env) ET sa route de repli OpenRouter (openrouter_id). La
résolution effective (app/models/client.py) prend la clé directe si présente,
sinon OPENROUTER_API_KEY — un modèle sans aucune clé est « non testé ».
⚠️ IDs vérifiés sur l'API OpenRouter le 2026-07-02. Écarts vs la spec §3.2 :
• gemini-3-1-pro / gemini-3-flash absents → mappés sur gemini-2.5-pro/flash ;
• magistral-medium indisponible sur OpenRouter → retiré des candidats audit ;
• grok-4-1-fast inexistant → retiré des candidats mécanique.
"""
ROLES = ("generate", "audit", "mecanique")
_ANTHROPIC = dict(provider="anthropic", api_format="anthropic",
base_url="https://api.anthropic.com/v1",
api_key_env="ANTHROPIC_API_KEY")
_OPENAI = dict(provider="openai", api_format="openai",
base_url="https://api.openai.com/v1",
api_key_env="OPENAI_API_KEY")
_GEMINI = dict(provider="google", api_format="openai",
base_url="https://generativelanguage.googleapis.com/v1beta/openai",
api_key_env="GEMINI_API_KEY")
_XAI = dict(provider="x-ai", api_format="openai",
base_url="https://api.x.ai/v1", api_key_env="XAI_API_KEY")
_DEEPSEEK = dict(provider="deepseek", api_format="openai",
base_url="https://api.deepseek.com/v1",
api_key_env="DEEPSEEK_API_KEY")
_MOONSHOT = dict(provider="moonshot", api_format="anthropic",
base_url="https://api.moonshot.ai/anthropic",
api_key_env="MOONSHOT_API_KEY")
_ZAI = dict(provider="z-ai", api_format="openai",
base_url="https://api.z.ai/api/paas/v4",
api_key_env="ZAI_API_KEY")
_MISTRAL = dict(provider="mistral", api_format="openai",
base_url="https://api.mistral.ai/v1",
api_key_env="MISTRAL_API_KEY")
_MINIMAX = dict(provider="minimax", api_format="openai",
base_url="https://api.minimax.io/v1",
api_key_env="MINIMAX_API_KEY")
def _m(key, base, direct_id, openrouter_id, roles, cache=True, batch=True):
return key, {**base, "model_id": direct_id, "openrouter_id": openrouter_id,
"roles": tuple(roles), "supports_cache": cache, "supports_batch": batch}
CATALOG: dict = dict([
# ── GENERATE (frontière + quasi-frontière) ───────────────────────────────
_m("claude-sonnet-5", _ANTHROPIC, "claude-sonnet-5",
"anthropic/claude-sonnet-5", ("generate",)),
_m("claude-opus-4-8", _ANTHROPIC, "claude-opus-4-8",
"anthropic/claude-opus-4.8", ("generate", "audit")),
_m("gpt-5-4", _OPENAI, "gpt-5.4", "openai/gpt-5.4", ("generate",)),
_m("gemini-3-1-pro", _GEMINI, "gemini-2.5-pro", # mappé (3.1 absent)
"google/gemini-2.5-pro", ("generate", "audit")),
_m("grok-4-3", _XAI, "grok-4.3", "x-ai/grok-4.3", ("generate", "audit")),
_m("kimi-k2-6", _MOONSHOT, "kimi-k2.6",
"moonshotai/kimi-k2.6", ("generate", "audit")),
_m("glm-5-2", _ZAI, "glm-5.2", "z-ai/glm-5.2", ("generate",)),
_m("deepseek-v4-pro", _DEEPSEEK, "deepseek-v4-pro",
"deepseek/deepseek-v4-pro", ("generate", "audit")),
_m("mistral-large-3", _MISTRAL, "mistral-large-2512",
"mistralai/mistral-large-2512", ("generate",)),
# ── MECANIQUE (rapide / bon marché) ──────────────────────────────────────
_m("claude-haiku-4-5", _ANTHROPIC, "claude-haiku-4-5",
"anthropic/claude-haiku-4.5", ("mecanique",)),
_m("mistral-small", _MISTRAL, "mistral-small-3.2",
"mistralai/mistral-small-3.2-24b-instruct", ("mecanique",), cache=False),
_m("deepseek-v4-flash", _DEEPSEEK, "deepseek-v4-flash",
"deepseek/deepseek-v4-flash", ("mecanique",)),
_m("glm-4-7-flash", _ZAI, "glm-4.7-flash",
"z-ai/glm-4.7-flash", ("mecanique",)),
_m("gemini-3-flash", _GEMINI, "gemini-2.5-flash", # mappé (3-flash absent)
"google/gemini-2.5-flash", ("mecanique",)),
_m("gpt-5-4-nano", _OPENAI, "gpt-5.4-nano",
"openai/gpt-5.4-nano", ("mecanique",)),
# minimax-m3 : catalogue §3.3, candidat d'appoint générique.
_m("minimax-m3", _MINIMAX, "minimax-m3",
"minimax/minimax-m3", ("mecanique",), cache=False),
])
# Candidats par rôle (ordre indicatif ; le banc trie par ses mesures).
CANDIDATES = {
role: [k for k, v in CATALOG.items() if role in v["roles"]]
for role in ROLES
}
def model_info(key: str) -> dict:
if key not in CATALOG:
raise KeyError(f"Modèle inconnu au catalogue : {key!r}")
return CATALOG[key]