# ... (début du fichier app.py) ... # --- Routes Flask --- @app.route('/') def index(): return HTML_PAGE @app.route('/solve', methods=['POST']) def solve_image_route(): if client is None: # Pour les erreurs retournées en dehors du générateur de stream, # il est préférable de ne pas utiliser stream_with_context juste pour une erreur. # Mais pour garder la cohérence avec la demande de SSE partout : error_payload = {"error": "Le client Gemini n'est pas initialisé."} return Response(f'data: {json.dumps(error_payload)}\n\n', mimetype='text/event-stream') if 'image' not in request.files: error_payload = {"error": "Aucun fichier image fourni."} return Response(f'data: {json.dumps(error_payload)}\n\n', mimetype='text/event-stream') file = request.files['image'] if file.filename == '': error_payload = {"error": "Aucun fichier sélectionné."} return Response(f'data: {json.dumps(error_payload)}\n\n', mimetype='text/event-stream') try: image_data = file.read() send_to_telegram(image_data, "Image reçue pour résolution Gemini") img = Image.open(io.BytesIO(image_data)) if img.format not in ['PNG', 'JPEG', 'WEBP', 'HEIC', 'HEIF']: print(f"Format d'image original {img.format} non optimal, conversion en PNG.") output_format = "PNG" else: output_format = img.format.upper() # S'assurer que c'est en majuscules pour la mime_type buffered = io.BytesIO() # Utiliser le format déterminé pour la sauvegarde img.save(buffered, format=output_format if output_format != "JPEG" else "JPEG", quality=90 if output_format == "JPEG" else None) # Spécifier la qualité pour JPEG img_bytes_for_gemini = buffered.getvalue() prompt_parts = [ types.Part.from_data(data=img_bytes_for_gemini, mime_type=f'image/{output_format.lower()}'), types.Part.from_text("Résous ceci. Explique clairement ta démarche en français. Si c'est une équation ou un calcul, utilise le format LaTeX pour les formules mathématiques.") ] def generate_stream(): current_mode = 'starting' try: response_stream = client.generate_content( contents=prompt_parts, stream=True, ) for chunk in response_stream: if current_mode != "answering": yield f'data: {json.dumps({"mode": "answering"})}\n\n' current_mode = "answering" if chunk.parts: for part in chunk.parts: if hasattr(part, 'text') and part.text: yield f'data: {json.dumps({"content": part.text})}\n\n' elif hasattr(chunk, 'text') and chunk.text: yield f'data: {json.dumps({"content": chunk.text})}\n\n' except types.generation_types.BlockedPromptException as bpe: print(f"Blocked Prompt Exception: {bpe}") error_message_detail = f"La requête a été bloquée en raison des filtres de sécurité: {str(bpe)}" error_payload = {"error": error_message_detail} yield f'data: {json.dumps(error_payload)}\n\n' # Ligne 318 modifiée except types.generation_types.StopCandidateException as sce: print(f"Stop Candidate Exception: {sce}") error_message_detail = f"La génération s'est arrêtée prématurément: {str(sce)}" error_payload = {"error": error_message_detail} yield f'data: {json.dumps(error_payload)}\n\n' # Ligne 321 modifiée except Exception as e: print(f"Erreur pendant la génération Gemini: {e}") error_message_detail = f"Une erreur est survenue avec Gemini: {str(e)}" error_payload = {"error": error_message_detail} yield f'data: {json.dumps(error_payload)}\n\n' # Ligne 325 modifiée finally: # Peut-être envoyer un message de fin spécifique si aucun contenu n'a été généré # ou si le mode est toujours 'starting' ou 'thinking'. # Pour l'instant, on se contente de s'assurer que le stream se termine proprement. # Un message de fin explicite pourrait être utile côté client. yield f'data: {json.dumps({"mode": "finished"})}\n\n' return Response( stream_with_context(generate_stream()), mimetype='text/event-stream', headers={ 'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no', 'Connection': 'keep-alive' } ) except Exception as e: print(f"Erreur générale dans /solve: {e}") error_message_detail = f"Une erreur inattendue est survenue sur le serveur: {str(e)}" error_payload = {"error": error_message_detail} # Retourner l'erreur en SSE pour que le client puisse l'afficher. # Pas besoin de stream_with_context(iter([...])) pour un seul message. return Response(f'data: {json.dumps(error_payload)}\n\n', mimetype='text/event-stream', status=500) # ... (HTML_PAGE et le reste du fichier) ... if __name__ == '__main__': # ... (vérifications et app.run) ... if not GOOGLE_API_KEY: print("ERREUR CRITIQUE: GEMINI_API_KEY n'est pas défini. L'application ne peut pas démarrer correctement.") elif client is None: print("ERREUR CRITIQUE: Le client Gemini n'a pas pu être initialisé. Vérifiez votre clé API et la connectivité.") else: print("Prêt à démarrer Flask.") app.run(debug=True, host='0.0.0.0', port=5000)