Introduction : Le Scandale d'une Fuite à 2 847 $ en 72 Heures
Il y a six mois, j'ai vécu ce que tout développeur SaaS redoute. Un dimanche soir, à 23h47, mon téléphone vibre avec une alerte Slack : « Budget mensuel dépassé de 340% ». En打开ant le dashboard HolySheep AI, je vois le chiffre glaçant : 2 847,23 $ engloutis en exactement 71 heures et 23 minutes. Le culprit ? Une boucle infinie dans notre système de récapitulatifs IA qui relançait la même requête GPT-4.1 sans condition d'arrêt. Chaque appel coûtait 0,008 $ — mais avec 356 000 appels ratés, la facture avait explosé.
Cette expérience douloureuse m'a poussé à concevoir une architecture de gouvernance des coûts béton. Aujourd'hui, je vais partager avec vous chaque ligne de code, chaque stratégie, chaque leçon apprise — pour que vous n'ayez jamais à subir ce que j'ai vécu. Ce guide est le résultat de 6 mois d'optimisation intensive sur HolySheep AI, avec des données réelles issues de notre production处理 2 millions de tokens par jour.
Comprendre l'Écosystème des Coûts HolySheep AI
Architecture de Facturation par Token
Avant d'aborder les stratégies d'optimisation, comprenons la anatomie d'une requête sur HolySheep AI. Chaque interaction avec l'API génère deux types de tokens :
- Tokens d'entrée (input) : le texte que vous envoyez au modèle (prompts, contexte, historique)
- Tokens de sortie (output) : le texte généré par le modèle (réponses, code, analyses)
HolySheep AI facture ces deux types séparément, avec des taux qui varient significativement selon le modèle choisi. La latence moyenne observée sur leurs serveurs est inférieure à 50ms pour les appels synchrones — un avantage compétitif majeur pour les applications temps réel.
Tableau Comparatif : Prix par Million de Tokens (Mai 2026)
| Modèle | Input ($/M tokens) | Output ($/M tokens) | Ratio Input/Output | Latence Moyenne | Cas d'Usage Optimal |
|---|---|---|---|---|---|
| GPT-4.1 | 8,00 $ | 24,00 $ | 1:3 | 1 250 ms | Raisonnement complexe, code advanced |
| Claude Sonnet 4.5 | 15,00 $ | 75,00 $ | 1:5 | 1 800 ms | Rédaction longue, analyses nuancées |
| Gemini 2.5 Flash | 2,50 $ | 10,00 $ | 1:4 | 380 ms | Traitement par lots, haute fréquence |
| DeepSeek V3.2 | 0,42 $ | 1,68 $ | 1:4 | 320 ms | Tâches simples, maximiser volume |
Source : Grille tarifaire HolySheep AI, mise à jour Mai 2026. Tous les prix en dollars USD.
Stratégie #1 : Implémentation d'un Système d'Alertes Budget en Temps Réel
La première ligne de défense contre les factures surprises est un système d'alertes granulaire. J'ai développé un module Python complet qui monitore l'utilisation en temps réel et envoie des notifications à plusieurs seuils critiques.
#!/usr/bin/env python3
"""
HolySheep AI — Budget Alert System v2.1
Surveillance temps réel avec seuils configurables
"""
import requests
import time
import smtplib
from datetime import datetime, timedelta
from collections import deque
import os
from dataclasses import dataclass
from typing import Optional
@dataclass
class BudgetConfig:
"""Configuration des seuils d'alerte"""
daily_limit_usd: float = 100.0 # Limite quotidienne
weekly_limit_usd: float = 500.0 # Limite hebdomadaire
monthly_limit_usd: float = 1500.0 # Limite mensuelle
warning_threshold: float = 0.75 # Alerte à 75% d'utilisation
critical_threshold: float = 0.90 # Alerte critique à 90%
cooldown_seconds: int = 300 # 5 minutes entre notifications
class HolySheepBudgetMonitor:
"""Moniteur de budget HolySheep AI avec alertes intelligentes"""
BASE_URL = "https://api.holysheep.ai/v1"
def __init__(self, api_key: str, config: Optional[BudgetConfig] = None):
self.api_key = api_key
self.config = config or BudgetConfig()
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
# Historique des coûts (dernières 24h)
self.cost_history = deque(maxlen=288) # 288 * 5 minutes = 24h
self.last_alert_time = {}
self.session_costs = 0.0
def get_usage_stats(self) -> dict:
"""Récupère les statistiques d'utilisation depuis l'API"""
try:
response = requests.get(
f"{self.BASE_URL}/usage",
headers=self.headers,
timeout=10
)
response.raise_for_status()
data = response.json()
return {
"daily_cost": data.get("daily_cost", 0.0),
"weekly_cost": data.get("weekly_cost", 0.0),
"monthly_cost": data.get("monthly_cost", 0.0),
"total_tokens_today": data.get("total_tokens", 0),
"request_count": data.get("request_count", 0),
"timestamp": datetime.now().isoformat()
}
except requests.exceptions.RequestException as e:
print(f"Erreur récupération stats : {e}")
return self._estimate_costs_from_history()
def _estimate_costs_from_history(self) -> dict:
"""Fallback : estimation basée sur l'historique local"""
total = sum(item["cost"] for item in self.cost_history)
return {
"daily_cost": total,
"weekly_cost": total * 7,
"monthly_cost": total * 30,
"total_tokens_today": 0,
"request_count": len(self.cost_history)
}
def track_request(self, input_tokens: int, output_tokens: int, model: str):
"""Enregistre une requête et calcule son coût"""
# Tarifs HolySheep AI (à jour Mai 2026)
pricing = {
"gpt-4.1": {"input": 8.00, "output": 24.00},
"claude-sonnet-4.5": {"input": 15.00, "output": 75.00},
"gemini-2.5-flash": {"input": 2.50, "output": 10.00},
"deepseek-v3.2": {"input": 0.42, "output": 1.68}
}
model_key = model.lower()
if model_key not in pricing:
print(f"Modèle {model} non reconnu, utilisation DeepSeek par défaut")
model_key = "deepseek-v3.2"
input_cost = (input_tokens / 1_000_000) * pricing[model_key]["input"]
output_cost = (output_tokens / 1_000_000) * pricing[model_key]["output"]
total_cost = input_cost + output_cost
self.session_costs += total_cost
self.cost_history.append({
"timestamp": datetime.now(),
"cost": total_cost,
"model": model,
"input_tokens": input_tokens,
"output_tokens": output_tokens
})
return total_cost
def check_thresholds(self, usage: dict) -> list:
"""Vérifie les seuils et retourne les alertes nécessaires"""
alerts = []
checks = [
("daily", usage["daily_cost"], self.config.daily_limit_usd),
("weekly", usage["weekly_cost"], self.config.weekly_limit_usd),
("monthly", usage["monthly_cost"], self.config.monthly_limit_usd)
]
for period, cost, limit in checks:
ratio = cost / limit
if ratio >= self.config.critical_threshold:
alerts.append({
"level": "CRITICAL",
"period": period,
"cost": cost,
"limit": limit,
"percentage": ratio * 100,
"message": f"⚠️ CRITIQUE : {period} {cost:.2f}$ / {limit:.2f}$ ({ratio*100:.1f}%)"
})
elif ratio >= self.config.warning_threshold:
alerts.append({
"level": "WARNING",
"period": period,
"cost": cost,
"limit": limit,
"percentage": ratio * 100,
"message": f"🔔 Alerte : {period} {cost:.2f}$ / {limit:.2f}$ ({ratio*100:.1f}%)"
})
return alerts
def send_alert(self, alert: dict):
"""Envoie une notification (email, Slack, webhook)"""
# Évite le spam : respect du cooldown
alert_key = f"{alert['level']}_{alert['period']}"
last_time = self.last_alert_time.get(alert_key, datetime.min)
if (datetime.now() - last_time).total_seconds() < self.config.cooldown_seconds:
return # Pas d'envoi, en cooldown
self.last_alert_time[alert_key] = datetime.now()
# Formatage du message
message = f"""
╔══════════════════════════════════════════════════════╗
║ 🚨 HOLYSHEEP AI — ALERTE BUDGET {alert['level']} ║
╠══════════════════════════════════════════════════════╣
║ Période : {alert['period'].upper():<33} ║
║ Coût actuel : {alert['cost']:<8.2f}$ ║
║ Limite : {alert['limit']:<8.2f}$ ║
║ Utilisation : {alert['percentage']:<5.1f}% ║
║ Timestamp : {datetime.now().strftime('%Y-%m-%d %H:%M:%S'):<20} ║
╚══════════════════════════════════════════════════════╝
"""
# Sortie console (dev)
print(message)
# TODO: Implémenter l'envoi email/Slack ici
# self._send_email_alert(alert)
# self._send_slack_notification(alert)
def run_monitoring_loop(self, check_interval: int = 60):
"""Boucle principale de monitoring"""
print(f"🎯 Démarrage HolySheep Budget Monitor")
print(f" Limites — Daily: {self.config.daily_limit_usd}$ | "
f"Weekly: {self.config.weekly_limit_usd}$ | "
f"Monthly: {self.config.monthly_limit_usd}$")
while True:
try:
usage = self.get_usage_stats()
alerts = self.check_thresholds(usage)
for alert in alerts:
self.send_alert(alert)
time.sleep(check_interval)
except KeyboardInterrupt:
print("\n⏹️ Monitoring arrêté")
break
except Exception as e:
print(f"❌ Erreur monitoring : {e}")
time.sleep(check_interval)
=== UTILISATION ===
if __name__ == "__main__":
API_KEY = os.environ.get("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")
config = BudgetConfig(
daily_limit_usd=50.0, # 50$ / jour pour dev
weekly_limit_usd=300.0, # 300$ / semaine
monthly_limit_usd=1000.0, # 1000$ / mois
warning_threshold=0.75,
critical_threshold=0.90
)
monitor = HolySheepBudgetMonitor(API_KEY, config)
monitor.run_monitoring_loop(check_interval=60)
Ce système surveille en temps réel votre consommation et alerte via console (ou email/Slack si configuré) dès que vous atteignez 75% ou 90% de vos limites. La fonctionnalité de cooldown évite le spam de notifications.
Stratégie #2 : Architecture de Downgrade Automatique avec Fallback Intelligent
Le concept clé ici : ne jamais utiliser un modèle surdimensionné quand un modèle plus économique fait l'affaire. J'ai implémenté un système de routing intelligent qui sélectionne automatiquement le modèle optimal selon la complexité de la tâche.
#!/usr/bin/env python3
"""
HolySheep AI — Smart Model Router avec Downgrade Automatique
Sélectionne le modèle optimal selon le type de tâche
"""
import requests
import json
import re
from enum import Enum
from typing import Optional, Callable
from dataclasses import dataclass
import hashlib
class TaskComplexity(Enum):
"""Niveaux de complexité de tâche"""
TRIVIAL = 1 # Q&A simple, classifications basiques
SIMPLE = 2 # Formatting, réécriture légère
MODERATE = 3 # Summarisation, traductions
COMPLEX = 4 # Code intermédiaire, analyses
ADVANCED = 5 # Raisonnement profond, code complexe
@dataclass
class ModelConfig:
"""Configuration d'un modèle"""
name: str
provider: str
complexity_range: tuple # (min, max)
cost_per_1k_input: float
cost_per_1k_output: float
max_tokens: int
supports_streaming: bool = True
class HolySheepModelRouter:
"""Router intelligent avec fallback automatique"""
BASE_URL = "https://api.holysheep.ai/v1"
# Annuaire des modèles HolySheep AI
MODELS = {
"deepseek-v3.2": ModelConfig(
name="DeepSeek V3.2",
provider="HolySheep",
complexity_range=(1, 2),
cost_per_1k_input=0.42,
cost_per_1k_output=1.68,
max_tokens=8192
),
"gemini-2.5-flash": ModelConfig(
name="Gemini 2.5 Flash",
provider="HolySheep",
complexity_range=(2, 3),
cost_per_1k_input=2.50,
cost_per_1k_output=10.00,
max_tokens=32768
),
"gpt-4.1": ModelConfig(
name="GPT-4.1",
provider="HolySheep",
complexity_range=(4, 5),
cost_per_1k_input=8.00,
cost_per_1k_output=24.00,
max_tokens=128000
),
"claude-sonnet-4.5": ModelConfig(
name="Claude Sonnet 4.5",
provider="HolySheep",
complexity_range=(3, 5),
cost_per_1k_input=15.00,
cost_per_1k_output=75.00,
max_tokens=200000
)
}
def __init__(self, api_key: str, budget_controller=None):
self.api_key = api_key
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
self.budget_controller = budget_controller
self.usage_stats = {"requests": 0, "total_cost": 0.0}
def analyze_complexity(self, prompt: str, context: Optional[str] = None) -> TaskComplexity:
"""Analyse la complexité d'une tâche basée sur le prompt"""
prompt_lower = prompt.lower()
context = context or ""
combined = (prompt + " " + context).lower()
# Indices de haute complexité
advanced_indicators = [
r'\b(fonction|algorithme|architecture|refactor|optimize)\b',
r'\b(debug|fix|error|exception|stack trace)\b',
r'\b(analyse|research|compare|evaluate|assess)\b',
r'\b(write code|implement|develop|build system)\b',
r'(?s)long context.*multiple.*files',
r'\b(step by step|reasoning|explain.*why)\b'
]
# Indices de basse complexité
trivial_indicators = [
r'\b(translate|summarize|list|what is|who is)\b',
r'\b(yes|no|true|false|confirm)\b',
r'\b(spell check|grammar|fix typo)\b',
r'^.{1,100}[?]$', # Questions courtes
r'\b(classify|categorize|tag)\s+\w+\s+(into|as)\b'
]
# Compteur de sophistication
score = 2 # Par défaut MODERATE
for pattern in advanced_indicators:
if re.search(pattern, combined):
score += 1
for pattern in trivial_indicators:
if re.search(pattern, combined):
score -= 1
# Limiter le score
score = max(1, min(5, score))
return TaskComplexity(score)
def select_model(self, complexity: TaskComplexity, force_model: Optional[str] = None) -> str:
"""Sélectionne le modèle optimal selon la complexité"""
if force_model and force_model in self.MODELS:
return force_model
# Mapping complexité -> modèle par défaut
complexity_model_map = {
TaskComplexity.TRIVIAL: "deepseek-v3.2",
TaskComplexity.SIMPLE: "deepseek-v3.2",
TaskComplexity.MODERATE: "gemini-2.5-flash",
TaskComplexity.COMPLEX: "gpt-4.1",
TaskComplexity.ADVANCED: "gpt-4.1"
}
selected = complexity_model_map.get(complexity, "gemini-2.5-flash")
# Vérification budget : downgrade si proche des limites
if self.budget_controller:
remaining = self.budget_controller.get_remaining_budget()
if remaining < 50: # Moins de 50$ restants
# Downgrade systématique vers modèle économique
selected = "deepseek-v3.2"
print(f"💰 Budget bas détecté ({remaining:.2f}$), downgrade vers DeepSeek")
elif remaining < 200:
selected = "gemini-2.5-flash"
print(f"💰 Budget modéré ({remaining:.2f}$), sélection Gemini Flash")
return selected
def estimate_cost(self, model: str, input_tokens: int, output_tokens: int) -> float:
"""Estime le coût d'une requête"""
if model not in self.MODELS:
return 0.0
config = self.MODELS[model]
input_cost = (input_tokens / 1000) * config.cost_per_1k_input
output_cost = (output_tokens / 1000) * config.cost_per_1k_output
return input_cost + output_cost
def make_request(self, prompt: str, context: Optional[str] = None,
force_model: Optional[str] = None,
max_output_tokens: int = 2048) -> dict:
"""Effectue une requête avec routing intelligent"""
# Étape 1 : Analyser la complexité
complexity = self.analyze_complexity(prompt, context)
print(f"🎯 Complexité détectée : {complexity.name} (score: {complexity.value})")
# Étape 2 : Sélectionner le modèle
model = self.select_model(complexity, force_model)
print(f"🤖 Modèle sélectionné : {self.MODELS[model].name}")
# Étape 3 : Vérifier le budget
estimated_tokens = len(prompt.split()) * 1.3 # Approximation
estimated_cost = self.estimate_cost(model, estimated_tokens, max_output_tokens)
if self.budget_controller:
if not self.budget_controller.can_afford(estimated_cost):
# Fallback vers modèle moins cher
model = "deepseek-v3.2"
print(f"⚠️ Budget insuffisant, fallback vers DeepSeek V3.2")
# Étape 4 : Exécuter la requête
try:
response = self._execute_completion(model, prompt, context, max_output_tokens)
# Étape 5 : Tracker les stats
self._update_stats(response, model)
return {
"success": True,
"model_used": model,
"model_name": self.MODELS[model].name,
"complexity": complexity.name,
"response": response["content"],
"tokens_used": response.get("usage", {}),
"actual_cost": response.get("cost", 0.0)
}
except Exception as e:
print(f"❌ Erreur avec {model}: {e}")
# Tentative de fallback automatique
return self._handle_failure_and_fallback(prompt, context, model, e)
def _execute_completion(self, model: str, prompt: str, context: Optional[str],
max_tokens: int) -> dict:
"""Appel effectif à l'API HolySheep"""
messages = []
if context:
messages.append({"role": "system", "content": context})
messages.append({"role": "user", "content": prompt})
payload = {
"model": model,
"messages": messages,
"max_tokens": max_tokens,
"temperature": 0.7
}
response = requests.post(
f"{self.BASE_URL}/chat/completions",
headers=self.headers,
json=payload,
timeout=30
)
if response.status_code == 401:
raise Exception("401 Unauthorized — Clé API invalide ou expiré")
elif response.status_code == 429:
raise Exception("429 Rate Limited — Trop de requêtes")
elif response.status_code != 200:
raise Exception(f"HTTP {response.status_code}: {response.text}")
data = response.json()
# Extraction des données
content = data["choices"][0]["message"]["content"]
usage = data.get("usage", {})
# Calcul du coût réel
cost = self.estimate_cost(
model,
usage.get("prompt_tokens", 0),
usage.get("completion_tokens", 0)
)
return {
"content": content,
"usage": {
"input_tokens": usage.get("prompt_tokens", 0),
"output_tokens": usage.get("completion_tokens", 0),
"total_tokens": usage.get("total_tokens", 0)
},
"cost": cost
}
def _handle_failure_and_fallback(self, prompt: str, context: Optional[str],
failed_model: str, error: Exception) -> dict:
"""Gère les échecs avec fallback intelligent"""
# Ordre de fallback : gpt-4.1 -> gemini -> deepseek
fallback_order = ["deepseek-v3.2"]
if "429" in str(error):
fallback_order = ["deepseek-v3.2", "gemini-2.5-flash"]
for fallback_model in fallback_order:
if fallback_model == failed_model:
continue
print(f"🔄 Tentative fallback vers {self.MODELS[fallback_model].name}...")
try:
response = self._execute_completion(
fallback_model, prompt, context, 2048
)
self._update_stats(response, fallback_model)
return {
"success": True,
"model_used": fallback_model,
"model_name": self.MODELS[fallback_model].name,
"complexity": "FALLBACK",
"response": response["content"],
"tokens_used": response.get("usage", {}),
"actual_cost": response.get("cost", 0.0),
"fallback_from": failed_model
}
except Exception:
continue
return {
"success": False,
"error": str(error),
"all_models_failed": True
}
def _update_stats(self, response: dict, model: str):
"""Met à jour les statistiques d'utilisation"""
self.usage_stats["requests"] += 1
self.usage_stats["total_cost"] += response.get("cost", 0.0)
def get_cost_report(self) -> dict:
"""Génère un rapport de coûts détaillé"""
return {
"total_requests": self.usage_stats["requests"],
"total_cost_usd": self.usage_stats["total_cost"],
"average_cost_per_request": (
self.usage_stats["total_cost"] / self.usage_stats["requests"]
if self.usage_stats["requests"] > 0 else 0
),
"currency_note": "Tous les montants en USD. Taux avantageux pour utilisateurs CNY."
}
=== CLASSE BUDGET CONTROLLER (pour le routing) ===
class SimpleBudgetController:
"""Contrôleur de budget minimal pour le router"""
def __init__(self, daily_limit: float = 100.0):
self.daily_limit = daily_limit
self.spent_today = 0.0
def can_afford(self, amount: float) -> bool:
return (self.spent_today + amount) <= self.daily_limit
def get_remaining_budget(self) -> float:
return max(0, self.daily_limit - self.spent_today)
def record_spending(self, amount: float):
self.spent_today += amount
=== EXEMPLE D'UTILISATION ===
if __name__ == "__main__":
API_KEY = "YOUR_HOLYSHEEP_API_KEY"
# Initialisation avec contrôleur de budget
budget = SimpleBudgetController(daily_limit=50.0)
router = HolySheepModelRouter(API_KEY, budget)
# Exemple 1 : Question simple (détournera vers DeepSeek)
result1 = router.make_request(
prompt="Quelle est la capitale du Japon ?",
max_output_tokens=100
)
print(f"\n📝 Résultat 1 : {result1['model_name']}")
# Exemple 2 : Tâche complexe (utilisera GPT-4.1)
result2 = router.make_request(
prompt="Implémente un algorithme de tri rapide en Python avec tests unitaires",
context="Langage: Python 3.10+",
max_output_tokens=2048
)
print(f"\n📝 Résultat 2 : {result2['model_name']}")
# Rapport de coûts
print(f"\n💰 Rapport de coûts : {router.get_cost_report()}")
Stratégie #3 : Configuration de Rate Limiting et Quotas par Clé API
Une autre couche de protection essentielle : limiter les dommages quand quelque chose tourne mal. Voici comment configurer des quotas stricts sur vos clés API HolySheep.
#!/usr/bin/env python3
"""
HolySheep AI — Rate Limiter & Quota Manager
Protection contre les surcharges et les abus
"""
import time
import threading
from datetime import datetime, timedelta
from collections import defaultdict
from dataclasses import dataclass, field
from typing import Dict, Optional
import hashlib
@dataclass
class QuotaConfig:
"""Configuration des quotas par clé API"""
requests_per_minute: int = 60
requests_per_hour: int = 1000
requests_per_day: int = 10000
tokens_per_minute: int = 100000
tokens_per_day: int = 5000000
max_cost_per_day_usd: float = 100.0
enabled: bool = True
class RateLimiter:
"""Rate limiter thread-safe avec quotas configurables"""
def __init__(self):
self.quotas: Dict[str, QuotaConfig] = {}
self.request_history: Dict[str, list] = defaultdict(list)
self.token_usage: Dict[str, list] = defaultdict(list)
self.lock = threading.Lock()
def register_key(self, api_key: str, quota: QuotaConfig):
"""Enregistre une clé API avec ses quotas"""
with self.lock:
# Hasher la clé pour le stockage (sécurité)
key_hash = hashlib.sha256(api_key.encode()).hexdigest()[:16]
self.quotas[key_hash] = quota
self.request_history[key_hash] = []
self.token_usage[key_hash] = []
def check_request_allowed(self, api_key: str, estimated_tokens: int = 0) -> tuple:
"""Vérifie si une requête est autorisée. Retourne (allowed, reason, wait_seconds)"""
key_hash = hashlib.sha256(api_key.encode()).hexdigest()[:16]
if key_hash not in self.quotas:
return True, "Aucune restriction", 0
quota = self.quotas[key_hash]
if not quota.enabled:
return True, "Quotas désactivés", 0
now = datetime.now()
history = self.request_history[key_hash]
tokens = self.token_usage[key_hash]
# Nettoyage des entrées expirées
self._cleanup_old_entries(key_hash, now)
# Vérification RPM (requests per minute)
one_minute_ago = now - timedelta(minutes=1)
recent_requests = [t for t in history if t > one_minute_ago]
if len(recent_requests) >= quota.requests_per_minute:
oldest = min(recent_requests)
wait = (oldest - one_minute_ago).total_seconds() + 1
return False, f"RPM limit ({quota.requests_per_minute}/min)", max(0, wait)
# Vérification RPH (requests per hour)
one_hour_ago = now - timedelta(hours=1)
hour_requests = [t for t in history if t > one_hour_ago]
if len(hour_requests) >= quota.requests_per_hour:
oldest = min(hour_requests)
wait = (oldest - one_hour_ago).total_seconds() + 60
return False, f"RPH limit ({quota.requests_per_hour}/hour)", max(0, wait)
# Vérification RPD (requests per day)
today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
day_requests = [t for t in history if t > today_start]
if len(day_requests) >= quota.requests_per_day:
return False, f"RPD limit reached ({quota.requests_per_day}/day)", 86400
# Vérification TPD (tokens per day)
day_tokens = sum(
t for t, _ in tokens
if datetime.fromtimestamp(t) > today_start
)
if day_tokens + estimated_tokens > quota.tokens_per_day:
return False, f"TPD limit ({quota.tokens_per_day:,}/day)", 86400
# Tout est bon
return True, "Allowed", 0
def record_request(self, api_key: str, tokens_used: int, cost_usd: float):
"""Enregistre une requête complétée"""
key_hash = hashlib.sha256(api_key.encode()).hexdigest()[:16]
now = datetime.now()
with self.lock:
self.request_history[key_hash].append(now)
self.token_usage[key_hash].append((time.time(), tokens_used))
def _cleanup_old_entries(self, key_hash: str, now: datetime):
"""Supprime les entrées plus anciennes que 24h"""
one_day_ago = now - timedelta(days=1)
# Nettoyer l'historique des requêtes
self.request_history[key_hash] = [
t for t in self.request_history[key_hash]
if t > one_day_ago
]
# Nettoyer l'utilisation des tokens
cutoff = time.time() - 86400
self.token_usage[key_hash]