Docfile commited on
Commit
cde384a
·
verified ·
1 Parent(s): d087a71

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +160 -11
app.py CHANGED
@@ -5,7 +5,11 @@ import os
5
  from PIL import Image
6
  import tempfile
7
  import json
8
- import logging # Optional: for better logging
 
 
 
 
9
 
10
  app = Flask(__name__)
11
 
@@ -39,6 +43,76 @@ SAFETY_SETTINGS = [
39
  )
40
  ]
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  # --- Prompts (Keep them as they are) ---
43
  prompt_tableau = """
44
  Traite selon cette méthodologie :
@@ -120,20 +194,20 @@ Voici un exercice a trous présentant la rédaction.. référence textuelle= rep
120
 
121
  EXERCICE À TROUS
122
 
123
- Le thème de ... (thème du texte) a souvent fait l'objet de nombreuses préoccupations dans le monde littéraire (mais pas que). Cest dans ce cadre que s'inscrit l'extrait ... (titre du texte) qui fait l'objet de notre étude, de l'écrivain... (nom de l'auteur), tiré de son œuvre ... (préciser le genre littéraire de l'œuvre) ... (maison d'édition), en ... (date de publication) à la (aux) page (s) …. Dans ce texte (type du texte) à ton ... (tonalité du texte/facultative), structure, nous verrons en premier lieu,...(axe 1) et en second lieu, ...(axe 2).
124
 
125
- Dans son extrait (poème), lauteur met en relief ... (axe 1) à travers ... (sous-axe 1) et ... (sous-axe 2).
126
 
127
- S'agissant de ... (sous-axe 1), l’écrivain utilise ... (outil d'analyse 1 + référence textuelle) pour montrer ... (interprétation). Aussi (de plus), par l'usage de... (outil d'analyse 2 + référence textuelle), l'écrivain ... (interprétation). Mieux encore, ... (outil d'analyse 3 + référence textuelle) nous donne également la possibilité dappréhender ... (sous-axe 2).
128
  De plus, l'homme de lettres emploie ... (outil d'analyse 1 + référence textuelle) pour ... (interprétation). Il se sert aussi de ...(outil d'analyse 2 + référence textuelle) afin de ... (interprétation). Pour continuer sa (description, représentation), le ...(nationalité de l'auteur) se manque pas de faire recours à ... (outil d'analyse 3 référence textuelle) Ici, il s'agit pour l'auteur autour de ... (sous-axe 1) et ... (sous-axe 2).
129
 
130
  Après avoir démontré ... (axe 1), voyons à présent ... (axe 2).
131
 
132
- En second lieu, le poète (l’écrivain ou lhomme de lettres) met en exergue ... (axe 2) en sappuyant dune part, sur... (sous-axe 1) et dautre part, sur... (sous-axe 2). En ce qui concerne ... (sous-axe 1), l'homme de lettres met d'abord en évidence l'aspect (le caractère) ... (interprétation) comme en témoigne l'emploi (l'usage de) ... (outil danalyse 1 + référence textuelle). Ensuite, ... (outil d'analyse 2 + référence textuelle) dévoile que... (interprétation) Enfin, ... (outil d'analyse 3 + référence textuelle) suggère que… (interprétation) . ... (axe 2) se révèle grâce à ….
133
- En parlant de ... (sous-axe 2), l'auteur met l'accent en premier sur… (interprétation), comme nous pouvons le voir avec la récurrence de (du/des) ... (rappel du sous-axe 2), le poète (l'auteur) souligne ... (interprétation) toujours dans le même sens de ... (rappel du sous-axe 2) . Il use de ... (outil danalyse 2 + référence textuelle). Dès lors, on peut déduire que ...(interprétation) utilise ... (outil danalyse 3 + référence textuelle).
134
  Ainsi, ... (axe 2) est lié (e) à ... (sous-axe 1) et à ... (sous-axe 2).
135
 
136
- Somme toute, ... (titre du texte) organise son sens autour de … (axe 1) et de ... (axe 2). De ces deux centres dintérêt découlent respectivement, dune part, … (sous-axe 1 de l'axe 1) et ... (sous-axe 2 de l'axe 1) et, dautre part, … (sous-axe 1 de l'axe 2) et … (sous-axe 2 de l'axe 2). À travers ce texte, ...(nom de l'auteur) nous ... (opinion personnelle). Une telle optique est perceptible dans la logique de... (nom de l'auteur nous permettant de faire un rapprochement thématique), dans son œuvre ...(titre de l’œuvre), dans lequel il aborde… (bref résumé de l'œuvre en question qui peut être facultatif).
137
  """
138
  # --- End Prompts ---
139
 
@@ -205,10 +279,49 @@ def index():
205
  # Assuming your main HTML file is index.html
206
  return render_template('index.html')
207
 
208
- # Removed /free route as it wasn't mentioned in the final HTML
209
- # @app.route('/free')
210
- # def free():
211
- # return render_template('free.html')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
  @app.route('/analyze', methods=['POST'])
214
  def analyze():
@@ -229,6 +342,12 @@ def analyze():
229
  model_id = MODEL_ID_STANDARD
230
  logging.info("Standard analysis requested, using standard model.")
231
 
 
 
 
 
 
 
232
  # Use a temporary file to handle the image upload
233
  temp_file = None # Initialize to None
234
  try:
@@ -242,6 +361,12 @@ def analyze():
242
  image.verify() # Verify image header
243
  # Re-open after verify
244
  image = Image.open(temp_file.name)
 
 
 
 
 
 
245
  except (IOError, SyntaxError) as e:
246
  logging.error(f"Invalid image file uploaded: {e}")
247
  return jsonify({'error': f'Invalid or corrupted image file: {e}'}), 400
@@ -254,6 +379,8 @@ def analyze():
254
  def generate():
255
  temp_file_path = temp_file.name # Store path for finally block
256
  full_tableau_content = "" # Accumulate full table content for dissertation
 
 
257
  try:
258
  logging.info("Starting table generation stream...")
259
  # Phase 1: Génération du tableau, passing the selected model_id
@@ -286,6 +413,7 @@ def analyze():
286
  yield chunk_json # Forward the error
287
  # Decide if you want to return here or let it finish
288
  elif chunk_data.get("type") == "dissertation":
 
289
  yield chunk_json # Stream chunk to client
290
  except json.JSONDecodeError:
291
  logging.error(f"Received invalid JSON from dissertation stream: {chunk_json}")
@@ -297,6 +425,27 @@ def analyze():
297
 
298
  logging.info("Dissertation generation stream finished.")
299
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  except Exception as e:
301
  logging.error(f"Error during streaming generation: {e}", exc_info=True)
302
  # Yield a JSON error message for the client
 
5
  from PIL import Image
6
  import tempfile
7
  import json
8
+ import logging
9
+ import sqlite3
10
+ from datetime import datetime
11
+ import base64
12
+ import io
13
 
14
  app = Flask(__name__)
15
 
 
43
  )
44
  ]
45
 
46
+ # --- Database Setup ---
47
+ def init_db():
48
+ """Initialize the SQLite database"""
49
+ conn = sqlite3.connect('analysis_data.db')
50
+ cursor = conn.cursor()
51
+
52
+ cursor.execute('''
53
+ CREATE TABLE IF NOT EXISTS analyses (
54
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
55
+ timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
56
+ image_name TEXT,
57
+ image_data TEXT,
58
+ consignes TEXT,
59
+ use_deepthink BOOLEAN,
60
+ model_used TEXT,
61
+ tableau_output TEXT,
62
+ dissertation_output TEXT,
63
+ user_ip TEXT,
64
+ processing_time REAL
65
+ )
66
+ ''')
67
+
68
+ conn.commit()
69
+ conn.close()
70
+
71
+ def save_analysis_data(image_name, image_data, consignes, use_deepthink, model_used, tableau_output, dissertation_output, user_ip, processing_time):
72
+ """Save analysis data to database"""
73
+ conn = sqlite3.connect('analysis_data.db')
74
+ cursor = conn.cursor()
75
+
76
+ cursor.execute('''
77
+ INSERT INTO analyses
78
+ (image_name, image_data, consignes, use_deepthink, model_used, tableau_output, dissertation_output, user_ip, processing_time)
79
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
80
+ ''', (image_name, image_data, consignes, use_deepthink, model_used, tableau_output, dissertation_output, user_ip, processing_time))
81
+
82
+ conn.commit()
83
+ conn.close()
84
+
85
+ def get_all_analyses():
86
+ """Get all analyses from database"""
87
+ conn = sqlite3.connect('analysis_data.db')
88
+ cursor = conn.cursor()
89
+
90
+ cursor.execute('''
91
+ SELECT id, timestamp, image_name, consignes, use_deepthink, model_used,
92
+ tableau_output, dissertation_output, user_ip, processing_time
93
+ FROM analyses
94
+ ORDER BY timestamp DESC
95
+ ''')
96
+
97
+ analyses = cursor.fetchall()
98
+ conn.close()
99
+
100
+ return analyses
101
+
102
+ def get_analysis_image(analysis_id):
103
+ """Get image data for a specific analysis"""
104
+ conn = sqlite3.connect('analysis_data.db')
105
+ cursor = conn.cursor()
106
+
107
+ cursor.execute('SELECT image_data FROM analyses WHERE id = ?', (analysis_id,))
108
+ result = cursor.fetchone()
109
+ conn.close()
110
+
111
+ return result[0] if result else None
112
+
113
+ # Initialize database on startup
114
+ init_db()
115
+
116
  # --- Prompts (Keep them as they are) ---
117
  prompt_tableau = """
118
  Traite selon cette méthodologie :
 
194
 
195
  EXERCICE À TROUS
196
 
197
+ Le thème de ... (thème du texte) a souvent fait l'objet de nombreuses préoccupations dans le monde littéraire (mais pas que). C'est dans ce cadre que s'inscrit l'extrait ... (titre du texte) qui fait l'objet de notre étude, de l'écrivain... (nom de l'auteur), tiré de son œuvre ... (préciser le genre littéraire de l'œuvre) ... (maison d'édition), en ... (date de publication) à la (aux) page (s) …. Dans ce texte (type du texte) à ton ... (tonalité du texte/facultative), structure, nous verrons en premier lieu,...(axe 1) et en second lieu, ...(axe 2).
198
 
199
+ Dans son extrait (poème), l'auteur met en relief ... (axe 1) à travers ... (sous-axe 1) et ... (sous-axe 2).
200
 
201
+ S'agissant de ... (sous-axe 1), l'écrivain utilise ... (outil d'analyse 1 + référence textuelle) pour montrer ... (interprétation). Aussi (de plus), par l'usage de... (outil d'analyse 2 + référence textuelle), l'écrivain ... (interprétation). Mieux encore, ... (outil d'analyse 3 + référence textuelle) nous donne également la possibilité d'appréhender ... (sous-axe 2).
202
  De plus, l'homme de lettres emploie ... (outil d'analyse 1 + référence textuelle) pour ... (interprétation). Il se sert aussi de ...(outil d'analyse 2 + référence textuelle) afin de ... (interprétation). Pour continuer sa (description, représentation), le ...(nationalité de l'auteur) se manque pas de faire recours à ... (outil d'analyse 3 référence textuelle) Ici, il s'agit pour l'auteur autour de ... (sous-axe 1) et ... (sous-axe 2).
203
 
204
  Après avoir démontré ... (axe 1), voyons à présent ... (axe 2).
205
 
206
+ En second lieu, le poète (l'écrivain ou l'homme de lettres) met en exergue ... (axe 2) en s'appuyant d'une part, sur... (sous-axe 1) et d'autre part, sur... (sous-axe 2). En ce qui concerne ... (sous-axe 1), l'homme de lettres met d'abord en évidence l'aspect (le caractère) ... (interprétation) comme en témoigne l'emploi (l'usage de) ... (outil d'analyse 1 + référence textuelle). Ensuite, ... (outil d'analyse 2 + référence textuelle) dévoile que... (interprétation) Enfin, ... (outil d'analyse 3 + référence textuelle) suggère que… (interprétation) . ... (axe 2) se révèle grâce à ….
207
+ En parlant de ... (sous-axe 2), l'auteur met l'accent en premier sur… (interprétation), comme nous pouvons le voir avec la récurrence de (du/des) ... (rappel du sous-axe 2), le poète (l'auteur) souligne ... (interprétation) toujours dans le même sens de ... (rappel du sous-axe 2) . Il use de ... (outil d'analyse 2 + référence textuelle). Dès lors, on peut déduire que ...(interprétation) utilise ... (outil d'analyse 3 + référence textuelle).
208
  Ainsi, ... (axe 2) est lié (e) à ... (sous-axe 1) et à ... (sous-axe 2).
209
 
210
+ Somme toute, ... (titre du texte) organise son sens autour de … (axe 1) et de ... (axe 2). De ces deux centres d'intérêt découlent respectivement, d'une part, … (sous-axe 1 de l'axe 1) et ... (sous-axe 2 de l'axe 1) et, d'autre part, … (sous-axe 1 de l'axe 2) et … (sous-axe 2 de l'axe 2). À travers ce texte, ...(nom de l'auteur) nous ... (opinion personnelle). Une telle optique est perceptible dans la logique de... (nom de l'auteur nous permettant de faire un rapprochement thématique), dans son œuvre ...(titre de l'œuvre), dans lequel il aborde… (bref résumé de l'œuvre en question qui peut être facultatif).
211
  """
212
  # --- End Prompts ---
213
 
 
279
  # Assuming your main HTML file is index.html
280
  return render_template('index.html')
281
 
282
+ @app.route('/gestion')
283
+ def gestion():
284
+ """Page de gestion pour afficher toutes les analyses"""
285
+ return render_template('gestion.html')
286
+
287
+ @app.route('/api/analyses')
288
+ def get_analyses():
289
+ """API endpoint to get all analyses data"""
290
+ try:
291
+ analyses = get_all_analyses()
292
+ analyses_data = []
293
+
294
+ for analysis in analyses:
295
+ analyses_data.append({
296
+ 'id': analysis[0],
297
+ 'timestamp': analysis[1],
298
+ 'image_name': analysis[2],
299
+ 'consignes': analysis[3],
300
+ 'use_deepthink': analysis[4],
301
+ 'model_used': analysis[5],
302
+ 'tableau_output': analysis[6],
303
+ 'dissertation_output': analysis[7],
304
+ 'user_ip': analysis[8],
305
+ 'processing_time': analysis[9]
306
+ })
307
+
308
+ return jsonify(analyses_data)
309
+ except Exception as e:
310
+ logging.error(f"Error fetching analyses: {e}")
311
+ return jsonify({'error': 'Erreur lors de la récupération des données'}), 500
312
+
313
+ @app.route('/api/analysis/<int:analysis_id>/image')
314
+ def get_analysis_image_endpoint(analysis_id):
315
+ """API endpoint to get image for a specific analysis"""
316
+ try:
317
+ image_data = get_analysis_image(analysis_id)
318
+ if image_data:
319
+ return Response(base64.b64decode(image_data), mimetype='image/jpeg')
320
+ else:
321
+ return jsonify({'error': 'Image non trouvée'}), 404
322
+ except Exception as e:
323
+ logging.error(f"Error fetching image: {e}")
324
+ return jsonify({'error': 'Erreur lors de la récupération de l\'image'}), 500
325
 
326
  @app.route('/analyze', methods=['POST'])
327
  def analyze():
 
342
  model_id = MODEL_ID_STANDARD
343
  logging.info("Standard analysis requested, using standard model.")
344
 
345
+ # Get user IP
346
+ user_ip = request.remote_addr
347
+
348
+ # Track processing time
349
+ start_time = datetime.now()
350
+
351
  # Use a temporary file to handle the image upload
352
  temp_file = None # Initialize to None
353
  try:
 
361
  image.verify() # Verify image header
362
  # Re-open after verify
363
  image = Image.open(temp_file.name)
364
+
365
+ # Convert image to base64 for storage
366
+ img_buffer = io.BytesIO()
367
+ image.save(img_buffer, format='JPEG')
368
+ image_base64 = base64.b64encode(img_buffer.getvalue()).decode('utf-8')
369
+
370
  except (IOError, SyntaxError) as e:
371
  logging.error(f"Invalid image file uploaded: {e}")
372
  return jsonify({'error': f'Invalid or corrupted image file: {e}'}), 400
 
379
  def generate():
380
  temp_file_path = temp_file.name # Store path for finally block
381
  full_tableau_content = "" # Accumulate full table content for dissertation
382
+ full_dissertation_content = "" # Accumulate full dissertation content
383
+
384
  try:
385
  logging.info("Starting table generation stream...")
386
  # Phase 1: Génération du tableau, passing the selected model_id
 
413
  yield chunk_json # Forward the error
414
  # Decide if you want to return here or let it finish
415
  elif chunk_data.get("type") == "dissertation":
416
+ full_dissertation_content += chunk_data.get("chunk", "")
417
  yield chunk_json # Stream chunk to client
418
  except json.JSONDecodeError:
419
  logging.error(f"Received invalid JSON from dissertation stream: {chunk_json}")
 
425
 
426
  logging.info("Dissertation generation stream finished.")
427
 
428
+ # Save analysis data to database
429
+ try:
430
+ end_time = datetime.now()
431
+ processing_time = (end_time - start_time).total_seconds()
432
+
433
+ save_analysis_data(
434
+ image_name=image_file.filename,
435
+ image_data=image_base64,
436
+ consignes=consignes,
437
+ use_deepthink=use_deepthink,
438
+ model_used=model_id,
439
+ tableau_output=full_tableau_content,
440
+ dissertation_output=full_dissertation_content,
441
+ user_ip=user_ip,
442
+ processing_time=processing_time
443
+ )
444
+ logging.info(f"Analysis data saved successfully for image: {image_file.filename}")
445
+ except Exception as save_error:
446
+ logging.error(f"Error saving analysis data: {save_error}")
447
+ # Don't yield error to client as analysis was successful
448
+
449
  except Exception as e:
450
  logging.error(f"Error during streaming generation: {e}", exc_info=True)
451
  # Yield a JSON error message for the client