Spaces:
Sleeping
Sleeping
| # app.py | |
| import os | |
| import logging | |
| import json | |
| from flask import Flask, jsonify, render_template, request | |
| from pydantic import BaseModel, Field | |
| from typing import List, Optional | |
| import psycopg2 | |
| from psycopg2.extras import RealDictCursor | |
| from google import genai | |
| from google.genai import types | |
| from utils import load_prompt | |
| # --- Configuration --- | |
| logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | |
| app = Flask(__name__) | |
| app.secret_key = os.environ.get("FLASK_SECRET_KEY", "un-secret-par-defaut") | |
| # --- Modèles de Données Pydantic pour la sortie structurée --- | |
| class Argument(BaseModel): | |
| paragraphe_argumentatif: str = Field(description="Un unique paragraphe formant un argument complet. Il doit commencer par un connecteur logique (ex: 'Premièrement,'), suivi de son développement.") | |
| class Partie(BaseModel): | |
| chapeau: str = Field(description="Le paragraphe d'introduction de la partie.") | |
| arguments: list[Argument] = Field(description="La liste des paragraphes argumentatifs qui suivent le chapeau.") | |
| transition: Optional[str] = Field(description="Phrase ou court paragraphe de transition.", default=None) | |
| class Dissertation(BaseModel): | |
| sujet: str = Field(description="Le sujet exact de la dissertation, tel que posé par l'utilisateur.") | |
| prof: str = Field(description="Le nom du professeur, qui est toujours 'Mariam AI'.", default="Mariam AI") | |
| introduction: str = Field(description="L'introduction complète de la dissertation.") | |
| parties: List[Partie] | |
| conclusion: str = Field(description="La conclusion complète de la dissertation.") | |
| # --- Configuration Gemini --- | |
| try: | |
| GOOGLE_API_KEY = os.environ.get("TOKEN") | |
| if not GOOGLE_API_KEY: | |
| logging.warning("La variable d'environnement TOKEN (GOOGLE_API_KEY) n'est pas définie.") | |
| client = None | |
| else: | |
| client = genai.Client(api_key=GOOGLE_API_KEY) | |
| except Exception as e: | |
| logging.error(f"Erreur lors de l'initialisation du client GenAI: {e}") | |
| client = None | |
| SAFETY_SETTINGS = [ | |
| {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"}, | |
| {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"}, | |
| {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE"}, | |
| {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"}, | |
| ] | |
| # --- Route Principale --- | |
| def philosophie(): | |
| return render_template("philosophie.html") | |
| # --- Route API pour la génération de dissertation --- | |
| def generate_dissertation_api(): | |
| if not client: | |
| return jsonify({"error": "Le service IA n'est pas correctement configuré."}), 503 | |
| data = request.json | |
| sujet = data.get('question', '').strip() | |
| if not sujet: | |
| return jsonify({"error": "Le champ 'question' est obligatoire."}), 400 | |
| try: | |
| prompt_template = load_prompt('philo_dissertation_json.txt') | |
| final_prompt = prompt_template.format(phi_prompt=sujet) | |
| config = types.GenerateContentConfig( | |
| safety_settings=SAFETY_SETTINGS, | |
| response_mime_type="application/json", | |
| response_schema=Dissertation, | |
| ) | |
| response = client.models.generate_content( | |
| model="gemini-2.5-flash", | |
| contents=final_prompt, | |
| config=config | |
| ) | |
| if response.parsed: | |
| return jsonify(response.parsed.dict()) | |
| else: | |
| logging.error(f"Erreur de parsing de la réponse structurée. Réponse brute : {response.text}") | |
| return jsonify({"error": "Le modèle n'a pas pu générer une structure valide."}), 500 | |
| except Exception as e: | |
| logging.error(f"Erreur de génération Gemini : {e}") | |
| return jsonify({"error": f"Une erreur est survenue avec le service IA : {e}"}), 500 | |
| if __name__ == '__main__': | |
| app.run(debug=True, port=5000) |