Il y a trois mois, ma startup a reçu une facture de 13 500 $ pour un seul mois d'utilisation d'API Claude. Le culprit ? Un pipeline RAG mal configuré qui envoyait systématiquement 800 000 tokens par requête, sans stratégie de cache ni budgétisation. J'ai passé 72 heures à corriger le problème, et c'est cette expérience qui m'a poussé à développer une architecture robuste de gestion des coûts pour les longs contextes. Aujourd'hui, je vais vous montrer exactement comment reproduire cette solution avec HolySheep AI, qui m'a permis de réduire mes coûts de 85% tout en maintenant une latence inférieure à 50ms.

Le Problème des Longs Contextes : Une Fuite Silencieuse dans Votre Budget

Les modèles comme Claude Sonnet 4.5 et Gemini 2.5 Flash supportent des contextes de 1 million de tokens. C'est impressionnant, mais chaque token a un coût. Voici la réalité financière que j'ai découverte à mes dépens :

Modèle Prix officiel (/M tokens) Prix HolySheep (/M tokens) Économie
Claude Sonnet 4.5 15,00 $ 2,25 $ 85%
Gemini 2.5 Flash 2,50 $ 0,375 $ 85%
GPT-4.1 8,00 $ 1,20 $ 85%
DeepSeek V3.2 0,42 $ 0,063 $ 85%

Avec un pipeline qui traitait 1000 requêtes/jour de 800K tokens chacune, le calcul devient effroyable : 800 000 × 1 000 × 15 $ / 1 000 000 = 12 000 $/jour. Avec HolySheep, ce même traitement coûte 1 800 $/jour. Sur un mois, l'économie atteint 306 000 $.

Architecture de Budget et Contexte : Le Code Complet

Avant de présenter le code, comprenez l'architecture que j'ai mise en place. Elle repose sur trois piliers : la budgétisation préventive, la troncature intelligente, et la mise en cache sémantique.

1. Configuration de Base avec Budget Guard

#!/usr/bin/env python3
"""
HolySheep AI - Budget Guard pour Longs Contextes
Auteur: HolySheep AI Technical Team
Version: 2.1037.0503
"""

import os
import time
import hashlib
import tiktoken
from dataclasses import dataclass, field
from typing import List, Dict, Optional, Tuple
from collections import OrderedDict
import requests

=== CONFIGURATION HOLYSHEEP ===

BASE_URL = "https://api.holysheep.ai/v1" API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")

=== BUDGETS PAR MODÈLE (en tokens) ===

CONTEXT_BUDGETS = { "claude-sonnet-4.5": 200_000, # 200K pour Claude "gemini-2.5-flash": 500_000, # 500K pour Gemini "gpt-4.1": 128_000, # 128K pour GPT-4.1 "deepseek-v3.2": 1_000_000 # 1M pour DeepSeek }

=== BUDGETS MENSUELS ($) ===

MONTHLY_BUDGETS = { "claude-sonnet-4.5": 100.0, # Max 100$/mois Claude "gemini-2.5-flash": 50.0, # Max 50$/mois Gemini "gpt-4.1": 30.0, # Max 30$/mois GPT-4.1 "deepseek-v3.2": 20.0 # Max 20$/mois DeepSeek } @dataclass class TokenBudget: """Gestionnaire de budget de tokens avec cache LRU.""" model: str max_context: int monthly_budget: float price_per_mtok: float cache: OrderedDict = field(default_factory=OrderedDict) cache_max_size: int = 1000 monthly_spent: float = 0.0 request_count: int = 0 def __post_init__(self): self.encoding = tiktoken.get_encoding("cl100k_base") def count_tokens(self, text: str) -> int: """Compte précisément les tokens d'un texte.""" return len(self.encoding.encode(text)) def truncate_to_budget(self, text: str) -> str: """Tronque le texte au budget maximal de tokens.""" tokens = self.encoding.encode(text) if len(tokens) <= self.max_context: return text truncated_tokens = tokens[:self.max_context] return self.encoding.decode(truncated_tokens) def estimate_cost(self, token_count: int) -> float: """Estime le coût en dollars.""" return (token_count / 1_000_000) * self.price_per_mtok def check_budget(self, token_count: int) -> Tuple[bool, str]: """Vérifie si la requête respecte le budget.""" estimated_cost = self.estimate_cost(token_count) if self.monthly_spent + estimated_cost > self.monthly_budget: return False, f"Budget mensuel dépassé: {self.monthly_spent:.2f}$ + {estimated_cost:.4f}$ > {self.monthly_budget}$" if token_count > self.max_context: return False, f"Dépassement contexte: {token_count} > {self.max_context} tokens" return True, "OK" def record_usage(self, token_count: int): """Enregistre l'utilisation pour le suivi du budget.""" cost = self.estimate_cost(token_count) self.monthly_spent += cost self.request_count += 1 def get_cache_key(self, text: str, max_results: int = 5) -> str: """Génère une clé de cache pour la mise en cache sémantique.""" text_hash = hashlib.md5(text.encode()).hexdigest() return f"{text_hash}_{max_results}" def get_cached(self, cache_key: str) -> Optional[str]: """Récupère depuis le cache si disponible.""" if cache_key in self.cache: self.cache.move_to_end(cache_key) return self.cache[cache_key] return None def set_cached(self, cache_key: str, response: str): """Met en cache une réponse.""" if len(self.cache) >= self.cache_max_size: self.cache.popitem(last=False) self.cache[cache_key] = response def get_stats(self) -> Dict: """Retourne les statistiques d'utilisation.""" return { "model": self.model, "monthly_spent": round(self.monthly_spent, 2), "monthly_budget": self.monthly_budget, "remaining": round(self.monthly_budget - self.monthly_spent, 2), "requests": self.request_count, "cache_hit_rate": self._calculate_cache_hit_rate() } def _calculate_cache_hit_rate(self) -> float: """Calcule le taux de succès du cache.""" total = self.request_count + len(self.cache) if total == 0: return 0.0 return len(self.cache) / total class HolySheepBudgetManager: """Gestionnaire centralisé des budgets pour tous les modèles.""" def __init__(self): self.budgets: Dict[str, TokenBudget] = {} self._initialize_budgets() def _initialize_budgets(self): """Initialise les budgets pour chaque modèle.""" prices = { "claude-sonnet-4.5": 2.25, # HolySheep pricing "gemini-2.5-flash": 0.375, "gpt-4.1": 1.20, "deepseek-v3.2": 0.063 } for model, max_ctx in CONTEXT_BUDGETS.items(): price = prices.get(model, 1.0) monthly = MONTHLY_BUDGETS.get(model, 100.0) self.budgets[model] = TokenBudget( model=model, max_context=max_ctx, monthly_budget=monthly, price_per_mtok=price ) def process_request(self, model: str, prompt: str, system: str = "") -> Dict: """Traite une requête avec contrôle de budget.""" budget = self.budgets.get(model) if not budget: return {"error": f"Modèle {model} non configuré"} full_text = f"{system}\n{prompt}" if system else prompt token_count = budget.count_tokens(full_text) within_budget, message = budget.check_budget(token_count) if not within_budget: truncated = budget.truncate_to_budget(full_text) truncated_tokens = budget.count_tokens(truncated) budget.record_usage(truncated_tokens) return { "status": "truncated", "message": message, "original_tokens": token_count, "truncated_tokens": truncated_tokens, "prompt": truncated, "cost_saved": round(budget.estimate_cost(token_count - truncated_tokens), 4) } budget.record_usage(token_count) return { "status": "approved", "tokens": token_count, "estimated_cost": round(budget.estimate_cost(token_count), 4), "prompt": full_text } def get_all_stats(self) -> List[Dict]: """Retourne les statistiques de tous les budgets.""" return [budget.get_stats() for budget in self.budgets.values()]

=== INSTANCE GLOBALE ===

budget_manager = HolySheepBudgetManager() if __name__ == "__main__": print("=== HolySheep Budget Manager v2.1037.0503 ===") print(f"Base URL: {BASE_URL}") print("\n--- Test de budgétisation ---\n") test_prompt = """ Analyse ce document technique de 500 pages et fournis un résumé structuré. Inclue les sections suivantes: Introduction, Méthodologie, Résultats, Discussion, Conclusion. Pour chaque section, fournis les points clés et les implications pratiques. """ for model in CONTEXT_BUDGETS.keys(): result = budget_manager.process_request(model, test_prompt) print(f"[{model}]") print(f" Status: {result['status']}") if 'tokens' in result: print(f" Tokens: {result['tokens']:,}") print(f" Coût estimé: {result['estimated_cost']:.4f}$") if 'truncated_tokens' in result: print(f" Tokens originaux: {result['original_tokens']:,}") print(f" Tokens après troncature: {result['truncated_tokens']:,}") print(f" Économie: {result['cost_saved']:.4f}$") print() print("--- Statistiques globales ---") for stats in budget_manager.get_all_stats(): print(f"{stats['model']}: {stats['monthly_spent']:.2f}$ / {stats['monthly_budget']:.2f}$ ({stats['requests']} requêtes)")

2. Stratégie de Troncature Intelligente et Cache Sémantique

#!/usr/bin/env python3
"""
HolySheep AI - Troncature Intelligente et Cache Sémantique
Optimisé pour les longs contextes avec HolySheep API
"""

import hashlib
import json
import time
from typing import List, Dict, Tuple, Optional
from collections import OrderedDict
import requests

BASE_URL = "https://api.holysheep.ai/v1"
API_KEY = "YOUR_HOLYSHEEP_API_KEY"

class SemanticChunker:
    """Découpe intelligent des documents pour optimiser le contexte."""
    
    def __init__(self, max_chunk_tokens: int = 8000, overlap_tokens: int = 500):
        self.max_chunk_tokens = max_chunk_tokens
        self.overlap_tokens = overlap_tokens
    
    def chunk_by_sentences(self, text: str) -> List[str]:
        """Découpe par phrases en préservant le sens."""
        sentences = text.replace('!', '.').replace('?', '.').split('.')
        chunks = []
        current_chunk = []
        current_tokens = 0
        
        for sentence in sentences:
            sentence = sentence.strip()
            if not sentence:
                continue
                
            # Estimation rapide (1 token ≈ 4 caractères)
            sentence_tokens = len(sentence) // 4
            
            if current_tokens + sentence_tokens > self.max_chunk_tokens:
                if current_chunk:
                    chunks.append('. '.join(current_chunk) + '.')
                # Overlap pour continuité
                overlap_text = '. '.join(current_chunk[-3:]) if len(current_chunk) > 3 else '. '.join(current_chunk)
                current_chunk = [overlap_text, sentence] if overlap_text else [sentence]
                current_tokens = len(overlap_text) // 4 + sentence_tokens
            else:
                current_chunk.append(sentence)
                current_tokens += sentence_tokens
        
        if current_chunk:
            chunks.append('. '.join(current_chunk) + '.')
        
        return chunks
    
    def chunk_by_sections(self, text: str, section_markers: List[str] = None) -> List[Dict]:
        """Découpe par sections avec métadonnées."""
        if section_markers is None:
            section_markers = ['\n## ', '\n### ', '\n\n', '\n---\n']
        
        sections = []
        current_pos = 0
        
        for marker in section_markers:
            parts = text.split(marker)
            for i, part in enumerate(parts[1:], 1):
                if part.strip():
                    sections.append({
                        'marker': marker.strip(),
                        'content': part.strip(),
                        'position': i
                    })
        
        return sections


class SemanticCache:
    """Cache sémantique avec similarité pour éviter les requêtes redondantes."""
    
    def __init__(self, max_size: int = 5000, similarity_threshold: float = 0.92):
        self.cache: OrderedDict = OrderedDict()
        self.max_size = max_size
        self.similarity_threshold = similarity_threshold
        self.hits = 0
        self.misses = 0
    
    def _compute_hash(self, text: str) -> str:
        """Hash stable pour une meilleure mise en cache."""
        return hashlib.sha256(text.encode('utf-8')).hexdigest()[:16]
    
    def _compute_similarity(self, text1: str, text2: str) -> float:
        """Calcule la similarité entre deux textes (Jaccard simple)."""
        set1 = set(text1.lower().split())
        set2 = set(text2.lower().split())
        intersection = len(set1 & set2)
        union = len(set1 | set2)
        return intersection / union if union > 0 else 0.0
    
    def get(self, query: str) -> Optional[str]:
        """Récupère une réponse cached si disponible."""
        query_hash = self._compute_hash(query)
        
        # Exact match
        if query_hash in self.cache:
            self.hits += 1
            self.cache.move_to_end(query_hash)
            return self.cache[query_hash]['response']
        
        # Similarity search
        for key, value in self.cache.items():
            similarity = self._compute_similarity(query, value['query'])
            if similarity >= self.similarity_threshold:
                self.hits += 1
                self.cache.move_to_end(key)
                return value['response']
        
        self.misses += 1
        return None
    
    def set(self, query: str, response: str):
        """Met en cache une réponse."""
        if len(self.cache) >= self.max_size:
            self.cache.popitem(last=False)
        
        query_hash = self._compute_hash(query)
        self.cache[query_hash] = {
            'query': query,
            'response': response,
            'timestamp': time.time()
        }
    
    def get_stats(self) -> Dict:
        """Statistiques du cache."""
        total = self.hits + self.misses
        hit_rate = (self.hits / total * 100) if total > 0 else 0
        return {
            'hits': self.hits,
            'misses': self.misses,
            'hit_rate': f"{hit_rate:.1f}%",
            'cache_size': len(self.cache)
        }


class HolySheepLongContextHandler:
    """Gestionnaire de longs contextes avec HolySheep API."""
    
    def __init__(self, api_key: str, budget_per_request: float = 0.10):
        self.api_key = api_key
        self.budget_per_request = budget_per_request
        self.chunker = SemanticChunker()
        self.cache = SemanticCache()
        self.usage_stats = {
            'total_tokens': 0,
            'total_cost': 0.0,
            'cache_savings': 0.0,
            'requests': 0
        }
    
    def _make_request(self, messages: List[Dict], model: str = "gemini-2.5-flash") -> Dict:
        """Fait une requête à l'API HolySheep."""
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": model,
            "messages": messages,
            "max_tokens": 4096,
            "temperature": 0.7
        }
        
        response = requests.post(
            f"{BASE_URL}/chat/completions",
            headers=headers,
            json=payload,
            timeout=30
        )
        
        if response.status_code != 200:
            raise Exception(f"API Error {response.status_code}: {response.text}")
        
        return response.json()
    
    def process_long_document(
        self,
        document: str,
        query: str,
        model: str = "gemini-2.5-flash",
        strategy: str = "smart"
    ) -> Dict:
        """
        Traite un long document avec la stratégie optimale.
        
        Stratégies disponibles:
        - 'truncate': Troncature simple (le plus rapide)
        - 'chunk': Découpage en chunks (le plus précis)
        - 'smart': Décision automatique basée sur la taille
        """
        # Vérification du cache
        cache_key = f"{query}|{document[:500]}"
        cached_response = self.cache.get(cache_key)
        if cached_response:
            return {
                'response': cached_response,
                'source': 'cache',
                'cost_saved': self._estimate_cost(len(document))
            }
        
        # Décision de stratégie
        doc_tokens = len(document) // 4
        context_limits = {
            'claude-sonnet-4.5': 200_000,
            'gemini-2.5-flash': 500_000,
            'gpt-4.1': 128_000,
            'deepseek-v3.2': 1_000_000
        }
        limit = context_limits.get(model, 128_000)
        
        if strategy == "smart":
            if doc_tokens <= limit * 0.8:
                strategy = "truncate"
            else:
                strategy = "chunk"
        
        if strategy == "truncate" and doc_tokens > limit:
            # Troncature intelligente
            truncated_doc = document[:limit * 4]
            self.usage_stats['total_tokens'] += limit
        else:
            # Découpage intelligent
            chunks = self.chunker.chunk_by_sentences(document)
            truncated_doc = '\n\n---\n\n'.join(chunks[:3])  # Limite à 3 chunks
            self.usage_stats['total_tokens'] += len(truncated_doc) // 4
        
        # Construction du prompt
        system_prompt = """Tu es un assistant d'analyse de documents. 
Réponds de manière précise et structurée. Si l'information n'est pas dans le document, dis-le clairement."""
        
        messages = [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": f"Document:\n{truncated_doc}\n\nQuestion: {query}"}
        ]
        
        # Calcul du coût estimé
        input_tokens = sum(len(m['content']) // 4 for m in messages)
        estimated_cost = self._estimate_cost(input_tokens)
        
        if estimated_cost > self.budget_per_request:
            return {
                'error': 'Budget par requête dépassé',
                'estimated_cost': estimated_cost,
                'budget': self.budget_per_request,
                'suggestion': 'Utilisez un modèle moins cher ou réduisez le contexte'
            }
        
        # Exécution de la requête
        try:
            response = self._make_request(messages, model)
            content = response['choices'][0]['message']['content']
            
            # Mise en cache
            self.cache.set(cache_key, content)
            
            # Mise à jour des statistiques
            self.usage_stats['requests'] += 1
            self.usage_stats['total_cost'] += estimated_cost
            
            return {
                'response': content,
                'source': 'api',
                'tokens_used': input_tokens,
                'cost': estimated_cost,
                'model': model,
                'strategy': strategy
            }
            
        except Exception as e:
            return {'error': str(e)}
    
    def _estimate_cost(self, tokens: int, model: str = "gemini-2.5-flash") -> float:
        """Estime le coût pour HolySheep."""
        prices = {
            'claude-sonnet-4.5': 0.00225,
            'gemini-2.5-flash': 0.000375,
            'gpt-4.1': 0.00120,
            'deepseek-v3.2': 0.000063
        }
        return (tokens / 1_000_000) * prices.get(model, 0.001) * 1000
    
    def batch_process(
        self,
        documents: List[str],
        queries: List[str],
        model: str = "deepseek-v3.2"
    ) -> List[Dict]:
        """Traite plusieurs documents en batch avec optimisation."""
        results = []
        
        for doc, query in zip(documents, queries):
            result = self.process_long_document(doc, query, model)
            results.append(result)
        
        return results
    
    def get_savings_report(self) -> Dict:
        """Génère un rapport d'économies."""
        cache_stats = self.cache.get_stats()
        
        return {
            'total_requests': self.usage_stats['requests'],
            'total_tokens': self.usage_stats['total_tokens'],
            'total_cost': round(self.usage_stats['total_cost'], 4),
            'cache_stats': cache_stats,
            'estimated_savings': round(
                cache_stats['hits'] * self.usage_stats['total_cost'] / max(self.usage_stats['requests'], 1) * 0.5,
                2
            ),
            'holy_sheep_advantage': '85% moins cher que les APIs officielles'
        }


=== UTILISATION ===

if __name__ == "__main__": handler = HolySheepLongContextHandler(API_KEY) # Document test (exemple) sample_doc = """ # Rapport Annuel 2026 ## Résumé Exécutif L'année 2026 a été marquée par une croissance de 45% de notre chiffre d'affaires. Notre stratégie d'expansion internationale porte ses fruits avec l'ouverture de bureaux dans 12 nouveaux pays. ## Performance Financière - Chiffre d'affaires: 45,2M€ (+45%) - EBITDA: 12,8M€ (+62%) - Marge nette: 18,4% ## Perspectives 2027 Nous anticipons une poursuite de la croissance avec un objectif de 60M€ de CA. """ result = handler.process_long_document( document=sample_doc, query="Donne-moi un résumé des performances financières et des perspectives.", model="gemini-2.5-flash", strategy="smart" ) print("=== Résultat du traitement ===") print(f"Source: {result.get('source', 'error')}") print(f"Coût: {result.get('cost', 0):.4f}$") print(f"Tokens: {result.get('tokens_used', 0):,}") print(f"\nRéponse:\n{result.get('response', result.get('error', 'N/A'))}") print("\n=== Rapport d'économies ===") report = handler.get_savings_report() print(json.dumps(report, indent=2))

3. Middleware de Monitoring en Temps Réel

#!/usr/bin/env python3
"""
HolySheep AI - Monitoring Temps Réel des Coûts
Dashboard intégré pour la surveillance des budgets
"""

import time
import threading
from datetime import datetime, timedelta
from collections import defaultdict
from typing import Dict, List, Callable
import json

class CostMonitor:
    """Surveillance en temps réel des coûts HolySheep."""
    
    def __init__(self, alerts_threshold_pct: float = 0.80):
        self.alerts_threshold_pct = alerts_threshold_pct
        self.model_costs = defaultdict(list)
        self.model_budgets = defaultdict(float)
        self.request_logs = []
        self.alerts = []
        self.lock = threading.Lock()
        
        # Prix HolySheep actualisés (2026)
        self.prices = {
            "claude-sonnet-4.5": 2.25,      # $/M tokens
            "gemini-2.5-flash": 0.375,
            "gpt-4.1": 1.20,
            "deepseek-v3.2": 0.063
        }
        
        # Limites de contexte
        self.context_limits = {
            "claude-sonnet-4.5": 200_000,
            "gemini-2.5-flash": 500_000,
            "gpt-4.1": 128_000,
            "deepseek-v3.2": 1_000_000
        }
    
    def set_budget(self, model: str, monthly_budget: float):
        """Définit le budget mensuel pour un modèle."""
        with self.lock:
            self.model_budgets[model] = monthly_budget
    
    def log_request(
        self,
        model: str,
        input_tokens: int,
        output_tokens: int,
        latency_ms: float,
        status: str = "success"
    ):
        """Enregistre une requête pour analyse."""
        with self.lock:
            total_tokens = input_tokens + output_tokens
            cost = (total_tokens / 1_000_000) * self.prices.get(model, 1.0)
            
            entry = {
                'timestamp': datetime.now().isoformat(),
                'model': model,
                'input_tokens': input_tokens,
                'output_tokens': output_tokens,
                'total_tokens': total_tokens,
                'cost': cost,
                'latency_ms': latency_ms,
                'status': status,
                'cost_per_1k': cost / total_tokens * 1000 if total_tokens > 0 else 0
            }
            
            self.request_logs.append(entry)
            self.model_costs[model].append(cost)
            
            # Vérification des alertes
            self._check_alerts(model, cost)
    
    def _check_alerts(self, model: str, cost: float):
        """Vérifie si une alerte doit être déclenchée."""
        budget = self.model_budgets.get(model, 0)
        if budget <= 0:
            return
        
        period_spend = self._get_period_spend(model)
        percentage = (period_spend + cost) / budget
        
        if percentage >= self.alerts_threshold_pct:
            alert = {
                'type': 'budget_warning',
                'model': model,
                'percentage': round(percentage * 100, 1),
                'message': f"⚠️ Alerte: {model} a atteint {percentage*100:.1f}% du budget mensuel",
                'timestamp': datetime.now().isoformat()
            }
            self.alerts.append(alert)
    
    def _get_period_spend(self, model: str, days: int = 30) -> float:
        """Calcule les dépenses sur une période."""
        cutoff = datetime.now() - timedelta(days=days)
        cutoff_iso = cutoff.isoformat()
        
        return sum(
            entry['cost'] 
            for entry in self.request_logs 
            if entry['model'] == model and entry['timestamp'] >= cutoff_iso
        )
    
    def get_dashboard_data(self) -> Dict:
        """Génère les données pour le dashboard."""
        with self.lock:
            models = list(self.prices.keys())
            
            dashboard = {
                'generated_at': datetime.now().isoformat(),
                'models': {},
                'total_spend': 0,
                'total_requests': len(self.request_logs),
                'alerts': self.alerts[-10:],  # 10 dernières alertes
                'recommendations': []
            }
            
            for model in models:
                period_cost = self._get_period_spend(model)
                budget = self.model_budgets.get(model, 0)
                
                model_requests = [
                    e for e in self.request_logs 
                    if e['model'] == model
                ]
                
                avg_latency = sum(e['latency_ms'] for e in model_requests) / len(model_requests) if model_requests else 0
                success_rate = len([e for e in model_requests if e['status'] == 'success']) / len(model_requests) * 100 if model_requests else 0
                
                dashboard['models'][model] = {
                    'period_spend': round(period_cost, 4),
                    'monthly_budget': budget,
                    'remaining': round(budget - period_cost, 4) if budget > 0 else None,
                    'percentage_used': round(period_cost / budget * 100, 1) if budget > 0 else None,
                    'request_count': len(model_requests),
                    'avg_latency_ms': round(avg_latency, 2),
                    'success_rate': round(success_rate, 1),
                    'context_limit': self.context_limits.get(model, 0),
                    'avg_tokens_per_request': (
                        sum(e['total_tokens'] for e in model_requests) // len(model_requests)
                        if model_requests else 0
                    )
                }
                
                dashboard['total_spend'] += period_cost
            
            # Recommandations intelligentes
            dashboard['recommendations'] = self._generate_recommendations(dashboard)
            
            return dashboard
    
    def _generate_recommendations(self, dashboard: Dict) -> List[Dict]:
        """Génère des recommandations d'optimisation."""
        recommendations = []
        
        for model, data in dashboard['models'].items():
            # Contexte non utilisé
            if data['avg_tokens_per_request'] < data['context_limit'] * 0.3:
                recommendations.append({
                    'type': 'context_underutilized',
                    'model': model,
                    'message': f"{model}: Contexte sous-utilisé ({data['avg_tokens_per_request']:,} / {data['context_limit']:,})",
                    'potential_savings': f"{data['request_count'] * 0.05:.2f}$/mois"
                })
            
            # Latence élevée
            if data['avg_latency_ms'] > 2000:
                recommendations.append({
                    'type': 'high_latency',
                    'model': model,
                    'message': f"{model}: Latence élevée ({data['avg_latency_ms']}ms)",
                    'suggestion': 'Réduire la taille du contexte ou utiliser un modèle plus rapide'
                })
            
            # Budget critique
            if data['percentage_used'] and data['percentage_used'] > 90:
                recommendations.append({
                    'type': 'budget_critical',
                    'model': model,
                    'message': f"🚨 {model}: Budget presque épuisé ({data['percentage_used']}%)",
                    'action': 'Augmenter le budget ou réduire l\'utilisation'
                })
        
        # Recommandation de modèle alternatif
        if dashboard['total_spend'] > 100:
            recommendations.append({
                'type': 'cost_optimization',
                'message': 'Économie potentielle: Migrer vers DeepSeek V3.2 (-85% sur certains cas)',
                'savings_estimate': f"{dashboard['total_spend'] * 0.4:.2f}$/mois"
            })
        
        return recommendations
    
    def export_logs(self, format: str = 'json') -> str:
        """Exporte les logs pour analyse externe."""
        with self.lock:
            if format == 'json':
                return json.dumps(self.request_logs, indent=2)
            elif format == 'csv':
                lines = ['timestamp,model,input_tokens,output_tokens,total_tokens,cost,latency_ms,status']
                for entry in self.request_logs:
                    lines.append(
                        f"{entry['timestamp']},{entry['model']},"
                        f"{entry['input_tokens']},{entry['output_tokens']},"
                        f"{entry['total_tokens']},{entry['cost']:.6f},"
                        f"{entry['latency_ms']:.2f},{entry['status']}"
                    )
                return '\n'.join(lines)
        
        return ""


=== DÉMO ===

if __name__ == "__main__": monitor = CostMonitor(alerts_threshold_pct=0.75) # Configuration des budgets monitor.set_budget("claude-sonnet-4.5", 200.0) monitor.set_budget("gemini-2.5-flash", 100.0) monitor.set_budget("deepseek-v3.2", 50.0) # Simulation de requêtes for i in