Docfile commited on
Commit
13cc55e
·
verified ·
1 Parent(s): 40dc451

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -7
app.py CHANGED
@@ -4,7 +4,8 @@ from google.genai import types
4
  from PIL import Image
5
  import json
6
  import logging
7
- from typing import Optional, Generator, Any
 
8
  import sys
9
  from pathlib import Path
10
 
@@ -19,6 +20,40 @@ logging.basicConfig(
19
  )
20
  logger = logging.getLogger(__name__)
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  class GeminiClient:
23
  """Classe pour gérer les interactions avec l'API Gemini"""
24
  def __init__(self, api_key: str):
@@ -47,7 +82,7 @@ class GeminiClient:
47
  config={'thinking_config': {'include_thoughts': True}},
48
  contents=[
49
  image,
50
- prompt
51
  ]
52
  )
53
  return response
@@ -55,14 +90,31 @@ class GeminiClient:
55
  logger.error(f"Erreur lors de l'analyse de l'image: {e}")
56
  raise
57
 
 
 
 
 
 
 
 
 
58
  def stream_response(container, response: Generator) -> None:
59
- """Gère le streaming de la réponse avec un affichage progressif et une gestion d'erreurs robuste"""
60
  mode = 'starting'
61
  thinking_placeholder = None
62
  answer_placeholder = None
63
  thinking_text = ""
64
  answer_text = ""
65
 
 
 
 
 
 
 
 
 
 
66
  try:
67
  for chunk in response:
68
  logger.debug(f"Chunk reçu: {chunk}")
@@ -93,6 +145,9 @@ def stream_response(container, response: Generator) -> None:
93
  text = getattr(part, 'text', '')
94
  if not text:
95
  continue
 
 
 
96
 
97
  if has_thought:
98
  if mode != "thinking":
@@ -100,7 +155,7 @@ def stream_response(container, response: Generator) -> None:
100
  with container.expander("Voir le raisonnement", expanded=False):
101
  thinking_placeholder = st.empty()
102
  mode = "thinking"
103
- thinking_text += text
104
  thinking_placeholder.markdown(thinking_text)
105
  else:
106
  if mode != "answering":
@@ -108,7 +163,7 @@ def stream_response(container, response: Generator) -> None:
108
  answer_placeholder = container.empty()
109
  container.subheader("Réponse")
110
  mode = "answering"
111
- answer_text += text
112
  answer_placeholder.markdown(answer_text)
113
 
114
  except json.JSONDecodeError as e:
@@ -127,7 +182,7 @@ def stream_response(container, response: Generator) -> None:
127
  finally:
128
  if not answer_text and not thinking_text:
129
  container.warning("Aucune réponse n'a pu être générée. Veuillez réessayer.")
130
-
131
  def validate_image(uploaded_file) -> Optional[Image.Image]:
132
  """Valide et ouvre une image téléchargée"""
133
  try:
@@ -147,6 +202,28 @@ def main():
147
 
148
  st.title("Mariam M-0")
149
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  # Récupération de la clé API
151
  try:
152
  api_key = st.secrets["GEMINI_API_KEY"]
@@ -175,7 +252,7 @@ def main():
175
  st.image(image, caption="Image téléchargée", use_container_width=True)
176
 
177
  model_name = "gemini-2.0-flash-thinking-exp-01-21"
178
- prompt = "Résous cet exercice. La réponse doit être bien présentée et espacée pour faciliter la lecture. Réponds en français."
179
 
180
  if st.button("Analyser l'image", type="primary"):
181
  response_container = st.container()
 
4
  from PIL import Image
5
  import json
6
  import logging
7
+ import re
8
+ from typing import Optional, Generator, Any, Tuple
9
  import sys
10
  from pathlib import Path
11
 
 
20
  )
21
  logger = logging.getLogger(__name__)
22
 
23
+ class LatexFormatter:
24
+ """Classe pour gérer le formatage LaTeX"""
25
+
26
+ @staticmethod
27
+ def format_inline_latex(text: str) -> str:
28
+ """Formate le LaTeX inline en ajoutant les délimiteurs appropriés"""
29
+ # Remplace les délimiteurs $ simples par $$ pour inline math
30
+ text = re.sub(r'(?<!\\)\$([^$]+)(?<!\\)\$', r'$\1$', text)
31
+ return text
32
+
33
+ @staticmethod
34
+ def format_block_latex(text: str) -> str:
35
+ """Formate les blocs LaTeX"""
36
+ # Ajoute des sauts de ligne avant et après les blocs LaTeX
37
+ text = re.sub(r'\$\$(.*?)\$\$', r'\n\n$$\1$$\n\n', text, flags=re.DOTALL)
38
+ return text
39
+
40
+ @staticmethod
41
+ def enhance_latex_display(text: str) -> str:
42
+ """Améliore l'affichage LaTeX global"""
43
+ # Gère les cas spéciaux de LaTeX
44
+ text = text.replace('\\[', '$$').replace('\\]', '$$') # Convertit \[ \] en $$
45
+ text = text.replace('\\(', '$').replace('\\)', '$') # Convertit \( \) en $
46
+
47
+ # Assure l'espacement correct autour des équations
48
+ text = re.sub(r'(\$\$.*?\$\$)', r'\n\n\1\n\n', text, flags=re.DOTALL)
49
+
50
+ # Améliore l'alignement des environnements mathématiques
51
+ text = re.sub(r'(\\begin{[^}]*})(.*?)(\\end{[^}]*})',
52
+ r'\n\n$$\1\2\3$$\n\n',
53
+ text, flags=re.DOTALL)
54
+
55
+ return text
56
+
57
  class GeminiClient:
58
  """Classe pour gérer les interactions avec l'API Gemini"""
59
  def __init__(self, api_key: str):
 
82
  config={'thinking_config': {'include_thoughts': True}},
83
  contents=[
84
  image,
85
+ prompt + " Si ta réponse contient des expressions mathématiques, utilise la notation LaTeX avec les délimiteurs appropriés ($ pour inline, $$ pour les blocs)."
86
  ]
87
  )
88
  return response
 
90
  logger.error(f"Erreur lors de l'analyse de l'image: {e}")
91
  raise
92
 
93
+ def format_text_with_latex(text: str) -> str:
94
+ """Formate le texte en appliquant les améliorations LaTeX"""
95
+ formatter = LatexFormatter()
96
+ text = formatter.format_inline_latex(text)
97
+ text = formatter.format_block_latex(text)
98
+ text = formatter.enhance_latex_display(text)
99
+ return text
100
+
101
  def stream_response(container, response: Generator) -> None:
102
+ """Gère le streaming de la réponse avec support LaTeX amélioré"""
103
  mode = 'starting'
104
  thinking_placeholder = None
105
  answer_placeholder = None
106
  thinking_text = ""
107
  answer_text = ""
108
 
109
+ # Configuration CSS pour améliorer l'affichage LaTeX
110
+ st.markdown("""
111
+ <style>
112
+ .katex { font-size: 1.1em !important; }
113
+ .katex-display { overflow: auto hidden; }
114
+ .markdown-text-container { max-width: 100%; }
115
+ </style>
116
+ """, unsafe_allow_html=True)
117
+
118
  try:
119
  for chunk in response:
120
  logger.debug(f"Chunk reçu: {chunk}")
 
145
  text = getattr(part, 'text', '')
146
  if not text:
147
  continue
148
+
149
+ # Formatage LaTeX du texte
150
+ formatted_text = format_text_with_latex(text)
151
 
152
  if has_thought:
153
  if mode != "thinking":
 
155
  with container.expander("Voir le raisonnement", expanded=False):
156
  thinking_placeholder = st.empty()
157
  mode = "thinking"
158
+ thinking_text += formatted_text
159
  thinking_placeholder.markdown(thinking_text)
160
  else:
161
  if mode != "answering":
 
163
  answer_placeholder = container.empty()
164
  container.subheader("Réponse")
165
  mode = "answering"
166
+ answer_text += formatted_text
167
  answer_placeholder.markdown(answer_text)
168
 
169
  except json.JSONDecodeError as e:
 
182
  finally:
183
  if not answer_text and not thinking_text:
184
  container.warning("Aucune réponse n'a pu être générée. Veuillez réessayer.")
185
+
186
  def validate_image(uploaded_file) -> Optional[Image.Image]:
187
  """Valide et ouvre une image téléchargée"""
188
  try:
 
202
 
203
  st.title("Mariam M-0")
204
 
205
+ # Configuration supplémentaire pour LaTeX
206
+ st.markdown("""
207
+ <style>
208
+ /* Styles globaux pour LaTeX */
209
+ .latex-container {
210
+ margin: 1em 0;
211
+ padding: 0.5em;
212
+ background: #f9f9f9;
213
+ border-radius: 4px;
214
+ }
215
+ /* Amélioration de l'espacement des équations */
216
+ .katex-display {
217
+ margin: 1.5em 0 !important;
218
+ padding: 0.5em 0;
219
+ }
220
+ /* Amélioration du rendu sur mobile */
221
+ @media (max-width: 768px) {
222
+ .katex { font-size: 1em !important; }
223
+ }
224
+ </style>
225
+ """, unsafe_allow_html=True)
226
+
227
  # Récupération de la clé API
228
  try:
229
  api_key = st.secrets["GEMINI_API_KEY"]
 
252
  st.image(image, caption="Image téléchargée", use_container_width=True)
253
 
254
  model_name = "gemini-2.0-flash-thinking-exp-01-21"
255
+ prompt = "Résous cet exercice mathématique. La réponse doit être bien présentée et espacée pour faciliter la lecture. Réponds en français et utilise la notation LaTeX pour toutes les expressions mathématiques."
256
 
257
  if st.button("Analyser l'image", type="primary"):
258
  response_container = st.container()