ernestmindres's picture
Update app.py
2502f0e verified
# app.py (Continuation du fichier)
import json
import os
import sys
from flask import Flask, request, jsonify, Response
from flask_cors import CORS
# Importation des modules backend
from model_handler import generate_text_response, get_model_instance, MODEL_LOADED_SUCCESSFULLY
from config import SYSTEM_PROMPT
# --- Initialisation de l'Application Flask ---
app = Flask(__name__)
# La clé secrète n'est plus nécessaire sans session, mais on la laisse pour les bonnes pratiques.
app.secret_key = os.environ.get("FLASK_SECRET_KEY", "simple_dev_key")
# Permettre CORS pour toutes les routes
CORS(app)
# -----------------------------------------------------
# ROUTE D'API (Chat)
# -----------------------------------------------------
# Route principale pour la génération de texte (streaming) - Reste INCHANGÉE
@app.route('/api/v1/generate_text', methods=['POST'])
def generate_text():
data = request.get_json(silent=True)
if not data:
return jsonify({"status": "Error", "message": "Données JSON manquantes ou format invalide."}), 400
prompt = data.get('prompt')
history = data.get('history', [])
if not prompt:
return jsonify({"status": "Error", "message": "Le 'prompt' est requis dans le corps JSON."}), 400
def stream_with_sse():
response_stream = generate_text_response(
prompt=prompt,
history=history
)
try:
for chunk in response_stream:
yield f"data: {json.dumps({'content': chunk})}\n\n"
except Exception as e:
error_message = f"Erreur de streaming LLM: {e}"
print(f"Erreur de streaming: {error_message}", file=sys.stderr)
yield f"data: {json.dumps({'error': 'Erreur interne du modèle de langage. ' + error_message})}\n\n"
finally:
yield "data: [DONE]\n\n"
response = Response(
stream_with_sse(),
mimetype='text/event-stream'
)
response.headers['Cache-Control'] = 'no-cache'
response.headers['Connection'] = 'keep-alive'
return response
# NOUVELLE ROUTE: Route pour la génération de texte AVEC des fichiers (streaming)
@app.route('/api/v1/generate_text_with_files', methods=['POST'])
def generate_text_with_files():
"""
Gère la conversation LLM en streaming avec des fichiers et de l'historique.
Reçoit 'prompt', 'history', et une liste de 'files' via le corps de la requête JSON.
Chaque fichier doit être encodé en base64.
"""
# 1. Préparation des données (JSON body)
data = request.get_json(silent=True)
if not data:
return jsonify({"status": "Error", "message": "Données JSON manquantes ou format invalide."}), 400
prompt = data.get('prompt', '') # Le prompt peut être vide si seuls des fichiers sont envoyés
history = data.get('history', [])
files = data.get('files', []) # Liste de dict: [{"filename": "...", "content": "base64", "mime_type": "..."}]
# Vérification minimale: au moins un prompt OU un fichier doit être présent
if not prompt and not files:
return jsonify({"status": "Error", "message": "Le 'prompt' ou au moins un fichier est requis."}), 400
# Fonction générateur pour le streaming SSE (similaire à la première route)
def stream_with_sse_and_files():
# Le générateur LLM (MODIFIÉ: Passage de l'historique ET des fichiers)
response_stream = generate_text_response(
prompt=prompt,
history=history,
files=files # NOUVEAU: Passage des fichiers
)
try:
for chunk in response_stream:
# Envoie le chunk comme un événement SSE
yield f"data: {json.dumps({'content': chunk})}\n\n"
except Exception as e:
error_message = f"Erreur de streaming LLM: {e}"
print(f"Erreur de streaming: {error_message}", file=sys.stderr)
yield f"data: {json.dumps({'error': 'Erreur interne du modèle de langage. ' + error_message})}\n\n"
finally:
# Envoie le message de fin
yield "data: [DONE]\n\n"
# 3. Retourner la réponse en streaming SSE
response = Response(
stream_with_sse_and_files(),
mimetype='text/event-stream'
)
response.headers['Cache-Control'] = 'no-cache'
response.headers['Connection'] = 'keep-alive'
return response
# Route de vérification de santé (Health Check)
@app.route('/health_check', methods=['GET'])
def health_check():
"""Vérifie si l'API est opérationnelle et si le modèle LLM est chargé."""
status_message = "Model Ready" if MODEL_LOADED_SUCCESSFULLY else "Model Error (Check API Key)"
return jsonify({"status": status_message, "service": "Operational"}), 200
# Route d'accueil simple pour vérification
@app.route('/', methods=['GET'])
def index():
return jsonify({"status": "API Operational", "version": "v1.0"}), 200
# --- Initialisation de l'Application ---
def init_app():
"""Fonctions à appeler au démarrage."""
print("--- Démarrage du Backend LLM ---", file=sys.stderr)
# 1. Vérification du statut de l'API Gemini
get_model_instance()
if MODEL_LOADED_SUCCESSFULLY:
print(f"INFO: Configuration API réussie. Modèle LLM prêt. (Vérifiez le log de self-test ci-dessus)", file=sys.stderr)
else:
print(f"ALERTE: 🔴 Client Gemini non initialisé au démarrage. (Vérifiez le log détaillé ci-dessus pour la cause exacte)", file=sys.stderr)
# Exécuter l'initialisation au démarrage de l'application
init_app()
if __name__ == '__main__':
# Utiliser un port spécifique pour Hugging Face Spaces (7860) ou le port par défaut de Flask
port = int(os.environ.get("PORT", 7860))
app.run(host='0.0.0.0', port=port, debug=True)