Docfile commited on
Commit
893eb54
·
verified ·
1 Parent(s): ffc0da7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -17
app.py CHANGED
@@ -5,18 +5,22 @@ import json
5
  from flask import Flask, jsonify, render_template, request
6
  from pydantic import BaseModel, Field
7
  from typing import List, Optional
8
- # import psycopg2 # La base de données n'est pas utilisée
9
- # from psycopg2.extras import RealDictCursor
10
  from google import genai
11
  from google.genai import types
12
  from utils import load_prompt
13
 
14
- # --- Configuration ---
15
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
16
  app = Flask(__name__)
17
  app.secret_key = os.environ.get("FLASK_SECRET_KEY", "un-secret-par-defaut")
18
 
19
- # --- Modèles de Données Pydantic pour la sortie structurée ---
 
 
 
 
20
  class Argument(BaseModel):
21
  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.")
22
 
@@ -32,14 +36,12 @@ class Dissertation(BaseModel):
32
  parties: List[Partie]
33
  conclusion: str = Field(description="La conclusion complète de la dissertation.")
34
 
35
- # --- Configuration Gemini (Ancien SDK) ---
36
  try:
37
- GOOGLE_API_KEY = os.environ.get("TOKEN")
38
  if not GOOGLE_API_KEY:
39
  logging.warning("La variable d'environnement TOKEN (GOOGLE_API_KEY) n'est pas définie.")
40
  client = None
41
  else:
42
- # On utilise genai.Client comme dans votre code original
43
  client = genai.Client(api_key=GOOGLE_API_KEY)
44
  except Exception as e:
45
  logging.error(f"Erreur lors de l'initialisation du client GenAI: {e}")
@@ -52,13 +54,43 @@ SAFETY_SETTINGS = [
52
  {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"},
53
  ]
54
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  # --- Route Principale ---
56
  @app.route('/')
57
  def philosophie():
58
- # Assurez-vous que le nom du template correspond à votre fichier HTML
59
- return render_template("philosophie.html")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
- # --- Route API pour la génération de dissertation ---
62
  @app.route('/api/generate_dissertation', methods=['POST'])
63
  def generate_dissertation_api():
64
  if not client:
@@ -66,7 +98,8 @@ def generate_dissertation_api():
66
 
67
  data = request.json
68
  sujet = data.get('question', '').strip()
69
- dissertation_type = data.get('type', 'type1').strip() # Récupère le type
 
70
 
71
  if not sujet:
72
  return jsonify({"error": "Le champ 'question' est obligatoire."}), 400
@@ -74,8 +107,26 @@ def generate_dissertation_api():
74
  if dissertation_type not in ['type1', 'type2']:
75
  return jsonify({"error": "Type de méthodologie invalide."}), 400
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  try:
78
- # Sélection dynamique du fichier de prompt
79
  prompt_filename = f"philo_dissertation_{dissertation_type}.txt"
80
  prompt_template = load_prompt(prompt_filename)
81
 
@@ -83,23 +134,21 @@ def generate_dissertation_api():
83
  logging.error(f"Fichier de prompt non trouvé : {prompt_filename}")
84
  return jsonify({"error": "Configuration du prompt introuvable pour ce type."}), 500
85
 
86
- final_prompt = prompt_template.format(phi_prompt=sujet)
 
87
 
88
- # Configuration de la réponse structurée (comme dans votre code original)
89
  config = types.GenerateContentConfig(
90
  safety_settings=SAFETY_SETTINGS,
91
  response_mime_type="application/json",
92
  response_schema=Dissertation,
93
  )
94
 
95
- # Appel à l'API avec la syntaxe client.models.generate_content
96
  response = client.models.generate_content(
97
- model="gemini-2.5-flash", # Modèle performant compatible avec cette syntaxe
98
  contents=final_prompt,
99
  config=config
100
  )
101
 
102
- # Traitement de la réponse (comme dans votre code original)
103
  if response.parsed:
104
  return jsonify(response.parsed.dict())
105
  else:
 
5
  from flask import Flask, jsonify, render_template, request
6
  from pydantic import BaseModel, Field
7
  from typing import List, Optional
8
+ import psycopg2
9
+ from psycopg2.extras import RealDictCursor
10
  from google import genai
11
  from google.genai import types
12
  from utils import load_prompt
13
 
14
+ # --- Configuration de l'application ---
15
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
16
  app = Flask(__name__)
17
  app.secret_key = os.environ.get("FLASK_SECRET_KEY", "un-secret-par-defaut")
18
 
19
+ # --- Configuration de la base de données et de l'API ---
20
+ DATABASE_URL = os.environ.get("DATABASE")
21
+ GOOGLE_API_KEY = os.environ.get("TOKEN")
22
+
23
+ # --- Modèles de Données Pydantic (inchangés) ---
24
  class Argument(BaseModel):
25
  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.")
26
 
 
36
  parties: List[Partie]
37
  conclusion: str = Field(description="La conclusion complète de la dissertation.")
38
 
39
+ # --- Configuration Gemini ---
40
  try:
 
41
  if not GOOGLE_API_KEY:
42
  logging.warning("La variable d'environnement TOKEN (GOOGLE_API_KEY) n'est pas définie.")
43
  client = None
44
  else:
 
45
  client = genai.Client(api_key=GOOGLE_API_KEY)
46
  except Exception as e:
47
  logging.error(f"Erreur lors de l'initialisation du client GenAI: {e}")
 
54
  {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"},
55
  ]
56
 
57
+ # --- Helpers de base de données (de l'exemple) ---
58
+ def create_connection():
59
+ """Crée et retourne une connexion à la base de données PostgreSQL."""
60
+ if not DATABASE_URL:
61
+ logging.error("La variable d'environnement DATABASE n'est pas configurée.")
62
+ return None
63
+ try:
64
+ return psycopg2.connect(DATABASE_URL)
65
+ except psycopg2.OperationalError as e:
66
+ logging.error(f"Impossible de se connecter à la base de données : {e}")
67
+ return None
68
+
69
  # --- Route Principale ---
70
  @app.route('/')
71
  def philosophie():
72
+ return render_template("philosophie (13).html")
73
+
74
+ # --- NOUVELLE Route API pour lister les cours ---
75
+ @app.route('/api/philosophy/courses', methods=['GET'])
76
+ def get_philosophy_courses():
77
+ """Récupère la liste de tous les cours de philosophie pour le menu déroulant."""
78
+ conn = create_connection()
79
+ if not conn:
80
+ return jsonify({"error": "Connexion à la base de données échouée."}), 503
81
+ try:
82
+ with conn.cursor(cursor_factory=RealDictCursor) as cur:
83
+ cur.execute("SELECT id, title FROM cours_philosophie ORDER BY title")
84
+ courses = cur.fetchall()
85
+ return jsonify(courses)
86
+ except Exception as e:
87
+ logging.error(f"Erreur lors de la récupération des cours : {e}")
88
+ return jsonify({"error": "Erreur interne du serveur lors de la récupération des cours."}), 500
89
+ finally:
90
+ if conn:
91
+ conn.close()
92
 
93
+ # --- Route API pour la génération de dissertation (MODIFIÉE) ---
94
  @app.route('/api/generate_dissertation', methods=['POST'])
95
  def generate_dissertation_api():
96
  if not client:
 
98
 
99
  data = request.json
100
  sujet = data.get('question', '').strip()
101
+ dissertation_type = data.get('type', 'type1').strip()
102
+ course_id = data.get('courseId') # Nouvel ID de cours optionnel
103
 
104
  if not sujet:
105
  return jsonify({"error": "Le champ 'question' est obligatoire."}), 400
 
107
  if dissertation_type not in ['type1', 'type2']:
108
  return jsonify({"error": "Type de méthodologie invalide."}), 400
109
 
110
+ # Récupérer le contenu du cours si un ID est fourni
111
+ context_str = ""
112
+ if course_id:
113
+ conn = create_connection()
114
+ if not conn:
115
+ return jsonify({"error": "Connexion à la base de données échouée pour récupérer le contexte."}), 503
116
+ try:
117
+ with conn.cursor(cursor_factory=RealDictCursor) as cur:
118
+ cur.execute("SELECT content FROM cours_philosophie WHERE id = %s", (course_id,))
119
+ result = cur.fetchone()
120
+ if result and result.get('content'):
121
+ context_str = f"\n\n--- EXTRAIT DE COURS À UTILISER COMME CONTEXTE PRINCIPAL ---\n{result['content']}"
122
+ except Exception as e:
123
+ logging.error(f"Erreur lors de la récupération du contexte du cours {course_id}: {e}")
124
+ # On continue sans le contexte en cas d'erreur DB
125
+ finally:
126
+ if conn:
127
+ conn.close()
128
+
129
  try:
 
130
  prompt_filename = f"philo_dissertation_{dissertation_type}.txt"
131
  prompt_template = load_prompt(prompt_filename)
132
 
 
134
  logging.error(f"Fichier de prompt non trouvé : {prompt_filename}")
135
  return jsonify({"error": "Configuration du prompt introuvable pour ce type."}), 500
136
 
137
+ # Injecter le sujet ET le contexte dans le prompt
138
+ final_prompt = prompt_template.format(phi_prompt=sujet, context=context_str)
139
 
 
140
  config = types.GenerateContentConfig(
141
  safety_settings=SAFETY_SETTINGS,
142
  response_mime_type="application/json",
143
  response_schema=Dissertation,
144
  )
145
 
 
146
  response = client.models.generate_content(
147
+ model="gemini-2.5-flash",
148
  contents=final_prompt,
149
  config=config
150
  )
151
 
 
152
  if response.parsed:
153
  return jsonify(response.parsed.dict())
154
  else: