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)