import tiktoken from modules.logger import log_event # Tarification indicative par token (À synchroniser avec OpenRouter) TARIFS_OPENROUTER = { "meta-llama/llama-3.1-8b-instruct:free": 0.0, "qwen/qwen-2.5-coder-32b-instruct:free": 0.0, "google/gemini-2.5-pro": 0.000005 # Exemple de modèle payant } def compter_tokens(texte, modele="cl100k_base"): """Compte le nombre de tokens en local pour éviter les requêtes API inutiles.""" try: enc = tiktoken.get_encoding(modele) return len(enc.encode(texte)) except Exception as e: log_event("ERROR", "BILLING", f"Erreur lors du comptage des tokens : {e}") return 0 def estimer_cout_facture(prompt, modele_id): """ Calcule le coût de la requête. Applique la marge stricte de 15% pour générer le Prix Facture HT. """ tokens = compter_tokens(prompt) cout_brut_api = tokens * TARIFS_OPENROUTER.get(modele_id, 0.0) if cout_brut_api == 0.0: return 0.0 # Application stricte de votre formule comptable prix_facture_ht = cout_brut_api / 0.85 return round(prix_facture_ht, 6) def verifier_et_valider_budget(prompt, modele_id, utilisateur_vip=False): """ Fonction appelée avant chaque requête par le Chat Handler. Si le coût > 0 et que l'utilisateur n'a pas explicitement validé, on stoppe tout. """ cout_estime = estimer_cout_facture(prompt, modele_id) # Les VIP ne paient pas de marge, on affiche juste le coût brut pour information if utilisateur_vip: log_event("INFO", "BILLING", f"Utilisateur VIP. Coût brut estimé de la requête : {cout_estime * 0.85} $") return True, 0.0 if cout_estime > 0.0: # Lève une exception spécifique que l'interface FastHTML devra attraper pour afficher le pop-up raise Exception(f"VALIDATION_PAIEMENT_REQUISE|{cout_estime}") return True, cout_estime