Public Access
fix: Migration vers le nouveau SDK Google GenAI et mise à jour des dépendances
Build and Push Docker Image / build-and-push (push) Successful in 2m4s
Build and Push Docker Image / build-and-push (push) Successful in 2m4s
This commit is contained in:
1 parent
5a4e7dd094
commit
a10c854b2b
11 files changed
+2122
-100
No files matched your search
+35
-13
@@ -11,6 +11,9 @@ from modules.ui_components import render_user_msg, render_ai_msg, render_sidebar
|
||||
from modules.logger import log_event
|
||||
from modules.billing_manager import verifier_et_valider_budget
|
||||
|
||||
# Import du nouveau module de modération
|
||||
from modules.moderator import analyser_intention_illicite, appliquer_sanction_et_archiver
|
||||
|
||||
async def handle_chat_request(request, session):
|
||||
start_time = time.time()
|
||||
try:
|
||||
@@ -18,13 +21,30 @@ async def handle_chat_request(request, session):
|
||||
prompt = form.get("prompt", "")
|
||||
chat_id = form.get("chat_id", str(uuid.uuid4()))
|
||||
files = form.getlist("files")
|
||||
session['current_chat_id'] = chat_id
|
||||
|
||||
# --- RÉCUPÉRATION DU CHOIX GRATUIT/PAYANT ---
|
||||
mode_payant = form.get("mode_payant") == "on"
|
||||
|
||||
session['current_chat_id'] = chat_id
|
||||
history = load_history()
|
||||
|
||||
# Identification temporaire de l'utilisateur (en attendant le module de connexion complet)
|
||||
# Identification
|
||||
utilisateur_nom = session.get('user', 'xavier')
|
||||
utilisateur_vip = utilisateur_nom.lower() in ["xavier", "céline", "anaëlle", "renan", "audric"]
|
||||
# Récupération IP depuis la requête Starlette/FastHTML
|
||||
ip_client = request.client.host if request.client else "Inconnue"
|
||||
|
||||
# --- 🚨 ÉTAPE 1 : MODÉRATION PRÉVENTIVE (Filtre Légal) 🚨 ---
|
||||
est_illicite, raison = analyser_intention_illicite(prompt, None)
|
||||
if est_illicite:
|
||||
sanction = appliquer_sanction_et_archiver(utilisateur_nom, prompt, raison, ip_client)
|
||||
return Div(
|
||||
H3("⚠️ Avertissement de Sécurité"),
|
||||
P("Votre requête enfreint les Conditions Générales d'Utilisation (Contenu illicite)."),
|
||||
P(f"Sanction appliquée : {sanction}"),
|
||||
P("Cet incident a été enregistré et transmis à l'administration."),
|
||||
style="color:red; background:#300; padding:15px; border-radius:10px;"
|
||||
)
|
||||
|
||||
# Extraction éphémère en RAM
|
||||
file_summary = []
|
||||
@@ -36,13 +56,14 @@ async def handle_chat_request(request, session):
|
||||
file_summary.append(f"\n--- Fichier: {f.filename} ---\n{content.decode('utf-8', errors='ignore')}")
|
||||
|
||||
liste_fichiers_str = ', '.join(file_names) if file_names else 'Aucun fichier'
|
||||
log_event("INFO", "SYSTEM", f"Requête reçue. Fichiers joints : {liste_fichiers_str}")
|
||||
log_mode = "PAYANT 👑" if mode_payant else "GRATUIT 🆓"
|
||||
log_event("INFO", "SYSTEM", f"Requête reçue [{log_mode}]. Fichiers joints : {liste_fichiers_str}")
|
||||
|
||||
# L'IA Local (Qwen) orchestre la décision ! Focus sur l'efficience.
|
||||
# L'IA Local (Qwen) orchestre la décision
|
||||
sec_prompt = f"""Tu es l'Orchestrateur système. Analyse la requête et choisis le meilleur fournisseur IA :
|
||||
- "gemini" : (OBLIGATOIRE si fichiers joints), rédaction complexe, comparaisons ou recherches web.
|
||||
- "openrouter_chat" : requêtes générales, texte rapide, traduction, bureautique (Modèles gratuits).
|
||||
- "openrouter_code" : programmation, scripts, mathématiques, logique (Modèles gratuits).
|
||||
- "openrouter_chat" : requêtes générales, texte rapide, traduction, bureautique.
|
||||
- "openrouter_code" : programmation, scripts, mathématiques, logique.
|
||||
- "local" : salutations basiques, questions très simples.
|
||||
Renvoie STRICTEMENT un JSON : {{"intention": "Résumé...", "fournisseur": "gemini|openrouter_chat|openrouter_code|local"}}
|
||||
Requête : {prompt}"""
|
||||
@@ -56,7 +77,6 @@ async def handle_chat_request(request, session):
|
||||
intention = decision.get('intention', 'Analyse')
|
||||
fournisseur = decision.get('fournisseur', 'openrouter_chat').lower()
|
||||
|
||||
# Sécurité Absolue Fichiers -> Gemini
|
||||
if file_names:
|
||||
fournisseur = "gemini"
|
||||
intention += " (Forcé Gemini via Sécurité Fichiers)"
|
||||
@@ -74,12 +94,15 @@ async def handle_chat_request(request, session):
|
||||
|
||||
# --- VÉRIFICATION FINANCIÈRE PRÉALABLE ---
|
||||
if "openrouter" in fournisseur:
|
||||
modele_estime = "qwen/qwen-2.5-coder-32b-instruct:free" if fournisseur == "openrouter_code" else "meta-llama/llama-3.1-8b-instruct:free"
|
||||
# Déclenche une exception bloquante si le solde est insuffisant ou nécessite une validation
|
||||
if mode_payant:
|
||||
modele_estime = "anthropic/claude-3.5-sonnet" if fournisseur == "openrouter_code" else "openai/gpt-4o-mini"
|
||||
else:
|
||||
modele_estime = "qwen/qwen-2.5-coder-32b-instruct:free" if fournisseur == "openrouter_code" else "meta-llama/llama-3.1-8b-instruct:free"
|
||||
|
||||
verifier_et_valider_budget(full_prompt, modele_estime, utilisateur_vip)
|
||||
|
||||
# Délégation de l'exécution au Moteur d'IA (Cascade)
|
||||
reponse, couleur, fournisseur_nom, modele = executer_requete_ia(fournisseur, full_prompt)
|
||||
# Exécution
|
||||
reponse, couleur, fournisseur_nom, modele = executer_requete_ia(fournisseur, full_prompt, mode_payant)
|
||||
|
||||
if chat_id not in history:
|
||||
history[chat_id] = {"title": (prompt[:30] if prompt else "Discussion") + "...", "pinned": False, "timestamp": time.time(), "messages": []}
|
||||
@@ -89,7 +112,7 @@ async def handle_chat_request(request, session):
|
||||
display_msg = prompt
|
||||
if file_names:
|
||||
display_msg += f"\n\n📎 **Fichiers joints :** {', '.join(file_names)}"
|
||||
display_msg += "\n> *🗑️ Note : Fichiers traités de manière éphémère en mémoire vive et détruits instantanément après analyse conformément aux règles de confidentialité.*"
|
||||
display_msg += "\n> *🗑️ Note : Fichiers traités de manière éphémère en mémoire vive et détruits instantanément après analyse.*"
|
||||
|
||||
history[chat_id]['messages'].append({"role": "user", "content": display_msg})
|
||||
history[chat_id]['messages'].append({"role": "ai", "content": reponse, "intention": intention, "fournisseur": fournisseur_nom, "modele": modele, "couleur": couleur, "execution_time": execution_time})
|
||||
@@ -100,7 +123,6 @@ async def handle_chat_request(request, session):
|
||||
|
||||
except Exception as e:
|
||||
log_event("CRITICAL", "SYSTEM", f"Erreur critique dans handle_chat_request: {e}")
|
||||
# Capture l'erreur de paiement pour avertir l'utilisateur dans l'UI
|
||||
msg_erreur = str(e)
|
||||
if "VALIDATION_PAIEMENT_REQUISE" in msg_erreur or "SOLDE_INSUFFISANT" in msg_erreur:
|
||||
return Div(f"⚠️ Alerte Financière : {msg_erreur.split('|')[0]}", style="color:orange; background:#331a00; padding:15px; border-radius:10px;")
|
||||
|
||||
Reference in new issue
Block a user