|
from flask import Flask, render_template, request, jsonify, send_file |
|
import threading |
|
import time |
|
import os |
|
from datetime import datetime |
|
from google import genai |
|
from google.genai import types |
|
import uuid |
|
import json |
|
|
|
app = Flask(__name__) |
|
|
|
|
|
GOOGLE_API_KEY = "AIzaSyAMYpF67aqFnWDJESWOx1dC-w3sEU29VcM" |
|
MODEL_ID = "gemini-2.5-flash-preview-05-20" |
|
UPLOAD_FOLDER = 'uploads' |
|
RESULTS_FOLDER = 'results' |
|
|
|
safety_settings = [ |
|
types.SafetySetting( |
|
category="HARM_CATEGORY_HARASSMENT", |
|
threshold="BLOCK_NONE", |
|
), |
|
types.SafetySetting( |
|
category="HARM_CATEGORY_HATE_SPEECH", |
|
threshold="BLOCK_NONE", |
|
), |
|
types.SafetySetting( |
|
category="HARM_CATEGORY_SEXUALLY_EXPLICIT", |
|
threshold="BLOCK_NONE", |
|
), |
|
types.SafetySetting( |
|
category="HARM_CATEGORY_DANGEROUS_CONTENT", |
|
threshold="BLOCK_NONE", |
|
), |
|
] |
|
|
|
|
|
os.makedirs(UPLOAD_FOLDER, exist_ok=True) |
|
os.makedirs(RESULTS_FOLDER, exist_ok=True) |
|
|
|
class TaskManager: |
|
def __init__(self): |
|
self.tasks = {} |
|
|
|
def create_task(self, task_id): |
|
self.tasks[task_id] = { |
|
'status': 'running', |
|
'progress': 0, |
|
'total': 470, |
|
'results_file': f'results_{task_id}.json', |
|
'start_time': datetime.now(), |
|
'errors': [], |
|
'last_update': datetime.now() |
|
} |
|
|
|
def update_progress(self, task_id, progress): |
|
if task_id in self.tasks: |
|
self.tasks[task_id]['progress'] = progress |
|
self.tasks[task_id]['last_update'] = datetime.now() |
|
|
|
def add_error(self, task_id, error_details): |
|
if task_id in self.tasks: |
|
self.tasks[task_id]['errors'].append(error_details) |
|
|
|
def complete_task(self, task_id): |
|
if task_id in self.tasks: |
|
self.tasks[task_id]['status'] = 'completed' |
|
self.tasks[task_id]['last_update'] = datetime.now() |
|
|
|
def get_task(self, task_id): |
|
return self.tasks.get(task_id) |
|
|
|
task_manager = TaskManager() |
|
|
|
def generate_synthetic_data(file_path, task_id): |
|
"""Fonction qui exécute les requêtes en arrière-plan et produit du JSON.""" |
|
try: |
|
client = genai.Client(api_key=GOOGLE_API_KEY) |
|
file_ref = client.files.upload(file=file_path) |
|
|
|
prompt = ( |
|
"J'aimerais générer des nouvelles données synthétiques à partir de ça. " |
|
"Une entrée en fang, une entrée en français. Je veux 400 phrases longues (respecte strictement cela).\n\n" |
|
"Réponds directement avec un objet JSON contenant les clés 'fang' et 'francais' pour chaque paire. " |
|
"Par exemple: {\"fang\": \"Texte en fang...\", \"francais\": \"Texte en français...\"}" |
|
) |
|
|
|
results_file_path = os.path.join(RESULTS_FOLDER, task_manager.get_task(task_id)['results_file']) |
|
|
|
all_generated_data = [] |
|
|
|
for i in range(task_manager.get_task(task_id)['total']): |
|
try: |
|
print(f"Task {task_id}: Requête {i+1}/{task_manager.get_task(task_id)['total']}...") |
|
response = client.models.generate_content( |
|
model=MODEL_ID, |
|
contents=[file_ref, prompt], |
|
generation_config=types.GenerationConfig( |
|
response_mime_type='application/json', |
|
|
|
), |
|
safety_settings=safety_settings |
|
) |
|
|
|
|
|
try: |
|
json_response = json.loads(response.text) |
|
all_generated_data.append(json_response) |
|
except json.JSONDecodeError as je: |
|
error_msg = f"Erreur de décodage JSON pour requête {i+1}: {str(je)}. Réponse reçue: {response.text[:200]}..." |
|
print(error_msg) |
|
task_manager.add_error(task_id, {"request_index": i+1, "error": error_msg, "raw_response": response.text}) |
|
|
|
all_generated_data.append({"error": "JSONDecodeError", "request_index": i+1, "details": response.text}) |
|
|
|
|
|
|
|
with open(results_file_path, 'w', encoding='utf-8') as f: |
|
json.dump(all_generated_data, f, ensure_ascii=False, indent=4) |
|
|
|
task_manager.update_progress(task_id, i + 1) |
|
print(f"Task {task_id}: Requête {i+1} complétée et sauvegardée.") |
|
|
|
time.sleep(4) |
|
|
|
except Exception as e: |
|
error_msg = f"Erreur pendant la requête {i+1}: {str(e)}" |
|
print(error_msg) |
|
task_manager.add_error(task_id, {"request_index": i+1, "error": error_msg}) |
|
|
|
all_generated_data.append({"error": "RequestException", "request_index": i+1, "details": str(e)}) |
|
|
|
with open(results_file_path, 'w', encoding='utf-8') as f: |
|
json.dump(all_generated_data, f, ensure_ascii=False, indent=4) |
|
|
|
|
|
|
|
task_manager.complete_task(task_id) |
|
print(f"Tâche {task_id} terminée. Résultats JSON dans {results_file_path}") |
|
|
|
except Exception as e: |
|
error_msg = f"Erreur générale dans la tâche {task_id}: {str(e)}" |
|
print(error_msg) |
|
task_manager.add_error(task_id, {"request_index": "general", "error": error_msg}) |
|
|
|
if task_manager.get_task(task_id): |
|
task_manager.get_task(task_id)['status'] = 'failed_or_completed_with_errors' |
|
|
|
|
|
@app.route('/') |
|
def index(): |
|
return render_template('index.html') |
|
|
|
@app.route('/upload', methods=['POST']) |
|
def upload_file_route(): |
|
if 'file' not in request.files: |
|
return jsonify({'error': 'Aucun fichier sélectionné'}), 400 |
|
|
|
file_obj = request.files['file'] |
|
if file_obj.filename == '': |
|
return jsonify({'error': 'Aucun fichier sélectionné'}), 400 |
|
|
|
if file_obj: |
|
task_id = str(uuid.uuid4()) |
|
filename = f"input_{task_id}{os.path.splitext(file_obj.filename)[1]}" |
|
file_path = os.path.join(UPLOAD_FOLDER, filename) |
|
file_obj.save(file_path) |
|
|
|
task_manager.create_task(task_id) |
|
|
|
thread = threading.Thread( |
|
target=generate_synthetic_data, |
|
args=(file_path, task_id) |
|
) |
|
thread.daemon = True |
|
thread.start() |
|
|
|
return jsonify({ |
|
'task_id': task_id, |
|
'message': 'Traitement démarré. Les résultats seront au format JSON.' |
|
}) |
|
|
|
@app.route('/status/<task_id>') |
|
def get_status(task_id): |
|
task = task_manager.get_task(task_id) |
|
if not task: |
|
return jsonify({'error': 'Tâche non trouvée'}), 404 |
|
|
|
|
|
start_time_str = task['start_time'].strftime('%Y-%m-%d %H:%M:%S') if isinstance(task['start_time'], datetime) else str(task['start_time']) |
|
last_update_str = task['last_update'].strftime('%Y-%m-%d %H:%M:%S') if isinstance(task['last_update'], datetime) else str(task['last_update']) |
|
|
|
return jsonify({ |
|
'status': task['status'], |
|
'progress': task['progress'], |
|
'total': task['total'], |
|
'percentage': round((task['progress'] / task['total']) * 100, 2) if task['total'] > 0 else 0, |
|
'errors_count': len(task['errors']), |
|
'errors_details': task['errors'][-5:], |
|
'start_time': start_time_str, |
|
'last_update': last_update_str, |
|
'results_file': task.get('results_file', f'results_{task_id}.json') |
|
}) |
|
|
|
@app.route('/download/<task_id>') |
|
def download_results(task_id): |
|
task = task_manager.get_task(task_id) |
|
if not task: |
|
return jsonify({'error': 'Tâche non trouvée'}), 404 |
|
|
|
|
|
results_filename = task.get('results_file', f'results_{task_id}.json') |
|
results_file_path = os.path.join(RESULTS_FOLDER, results_filename) |
|
|
|
if not os.path.exists(results_file_path): |
|
|
|
if task['status'] == 'running' and task['progress'] == 0: |
|
return jsonify({'message': 'La génération vient de commencer, aucun résultat à télécharger pour le moment.'}), 202 |
|
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 |
|
|
|
|
|
|
|
status_indicator = "complet" if task['status'] == 'completed' else "partiel_en_cours" |
|
download_name = f'donnees_synthetiques_{status_indicator}_{task_id}.json' |
|
|
|
return send_file( |
|
results_file_path, |
|
as_attachment=True, |
|
download_name=download_name, |
|
mimetype='application/json' |
|
) |
|
|
|
@app.route('/tasks') |
|
def list_tasks(): |
|
task_list = [] |
|
for task_id, task_info in task_manager.tasks.items(): |
|
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']) |
|
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']) |
|
|
|
task_list.append({ |
|
'id': task_id, |
|
'status': task_info['status'], |
|
'progress': task_info['progress'], |
|
'total': task_info['total'], |
|
'percentage': round((task_info['progress'] / task_info['total']) * 100, 2) if task_info['total'] > 0 else 0, |
|
'start_time': start_time_str, |
|
'last_update': last_update_str, |
|
'errors_count': len(task_info['errors']), |
|
'results_file': task_info.get('results_file', f'results_{task_id}.json') |
|
}) |
|
|
|
task_list.sort(key=lambda x: x['start_time'], reverse=True) |
|
return jsonify(task_list) |
|
|
|
@app.route('/cleanup') |
|
def cleanup_temp_files(): |
|
|
|
|
|
|
|
return jsonify({'message': 'Nettoyage des fichiers temporaires (JSON partiels) non applicable avec la nouvelle stratégie.'}) |
|
|
|
if __name__ == '__main__': |
|
print("🚀 Démarrage du serveur Flask...") |
|
print(f"📂 Dossier d'upload: {os.path.abspath(UPLOAD_FOLDER)}") |
|
print(f"📂 Dossier de résultats: {os.path.abspath(RESULTS_FOLDER)}") |
|
print("🌐 Application disponible sur: http://localhost:5000 (ou l'IP de votre machine si accessible de l'extérieur)") |
|
app.run(debug=True, threaded=True, host='0.0.0.0') |