feat(admin): canaux IA par palier (z.ai/DeepSeek directs), emails generes par IA, reductions Stripe
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m40s

- Chaque modele d'un palier devient une route {canal, modele} : openrouter,
  deepseek direct, zhipu (z.ai, nouveau canal), minimax, openai, xai ;
  repli automatique sur la route suivante si la cle manque, compatibilite
  ascendante avec les anciens reglages a chaines
- Page Fournisseurs refondue en sections ; interrupteurs et chaine de
  secours retablis ; tests de connexion avec delai d'attente
- Emails de relance generes par IA (canal au choix, prompt construit depuis
  le plan marketing, HTML sane, RTL arabe/persan, jamais d'envoi automatique)
- Codes promo : validation locale avant Stripe, Coupon+PromotionCode avec
  double plafond, comptage par session (webhook+sync=1 fois), ecriture
  atomique, relier-a-Stripe, suppression, validation publique au checkout
- Page Tarifs : champ code promo (?promo=) avec verification traduite
- Tests : 1357 verts (facturation par palier testee dans le worker,
  point de contact providers/available, promos, generation)
This commit is contained in:
2026-09-05 19:46:33 +02:00
parent 6c26712687
commit 0a013c679d
47 changed files with 7210 additions and 679 deletions

View File

@@ -5,7 +5,7 @@ Loads API keys, URLs, and enable/disable flags from environment variables.
"""
import os
from typing import List, Optional
from typing import Dict, List, Optional
from pydantic import BaseModel
@@ -100,6 +100,16 @@ class ProvidersConfig:
MINIMAX_MAX_RETRIES: int = int(os.getenv("MINIMAX_MAX_RETRIES", "3"))
MINIMAX_RETRY_DELAY: float = float(os.getenv("MINIMAX_RETRY_DELAY", "1.0"))
# z.ai / Zhipu (modèles GLM — API directe compatible OpenAI)
# Clé : https://z.ai/manage-apikey/apikey-list — base par défaut https://api.z.ai/api/paas/v4
ZHIPU_ENABLED: bool = os.getenv("ZHIPU_ENABLED", "false").lower() == "true"
ZHIPU_API_KEY: str = os.getenv("ZHIPU_API_KEY", "")
ZHIPU_MODEL: str = os.getenv("ZHIPU_MODEL", "glm-5.3")
ZHIPU_BASE_URL: str = os.getenv("ZHIPU_BASE_URL", "https://api.z.ai/api/paas/v4")
ZHIPU_TIMEOUT: int = int(os.getenv("ZHIPU_TIMEOUT", "60"))
ZHIPU_MAX_RETRIES: int = int(os.getenv("ZHIPU_MAX_RETRIES", "3"))
ZHIPU_RETRY_DELAY: float = float(os.getenv("ZHIPU_RETRY_DELAY", "1.0"))
# Fallback chain configuration
#
# IMPORTANT: the registry-based fallback (translate_with_fallback) only
@@ -199,6 +209,12 @@ class ProvidersConfig:
base_url=cls.MINIMAX_BASE_URL,
model=cls.MINIMAX_MODEL,
),
"zhipu": ProviderSettings(
enabled=cls.ZHIPU_ENABLED,
api_key=cls.ZHIPU_API_KEY if cls.ZHIPU_API_KEY else None,
base_url=cls.ZHIPU_BASE_URL,
model=cls.ZHIPU_MODEL,
),
}
return settings_map.get(provider_name.lower(), ProviderSettings())
@@ -219,7 +235,7 @@ class ProvidersConfig:
return False
# Providers requiring API keys
providers_requiring_key = {"openai", "openrouter", "google_cloud", "deepseek", "minimax"}
providers_requiring_key = {"openai", "openrouter", "google_cloud", "deepseek", "minimax", "zhipu"}
if provider_name.lower() in providers_requiring_key:
return bool(settings.api_key)
@@ -238,3 +254,59 @@ class ProvidersConfig:
providers_config = ProvidersConfig()
# Canaux LLM (tous compatibles OpenAI) utilisables dans les routes de palier
# « ai_tiers » et par la génération d'emails marketing. Pour chaque canal :
# base_url par défaut, variable d'environnement de la clé API, variable du
# modèle et modèle par défaut. Les réglages admin (provider_settings.json)
# priment sur les variables d'environnement.
LLM_CHANNELS: Dict[str, Dict[str, str]] = {
"openrouter": {
"base_url": "https://openrouter.ai/api/v1",
"key_env": "OPENROUTER_API_KEY",
"model_env": "OPENROUTER_MODEL",
"default_model": "deepseek/deepseek-v4-flash",
},
"openrouter_premium": {
"base_url": "https://openrouter.ai/api/v1",
"key_env": "OPENROUTER_API_KEY",
"model_env": "OPENROUTER_PREMIUM_MODEL",
"default_model": "anthropic/claude-sonnet-5",
},
"deepseek": {
"base_url": "https://api.deepseek.com/v1",
"key_env": "DEEPSEEK_API_KEY",
"model_env": "DEEPSEEK_MODEL",
"url_env": "DEEPSEEK_BASE_URL",
"default_model": "deepseek-chat",
},
"zhipu": {
"base_url": "https://api.z.ai/api/paas/v4",
"key_env": "ZHIPU_API_KEY",
"model_env": "ZHIPU_MODEL",
"url_env": "ZHIPU_BASE_URL",
"default_model": "glm-5.3",
},
"minimax": {
"base_url": "https://api.minimax.io/v1",
"key_env": "MINIMAX_API_KEY",
"model_env": "MINIMAX_MODEL",
"url_env": "MINIMAX_BASE_URL",
"default_model": "MiniMax-M3",
},
"openai": {
"base_url": "https://api.openai.com/v1",
"key_env": "OPENAI_API_KEY",
"model_env": "OPENAI_MODEL",
"url_env": "OPENAI_BASE_URL",
"default_model": "gpt-4o-mini",
},
"zai": {
"base_url": "https://api.x.ai/v1",
"key_env": "ZAI_API_KEY",
"model_env": "ZAI_MODEL",
"url_env": "ZAI_BASE_URL",
"default_model": "grok-2-1212",
},
}