Docfile commited on
Commit
5309523
·
verified ·
1 Parent(s): b1cb01c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +359 -110
app.py CHANGED
@@ -2,27 +2,26 @@ from flask import Flask, render_template, request, jsonify, Response, stream_wit
2
  from google import genai
3
  from google.genai import types
4
  import os
 
 
 
5
  from PIL import Image
6
  import io
7
  import base64
8
- import json
9
- import requests # Pourb les requêtes HTTP vers l'API Telegram
10
 
11
  app = Flask(__name__)
12
 
13
  # API Keys
14
  GOOGLE_API_KEY = os.environ.get("GEMINI_API_KEY")
15
  TELEGRAM_BOT_TOKEN = "8004545342:AAGcZaoDjYg8dmbbXRsR1N3TfSSbEiAGz88"
 
16
 
17
- # Ajouter cette variable d'environnement
18
- TELEGRAM_CHAT_ID = "-1002497861230" # ID du chat où envoyer les images
19
 
20
- client = genai.Client(
21
- api_key=GOOGLE_API_KEY,
22
- )
23
-
24
- pp = r"""
25
- # 📝 GÉNÉRATEUR DE CORRECTION MATHÉMATIQUE (Version Directe)
26
 
27
  ## 🎓 VOTRE RÔLE
28
  Vous êtes **Mariam-MATHEX-PRO**, un expert en mathématiques chargé de fournir des corrections. Votre objectif est d'être clair, précis et d'aller droit au but.
@@ -31,7 +30,7 @@ Vous êtes **Mariam-MATHEX-PRO**, un expert en mathématiques chargé de fournir
31
 
32
  **ENTRÉE:** L'énoncé d'un exercice mathématique (niveau Terminale/Supérieur).
33
 
34
- **SORTIE:** UNIQUEMENT la correction de l'exercice.
35
 
36
  ## 🛠️ INSTRUCTIONS POUR LA CORRECTION
37
 
@@ -49,30 +48,239 @@ Vous êtes **Mariam-MATHEX-PRO**, un expert en mathématiques chargé de fournir
49
  4. **RÉSULTATS :**
50
  * Indiquez clairement les résultats intermédiaires si pertinent, et énoncez distinctement le résultat final de chaque question ou sous-question.
51
 
 
 
 
 
 
 
52
  ## ✅ OBJECTIF PRINCIPAL
53
- Fournir une correction mathématique textuelle qui va **droit au but**. Chaque étape de calcul doit être détaillée, et chaque explication doit être **très brève** et se concentrer sur le "comment" ou le "pourquoi" immédiat de l'opération mathématique.
 
 
 
 
54
 
 
 
 
 
 
 
 
 
 
 
 
55
  """
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
 
 
 
58
 
 
 
59
 
 
 
 
 
 
 
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  def send_to_telegram(image_data, caption="Nouvelle image uploadée"):
63
  """Envoie l'image à un chat Telegram spécifié"""
64
  try:
65
- # URL de l'API Telegram pour envoyer des photos
66
  url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendPhoto"
67
-
68
- # Préparer les données pour l'envoi
69
  files = {'photo': ('image.png', image_data)}
70
  data = {'chat_id': TELEGRAM_CHAT_ID, 'caption': caption}
71
 
72
- # Envoyer la requête
73
  response = requests.post(url, files=files, data=data)
74
 
75
- # Vérifier si l'envoi a réussi
76
  if response.status_code == 200:
77
  print("Image envoyée avec succès à Telegram")
78
  return True
@@ -85,22 +293,27 @@ def send_to_telegram(image_data, caption="Nouvelle image uploadée"):
85
 
86
  @app.route('/')
87
  def index():
88
- #return "La plateforme est en maintenance."
89
  return render_template('index.html')
90
 
91
- @app.route('/free')
92
- def indexx():
93
- return render_template('maj.html')
94
-
95
  @app.route('/solve', methods=['POST'])
96
  def solve():
97
  try:
98
- # Lire l'image
99
  image_data = request.files['image'].read()
 
 
 
100
  img = Image.open(io.BytesIO(image_data))
101
-
102
- # Envoyer l'image à Telegram
103
- send_to_telegram(image_data, "Nouvelle image pour résolution (modèle standard)")
 
 
 
 
 
 
 
104
 
105
  # Traitement pour Gemini
106
  buffered = io.BytesIO()
@@ -110,98 +323,133 @@ def solve():
110
  def generate():
111
  mode = 'starting'
112
  try:
113
- response = client.models.generate_content_stream(
114
- model="gemini-2.5-flash",
115
- contents=[
116
- {'inline_data': {'mime_type': 'image/png', 'data': img_str}},
117
- pp
118
-
119
- ],
120
- config=types.GenerateContentConfig(
121
- temperature=0.3,
122
- thinking_config=types.ThinkingConfig(
123
- include_thoughts=True
124
- )
125
- )
126
- )
127
-
128
- for chunk in response:
129
- for part in chunk.candidates[0].content.parts:
130
- if part.thought:
131
- if mode != "thinking":
132
- yield f'data: {json.dumps({"mode": "thinking"})}\n\n'
133
- mode = "thinking"
134
- else:
135
- if mode != "answering":
136
- yield f'data: {json.dumps({"mode": "answering"})}\n\n'
137
- mode = "answering"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
- yield f'data: {json.dumps({"content": part.text})}\n\n'
140
-
141
- except Exception as e:
142
- print(f"Error during generation: {e}")
143
- yield f'data: {json.dumps({"error": "Une erreur inattendue est survenue"})}\n\n'
144
-
145
- return Response(
146
- stream_with_context(generate()),
147
- mimetype='text/event-stream',
148
- headers={
149
- 'Cache-Control': 'no-cache',
150
- 'X-Accel-Buffering': 'no'
151
- }
152
- )
153
-
154
- except Exception as e:
155
- return jsonify({'error':'Une erreur inattendue est survenue' }), 500
156
-
157
- @app.route('/solved', methods=['POST'])
158
- def solved():
159
- try:
160
- # Lire l'image
161
- image_data = request.files['image'].read()
162
- img = Image.open(io.BytesIO(image_data))
163
-
164
- # Envoyer l'image à Telegram
165
- send_to_telegram(image_data, "Nouvelle image pour résolution (modèle premium)")
166
-
167
- # Traitement pour Gemini
168
- buffered = io.BytesIO()
169
- img.save(buffered, format="PNG")
170
- img_str = base64.b64encode(buffered.getvalue()).decode()
171
 
172
- def generate():
173
- mode = 'starting'
174
- try:
175
- response = client.models.generate_content_stream(
176
- model="gemini-2.5-flash",
177
- contents=[
178
- {'inline_data': {'mime_type': 'image/png', 'data': img_str}},
179
- pp],
180
- config=types.GenerateContentConfig(
181
  temperature=0.3,
182
- thinking_config=types.ThinkingConfig(
183
- include_thoughts=True
184
- )
185
  )
186
 
187
- )
188
-
189
- for chunk in response:
190
- for part in chunk.candidates[0].content.parts:
191
- if part.thought:
192
- if mode != "thinking":
193
- yield f'data: {json.dumps({"mode": "thinking"})}\n\n'
194
- mode = "thinking"
195
- else:
196
- if mode != "answering":
197
- yield f'data: {json.dumps({"mode": "answering"})}\n\n'
198
- mode = "answering"
199
-
200
- yield f'data: {json.dumps({"content": part.text})}\n\n'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
  except Exception as e:
203
  print(f"Error during generation: {e}")
204
  yield f'data: {json.dumps({"error": "Une erreur inattendue est survenue"})}\n\n'
 
205
  return Response(
206
  stream_with_context(generate()),
207
  mimetype='text/event-stream',
@@ -212,7 +460,8 @@ def solved():
212
  )
213
 
214
  except Exception as e:
215
- return jsonify({'error':'Une erreur inattendue est survenue' }), 500
 
216
 
217
  if __name__ == '__main__':
218
  app.run(debug=True)
 
2
  from google import genai
3
  from google.genai import types
4
  import os
5
+ import json
6
+ import requests
7
+ import time
8
  from PIL import Image
9
  import io
10
  import base64
11
+ from pathlib import Path
 
12
 
13
  app = Flask(__name__)
14
 
15
  # API Keys
16
  GOOGLE_API_KEY = os.environ.get("GEMINI_API_KEY")
17
  TELEGRAM_BOT_TOKEN = "8004545342:AAGcZaoDjYg8dmbbXRsR1N3TfSSbEiAGz88"
18
+ TELEGRAM_CHAT_ID = "-1002497861230"
19
 
20
+ client = genai.Client(api_key=GOOGLE_API_KEY)
 
21
 
22
+ # Prompt de base pour la correction mathématique
23
+ BASE_PROMPT = r"""
24
+ # 🔍 GÉNÉRATEUR DE CORRECTION MATHÉMATIQUE (Version Directe)
 
 
 
25
 
26
  ## 🎓 VOTRE RÔLE
27
  Vous êtes **Mariam-MATHEX-PRO**, un expert en mathématiques chargé de fournir des corrections. Votre objectif est d'être clair, précis et d'aller droit au but.
 
30
 
31
  **ENTRÉE:** L'énoncé d'un exercice mathématique (niveau Terminale/Supérieur).
32
 
33
+ **SORTIE:** UNIQUEMENT la correction de l'exercice **en français** avec rendu LaTeX.
34
 
35
  ## 🛠️ INSTRUCTIONS POUR LA CORRECTION
36
 
 
48
  4. **RÉSULTATS :**
49
  * Indiquez clairement les résultats intermédiaires si pertinent, et énoncez distinctement le résultat final de chaque question ou sous-question.
50
 
51
+ ## 🔧 RENDU MATHÉMATIQUE
52
+
53
+ 5. **RENDU MATHÉMATIQUE :**
54
+ * Utilisez le rendu LaTeX pour toutes les expressions mathématiques, équations et formules.
55
+ * Formatez correctement les calculs avec la syntaxe LaTeX appropriée.
56
+
57
  ## ✅ OBJECTIF PRINCIPAL
58
+ Fournir une correction mathématique textuelle **en français** qui va **droit au but**. Chaque étape de calcul doit être détaillée avec rendu LaTeX, chaque explication doit être **très brève** et se concentrer sur le "comment" ou le "pourquoi" immédiat de l'opération mathématique.
59
+ """
60
+
61
+ # Extension du prompt pour l'exécution de code
62
+ CODE_EXTENSION = r"""
63
 
64
+ ## 🧮 EXIGENCES TECHNIQUES (MODE CALCULATRICE ACTIVÉ)
65
+
66
+ 6. **CALCULS ET FIGURES :**
67
+ * Utilisez Python pour effectuer tous les calculs numériques et créer les graphiques nécessaires.
68
+ * Pour chaque figure ou graphique : générez-le avec Python, sauvegardez-le comme fichier image, puis affichez l'image.
69
+ * Intégrez le code Python dans la correction pour montrer la démarche de calcul.
70
+ * Utilisez des bibliothèques comme numpy, matplotlib, sympy selon les besoins.
71
+
72
+ 7. **VÉRIFICATION NUMÉRIQUE :**
73
+ * Vérifiez vos calculs analytiques avec des calculs numériques en Python.
74
+ * Créez des visualisations graphiques pour illustrer les concepts mathématiques.
75
  """
76
 
77
+ class AgentSystem:
78
+ def __init__(self):
79
+ self.prompts_dir = Path("prompts")
80
+ self.prompts = self.load_prompts()
81
+
82
+ def load_prompts(self):
83
+ """Load all agent prompts from files"""
84
+ prompts = {}
85
+ try:
86
+ # Create prompts directory if it doesn't exist
87
+ self.prompts_dir.mkdir(exist_ok=True)
88
+
89
+ # Define default prompts if files don't exist
90
+ default_prompts = {
91
+ "step1_initial_solution.md": """### Core Instructions ###
92
+
93
+ * **Rigor is Paramount:** Your primary goal is to produce a complete and rigorously justified solution. Every step in your solution must be logically sound and clearly explained. A correct final answer derived from flawed or incomplete reasoning is considered a failure.
94
+ * **Honesty About Completeness:** If you cannot find a complete solution, you must **not** guess or create a solution that appears correct but contains hidden flaws or justification gaps. Instead, you should present only significant partial results that you can rigorously prove. A partial result is considered significant if it represents a substantial advancement toward a full solution. Examples include:
95
+ * Proving a key lemma.
96
+ * Fully resolving one or more cases within a logically sound case-based proof.
97
+ * **Use TeX for All Mathematics:** All mathematical variables, expressions, and relations must be enclosed in TeX delimiters (e.g., 'Let $n$ be an integer.').
98
+
99
+ ### Output Format ###
100
+
101
+ Your response MUST be structured into the following sections, in this exact order.
102
+
103
+ **1. Summary**
104
+
105
+ Provide a concise overview of your findings. This section must contain two parts:
106
+
107
+ * **a. Verdict:** State clearly whether you have found a complete solution or a partial solution.
108
+ * **For a complete solution:** State the final answer, e.g., "I have successfully solved the problem. The final answer is..."
109
+ * **For a partial solution:** State the main rigorous conclusion(s) you were able to prove, e.g., "I have not found a complete solution, but I have rigorously proven that..."
110
+ * **b. Method Sketch:** Present a high-level, conceptual outline of your solution. This sketch should allow an expert to understand the logical flow of your argument without reading the full detail. It should include:
111
+ * A narrative of your overall strategy.
112
+ * The full and precise mathematical statements of any key lemmas or major intermediate results.
113
+ * If applicable, describe any key constructions or case splits that form the backbone of your argument.
114
+
115
+ **2. Detailed Solution**
116
+
117
+ Present the full, step-by-step mathematical proof. Each step must be logically justified and clearly explained. The level of detail should be sufficient for an expert to verify the correctness of your reasoning without needing to fill in any gaps. This section must contain ONLY the complete, rigorous proof, free of any internal commentary, alternative approaches, or failed attempts.
118
+
119
+ ### Self-Correction Instruction ###
120
+
121
+ Before finalizing your output, carefully review your "Method Sketch" and "Detailed Solution" to ensure they are clean, rigorous, and strictly adhere to all instructions provided above. Verify that every statement contributes directly to the final, coherent mathematical argument.
122
+
123
+ ### Problem ###
124
+ [The mathematical problem will be inserted here]""",
125
+
126
+ "step2_self_improvement.md": """You are a world-class mathematician. You have just produced the following draft solution.
127
+ Your task is to review it carefully, identify any potential flaws, gaps in logic, or areas that could be explained more clearly.
128
+ Then, produce a new, improved, and more rigorous version of the solution.
129
+
130
+ ### Draft Solution ###
131
+ [The initial solution attempt will be inserted here]
132
+
133
+ ### Your Task ###
134
+ Provide the improved and finalized version of the solution. Do not include comments about the changes, just the final, clean proof.""",
135
+
136
+ "step3_verification.md": """You are an expert mathematician and a meticulous grader for an International Mathematical Olympiad (IMO) level exam. Your primary task is to rigorously verify the provided mathematical solution. A solution is to be judged correct **only if every step is rigorously justified.** A solution that arrives at a correct final answer through flawed reasoning, educated guesses, or with gaps in its arguments must be flagged as incorrect or incomplete.
137
+
138
+ ### Instructions ###
139
 
140
+ **1. Core Instructions**
141
+ * Your sole task is to find and report all issues in the provided solution. You must act as a **verifier**, NOT a solver. **Do NOT attempt to correct the errors or fill the gaps you find.**
142
+ * You must perform a **step-by-step** check of the entire solution. This analysis will be presented in a **Detailed Verification Log**, where you justify your assessment of each step: for correct steps, a brief justification suffices; for steps with errors or gaps, you must provide a detailed explanation.
143
 
144
+ **2. How to Handle Issues in the Solution**
145
+ When you identify an issue in a step, you MUST first classify it into one of the following two categories and then follow the specified procedure.
146
 
147
+ * **a. Critical Error:**
148
+ This is any error that breaks the logical chain of the proof. This includes both **logical fallacies** (e.g., claiming that 'A>B, C>D' implies 'A-C>B-D') and **factual errors** (e.g., a calculation error like '2+3=6').
149
+ * **Procedure:**
150
+ * Explain the specific error and state that it **invalidates the current line of reasoning**.
151
+ * Do NOT check any further steps that rely on this error.
152
+ * You MUST, however, scan the rest of the solution to identify and verify any fully independent parts. For example, if a proof is split into multiple cases, an error in one case does not prevent you from checking the other cases.
153
 
154
+ * **b. Justification Gap:**
155
+ This is for steps where the conclusion may be correct, but the provided argument is incomplete, hand-wavy, or lacks sufficient rigor.
156
+ * **Procedure:**
157
+ * Explain the gap in the justification.
158
+ * State that you will **assume the step's conclusion is true** for the sake of argument.
159
+ * Then, proceed to verify all subsequent steps to check if the remainder of the argument is sound.
160
+
161
+ **3. Output Format**
162
+ Your response MUST be structured into two main sections: a **Summary** followed by the **Detailed Verification Log**.
163
+
164
+ * **a. Summary**
165
+ This section MUST be at the very beginning of your response. It must contain two components:
166
+ * **Final Verdict:** A single, clear sentence declaring the overall validity of the solution. For example: "The solution is correct," "The solution contains a Critical Error and is therefore invalid," or "The solution's approach is viable but contains several Justification Gaps."
167
+ * **List of Findings:** A bulleted list that summarizes **every** issue you discovered. For each finding, you must provide:
168
+ * **Location:** A direct quote of the key phrase or equation where the issue occurs.
169
+ * **Issue:** A brief description of the problem and its classification (**Critical Error** or **Justification Gap**).
170
+
171
+ * **b. Detailed Verification Log**
172
+ Following the summary, provide the full, step-by-step verification log as defined in the Core Instructions. When you refer to a specific part of the solution, **quote the relevant text** to make your reference clear before providing your detailed analysis of that part.
173
+
174
+ ---
175
+ ### Problem ###
176
+ [The mathematical problem will be inserted here]
177
+
178
+ ---
179
+ ### Solution ###
180
+ [The solution to be verified will be inserted here]
181
+
182
+ ---
183
+ ### Verification Task Reminder ###
184
+ Your task is to act as an IMO grader. Now, generate the **summary** and the **step-by-step verification log** for the solution above. In your log, justify each correct step and explain in detail any errors or justification gaps you find, as specified in the instructions above.""",
185
+
186
+ "step5_correction.md": """You are a brilliant mathematician attempting to solve a difficult problem.
187
+ Your previous solution attempt has been reviewed by a verifier, who produced the report below.
188
+ Your task is to write a new, corrected version of your solution that meticulously addresses all the issues raised in the report.
189
+
190
+ ### Verification Report on Your Last Attempt ###
191
+ [The full verification report will be inserted here]
192
+
193
+ ### Your Previous Flawed Solution ###
194
+ [The previous solution attempt will be inserted here]
195
+
196
+ ### Your Task ###
197
+ Provide a new, complete, and rigorously correct solution that fixes all identified issues. Remember to follow the structured output format (Summary and Detailed Solution) requested in the original problem."""
198
+ }
199
+
200
+ # Create prompt files if they don't exist
201
+ for filename, content in default_prompts.items():
202
+ prompt_file = self.prompts_dir / filename
203
+ if not prompt_file.exists():
204
+ prompt_file.write_text(content, encoding='utf-8')
205
+
206
+ prompts[filename.replace('.md', '')] = content
207
+
208
+ # Load existing prompts
209
+ for prompt_file in self.prompts_dir.glob("*.md"):
210
+ prompts[prompt_file.stem] = prompt_file.read_text(encoding='utf-8')
211
+
212
+ except Exception as e:
213
+ print(f"Error loading prompts: {e}")
214
+ # Fallback to hardcoded prompts
215
+ prompts = {
216
+ "step1_initial_solution": default_prompts["step1_initial_solution.md"],
217
+ "step2_self_improvement": default_prompts["step2_self_improvement.md"],
218
+ "step3_verification": default_prompts["step3_verification.md"],
219
+ "step5_correction": default_prompts["step5_correction.md"]
220
+ }
221
+
222
+ return prompts
223
+
224
+ def extract_problem_text(self, img_str):
225
+ """Extract problem text from image using Gemini"""
226
+ try:
227
+ response = client.models.generate_content(
228
+ model="gemini-2.5-flash",
229
+ contents=[
230
+ {'inline_data': {'mime_type': 'image/png', 'data': img_str}},
231
+ "Extract the mathematical problem statement from this image. Provide only the problem text in LaTeX format where appropriate, without any solution or commentary."
232
+ ],
233
+ config=types.GenerateContentConfig(temperature=0.1)
234
+ )
235
+
236
+ problem_text = ""
237
+ for part in response.candidates[0].content.parts:
238
+ if hasattr(part, 'text') and part.text:
239
+ problem_text += part.text
240
+
241
+ return problem_text.strip()
242
+ except Exception as e:
243
+ print(f"Error extracting problem text: {e}")
244
+ return "[Problem extraction failed]"
245
+
246
+ def run_agent_step(self, step_name, prompt, use_calculator=False):
247
+ """Run a single agent step"""
248
+ try:
249
+ config = types.GenerateContentConfig(
250
+ temperature=0.3,
251
+ thinking_config=types.ThinkingConfig(include_thoughts=True)
252
+ )
253
+
254
+ if use_calculator:
255
+ config.tools = [types.Tool(code_execution=types.ToolCodeExecution)]
256
+
257
+ response = client.models.generate_content_stream(
258
+ model="gemini-2.5-flash",
259
+ contents=[prompt],
260
+ config=config
261
+ )
262
+
263
+ result = ""
264
+ for chunk in response:
265
+ for part in chunk.candidates[0].content.parts:
266
+ if hasattr(part, 'text') and part.text:
267
+ result += part.text
268
+
269
+ return result.strip()
270
+
271
+ except Exception as e:
272
+ print(f"Error in agent step {step_name}: {e}")
273
+ return f"[Error in {step_name}: {str(e)}]"
274
 
275
  def send_to_telegram(image_data, caption="Nouvelle image uploadée"):
276
  """Envoie l'image à un chat Telegram spécifié"""
277
  try:
 
278
  url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendPhoto"
 
 
279
  files = {'photo': ('image.png', image_data)}
280
  data = {'chat_id': TELEGRAM_CHAT_ID, 'caption': caption}
281
 
 
282
  response = requests.post(url, files=files, data=data)
283
 
 
284
  if response.status_code == 200:
285
  print("Image envoyée avec succès à Telegram")
286
  return True
 
293
 
294
  @app.route('/')
295
  def index():
 
296
  return render_template('index.html')
297
 
 
 
 
 
298
  @app.route('/solve', methods=['POST'])
299
  def solve():
300
  try:
301
+ # Récupération des données
302
  image_data = request.files['image'].read()
303
+ use_calculator = request.form.get('use_calculator', 'false').lower() == 'true'
304
+ use_extended_reasoning = request.form.get('use_extended_reasoning', 'false').lower() == 'true'
305
+
306
  img = Image.open(io.BytesIO(image_data))
307
+
308
+ # Envoyer l'image à Telegram avec indication du mode
309
+ mode_info = []
310
+ if use_calculator:
311
+ mode_info.append("calculatrice")
312
+ if use_extended_reasoning:
313
+ mode_info.append("réflexion étendue")
314
+
315
+ caption = f"Nouvelle image pour résolution ({', '.join(mode_info) if mode_info else 'mode standard'})"
316
+ send_to_telegram(image_data, caption)
317
 
318
  # Traitement pour Gemini
319
  buffered = io.BytesIO()
 
323
  def generate():
324
  mode = 'starting'
325
  try:
326
+ if use_extended_reasoning:
327
+ # Mode réflexion étendue - système d'agents
328
+ agent_system = AgentSystem()
329
+
330
+ # Étape 0: Extraction du problème
331
+ yield f'data: {json.dumps({"mode": "thinking"})}\n\n'
332
+ yield f'data: {json.dumps({"content": "# 🔍 EXTRACTION DU PROBLÈME\n\nAnalyse de l\'image pour extraire l\'énoncé du problème...\n\n", "type": "text"})}\n\n'
333
+
334
+ problem_text = agent_system.extract_problem_text(img_str)
335
+ yield f'data: {json.dumps({"content": f"**Problème identifié:**\n{problem_text}\n\n", "type": "text"})}\n\n'
336
+
337
+ # Étape 1: Solution initiale
338
+ yield f'data: {json.dumps({"content": "---\n\n# 📝 ÉTAPE 1: GÉNÉRATION DE LA SOLUTION INITIALE\n\n", "type": "text"})}\n\n'
339
+
340
+ step1_prompt = agent_system.prompts["step1_initial_solution"].replace(
341
+ "[The mathematical problem will be inserted here]", problem_text
342
+ )
343
+
344
+ initial_solution = agent_system.run_agent_step("step1", step1_prompt, use_calculator)
345
+ yield f'data: {json.dumps({"content": f"{initial_solution}\n\n", "type": "text"})}\n\n'
346
+
347
+ # Étape 2: Auto-amélioration
348
+ yield f'data: {json.dumps({"content": "---\n\n# 🔧 ÉTAPE 2: AUTO-AMÉLIORATION\n\n", "type": "text"})}\n\n'
349
+
350
+ step2_prompt = agent_system.prompts["step2_self_improvement"].replace(
351
+ "[The initial solution attempt will be inserted here]", initial_solution
352
+ )
353
+
354
+ improved_solution = agent_system.run_agent_step("step2", step2_prompt, use_calculator)
355
+ yield f'data: {json.dumps({"content": f"{improved_solution}\n\n", "type": "text"})}\n\n'
356
+
357
+ # Étape 3: Vérification
358
+ yield f'data: {json.dumps({"content": "---\n\n# ✅ ÉTAPE 3: VÉRIFICATION RIGOUREUSE\n\n", "type": "text"})}\n\n'
359
+
360
+ step3_prompt = agent_system.prompts["step3_verification"].replace(
361
+ "[The mathematical problem will be inserted here]", problem_text
362
+ ).replace(
363
+ "[The solution to be verified will be inserted here]", improved_solution
364
+ )
365
+
366
+ verification_result = agent_system.run_agent_step("step3", step3_prompt, False)
367
+ yield f'data: {json.dumps({"content": f"{verification_result}\n\n", "type": "text"})}\n\n'
368
+
369
+ # Vérifier si des corrections sont nécessaires
370
+ needs_correction = (
371
+ "Critical Error" in verification_result or
372
+ "Justification Gap" in verification_result or
373
+ "invalid" in verification_result.lower()
374
+ )
375
+
376
+ if needs_correction:
377
+ # Étape 5: Correction
378
+ yield f'data: {json.dumps({"content": "---\n\n# 🛠️ ÉTAPE 5: CORRECTION DES ERREURS IDENTIFIÉES\n\n", "type": "text"})}\n\n'
379
 
380
+ step5_prompt = agent_system.prompts["step5_correction"].replace(
381
+ "[The full verification report will be inserted here]", verification_result
382
+ ).replace(
383
+ "[The previous solution attempt will be inserted here]", improved_solution
384
+ )
385
+
386
+ corrected_solution = agent_system.run_agent_step("step5", step5_prompt, use_calculator)
387
+ yield f'data: {json.dumps({"content": f"{corrected_solution}\n\n", "type": "text"})}\n\n'
388
+
389
+ final_solution = corrected_solution
390
+ else:
391
+ yield f'data: {json.dumps({"content": "✅ **La solution a passé la vérification avec succès!**\n\n", "type": "text"})}\n\n'
392
+ final_solution = improved_solution
393
+
394
+ # Passage à la réponse finale
395
+ yield f'data: {json.dumps({"mode": "answering"})}\n\n'
396
+ yield f'data: {json.dumps({"content": "# 📋 SOLUTION FINALE\n\n", "type": "text"})}\n\n'
397
+ yield f'data: {json.dumps({"content": final_solution, "type": "text"})}\n\n'
398
+
399
+ else:
400
+ # Mode standard
401
+ prompt = BASE_PROMPT
402
+ if use_calculator:
403
+ prompt += CODE_EXTENSION
 
 
 
 
 
 
 
 
404
 
405
+ config = types.GenerateContentConfig(
 
 
 
 
 
 
 
 
406
  temperature=0.3,
407
+ thinking_config=types.ThinkingConfig(include_thoughts=True)
 
 
408
  )
409
 
410
+ if use_calculator:
411
+ config.tools = [types.Tool(code_execution=types.ToolCodeExecution)]
412
+
413
+ response = client.models.generate_content_stream(
414
+ model="gemini-2.5-flash",
415
+ contents=[
416
+ {'inline_data': {'mime_type': 'image/png', 'data': img_str}},
417
+ prompt
418
+ ],
419
+ config=config
420
+ )
421
+
422
+ for chunk in response:
423
+ for part in chunk.candidates[0].content.parts:
424
+ # Gestion des pensées
425
+ if hasattr(part, 'thought') and part.thought:
426
+ if mode != "thinking":
427
+ yield f'data: {json.dumps({"mode": "thinking"})}\n\n'
428
+ mode = "thinking"
429
+ yield f'data: {json.dumps({"content": part.text, "type": "text"})}\n\n'
430
+ else:
431
+ if mode != "answering":
432
+ yield f'data: {json.dumps({"mode": "answering"})}\n\n'
433
+ mode = "answering"
434
+
435
+ # Gestion des différents types de contenu
436
+ if hasattr(part, 'text') and part.text is not None:
437
+ yield f'data: {json.dumps({"content": part.text, "type": "text"})}\n\n'
438
+
439
+ if hasattr(part, 'executable_code') and part.executable_code is not None:
440
+ yield f'data: {json.dumps({"content": part.executable_code.code, "type": "code"})}\n\n'
441
+
442
+ if hasattr(part, 'code_execution_result') and part.code_execution_result is not None:
443
+ yield f'data: {json.dumps({"content": part.code_execution_result.output, "type": "result"})}\n\n'
444
+
445
+ if hasattr(part, 'inline_data') and part.inline_data is not None:
446
+ img_data = base64.b64encode(part.inline_data.data).decode('utf-8')
447
+ yield f'data: {json.dumps({"content": img_data, "type": "image"})}\n\n'
448
 
449
  except Exception as e:
450
  print(f"Error during generation: {e}")
451
  yield f'data: {json.dumps({"error": "Une erreur inattendue est survenue"})}\n\n'
452
+
453
  return Response(
454
  stream_with_context(generate()),
455
  mimetype='text/event-stream',
 
460
  )
461
 
462
  except Exception as e:
463
+ print(f"Error in solve endpoint: {e}")
464
+ return jsonify({'error': 'Une erreur inattendue est survenue'}), 500
465
 
466
  if __name__ == '__main__':
467
  app.run(debug=True)