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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +164 -10
app.py CHANGED
@@ -2,6 +2,7 @@
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
@@ -20,6 +21,13 @@ app.secret_key = os.environ.get("FLASK_SECRET_KEY", "un-secret-par-defaut")
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.")
@@ -66,11 +74,140 @@ def create_connection():
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():
@@ -90,11 +227,13 @@ def get_philosophy_courses():
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:
97
- return jsonify({"error": "Le service IA n'est pas correctement configuré."}), 503
 
 
98
 
99
  data = request.json
100
  sujet = data.get('question', '').strip()
@@ -102,17 +241,23 @@ def generate_dissertation_api():
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
 
 
106
 
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,))
@@ -131,8 +276,10 @@ def generate_dissertation_api():
131
  prompt_template = load_prompt(prompt_filename)
132
 
133
  if "Erreur:" in prompt_template:
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)
@@ -150,14 +297,21 @@ def generate_dissertation_api():
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
 
157
 
158
  except Exception as e:
 
159
  logging.error(f"Erreur de génération Gemini : {e}")
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)
 
2
  import os
3
  import logging
4
  import json
5
+ from datetime import datetime
6
  from flask import Flask, jsonify, render_template, request
7
  from pydantic import BaseModel, Field
8
  from typing import List, Optional
 
21
  DATABASE_URL = os.environ.get("DATABASE")
22
  GOOGLE_API_KEY = os.environ.get("TOKEN")
23
 
24
+ # Dossier pour stocker les données de gestion
25
+ DATA_DIR = "data"
26
+ DISSERTATIONS_FILE = os.path.join(DATA_DIR, "dissertations_log.json")
27
+
28
+ # Créer le dossier data s'il n'existe pas
29
+ os.makedirs(DATA_DIR, exist_ok=True)
30
+
31
  # --- Modèles de Données Pydantic (inchangés) ---
32
  class Argument(BaseModel):
33
  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.")
 
74
  logging.error(f"Impossible de se connecter à la base de données : {e}")
75
  return None
76
 
77
+ # --- Helpers pour la gestion des données ---
78
+ def save_dissertation_data(input_data, output_data, success=True, error_message=None):
79
+ """Sauvegarde les données d'entrée et de sortie dans un fichier JSON."""
80
+ try:
81
+ # Lire les données existantes
82
+ if os.path.exists(DISSERTATIONS_FILE):
83
+ with open(DISSERTATIONS_FILE, 'r', encoding='utf-8') as f:
84
+ data = json.load(f)
85
+ else:
86
+ data = []
87
+
88
+ # Préparer le nouvel enregistrement
89
+ record = {
90
+ "timestamp": datetime.now().isoformat(),
91
+ "input": {
92
+ "question": input_data.get('question', ''),
93
+ "type": input_data.get('type', ''),
94
+ "courseId": input_data.get('courseId')
95
+ },
96
+ "output": output_data if success else None,
97
+ "success": success,
98
+ "error": error_message,
99
+ "id": len(data) + 1
100
+ }
101
+
102
+ # Ajouter le nouvel enregistrement
103
+ data.append(record)
104
+
105
+ # Sauvegarder
106
+ with open(DISSERTATIONS_FILE, 'w', encoding='utf-8') as f:
107
+ json.dump(data, f, ensure_ascii=False, indent=2)
108
+
109
+ except Exception as e:
110
+ logging.error(f"Erreur lors de la sauvegarde des données: {e}")
111
+
112
+ def load_dissertations_data():
113
+ """Charge toutes les données des dissertations depuis le fichier JSON."""
114
+ try:
115
+ if os.path.exists(DISSERTATIONS_FILE):
116
+ with open(DISSERTATIONS_FILE, 'r', encoding='utf-8') as f:
117
+ return json.load(f)
118
+ return []
119
+ except Exception as e:
120
+ logging.error(f"Erreur lors du chargement des données: {e}")
121
+ return []
122
+
123
  # --- Route Principale ---
124
  @app.route('/')
125
  def philosophie():
126
  return render_template("philosophie.html")
127
 
128
+ # --- Route de Gestion ---
129
+ @app.route('/gestion')
130
+ def gestion():
131
+ return render_template("gestion.html")
132
+
133
+ # --- API pour récupérer les données de gestion ---
134
+ @app.route('/api/gestion/dissertations', methods=['GET'])
135
+ def get_dissertations_data():
136
+ """Récupère toutes les données des dissertations générées."""
137
+ try:
138
+ data = load_dissertations_data()
139
+ return jsonify({
140
+ "success": True,
141
+ "data": data,
142
+ "total": len(data)
143
+ })
144
+ except Exception as e:
145
+ logging.error(f"Erreur lors de la récupération des données de gestion: {e}")
146
+ return jsonify({
147
+ "success": False,
148
+ "error": "Erreur lors de la récupération des données"
149
+ }), 500
150
+
151
+ # --- API pour supprimer une entrée ---
152
+ @app.route('/api/gestion/dissertations/<int:record_id>', methods=['DELETE'])
153
+ def delete_dissertation_record(record_id):
154
+ """Supprime un enregistrement spécifique."""
155
+ try:
156
+ data = load_dissertations_data()
157
+
158
+ # Trouver l'index de l'enregistrement à supprimer
159
+ record_index = None
160
+ for i, record in enumerate(data):
161
+ if record.get('id') == record_id:
162
+ record_index = i
163
+ break
164
+
165
+ if record_index is None:
166
+ return jsonify({
167
+ "success": False,
168
+ "error": "Enregistrement non trouvé"
169
+ }), 404
170
+
171
+ # Supprimer l'enregistrement
172
+ deleted_record = data.pop(record_index)
173
+
174
+ # Sauvegarder
175
+ with open(DISSERTATIONS_FILE, 'w', encoding='utf-8') as f:
176
+ json.dump(data, f, ensure_ascii=False, indent=2)
177
+
178
+ return jsonify({
179
+ "success": True,
180
+ "message": "Enregistrement supprimé avec succès"
181
+ })
182
+
183
+ except Exception as e:
184
+ logging.error(f"Erreur lors de la suppression: {e}")
185
+ return jsonify({
186
+ "success": False,
187
+ "error": "Erreur lors de la suppression"
188
+ }), 500
189
+
190
+ # --- API pour vider toutes les données ---
191
+ @app.route('/api/gestion/dissertations/clear', methods=['DELETE'])
192
+ def clear_all_dissertations():
193
+ """Vide toutes les données des dissertations."""
194
+ try:
195
+ # Créer un fichier vide
196
+ with open(DISSERTATIONS_FILE, 'w', encoding='utf-8') as f:
197
+ json.dump([], f)
198
+
199
+ return jsonify({
200
+ "success": True,
201
+ "message": "Toutes les données ont été supprimées"
202
+ })
203
+
204
+ except Exception as e:
205
+ logging.error(f"Erreur lors de la suppression générale: {e}")
206
+ return jsonify({
207
+ "success": False,
208
+ "error": "Erreur lors de la suppression"
209
+ }), 500
210
+
211
  # --- NOUVELLE Route API pour lister les cours ---
212
  @app.route('/api/philosophy/courses', methods=['GET'])
213
  def get_philosophy_courses():
 
227
  if conn:
228
  conn.close()
229
 
230
+ # --- Route API pour la génération de dissertation (MODIFIÉE avec logging) ---
231
  @app.route('/api/generate_dissertation', methods=['POST'])
232
  def generate_dissertation_api():
233
  if not client:
234
+ error_msg = "Le service IA n'est pas correctement configuré."
235
+ save_dissertation_data(request.json or {}, None, False, error_msg)
236
+ return jsonify({"error": error_msg}), 503
237
 
238
  data = request.json
239
  sujet = data.get('question', '').strip()
 
241
  course_id = data.get('courseId') # Nouvel ID de cours optionnel
242
 
243
  if not sujet:
244
+ error_msg = "Le champ 'question' est obligatoire."
245
+ save_dissertation_data(data, None, False, error_msg)
246
+ return jsonify({"error": error_msg}), 400
247
 
248
  if dissertation_type not in ['type1', 'type2']:
249
+ error_msg = "Type de méthodologie invalide."
250
+ save_dissertation_data(data, None, False, error_msg)
251
+ return jsonify({"error": error_msg}), 400
252
 
253
  # Récupérer le contenu du cours si un ID est fourni
254
  context_str = ""
255
  if course_id:
256
  conn = create_connection()
257
  if not conn:
258
+ error_msg = "Connexion à la base de données échouée pour récupérer le contexte."
259
+ save_dissertation_data(data, None, False, error_msg)
260
+ return jsonify({"error": error_msg}), 503
261
  try:
262
  with conn.cursor(cursor_factory=RealDictCursor) as cur:
263
  cur.execute("SELECT content FROM cours_philosophie WHERE id = %s", (course_id,))
 
276
  prompt_template = load_prompt(prompt_filename)
277
 
278
  if "Erreur:" in prompt_template:
279
+ error_msg = "Configuration du prompt introuvable pour ce type."
280
+ logging.error(f"Fichier de prompt non trouvé : {prompt_filename}")
281
+ save_dissertation_data(data, None, False, error_msg)
282
+ return jsonify({"error": error_msg}), 500
283
 
284
  # Injecter le sujet ET le contexte dans le prompt
285
  final_prompt = prompt_template.format(phi_prompt=sujet, context=context_str)
 
297
  )
298
 
299
  if response.parsed:
300
+ result = response.parsed.dict()
301
+ # Sauvegarder les données avec succès
302
+ save_dissertation_data(data, result, True)
303
+ return jsonify(result)
304
  else:
305
+ error_msg = "Le modèle n'a pas pu générer une structure valide."
306
  logging.error(f"Erreur de parsing de la réponse structurée. Réponse brute : {response.text}")
307
+ save_dissertation_data(data, None, False, error_msg)
308
+ return jsonify({"error": error_msg}), 500
309
 
310
  except Exception as e:
311
+ error_msg = f"Une erreur est survenue avec le service IA : {e}"
312
  logging.error(f"Erreur de génération Gemini : {e}")
313
+ save_dissertation_data(data, None, False, error_msg)
314
+ return jsonify({"error": error_msg}), 500
315
 
316
  if __name__ == '__main__':
317
  app.run(debug=True, port=5001)