File size: 5,941 Bytes
8a641ea 79b1a5a fc53ab2 79b1a5a 8a641ea 43f84cb 79b1a5a 8a641ea 43f84cb 79b1a5a 8a641ea 43f84cb 79b1a5a 8a641ea fc53ab2 79b1a5a 8a641ea 79b1a5a 8a641ea 79b1a5a 8a641ea 79b1a5a 8a641ea 79b1a5a 8a641ea 79b1a5a 8a641ea 79b1a5a 8a641ea 79b1a5a 43f84cb 79b1a5a 8a641ea 79b1a5a fc53ab2 8a641ea 79b1a5a 8a641ea 79b1a5a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# ... (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) |