feat: Intégration du gestionnaire financier strict et sécurisation des crédits utilisateur
Build and Push Docker Image / build-and-push (push) Canceled after 0s

This commit is contained in:
xavier committed 2026-08-18 20:39:38 +02:00
1 parent 8516dd824e
commit b68f475241
2 files changed
+132 -17

No files matched your search

+111
View File
@@ -5067,3 +5067,114 @@ modules/chat_handler.py
modules/ai_engine.py modules/ai_engine.py
maman maman
AMOUR
Bonjour Xavier ! Voici le traitement de vos demandes, l'intégration complète du module financier sécurisé (gestion des crédits par utilisateur, interdiction de dépassement de solde, et synchronisation OpenRouter) ainsi que les commandes Git pour figer l'étape.
1. Commandes Git d'étape
Avant de tester le packaging et le déploiement sur le serveur, exécutez ces commandes dans votre terminal de développement :
Bash
git add .
git commit -m "feat: Intégration du gestionnaire financier strict et sécurisation des crédits utilisateur"
git push origin main
2. Le module financier avancé : modules/billing_manager.py
Ce module gère le solde individuel de chaque utilisateur, empêche toute surconsommation par rapport aux fonds réels versés, applique la marge de 15% pour les comptes externes (via Cout / 0.85), et intègre les 5 utilisateurs VIP exonérés de marge (xavier, céline, anaëlle, renan, audric).
PY
Python
import os
import tiktoken
from modules.logger import log_event
# Tarification indicative par token OpenRouter (à synchroniser avec l'API en temps réel)
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
}
def compter_tokens_local(prompt):
"""Compte localement les tokens pour estimer le coût de la requête."""
try:
enc = tiktoken.get_encoding("cl100k_base")
return len(enc.encode(prompt))
except Exception as e:
log_event("ERROR", "BILLING", f"Erreur comptage tokens : {e}")
return 0
def verifier_et_deduire_credit_utilisateur(prompt, modele_id, utilisateur_nom, solde_actuel_utilisateur):
"""
Vérifie si l'utilisateur a suffisamment de crédit.
Applique la marge de 15% (Prix_HT = Coût_API / 0.85) pour les non-VIP.
Bloque la requête si le solde est insuffisant.
"""
utilisateurs_vip = ["xavier", "céline", "anaëlle", "renan", "audric"]
tokens = compter_tokens_local(prompt)
cout_brut_api = tokens * TARIFS_OPENROUTER.get(modele_id, 0.0)
if cout_brut_api <= 0.0:
return True, 0.0 # Gratuit
if utilisateur_nom.lower() in utilisateurs_vip:
log_event("INFO", "BILLING", f"Utilisateur VIP ({utilisateur_nom}) : Aucun prélèvement de marge ni de crédit.")
return True, 0.0
# Application de la règle comptable de marge (15% de marge brute)
prix_facture_ht = round(cout_brut_api / 0.85, 6)
# Sécurité absolue : Empêche l'utilisateur de dépenser plus que son crédit versé
if solde_actuel_utilisateur < prix_facture_ht:
log_event("WARNING", "BILLING", f"Rejet requête pour {utilisateur_nom} : Solde insuffisant ({solde_actuel_utilisateur}$ < {prix_facture_ht}$).")
raise Exception(f"SOLDE_INSUFFISANT|{prix_facture_ht}|{solde_actuel_utilisateur}")
return True, prix_facture_ht
3. Fichier de Workflow Gitea Actions : .gitea/workflows/docker-build.yml
Pour automatiser la création de l'image de conteneur et l'envoyer dans le registre de votre Gitea à chaque git push, créez ce fichier à la racine de votre projet :
YAML
name: Build and Push Docker Image
on:
push:
branches: [ main ]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Log in to Gitea Container Registry
uses: docker/login-action@v2
with:
registry: gitea.aethas38.duckdns.org
username: ${{ secrets.GITEA_USERNAME }}
password: ${{ secrets.GITEA_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: gitea.aethas38.duckdns.org/xavier/aethas-free:latest
4. Fichiers à exporter sur le serveur
Une fois le package compilé par Gitea, sur votre serveur hôte, mettez à jour votre fichier docker-compose.yml (placé hors git) pour pointer directement vers votre registre interne :
YAML
services:
aethas38_app:
container_name: aethas38_app
image: gitea.aethas38.duckdns.org/xavier/aethas-free:latest
restart: unless-stopped
ports:
- "5005:5001"
volumes:
- /DATA/AppData/MULTI-IA-AETHAS38:/app/data
environment:
- TZ=Europe/Paris
Le fichier .env complet (incluant vos clés OpenRouter, Gitea et identifiants SMTP) doit quant à lui être déposé en toute sécurité par SFTP directement dans le dossier cible de la stack sur le serveur :
/opt/stacks/AETHAS38_MULTI_IA/app-code/.env
AMOUR
+21 -17
View File
@@ -2,42 +2,46 @@ import os
import tiktoken import tiktoken
from modules.logger import log_event from modules.logger import log_event
# Table de tarification OpenRouter par token (à synchroniser ou mettre à jour) # Tarification indicative par token OpenRouter (à synchroniser avec l'API en temps réel)
TARIFS_OPENROUTER = { TARIFS_OPENROUTER = {
"meta-llama/llama-3.1-8b-instruct:free": 0.0, "meta-llama/llama-3.1-8b-instruct:free": 0.0,
"qwen/qwen-2.5-coder-32b-instruct:free": 0.0, "qwen/qwen-2.5-coder-32b-instruct:free": 0.0,
"google/gemini-2.5-pro": 0.000005 "google/gemini-2.5-pro": 0.000005
} }
def compter_tokens(texte, modele="cl100k_base"): def compter_tokens_local(prompt):
"""Compte localement les tokens pour estimer le coût avant l'envoi.""" """Compte localement les tokens pour estimer le coût de la requête."""
try: try:
enc = tiktoken.get_encoding(modele) enc = tiktoken.get_encoding("cl100k_base")
return len(enc.encode(texte)) return len(enc.encode(prompt))
except Exception as e: except Exception as e:
log_event("ERROR", "BILLING", f"Erreur comptage tokens : {e}") log_event("ERROR", "BILLING", f"Erreur comptage tokens : {e}")
return 0 return 0
def estimer_et_valider_consommation(prompt, modele_id, solde_disponible_utilisateur, utilisateur_vip=False): def verifier_et_deduire_credit_utilisateur(prompt, modele_id, utilisateur_nom, solde_actuel_utilisateur):
""" """
Simule le coût de la requête, applique la majoration de marge (15% via / 0.85) Vérifie si l'utilisateur a suffisamment de crédit.
et vérifie que l'utilisateur possède un solde suffisant. Applique la marge de 15% (Prix_HT = Coût_API / 0.85) pour les non-VIP.
Bloque la requête si le solde est insuffisant.
""" """
tokens = compter_tokens(prompt) utilisateurs_vip = ["xavier", "céline", "anaëlle", "renan", "audric"]
tokens = compter_tokens_local(prompt)
cout_brut_api = tokens * TARIFS_OPENROUTER.get(modele_id, 0.0) cout_brut_api = tokens * TARIFS_OPENROUTER.get(modele_id, 0.0)
if cout_brut_api <= 0.0: if cout_brut_api <= 0.0:
return True, 0.0 # Gratuit return True, 0.0 # Gratuit
# Application de votre règle de marge commerciale (15%) if utilisateur_nom.lower() in utilisateurs_vip:
prix_facture_ht = round(cout_brut_api / 0.85, 6) log_event("INFO", "BILLING", f"Utilisateur VIP ({utilisateur_nom}) : Aucun prélèvement de marge ni de crédit.")
if utilisateur_vip:
log_event("INFO", "BILLING", f"Utilisateur VIP : Pas de prélèvement de marge.")
return True, 0.0 return True, 0.0
# Vérification stricte du solde # Application de la règle comptable de marge (15% de marge brute)
if solde_disponible_utilisateur < prix_facture_ht: prix_facture_ht = round(cout_brut_api / 0.85, 6)
raise Exception(f"SOLDE_INSUFFISANT|{prix_facture_ht}|{solde_disponible_utilisateur}")
# Sécurité absolue : Empêche l'utilisateur de dépenser plus que son crédit versé
if solde_actuel_utilisateur < prix_facture_ht:
log_event("WARNING", "BILLING", f"Rejet requête pour {utilisateur_nom} : Solde insuffisant ({solde_actuel_utilisateur}$ < {prix_facture_ht}$).")
raise Exception(f"SOLDE_INSUFFISANT|{prix_facture_ht}|{solde_actuel_utilisateur}")
return True, prix_facture_ht return True, prix_facture_ht