Docfile commited on
Commit
c62ab64
·
verified ·
1 Parent(s): 2e83990

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +12 -210
app.py CHANGED
@@ -2,7 +2,7 @@
2
  import os
3
  import logging
4
  import json
5
- from flask impobbbbrt Flask, jsonify, render_template, request
6
  from pydantic import BaseModel, Field
7
  from typing import List, Optional
8
  import psycopg2
@@ -10,7 +10,6 @@ from psycopg2.extras import RealDictCursor
10
  from google import genai
11
  from google.genai import types
12
  from utils import load_prompt
13
- from datetime import datetime
14
 
15
  # --- Configuration de l'application ---
16
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@@ -55,7 +54,7 @@ SAFETY_SETTINGS = [
55
  {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"},
56
  ]
57
 
58
- # --- Helpers de base de données ---
59
  def create_connection():
60
  """Crée et retourne une connexion à la base de données PostgreSQL."""
61
  if not DATABASE_URL:
@@ -67,68 +66,12 @@ def create_connection():
67
  logging.error(f"Impossible de se connecter à la base de données : {e}")
68
  return None
69
 
70
- def init_database():
71
- """Initialise la table de sauvegarde des dissertations si elle n'existe pas."""
72
- conn = create_connection()
73
- if not conn:
74
- return False
75
- try:
76
- with conn.cursor() as cur:
77
- cur.execute("""
78
- CREATE TABLE IF NOT EXISTS dissertations (
79
- id SERIAL PRIMARY KEY,
80
- user_ip VARCHAR(45),
81
- user_agent TEXT,
82
- question TEXT NOT NULL,
83
- dissertation_type VARCHAR(10) NOT NULL,
84
- course_id INTEGER,
85
- course_title VARCHAR(255),
86
- generated_content JSONB,
87
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
88
- pdf_generated BOOLEAN DEFAULT FALSE
89
- )
90
- """)
91
- conn.commit()
92
- return True
93
- except Exception as e:
94
- logging.error(f"Erreur lors de l'initialisation de la base de données : {e}")
95
- return False
96
- finally:
97
- if conn:
98
- conn.close()
99
-
100
- def save_dissertation(user_ip, user_agent, question, dissertation_type, course_id, course_title, content):
101
- """Sauvegarde une dissertation générée en base de données."""
102
- conn = create_connection()
103
- if not conn:
104
- return None
105
- try:
106
- with conn.cursor() as cur:
107
- cur.execute("""
108
- INSERT INTO dissertations (user_ip, user_agent, question, dissertation_type, course_id, course_title, generated_content)
109
- VALUES (%s, %s, %s, %s, %s, %s, %s)
110
- RETURNING id
111
- """, (user_ip, user_agent, question, dissertation_type, course_id, course_title, json.dumps(content)))
112
- conn.commit()
113
- return cur.fetchone()[0]
114
- except Exception as e:
115
- logging.error(f"Erreur lors de la sauvegarde de la dissertation : {e}")
116
- return None
117
- finally:
118
- if conn:
119
- conn.close()
120
-
121
- # --- Routes Principales ---
122
  @app.route('/')
123
  def philosophie():
124
  return render_template("philosophie.html")
125
 
126
- @app.route('/gestion')
127
- def gestion():
128
- """Page de gestion pour afficher toutes les dissertations."""
129
- return render_template("gestion.html")
130
-
131
- # --- Routes API ---
132
  @app.route('/api/philosophy/courses', methods=['GET'])
133
  def get_philosophy_courses():
134
  """Récupère la liste de tous les cours de philosophie pour le menu déroulant."""
@@ -147,130 +90,7 @@ def get_philosophy_courses():
147
  if conn:
148
  conn.close()
149
 
150
- @app.route('/api/dissertations', methods=['GET'])
151
- def get_dissertations():
152
- """Récupère toutes les dissertations avec pagination."""
153
- page = int(request.args.get('page', 1))
154
- per_page = int(request.args.get('per_page', 10))
155
- search = request.args.get('search', '').strip()
156
-
157
- conn = create_connection()
158
- if not conn:
159
- return jsonify({"error": "Connexion à la base de données échouée."}), 503
160
-
161
- try:
162
- with conn.cursor(cursor_factory=RealDictCursor) as cur:
163
- # Construire la requête avec recherche optionnelle
164
- base_query = """
165
- SELECT d.*, COUNT(*) OVER() as total_count
166
- FROM dissertations d
167
- """
168
- where_clause = ""
169
- params = []
170
-
171
- if search:
172
- where_clause = " WHERE d.question ILIKE %s OR d.course_title ILIKE %s"
173
- params = [f"%{search}%", f"%{search}%"]
174
-
175
- query = base_query + where_clause + """
176
- ORDER BY d.created_at DESC
177
- LIMIT %s OFFSET %s
178
- """
179
- params.extend([per_page, (page - 1) * per_page])
180
-
181
- cur.execute(query, params)
182
- results = cur.fetchall()
183
-
184
- total_count = results[0]['total_count'] if results else 0
185
- dissertations = []
186
-
187
- for row in results:
188
- dissertations.append({
189
- 'id': row['id'],
190
- 'user_ip': row['user_ip'],
191
- 'user_agent': row['user_agent'],
192
- 'question': row['question'],
193
- 'dissertation_type': row['dissertation_type'],
194
- 'course_id': row['course_id'],
195
- 'course_title': row['course_title'],
196
- 'created_at': row['created_at'].isoformat() if row['created_at'] else None,
197
- 'pdf_generated': row['pdf_generated'],
198
- 'content_preview': row['generated_content'].get('introduction', '')[:200] + '...' if row['generated_content'] else ''
199
- })
200
-
201
- return jsonify({
202
- 'dissertations': dissertations,
203
- 'total': total_count,
204
- 'page': page,
205
- 'per_page': per_page,
206
- 'total_pages': (total_count + per_page - 1) // per_page
207
- })
208
-
209
- except Exception as e:
210
- logging.error(f"Erreur lors de la récupération des dissertations : {e}")
211
- return jsonify({"error": "Erreur interne du serveur."}), 500
212
- finally:
213
- if conn:
214
- conn.close()
215
-
216
- @app.route('/api/dissertations/<int:dissertation_id>', methods=['GET'])
217
- def get_dissertation_detail(dissertation_id):
218
- """Récupère le détail complet d'une dissertation."""
219
- conn = create_connection()
220
- if not conn:
221
- return jsonify({"error": "Connexion à la base de données échouée."}), 503
222
-
223
- try:
224
- with conn.cursor(cursor_factory=RealDictCursor) as cur:
225
- cur.execute("""
226
- SELECT * FROM dissertations WHERE id = %s
227
- """, (dissertation_id,))
228
- result = cur.fetchone()
229
-
230
- if not result:
231
- return jsonify({"error": "Dissertation non trouvée."}), 404
232
-
233
- return jsonify({
234
- 'id': result['id'],
235
- 'user_ip': result['user_ip'],
236
- 'user_agent': result['user_agent'],
237
- 'question': result['question'],
238
- 'dissertation_type': result['dissertation_type'],
239
- 'course_id': result['course_id'],
240
- 'course_title': result['course_title'],
241
- 'created_at': result['created_at'].isoformat() if result['created_at'] else None,
242
- 'pdf_generated': result['pdf_generated'],
243
- 'generated_content': result['generated_content']
244
- })
245
-
246
- except Exception as e:
247
- logging.error(f"Erreur lors de la récupération de la dissertation {dissertation_id} : {e}")
248
- return jsonify({"error": "Erreur interne du serveur."}), 500
249
- finally:
250
- if conn:
251
- conn.close()
252
-
253
- @app.route('/api/dissertations/<int:dissertation_id>', methods=['DELETE'])
254
- def delete_dissertation(dissertation_id):
255
- """Supprime une dissertation."""
256
- conn = create_connection()
257
- if not conn:
258
- return jsonify({"error": "Connexion à la base de données échouée."}), 503
259
-
260
- try:
261
- with conn.cursor() as cur:
262
- cur.execute("DELETE FROM dissertations WHERE id = %s", (dissertation_id,))
263
- if cur.rowcount == 0:
264
- return jsonify({"error": "Dissertation non trouvée."}), 404
265
- conn.commit()
266
- return jsonify({"message": "Dissertation supprimée avec succès."})
267
- except Exception as e:
268
- logging.error(f"Erreur lors de la suppression de la dissertation {dissertation_id} : {e}")
269
- return jsonify({"error": "Erreur interne du serveur."}), 500
270
- finally:
271
- if conn:
272
- conn.close()
273
-
274
  @app.route('/api/generate_dissertation', methods=['POST'])
275
  def generate_dissertation_api():
276
  if not client:
@@ -279,7 +99,7 @@ def generate_dissertation_api():
279
  data = request.json
280
  sujet = data.get('question', '').strip()
281
  dissertation_type = data.get('type', 'type1').strip()
282
- course_id = data.get('courseId')
283
 
284
  if not sujet:
285
  return jsonify({"error": "Le champ 'question' est obligatoire."}), 400
@@ -289,21 +109,19 @@ def generate_dissertation_api():
289
 
290
  # Récupérer le contenu du cours si un ID est fourni
291
  context_str = ""
292
- course_title = None
293
  if course_id:
294
  conn = create_connection()
295
  if not conn:
296
  return jsonify({"error": "Connexion à la base de données échouée pour récupérer le contexte."}), 503
297
  try:
298
  with conn.cursor(cursor_factory=RealDictCursor) as cur:
299
- cur.execute("SELECT title, content FROM cours_philosophie WHERE id = %s", (course_id,))
300
  result = cur.fetchone()
301
- if result:
302
- course_title = result['title']
303
- if result.get('content'):
304
- context_str = f"\n\n--- EXTRAIT DE COURS À UTILISER COMME CONTEXTE PRINCIPAL ---\n{result['content']}"
305
  except Exception as e:
306
  logging.error(f"Erreur lors de la récupération du contexte du cours {course_id}: {e}")
 
307
  finally:
308
  if conn:
309
  conn.close()
@@ -316,6 +134,7 @@ def generate_dissertation_api():
316
  logging.error(f"Fichier de prompt non trouvé : {prompt_filename}")
317
  return jsonify({"error": "Configuration du prompt introuvable pour ce type."}), 500
318
 
 
319
  final_prompt = prompt_template.format(phi_prompt=sujet, context=context_str)
320
 
321
  config = types.GenerateContentConfig(
@@ -331,23 +150,7 @@ def generate_dissertation_api():
331
  )
332
 
333
  if response.parsed:
334
- # Sauvegarder en base de données
335
- user_ip = request.environ.get('HTTP_X_FORWARDED_FOR', request.environ.get('REMOTE_ADDR', 'unknown'))
336
- user_agent = request.headers.get('User-Agent', 'unknown')
337
-
338
- dissertation_id = save_dissertation(
339
- user_ip=user_ip,
340
- user_agent=user_agent,
341
- question=sujet,
342
- dissertation_type=dissertation_type,
343
- course_id=course_id,
344
- course_title=course_title,
345
- content=response.parsed.dict()
346
- )
347
-
348
- result = response.parsed.dict()
349
- result['dissertation_id'] = dissertation_id
350
- return jsonify(result)
351
  else:
352
  logging.error(f"Erreur de parsing de la réponse structurée. Réponse brute : {response.text}")
353
  return jsonify({"error": "Le modèle n'a pas pu générer une structure valide."}), 500
@@ -357,5 +160,4 @@ def generate_dissertation_api():
357
  return jsonify({"error": f"Une erreur est survenue avec le service IA : {e}"}), 500
358
 
359
  if __name__ == '__main__':
360
- init_database() # Initialiser la base de données au démarrage
361
  app.run(debug=True, port=5001)
 
2
  import os
3
  import logging
4
  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
 
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')
 
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:
 
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.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."""
 
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:
 
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
 
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()
 
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(
 
150
  )
151
 
152
  if response.parsed:
153
+ return jsonify(response.parsed.dict())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  else:
155
  logging.error(f"Erreur de parsing de la réponse structurée. Réponse brute : {response.text}")
156
  return jsonify({"error": "Le modèle n'a pas pu générer une structure valide."}), 500
 
160
  return jsonify({"error": f"Une erreur est survenue avec le service IA : {e}"}), 500
161
 
162
  if __name__ == '__main__':
 
163
  app.run(debug=True, port=5001)