Docfile commited on
Commit
19d03a3
·
verified ·
1 Parent(s): fc67ac0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +115 -134
app.py CHANGED
@@ -4,14 +4,13 @@ import time
4
  import os
5
  from datetime import datetime
6
  from google import genai
7
- from google.genai import types
8
-
9
-
10
  import uuid
 
11
 
12
  app = Flask(__name__)
13
 
14
- # Configubration
15
  GOOGLE_API_KEY = "AIzaSyAMYpF67aqFnWDJESWOx1dC-w3sEU29VcM" # Remplacez par votre clé API
16
  MODEL_ID = "gemini-2.5-flash-preview-05-20" # Ou le modèle que vous utilisez
17
  UPLOAD_FOLDER = 'uploads'
@@ -36,14 +35,10 @@ safety_settings = [
36
  ),
37
  ]
38
 
39
-
40
  # Créer les dossiers s'ils n'existent pas
41
  os.makedirs(UPLOAD_FOLDER, exist_ok=True)
42
  os.makedirs(RESULTS_FOLDER, exist_ok=True)
43
 
44
- # Stockage des tâches en cours
45
- tasks = {}
46
-
47
  class TaskManager:
48
  def __init__(self):
49
  self.tasks = {}
@@ -52,8 +47,8 @@ class TaskManager:
52
  self.tasks[task_id] = {
53
  'status': 'running',
54
  'progress': 0,
55
- 'total': 470,
56
- 'results_file': f'results_{task_id}.txt',
57
  'start_time': datetime.now(),
58
  'errors': [],
59
  'last_update': datetime.now()
@@ -64,9 +59,9 @@ class TaskManager:
64
  self.tasks[task_id]['progress'] = progress
65
  self.tasks[task_id]['last_update'] = datetime.now()
66
 
67
- def add_error(self, task_id, error):
68
  if task_id in self.tasks:
69
- self.tasks[task_id]['errors'].append(error)
70
 
71
  def complete_task(self, task_id):
72
  if task_id in self.tasks:
@@ -79,94 +74,101 @@ class TaskManager:
79
  task_manager = TaskManager()
80
 
81
  def generate_synthetic_data(file_path, task_id):
82
- """Fonction qui exécute les 470 requêtes en arrière-plan"""
83
  try:
84
- # Initialiser le client Google AI
85
  client = genai.Client(api_key=GOOGLE_API_KEY)
86
-
87
- # Uploader le fichier
88
  file_ref = client.files.upload(file=file_path)
89
 
90
- # Prompt pour chaque requête
91
- prompt = ("J'aimerais générer des nouvelles données synthétiques à partir de ça. "
92
- "Une fang, une français. Je veux 400 phrases longues(respecte strictement cela).\n\n"
93
- "Selon le format : fang :.... / Français :.... reponds directement.")
 
 
94
 
95
- # Fichier de résultats
96
- results_file = os.path.join(RESULTS_FOLDER, f'results_{task_id}.txt')
97
 
98
- with open(results_file, 'w', encoding='utf-8') as f:
99
- f.write(f"Génération de données synthétiques - Démarré le {datetime.now()}\n")
100
- f.write("="*60 + "\n\n")
101
-
102
- for i in range(470):
 
 
 
 
 
 
 
 
 
 
 
103
  try:
104
- # Faire la requête
105
- response = client.models.generate_content(
106
- model=MODEL_ID,
107
- contents=[file_ref, prompt],
108
- config=types.GenerateContentConfig(
109
- safety_settings=safety_settings,
110
- )
111
- )
112
-
113
- # Écrire la réponse dans le fichier
114
- f.write(f"--- Requête {i+1}/470 ---\n")
115
- f.write(response.text)
116
- f.write("\n" + "="*60 + "\n\n")
117
- f.flush() # Forcer l'écriture immédiate
118
-
119
- # Mettre à jour le progrès
120
- task_manager.update_progress(task_id, i + 1)
121
-
122
- print(f"Requête {i+1}/470 complétée")
123
-
124
- # Pause pour éviter de surcharger l'API
125
- time.sleep(40)
126
-
127
- except Exception as e:
128
- error_msg = f"Erreur requête {i+1}: {str(e)}"
129
- task_manager.add_error(task_id, error_msg)
130
- f.write(f"ERREUR - Requête {i+1}: {str(e)}\n")
131
- f.write("="*60 + "\n\n")
132
- f.flush() # Forcer l'écriture même en cas d'erreur
133
  print(error_msg)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
 
135
  task_manager.complete_task(task_id)
136
- print(f"Tâche {task_id} terminée avec succès")
137
 
138
  except Exception as e:
139
- error_msg = f"Erreur générale: {str(e)}"
140
- task_manager.add_error(task_id, error_msg)
141
  print(error_msg)
 
 
 
 
 
142
 
143
  @app.route('/')
144
  def index():
145
- # Servir directement le HTML depuis le même dossier
146
  return render_template('index.html')
147
 
148
  @app.route('/upload', methods=['POST'])
149
- def upload_file():
150
  if 'file' not in request.files:
151
  return jsonify({'error': 'Aucun fichier sélectionné'}), 400
152
 
153
- file = request.files['file']
154
- if file.filename == '':
155
  return jsonify({'error': 'Aucun fichier sélectionné'}), 400
156
 
157
- if file:
158
- # Générer un ID unique pour cette tâche
159
  task_id = str(uuid.uuid4())
160
-
161
- # Sauvegarder le fichier
162
- filename = f"input_{task_id}.txt"
163
  file_path = os.path.join(UPLOAD_FOLDER, filename)
164
- file.save(file_path)
165
 
166
- # Créer la tâche
167
  task_manager.create_task(task_id)
168
 
169
- # Démarrer le traitement en arrière-plan
170
  thread = threading.Thread(
171
  target=generate_synthetic_data,
172
  args=(file_path, task_id)
@@ -176,7 +178,7 @@ def upload_file():
176
 
177
  return jsonify({
178
  'task_id': task_id,
179
- 'message': 'Traitement démarré en arrière-plan'
180
  })
181
 
182
  @app.route('/status/<task_id>')
@@ -185,14 +187,20 @@ def get_status(task_id):
185
  if not task:
186
  return jsonify({'error': 'Tâche non trouvée'}), 404
187
 
 
 
 
 
188
  return jsonify({
189
  'status': task['status'],
190
  'progress': task['progress'],
191
  'total': task['total'],
192
- 'percentage': round((task['progress'] / task['total']) * 100, 2),
193
  'errors_count': len(task['errors']),
194
- 'start_time': task['start_time'].strftime('%Y-%m-%d %H:%M:%S'),
195
- 'last_update': task['last_update'].strftime('%Y-%m-%d %H:%M:%S')
 
 
196
  })
197
 
198
  @app.route('/download/<task_id>')
@@ -201,87 +209,60 @@ def download_results(task_id):
201
  if not task:
202
  return jsonify({'error': 'Tâche non trouvée'}), 404
203
 
204
- results_file = os.path.join(RESULTS_FOLDER, f'results_{task_id}.txt')
205
-
206
- if not os.path.exists(results_file):
207
- return jsonify({'error': 'Fichier de résultats non trouvé'}), 404
208
-
209
- # Vérifier si c'est un téléchargement partiel
210
- is_partial = request.args.get('partial', 'false').lower() == 'true'
211
 
212
- if is_partial and task['status'] == 'running':
213
- # Créer un fichier temporaire avec les données actuelles
214
- temp_file = os.path.join(RESULTS_FOLDER, f'temp_results_{task_id}.txt')
215
-
216
- # Copier le contenu actuel vers le fichier temporaire
217
- try:
218
- with open(results_file, 'r', encoding='utf-8') as original:
219
- content = original.read()
220
-
221
- with open(temp_file, 'w', encoding='utf-8') as temp:
222
- temp.write(content)
223
- temp.write(f"\n\n--- TÉLÉCHARGEMENT PARTIEL ---\n")
224
- temp.write(f"Téléchargé le: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
225
- temp.write(f"Progrès: {task['progress']}/{task['total']} ({round((task['progress'] / task['total']) * 100, 2)}%)\n")
226
- temp.write("Génération en cours... Ce fichier contient les données générées jusqu'à présent.\n")
227
-
228
- return send_file(
229
- temp_file,
230
- as_attachment=True,
231
- download_name=f'donnees_synthetiques_partiel_{task_id}.txt'
232
- )
233
- except Exception as e:
234
- return jsonify({'error': f'Erreur lors de la création du fichier partiel: {str(e)}'}), 500
235
 
236
- # Téléchargement normal (complet)
237
- download_name = f'donnees_synthetiques_{"complet" if task["status"] == "completed" else "actuel"}_{task_id}.txt'
 
 
238
 
239
  return send_file(
240
- results_file,
241
  as_attachment=True,
242
- download_name=download_name
 
243
  )
244
 
245
  @app.route('/tasks')
246
  def list_tasks():
247
- """Liste toutes les tâches"""
248
  task_list = []
249
  for task_id, task_info in task_manager.tasks.items():
 
 
 
250
  task_list.append({
251
  'id': task_id,
252
  'status': task_info['status'],
253
  'progress': task_info['progress'],
254
  'total': task_info['total'],
255
- 'percentage': round((task_info['progress'] / task_info['total']) * 100, 2),
256
- 'start_time': task_info['start_time'].strftime('%Y-%m-%d %H:%M:%S'),
257
- 'last_update': task_info['last_update'].strftime('%Y-%m-%d %H:%M:%S'),
258
- 'errors_count': len(task_info['errors'])
 
259
  })
260
 
261
- # Trier par heure de début (plus récent en premier)
262
  task_list.sort(key=lambda x: x['start_time'], reverse=True)
263
-
264
  return jsonify(task_list)
265
 
266
  @app.route('/cleanup')
267
  def cleanup_temp_files():
268
- """Nettoyer les fichiers temporaires (optionnel)"""
269
- try:
270
- temp_files_deleted = 0
271
- for filename in os.listdir(RESULTS_FOLDER):
272
- if filename.startswith('temp_results_'):
273
- file_path = os.path.join(RESULTS_FOLDER, filename)
274
- os.remove(file_path)
275
- temp_files_deleted += 1
276
-
277
- return jsonify({
278
- 'message': f'{temp_files_deleted} fichiers temporaires supprimés'
279
- })
280
- except Exception as e:
281
- return jsonify({'error': f'Erreur lors du nettoyage: {str(e)}'}), 500
282
 
283
  if __name__ == '__main__':
284
- print("🚀 Démarrage du serveur...")
285
- print("📂 Dossiers créés:", UPLOAD_FOLDER, RESULTS_FOLDER)
286
- print("🌐 Application disponible sur: http://localhost:5000")
287
- app.run(debug=True, threaded=True)
 
 
4
  import os
5
  from datetime import datetime
6
  from google import genai
7
+ from google.genai import types # Explicitly import types
 
 
8
  import uuid
9
+ import json # Import json module
10
 
11
  app = Flask(__name__)
12
 
13
+ # Configuration
14
  GOOGLE_API_KEY = "AIzaSyAMYpF67aqFnWDJESWOx1dC-w3sEU29VcM" # Remplacez par votre clé API
15
  MODEL_ID = "gemini-2.5-flash-preview-05-20" # Ou le modèle que vous utilisez
16
  UPLOAD_FOLDER = 'uploads'
 
35
  ),
36
  ]
37
 
 
38
  # Créer les dossiers s'ils n'existent pas
39
  os.makedirs(UPLOAD_FOLDER, exist_ok=True)
40
  os.makedirs(RESULTS_FOLDER, exist_ok=True)
41
 
 
 
 
42
  class TaskManager:
43
  def __init__(self):
44
  self.tasks = {}
 
47
  self.tasks[task_id] = {
48
  'status': 'running',
49
  'progress': 0,
50
+ 'total': 470, # Nombre total de requêtes
51
+ 'results_file': f'results_{task_id}.json', # Changed to .json
52
  'start_time': datetime.now(),
53
  'errors': [],
54
  'last_update': datetime.now()
 
59
  self.tasks[task_id]['progress'] = progress
60
  self.tasks[task_id]['last_update'] = datetime.now()
61
 
62
+ def add_error(self, task_id, error_details): # error_details can be a dict
63
  if task_id in self.tasks:
64
+ self.tasks[task_id]['errors'].append(error_details)
65
 
66
  def complete_task(self, task_id):
67
  if task_id in self.tasks:
 
74
  task_manager = TaskManager()
75
 
76
  def generate_synthetic_data(file_path, task_id):
77
+ """Fonction qui exécute les requêtes en arrière-plan et produit du JSON."""
78
  try:
 
79
  client = genai.Client(api_key=GOOGLE_API_KEY)
 
 
80
  file_ref = client.files.upload(file=file_path)
81
 
82
+ prompt = (
83
+ "J'aimerais générer des nouvelles données synthétiques à partir de ça. "
84
+ "Une entrée en fang, une entrée en français. Je veux 400 phrases longues (respecte strictement cela).\n\n"
85
+ "Réponds directement avec un objet JSON contenant les clés 'fang' et 'francais' pour chaque paire. "
86
+ "Par exemple: {\"fang\": \"Texte en fang...\", \"francais\": \"Texte en français...\"}"
87
+ )
88
 
89
+ results_file_path = os.path.join(RESULTS_FOLDER, task_manager.get_task(task_id)['results_file'])
 
90
 
91
+ all_generated_data = [] # Liste pour stocker tous les objets JSON générés
92
+
93
+ for i in range(task_manager.get_task(task_id)['total']):
94
+ try:
95
+ print(f"Task {task_id}: Requête {i+1}/{task_manager.get_task(task_id)['total']}...")
96
+ response = client.models.generate_content(
97
+ model=MODEL_ID,
98
+ contents=[file_ref, prompt],
99
+ generation_config=types.GenerationConfig( # Use GenerationConfig
100
+ response_mime_type='application/json',
101
+ # Vous pourriez ajouter response_schema ici si vous avez un modèle > 1.5 et une classe TypedDict définie
102
+ ),
103
+ safety_settings=safety_settings # safety_settings renommé ici aussi
104
+ )
105
+
106
+ # L'API devrait retourner du texte qui est une chaîne JSON
107
  try:
108
+ json_response = json.loads(response.text)
109
+ all_generated_data.append(json_response)
110
+ except json.JSONDecodeError as je:
111
+ error_msg = f"Erreur de décodage JSON pour requête {i+1}: {str(je)}. Réponse reçue: {response.text[:200]}..."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  print(error_msg)
113
+ task_manager.add_error(task_id, {"request_index": i+1, "error": error_msg, "raw_response": response.text})
114
+ # Optionnel: ajouter un placeholder ou l'erreur dans all_generated_data
115
+ all_generated_data.append({"error": "JSONDecodeError", "request_index": i+1, "details": response.text})
116
+
117
+
118
+ # Sauvegarder la liste complète des données JSON après chaque ajout
119
+ with open(results_file_path, 'w', encoding='utf-8') as f:
120
+ json.dump(all_generated_data, f, ensure_ascii=False, indent=4)
121
+
122
+ task_manager.update_progress(task_id, i + 1)
123
+ print(f"Task {task_id}: Requête {i+1} complétée et sauvegardée.")
124
+
125
+ time.sleep(4) # Pause
126
+
127
+ except Exception as e:
128
+ error_msg = f"Erreur pendant la requête {i+1}: {str(e)}"
129
+ print(error_msg)
130
+ task_manager.add_error(task_id, {"request_index": i+1, "error": error_msg})
131
+ # Optionnel: ajouter un placeholder ou l'erreur dans all_generated_data
132
+ all_generated_data.append({"error": "RequestException", "request_index": i+1, "details": str(e)})
133
+ # Sauvegarder même en cas d'erreur pour ne pas perdre les données précédentes
134
+ with open(results_file_path, 'w', encoding='utf-8') as f:
135
+ json.dump(all_generated_data, f, ensure_ascii=False, indent=4)
136
+ # Continuer avec la prochaine requête si possible, ou décider d'arrêter.
137
+ # Ici, on continue.
138
 
139
  task_manager.complete_task(task_id)
140
+ print(f"Tâche {task_id} terminée. Résultats JSON dans {results_file_path}")
141
 
142
  except Exception as e:
143
+ error_msg = f"Erreur générale dans la tâche {task_id}: {str(e)}"
 
144
  print(error_msg)
145
+ task_manager.add_error(task_id, {"request_index": "general", "error": error_msg})
146
+ # Si une erreur générale se produit, marquer la tâche comme échouée ou la compléter avec erreurs
147
+ if task_manager.get_task(task_id):
148
+ task_manager.get_task(task_id)['status'] = 'failed_or_completed_with_errors'
149
+
150
 
151
  @app.route('/')
152
  def index():
 
153
  return render_template('index.html')
154
 
155
  @app.route('/upload', methods=['POST'])
156
+ def upload_file_route(): # Renommé pour éviter conflit avec variable 'file'
157
  if 'file' not in request.files:
158
  return jsonify({'error': 'Aucun fichier sélectionné'}), 400
159
 
160
+ file_obj = request.files['file'] # Renommé pour éviter conflit
161
+ if file_obj.filename == '':
162
  return jsonify({'error': 'Aucun fichier sélectionné'}), 400
163
 
164
+ if file_obj:
 
165
  task_id = str(uuid.uuid4())
166
+ filename = f"input_{task_id}{os.path.splitext(file_obj.filename)[1]}" # Conserver l'extension originale pour le fichier d'input
 
 
167
  file_path = os.path.join(UPLOAD_FOLDER, filename)
168
+ file_obj.save(file_path)
169
 
 
170
  task_manager.create_task(task_id)
171
 
 
172
  thread = threading.Thread(
173
  target=generate_synthetic_data,
174
  args=(file_path, task_id)
 
178
 
179
  return jsonify({
180
  'task_id': task_id,
181
+ 'message': 'Traitement démarré. Les résultats seront au format JSON.'
182
  })
183
 
184
  @app.route('/status/<task_id>')
 
187
  if not task:
188
  return jsonify({'error': 'Tâche non trouvée'}), 404
189
 
190
+ # S'assurer que les datetime sont bien des objets datetime
191
+ start_time_str = task['start_time'].strftime('%Y-%m-%d %H:%M:%S') if isinstance(task['start_time'], datetime) else str(task['start_time'])
192
+ last_update_str = task['last_update'].strftime('%Y-%m-%d %H:%M:%S') if isinstance(task['last_update'], datetime) else str(task['last_update'])
193
+
194
  return jsonify({
195
  'status': task['status'],
196
  'progress': task['progress'],
197
  'total': task['total'],
198
+ 'percentage': round((task['progress'] / task['total']) * 100, 2) if task['total'] > 0 else 0,
199
  'errors_count': len(task['errors']),
200
+ 'errors_details': task['errors'][-5:], # Afficher les 5 dernières erreurs par exemple
201
+ 'start_time': start_time_str,
202
+ 'last_update': last_update_str,
203
+ 'results_file': task.get('results_file', f'results_{task_id}.json') # S'assurer qu'il y a une valeur par défaut
204
  })
205
 
206
  @app.route('/download/<task_id>')
 
209
  if not task:
210
  return jsonify({'error': 'Tâche non trouvée'}), 404
211
 
212
+ # Le nom du fichier est maintenant stocké dans les détails de la tâche
213
+ results_filename = task.get('results_file', f'results_{task_id}.json')
214
+ results_file_path = os.path.join(RESULTS_FOLDER, results_filename)
 
 
 
 
215
 
216
+ if not os.path.exists(results_file_path):
217
+ # Si le fichier n'existe pas encore mais que la tâche est en cours, c'est normal
218
+ if task['status'] == 'running' and task['progress'] == 0:
219
+ return jsonify({'message': 'La génération vient de commencer, aucun résultat à télécharger pour le moment.'}), 202 # Accepted
220
+ return jsonify({'error': f'Fichier de résultats {results_filename} non trouvé. La génération est peut-être encore en cours ou a échoué avant de créer le fichier.'}), 404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
+ # Pour JSON, un "partiel" est juste l'état actuel du fichier JSON.
223
+ # Le nom du fichier téléchargé indiquera s'il est complet ou partiel.
224
+ status_indicator = "complet" if task['status'] == 'completed' else "partiel_en_cours"
225
+ download_name = f'donnees_synthetiques_{status_indicator}_{task_id}.json'
226
 
227
  return send_file(
228
+ results_file_path,
229
  as_attachment=True,
230
+ download_name=download_name,
231
+ mimetype='application/json' # Spécifier le mimetype JSON
232
  )
233
 
234
  @app.route('/tasks')
235
  def list_tasks():
 
236
  task_list = []
237
  for task_id, task_info in task_manager.tasks.items():
238
+ start_time_str = task_info['start_time'].strftime('%Y-%m-%d %H:%M:%S') if isinstance(task_info['start_time'], datetime) else str(task_info['start_time'])
239
+ last_update_str = task_info['last_update'].strftime('%Y-%m-%d %H:%M:%S') if isinstance(task_info['last_update'], datetime) else str(task_info['last_update'])
240
+
241
  task_list.append({
242
  'id': task_id,
243
  'status': task_info['status'],
244
  'progress': task_info['progress'],
245
  'total': task_info['total'],
246
+ 'percentage': round((task_info['progress'] / task_info['total']) * 100, 2) if task_info['total'] > 0 else 0,
247
+ 'start_time': start_time_str,
248
+ 'last_update': last_update_str,
249
+ 'errors_count': len(task_info['errors']),
250
+ 'results_file': task_info.get('results_file', f'results_{task_id}.json')
251
  })
252
 
 
253
  task_list.sort(key=lambda x: x['start_time'], reverse=True)
 
254
  return jsonify(task_list)
255
 
256
  @app.route('/cleanup')
257
  def cleanup_temp_files():
258
+ # Cette fonction n'est plus nécessaire si nous n'utilisons plus de fichiers 'temp_results_*.txt'
259
+ # Elle pourrait être adaptée pour nettoyer de vieux fichiers de résultats ou d'upload si besoin.
260
+ # Pour l'instant, on peut la laisser comme no-op ou la supprimer.
261
+ return jsonify({'message': 'Nettoyage des fichiers temporaires (JSON partiels) non applicable avec la nouvelle stratégie.'})
 
 
 
 
 
 
 
 
 
 
262
 
263
  if __name__ == '__main__':
264
+ print("🚀 Démarrage du serveur Flask...")
265
+ print(f"📂 Dossier d'upload: {os.path.abspath(UPLOAD_FOLDER)}")
266
+ print(f"📂 Dossier de résultats: {os.path.abspath(RESULTS_FOLDER)}")
267
+ print("🌐 Application disponible sur: http://localhost:5000 (ou l'IP de votre machine si accessible de l'extérieur)")
268
+ app.run(debug=True, threaded=True, host='0.0.0.0') # host='0.0.0.0' pour rendre accessible sur le réseau local