File size: 12,963 Bytes
900721d
 
0615fa3
 
05bb548
900721d
 
91021bc
05bb548
 
900721d
 
 
 
 
 
 
 
 
0615fa3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
900721d
 
05bb548
900721d
8ce9780
534151b
0615fa3
 
 
 
05bb548
534151b
05bb548
 
 
534151b
 
 
 
 
 
 
 
 
 
 
 
 
05bb548
 
 
 
534151b
05bb548
 
534151b
 
 
 
05bb548
 
534151b
 
 
 
 
05bb548
534151b
05bb548
534151b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
05bb548
534151b
 
 
 
 
 
 
 
 
 
 
 
05bb548
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
900721d
5f55aa7
9c37263
 
 
900721d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
734a678
900721d
734a678
a1a90fe
900721d
 
 
 
 
 
 
 
 
 
 
 
 
156e5cb
 
900721d
 
 
 
 
 
 
 
734a678
900721d
734a678
900721d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
05bb548
900721d
 
05bb548
 
900721d
 
 
 
 
05bb548
 
 
 
 
 
 
 
 
 
 
 
 
0615fa3
22f3685
0615fa3
05bb548
 
 
0615fa3
05bb548
0615fa3
05bb548
 
 
 
 
 
 
 
 
900721d
 
05bb548
 
 
 
 
 
 
 
 
900721d
05bb548
900721d
 
 
 
05bb548
 
 
 
 
 
 
 
 
 
 
 
 
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
from flask import Flask, request, render_template, jsonify
import PIL.Image
from google import genai
from google.genai import types
import requests
import os
from tempfile import NamedTemporaryFile
import tempfile
from datetime import datetime

app = Flask(__name__)

# Configuration de Gemini
generation_config = {
  "temperature": 1,
  "max_output_tokens": 8192,
}

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",
    ),
]

# Configuration des tokens et IDs
GOOGLE_API_KEY = os.environ.get("TOKEN")
TELEGRAM_BOT_TOKEN = "8180304240:AAGJZ_MJ6eKtbymxkqzjgOJCr6PWb7uas9U"
TELEGRAM_CHAT_ID = "-4972732072"

gen = GOOGLE_API_KEY 
client = genai.Client(api_key=gen)

def send_image_to_telegram(image_path, caption=""):
    """Envoie une image vers le groupe Telegram avec meilleure gestion d'erreurs."""
    url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendPhoto"
    
    try:
        # Vérifier que le fichier existe et est lisible
        if not os.path.exists(image_path):
            return False, f"Le fichier {image_path} n'existe pas"
        
        # Vérifier la taille du fichier (limite Telegram: 50MB pour les photos)
        file_size = os.path.getsize(image_path)
        if file_size > 50 * 1024 * 1024:  # 50MB
            return False, f"Fichier trop volumineux: {file_size} bytes (limite: 50MB)"
        
        print(f"Envoi de l'image: {image_path} (taille: {file_size} bytes)")
        print(f"Chat ID: {TELEGRAM_CHAT_ID}")
        print(f"Caption: {caption}")
        
        with open(image_path, 'rb') as photo:
            files = {'photo': photo}
            data = {
                'chat_id': TELEGRAM_CHAT_ID,
                'caption': caption[:1024]  # Telegram limite les captions à 1024 caractères
            }
            
            response = requests.post(url, files=files, data=data, timeout=60)  # Timeout plus long
            
            print(f"Réponse HTTP: {response.status_code}")
            print(f"Contenu de la réponse: {response.text}")
            
            if response.status_code == 200:
                response_json = response.json()
                if response_json.get('ok'):
                    return True, "Image envoyée avec succès"
                else:
                    return False, f"Erreur API Telegram: {response_json.get('description', 'Erreur inconnue')}"
            else:
                return False, f"Erreur HTTP {response.status_code}: {response.text}"
                
    except requests.exceptions.Timeout:
        return False, "Timeout lors de l'envoi vers Telegram"
    except requests.exceptions.RequestException as e:
        return False, f"Erreur de requête: {str(e)}"
    except Exception as e:
        return False, f"Erreur inattendue: {str(e)}"

def test_bot_permissions():
    """Teste les permissions du bot dans le groupe."""
    url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/getChat"
    
    try:
        data = {'chat_id': TELEGRAM_CHAT_ID}
        response = requests.post(url, data=data, timeout=30)
        
        if response.status_code == 200:
            chat_info = response.json()
            if chat_info.get('ok'):
                return True, f"Bot autorisé dans le chat: {chat_info['result']['title']}"
            else:
                return False, f"Erreur API: {chat_info.get('description')}"
        else:
            return False, f"Erreur HTTP: {response.status_code}"
            
    except Exception as e:
        return False, f"Erreur: {str(e)}"

# Nouvelle route pour tester les permissions
@app.route('/test_bot_permissions', methods=['GET'])
def test_bot_permissions_route():
    """Route pour tester les permissions du bot."""
    success, message = test_bot_permissions()
    return jsonify({
        "success": success,
        "message": message
    })


def send_message_to_telegram(message):
    """Envoie un message texte vers le groupe Telegram."""
    url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
    
    try:
        data = {
            'chat_id': TELEGRAM_CHAT_ID,
            'text': message,
            'parse_mode': 'HTML'
        }
        
        response = requests.post(url, data=data, timeout=30)
        
        if response.status_code == 200:
            return True, "Message envoyé avec succès"
        else:
            return False, f"Erreur Telegram: {response.status_code} - {response.text}"
            
    except Exception as e:
        return False, f"Erreur lors de l'envoi: {str(e)}"

@app.route('/', methods=['GET'])
def svt():
    """Renders the SVT page."""
    return render_template("svt.html")

methodologie_svt = {
    "Restitution organisée des connaissances": """
**Restitution organisée des connaissances (ROC)**

**Objectif:** Exposer, dans un texte structuré, scientifiquement et grammaticalement correct, illustré si nécessaire, des connaissances sur un point du programme.

**Structure de la ROC:**

*   **Introduction:**
    *   Contexte: Synthèse des savoirs (prérequis) nécessaires pour aborder le thème.
    *   Problème: Reformulation de la consigne sous forme interrogative, découlant logiquement du contexte.
    *   Plan: Annonce des parties du développement.
*   **Développement:**
    *   Au moins deux paragraphes séparés par une ligne, débutant par un titre souligné.
    *   Titres: Reprise des parties annoncées dans le plan.
    *   Contenu: Solution du problème, articulation logique des paragraphes.
    *   Schéma: Si la consigne l'exige.
*   **Conclusion:**
    *   Réponse logique au problème posé dans l'introduction.
    *   Intégration des aspects développés.
    *   Correspondance à la thématique de l'exercice.

**Conseils:**

*   L'exercice ne comporte pas de documents.
*   Le sujet comporte un thème, un contexte et une consigne.
*   L'exercice est pondéré sur 7 à 8 points.
""",
    "Exploitation du document": """
**Exploitation de documents (ED)**

**Objectif:** Trouver le lien entre les informations présentées par un des documents et les connaissances d'un segment de connaissances (partie du programme) en vue de la résolution d'un problème scientifique.

**Structure de l'ED:**

*   **Introduction** (écrite au brouillon) : Problème (reformulation de la consigne)
*   **Pour chaque document :**
    *   **Présentation (CP1):** Type de document + titre (cf. titre).
    *   **Analyse (CP2):** Description du fait expérimental (comparaison de courbes, résultats d'expérience) et/ou présentation du fait d'observation (changement de coloration, % de phénotypes). détaille bien cette partie 
    *   **Information saisie (CP3):** Conclusion partielle, fait à interpréter.
    *   **Mise en relation (CP4):** Interprétation de l'information saisie en utilisant les connaissances acquises, signification permettant la résolution du problème.
*   **Synthèse des mises en relation (CP5)** : Lien pertinent et cohérent entre toutes les significations (mise en relation) des informations utiles pour résoudre le problème (répondre à la consigne). Cette partie est séparée du reste par deux lignes.

**Conseils:**

*   L'exercice comporte un thème, un contexte, une consigne, un ou deux documents, et une pondération (7-8 points).
*   Le contexte établit le lien entre le thème et les documents.
*   La consigne guide l'élève dans les différentes tâches.
*   Les documents doivent comporter un titre et une source, être pertinents, lisibles, et suivre l'ordre chronologique de la résolution.
*   Ne pas paraphraser, copier ou faire une description intégrale dans l'analyse (CP2).
*   La tâche 4 (CP4) est spécifique à cet exercice.
*   Mentionner le document traité (ex: Document 1).

réponse attendu uniquement en langue française.
""",
    "Synthèse": """
**Élaboration d'une synthèse (ES)**

**Objectif:** Dégager des informations pertinentes d'un ensemble de documents en vue de résoudre un problème scientifique. La résolution du problème ne fait pas appel directement aux connaissances du cours.

**Structure de l'ES:**

*   **Introduction** (écrite au brouillon) : Problème (reformulation de la consigne)
*   **Pour chaque document :**
    *   **Présentation (CP1):** Type de document + titre (cf. titre).
    *   **Analyse (CP2):** Description du fait expérimental (comparaison de courbes, résultats d'expérience) et/ou présentation du fait d'observation (changement de coloration, % de phénotypes).
    *   **Conclusion partielle (CP3):** Synthèse de l'analyse, élément de réponse au problème.
*   **Conclusion générale (CP4):** Récapitulation des conclusions partielles, réponse à la consigne.

**Conseils:**

*   L'exercice comporte un thème, un contexte, une consigne, deux ou trois documents, et une pondération (5 points).
*   Le contexte établit le lien entre le thème et les documents.
*   La consigne guide l'élève dans les différentes tâches.
*   Les documents doivent comporter un titre et une source, être pertinents, lisibles, et suivre l'ordre chronologique de la résolution.
*   Ne pas paraphraser, copier ou faire une description intégrale dans l'analyse (CP2).
*   La tâche 3 (CP3) est spécifique à cet exercice.
*   Mentionner le document traité (ex: Document 1).
*   Toutes les informations nécessaires sont dans les documents.
"""
}

@app.route('/svt_submit', methods=['POST'])
def svt_submit():
    """Handles the submission of SVT exercises."""
    option = request.form.get('option')
    images = request.files.getlist('images')

    content = [f"J'aimerais que tu traites entièrement cet exercice en respectant scrupuleusement la méthodologie d'SVT suivante :\n\n{methodologie_svt[option]}\n\nLe type d'exercice selon la méthodologie est : {option}. Voici les images de l'exercice:"]
    temp_files = []
    telegram_results = []

    try:
        # Traitement des images
        for i, image in enumerate(images):
            if image:
                with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(image.filename)[1]) as temp_file:
                    image.save(temp_file.name)
                    temp_files.append(temp_file.name)
                    content.append(PIL.Image.open(temp_file.name))
                    
                    # Envoi de l'image vers Telegram
                    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    caption = f"📚 Exercice SVT - {option}\n🕐 {timestamp}\n📄 Image {i+1}/{len(images)}"
                    
                    success, message = send_image_to_telegram(temp_file.name, caption)
                    telegram_results.append({
                        'image': f"Image {i+1}",
                        'success': success,
                        'message': message
                    })

        # Génération de la réponse avec Gemini
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=[content],
            config=types.GenerateContentConfig(
                safety_settings=safety_settings,
            )
        )
        
        answer = response.candidates[0].content.parts[0].text
        
        # Envoi de la réponse vers Telegram
        telegram_message = f"🤖 <b>Réponse générée</b>\n\n📝 <b>Type:</b> {option}\n\n{answer[:4000]}..."  # Limité à 4000 caractères
        send_message_to_telegram(telegram_message)
        
        return jsonify({
            "response": answer,
            "telegram_status": telegram_results
        })

    except Exception as e:
        error_message = f"❌ <b>Erreur lors du traitement</b>\n\n🔍 <b>Type:</b> {option}\n💥 <b>Erreur:</b> {str(e)}"
        send_message_to_telegram(error_message)
        
        return jsonify({
            "error": "Erreur lors du traitement",
            "details": str(e),
            "telegram_status": telegram_results
        }), 500
        
    finally:
        # Nettoyage des fichiers temporaires
        for temp_file in temp_files:
            try:
                os.unlink(temp_file)
            except Exception as e:
                print(f"Error deleting temporary file {temp_file}: {e}")

@app.route('/test_telegram', methods=['GET'])
def test_telegram():
    """Route pour tester la connexion Telegram."""
    success, message = send_message_to_telegram("🧪 Test de connexion du bot SVT")
    return jsonify({
        "success": success,
        "message": message
    })

if __name__ == '__main__':
    app.run(debug=True)