Docfile commited on
Commit
f7864af
·
verified ·
1 Parent(s): 0cb856b

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +484 -205
templates/index.html CHANGED
@@ -1,215 +1,494 @@
1
  <!DOCTYPE html>
2
  <html lang="fr">
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>Math Solver Version Gratuite</title>
7
- <!-- Font Awesome & Highlight.js -->
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
9
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css">
10
- <!-- Stylesheet -->
11
- <style>
12
- :root {
13
- --primary: #4a6fa5;
14
- --secondary: #166088;
15
- --accent: #4fc3f7;
16
- --bg: #f8f9fa;
17
- --text: #333;
18
- --light: #fff;
19
- --shadow: rgba(0,0,0,0.1);
20
- }
21
- * { box-sizing: border-box; }
22
- body {
23
- margin: 0;
24
- font-family: 'Segoe UI', Tahoma, Geneva, sans-serif;
25
- color: var(--text);
26
- background: var(--bg);
27
- line-height: 1.5;
28
- }
29
- header, main, footer { max-width: 900px; margin: 0 auto; padding: 1rem; }
30
- header { text-align: center; padding-top: 2rem; }
31
- .logo { font-size: 2.5rem; color: var(--primary); margin-bottom: .5rem; }
32
- .subtitle { color: var(--secondary); font-size: 1.1rem; }
33
-
34
- .card {
35
- background: var(--light);
36
- border-radius: 8px;
37
- box-shadow: 0 4px 8px var(--shadow);
38
- padding: 2rem;
39
- margin: 2rem 0;
40
- }
41
- .card h2 { color: var(--primary); margin-top: 0; }
42
-
43
- .features {
44
- display: grid;
45
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
46
- gap: 1rem;
47
- list-style: none;
48
- padding: 0;
49
- margin: 1.5rem 0;
50
- }
51
- .features li {
52
- display: flex;
53
- align-items: center;
54
- font-size: .95rem;
55
- }
56
- .features li i {
57
- margin-right: .5rem;
58
- color: var(--accent);
59
- }
60
- .features li.disabled i { color: #ccc; }
61
- .features li.disabled span { color: #999; }
62
-
63
- .btn {
64
- display: inline-flex;
65
- align-items: center;
66
- gap: .5rem;
67
- background: var(--primary);
68
- color: var(--light);
69
- padding: .75rem 1.5rem;
70
- border: none;
71
- border-radius: 4px;
72
- font-weight: 600;
73
- cursor: pointer;
74
- transition: transform .2s, background .2s;
75
- text-decoration: none;
76
- }
77
- .btn:hover { background: var(--secondary); transform: translateY(-2px); }
78
- .btn.secondary { background: var(--secondary); }
79
-
80
- /* Upload & Preview */
81
- .upload { text-align: center; margin: 1.5rem 0; }
82
- .upload input { display: none; }
83
- .preview {
84
- margin: 1rem auto;
85
- max-width: 100%;
86
- border-radius: 6px;
87
- box-shadow: 0 4px 6px var(--shadow);
88
- display: none;
89
- }
90
-
91
- /* Solution & Indicators */
92
- .solution {
93
- margin-top: 2rem;
94
- display: none;
95
- }
96
- .indicator {
97
- display: flex;
98
- align-items: center;
99
- gap: .5rem;
100
- padding: .75rem;
101
- border-radius: 4px;
102
- font-size: .9rem;
103
- }
104
- .indicator.think { background: #e3f2fd; color: #1565c0; }
105
- .indicator.exec { background: #ede7f6; color: #5e35b1; }
106
- .indicator.answer{ background: #e8f5e9; color: #2e7d32; }
107
- .indicator .fa { animation: pulse 1.4s infinite; }
108
- @keyframes pulse { 0%,100% { opacity:.6; } 50% { opacity:1; } }
109
-
110
- .step { background: #f9f9f9; border-left: 5px solid var(--primary); padding: 1rem; margin: 1rem 0; overflow-x:auto; }
111
- pre { margin: 0; }
112
- .code-block { margin: 1rem 0; border-radius: 6px; overflow: hidden; box-shadow: 0 2px 4px var(--shadow); }
113
- .code-block header { background: #343a40; color:#fff; padding:.5rem 1rem; font-family: monospace; font-size:.9rem; }
114
- .code-block pre { background: #2c323c; color: #e6e6e6; padding:1rem; font-family: monospace; font-size:.9rem; }
115
- .output-block { background: var(--light); border-top:1px solid #ddd; padding:1rem; font-family: monospace; white-space: pre-wrap; }
116
-
117
- footer { text-align: center; font-size:.85rem; color:#666; padding:2rem 1rem; }
118
-
119
- @media(max-width:600px) {
120
- .features { grid-template-columns: 1fr; }
121
- .btn { width: 100%; justify-content: center; }
122
- }
123
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  </head>
125
  <body>
 
 
 
 
 
126
 
127
- <header>
128
- <div class="logo">Math Solver</div>
129
- <div class="subtitle">La solution intelligente pour vos problèmes mathématiques</div>
130
- </header>
131
-
132
- <main>
133
- <section class="card">
134
- <h2>Version Gratuite</h2>
135
- <p>3 problèmes gratuits par jour avec explication pas-à-pas.</p>
136
-
137
- <ul class="features">
138
- <li><i class="fas fa-check-circle"></i> Problèmes basiques</li>
139
- <li><i class="fas fa-check-circle"></i> 3 par jour</li>
140
- <li><i class="fas fa-check-circle"></i> Explications détaillées</li>
141
- <li class="disabled"><i class="fas fa-times-circle"></i><span>Code avancé (Pro)</span></li>
142
- <li class="disabled"><i class="fas fa-times-circle"></i><span>Illimité (Pro)</span></li>
143
- <li class="disabled"><i class="fas fa-times-circle"></i><span>Support prioritaire (Pro)</span></li>
144
- </ul>
145
-
146
- <div class="upload">
147
- <input type="file" id="imgInput" accept="image/*">
148
- <button class="btn" id="btnSelect"><i class="fas fa-upload"></i> Choisir une image</button>
149
- </div>
150
- <img id="imgPreview" class="preview" alt="Aperçu du problème">
151
- <button class="btn secondary" id="btnSolve" style="display:none;"><i class="fas fa-calculator"></i> Résoudre</button>
152
 
153
- <div class="solution" id="solutionArea">
154
- <div class="indicator think" id="indicator"><i class="fas fa-brain"></i><span>Je réfléchis...</span></div>
155
- <div id="solutionContent"></div>
156
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
- <div style="text-align:center; margin-top:2rem;">
159
- <a href="#" class="btn">Passer à la version Pro</a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  </div>
161
- </section>
162
- </main>
163
-
164
- <footer>&copy; 2025 Math Solver. Tous droits réservés.</footer>
165
-
166
- <!-- Scripts -->
167
- <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
168
- <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
169
- <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
170
- <script>
171
- // Element references
172
- const imgInput = document.getElementById('imgInput');
173
- const preview = document.getElementById('imgPreview');
174
- const btnSelect = document.getElementById('btnSelect');
175
- const btnSolve = document.getElementById('btnSolve');
176
- const solArea = document.getElementById('solutionArea');
177
- const solCont = document.getElementById('solutionContent');
178
- const indicator = document.getElementById('indicator');
179
-
180
- btnSelect.addEventListener('click', () => imgInput.click());
181
- imgInput.addEventListener('change', e => {
182
- const file = e.target.files[0];
183
- if (!file) return;
184
- const url = URL.createObjectURL(file);
185
- preview.src = url;
186
- preview.style.display = 'block';
187
- btnSolve.style.display = 'inline-flex';
188
- });
189
-
190
- btnSolve.addEventListener('click', () => {
191
- solArea.style.display = 'block';
192
- solCont.innerHTML = '';
193
- indicator.className = 'indicator think';
194
- indicator.querySelector('span').textContent = 'Je réfléchis...';
195
-
196
- fetch('/solved', { method: 'POST', body: new FormData(document.querySelector('form')) })
197
- .then(res => {
198
- // streaming logic...
199
- })
200
- .catch(err => console.error(err));
201
- });
202
-
203
- function updateIndicator(mode) {
204
- indicator.className = 'indicator ' + mode;
205
- const icons = { think: 'fa-brain', exec: 'fa-code', answer: 'fa-paste' };
206
- indicator.querySelector('i').className = 'fas ' + icons[mode];
207
- indicator.querySelector('span').textContent = {
208
- think: 'Je réfléchis...',
209
- exec: 'Exécution du code...',
210
- answer: 'Rédaction de la solution...',
211
- }[mode];
212
- }
213
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  </body>
215
- </html>
 
1
  <!DOCTYPE html>
2
  <html lang="fr">
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Math Solver - Version Gratuite</title>
7
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
8
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css" rel="stylesheet">
9
+ <style>
10
+ :root {
11
+ --primary-color: #4a6fa5;
12
+ --secondary-color: #166088;
13
+ --accent-color: #4fc3f7;
14
+ --background-color: #f8f9fa;
15
+ --text-color: #333;
16
+ --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
17
+ --code-bg: #2c323c;
18
+ --output-bg: #f1f8f9;
19
+ }
20
+
21
+ body {
22
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
23
+ line-height: 1.6;
24
+ margin: 0;
25
+ padding: 0;
26
+ background-color: var(--background-color);
27
+ color: var(--text-color);
28
+ }
29
+
30
+ .container {
31
+ max-width: 1000px;
32
+ margin: 0 auto;
33
+ padding: 20px;
34
+ }
35
+
36
+ header {
37
+ text-align: center;
38
+ padding: 20px 0;
39
+ margin-bottom: 30px;
40
+ }
41
+
42
+ .logo {
43
+ font-size: 2.5rem;
44
+ font-weight: bold;
45
+ color: var(--primary-color);
46
+ margin-bottom: 10px;
47
+ }
48
+
49
+ .subtitle {
50
+ font-size: 1.2rem;
51
+ color: var(--secondary-color);
52
+ margin-bottom: 20px;
53
+ }
54
+
55
+ .content-box {
56
+ background-color: white;
57
+ border-radius: 10px;
58
+ box-shadow: var(--box-shadow);
59
+ padding: 30px;
60
+ margin-bottom: 30px;
61
+ text-align: center;
62
+ }
63
+
64
+ h1 {
65
+ color: var(--primary-color);
66
+ margin-top: 0;
67
+ }
68
+
69
+ .feature-list {
70
+ list-style-type: none;
71
+ padding: 0;
72
+ margin: 30px 0;
73
+ text-align: left;
74
+ }
75
+
76
+ .feature-list li {
77
+ padding: 10px 0;
78
+ margin-bottom: 10px;
79
+ display: flex;
80
+ align-items: center;
81
+ }
82
+
83
+ .feature-list i {
84
+ color: var(--accent-color);
85
+ margin-right: 10px;
86
+ font-size: 1.2rem;
87
+ }
88
+
89
+ .cta-button {
90
+ display: inline-block;
91
+ background-color: var(--primary-color);
92
+ color: white;
93
+ padding: 12px 25px;
94
+ border-radius: 5px;
95
+ text-decoration: none;
96
+ font-weight: bold;
97
+ transition: all 0.3s ease;
98
+ margin: 20px 10px;
99
+ border: none;
100
+ cursor: pointer;
101
+ }
102
+
103
+ .cta-button:hover {
104
+ background-color: var(--secondary-color);
105
+ transform: translateY(-2px);
106
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
107
+ }
108
+
109
+ .upgrade-section {
110
+ margin-top: 30px;
111
+ padding: 20px;
112
+ border-top: 1px solid #ddd;
113
+ }
114
+
115
+ footer {
116
+ text-align: center;
117
+ padding: 20px 0;
118
+ color: #666;
119
+ font-size: 0.9rem;
120
+ }
121
+
122
+ #solution {
123
+ background: #fff;
124
+ padding: 20px;
125
+ border-radius: 8px;
126
+ text-align: left;
127
+ line-height: 1.8;
128
+ font-size: 16px;
129
+ }
130
+
131
+ .code-section {
132
+ margin: 20px 0;
133
+ border-radius: 8px;
134
+ overflow: hidden;
135
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
136
+ }
137
+
138
+ .code-header {
139
+ background-color: #343a40;
140
+ color: white;
141
+ padding: 8px 15px;
142
+ font-size: 14px;
143
+ font-family: 'Courier New', monospace;
144
+ display: flex;
145
+ justify-content: space-between;
146
+ align-items: center;
147
+ }
148
+
149
+ .code-content {
150
+ margin: 0;
151
+ padding: 15px;
152
+ background-color: var(--code-bg);
153
+ color: #e6e6e6;
154
+ overflow-x: auto;
155
+ font-family: 'Courier New', monospace;
156
+ font-size: 14px;
157
+ line-height: 1.5;
158
+ }
159
+
160
+ .output-section {
161
+ background-color: var(--output-bg);
162
+ padding: 15px;
163
+ border-radius: 0 0 8px 8px;
164
+ border-top: 1px solid #ddd;
165
+ color: #333;
166
+ font-family: 'Courier New', monospace;
167
+ font-size: 14px;
168
+ white-space: pre-wrap;
169
+ overflow-x: auto;
170
+ }
171
+
172
+ .step-section {
173
+ margin: 25px 0;
174
+ padding: 15px;
175
+ background-color: #f9f9f9;
176
+ border-left: 4px solid var(--primary-color);
177
+ border-radius: 0 8px 8px 0;
178
+ overflow-x: auto; /* Pour les formules LaTeX larges */
179
+ white-space: pre-wrap; /* Preserve whitespace/line breaks from stream */
180
+ }
181
+
182
+ .latex-display {
183
+ overflow-x: auto;
184
+ padding: 10px 0;
185
+ margin: 15px 0;
186
+ text-align: center;
187
+ }
188
+
189
+ .thinking-indicator, .executing-indicator, .answering-indicator {
190
+ display: flex;
191
+ align-items: center;
192
+ padding: 10px;
193
+ margin: 10px 0;
194
+ border-radius: 8px;
195
+ font-size: 0.9rem;
196
+ }
197
+
198
+ .thinking-indicator {
199
+ background-color: #e3f2fd;
200
+ color: #1565c0;
201
+ }
202
+
203
+ .executing-indicator {
204
+ background-color: #ede7f6;
205
+ color: #5e35b1;
206
+ }
207
+
208
+ .answering-indicator {
209
+ background-color: #e8f5e9;
210
+ color: #2e7d32;
211
+ }
212
+
213
+ .indicator-icon {
214
+ margin-right: 10px;
215
+ animation: pulse 1.5s infinite ease-in-out;
216
+ }
217
+
218
+ @keyframes pulse {
219
+ 0% { opacity: 0.6; }
220
+ 50% { opacity: 1; }
221
+ 100% { opacity: 0.6; }
222
+ }
223
+
224
+ /* Styles spécifiques à MathJax pour le rendu */
225
+ /* Ensure rendered math doesn't cause excessive layout shifts or overflow */
226
+ mjx-container {
227
+ overflow-x: auto;
228
+ overflow-y: hidden;
229
+ display: block; /* Treat block math as a block */
230
+ margin: 1em 0; /* Add some vertical spacing */
231
+ text-align: initial; /* Inherit text alignment from parent */
232
+ }
233
+ mjx-assistive-mml { /* Hide the assistive MML */
234
+ display: none !important;
235
+ }
236
+
237
+ /* Ensure inline math flows correctly */
238
+ .MathJax nobr,.MathJax .mjx-chtml{
239
+ display: inline-block !important; /* Keep inline math inline */
240
+ white-space: normal !important; /* Allow text wrapping around inline math */
241
+ }
242
+ .step-section span.MathJax_Preview { /* Hide MathJax preview spans */
243
+ display: none !important;
244
+ }
245
+
246
+ </style>
247
  </head>
248
  <body>
249
+ <div class="container">
250
+ <header>
251
+ <div class="logo">Math Solver</div>
252
+ <div class="subtitle">La solution intelligente pour vos problèmes mathématiques</div>
253
+ </header>
254
 
255
+ <div class="content-box">
256
+ <h1>Version Gratuite</h1>
257
+ <p>Vous utilisez actuellement la version gratuite de Math Solver qui vous permet de résoudre 3 problèmes par jour.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
+ <div class="feature-list">
260
+ <h2>Fonctionnalités disponibles :</h2>
261
+ <ul class="feature-list">
262
+ <li><i class="fas fa-check-circle"></i> Résolution de problèmes mathématiques basiques</li>
263
+ <li><i class="fas fa-check-circle"></i> 3 résolutions gratuites par jour</li>
264
+ <li><i class="fas fa-check-circle"></i> Explication des étapes de résolution</li>
265
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Mode d'exécution de code avancé (version Pro)</span></li>
266
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Résolutions illimitées (version Pro)</span></li>
267
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Support prioritaire (version Pro)</span></li>
268
+ </ul>
269
+ </div>
270
+
271
+ <div class="upload-section">
272
+ <form id="imageForm" enctype="multipart/form-data">
273
+ <input type="file" id="imageInput" name="image" accept="image/*" style="display: none;">
274
+ <button type="button" id="uploadButton" class="cta-button" onclick="document.getElementById('imageInput').click()">
275
+ <i class="fas fa-upload"></i> Télécharger une image
276
+ </button>
277
+ </form>
278
+
279
+ <p id="uploadStatus"></p>
280
+ <div id="imagePreview" style="display: none; margin: 20px auto; max-width: 500px;">
281
+ <img id="preview" style="width: 100%; border-radius: 8px; box-shadow: var(--box-shadow);">
282
+ </div>
283
+
284
+ <button id="solveButton" class="cta-button" style="display: none; background-color: var(--secondary-color);">
285
+ <i class="fas fa-calculator"></i> Résoudre ce problème
286
+ </button>
287
+ </div>
288
 
289
+ <div id="solutionOutput" style="margin-top: 30px; text-align: left; display: none;">
290
+ <h3>Solution :</h3>
291
+ <div id="loadingIndicator" class="thinking-indicator" style="display: none;">
292
+ <i class="fas fa-brain indicator-icon"></i>
293
+ <span>Je réfléchis au problème...</span>
294
+ </div>
295
+ <div id="solution" style="background: #fff; padding: 20px; border-radius: 8px;"></div>
296
+ </div>
297
+
298
+ <div class="upgrade-section">
299
+ <h2>Besoin de plus de puissance ?</h2>
300
+ <p>Passez à la version Pro pour des fonctionnalités avancées et des résolutions illimitées.</p>
301
+ <a href="#" class="cta-button">Passer à la version Pro</a>
302
+ </div>
303
+ </div>
304
+
305
+ <footer>
306
+ <p>© 2025 Math Solver. Tous droits réservés.</p>
307
+ </footer>
308
  </div>
309
+
310
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
311
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
312
+
313
+ <!-- MathJax Configuration -->
314
+ <script>
315
+ window.MathJax = {
316
+ tex: {
317
+ inlineMath: [['$', '$'], ['\\(', '\\)']],
318
+ displayMath: [['$$', '$$'], ['\\[', '\\]']],
319
+ processEscapes: true,
320
+ processEnvironments: true,
321
+ packages: {'[+]': ['ams', 'noerrors', 'physics', 'cancel', 'color', 'mhchem', 'mathtools']}
322
+ },
323
+ options: {
324
+ enableMenu: false, // Disable menu
325
+ ignoreHtmlClass: 'code-content', // Don't process code blocks
326
+ processHtmlClass: 'step-section|latex-display', // Only process these classes
327
+ skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'] // Skip these tags
328
+ },
329
+ loader: {
330
+ load: ['[tex]/ams', '[tex]/noerrors', '[tex]/physics', '[tex]/cancel', '[tex]/color', '[tex]/mhchem', '[tex]/mathtools']
331
+ },
332
+ svg: {
333
+ fontCache: 'global'
334
+ }
335
+ };
336
+ </script>
337
+ <!-- Load MathJax library -->
338
+ <script id="MathJax-script" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-svg.js"></script>
339
+
340
+ <script>
341
+ document.getElementById('imageInput').addEventListener('change', function(event) {
342
+ const file = event.target.files[0];
343
+ if (file) {
344
+ const reader = new FileReader();
345
+ reader.onload = function(e) {
346
+ document.getElementById('preview').src = e.target.result;
347
+ document.getElementById('imagePreview').style.display = 'block';
348
+ document.getElementById('solveButton').style.display = 'inline-block';
349
+ document.getElementById('uploadStatus').textContent = `Image sélectionnée : ${file.name}`;
350
+ }
351
+ reader.readAsDataURL(file);
352
+ }
353
+ });
354
+
355
+ document.getElementById('solveButton').addEventListener('click', function() {
356
+ const formData = new FormData(document.getElementById('imageForm'));
357
+ const solutionOutput = document.getElementById('solutionOutput');
358
+ const loadingIndicator = document.getElementById('loadingIndicator');
359
+ const solution = document.getElementById('solution');
360
+
361
+ solutionOutput.style.display = 'block';
362
+ loadingIndicator.style.display = 'flex';
363
+ solution.innerHTML = ''; // Clear previous solution
364
+
365
+ fetch('/solved', {
366
+ method: 'POST',
367
+ body: formData
368
+ })
369
+ .then(response => {
370
+ const reader = response.body.getReader();
371
+ const decoder = new TextDecoder();
372
+ let buffer = '';
373
+
374
+ function processStream({ done, value }) {
375
+ if (done) {
376
+ loadingIndicator.style.display = 'none';
377
+ // Optional: Final typeset on the whole container if needed, but per-chunk should be enough
378
+ // MathJax.typesetPromise([solution]).catch(e => console.error('Final MathJax typesetting error:', e));
379
+ return;
380
+ }
381
+
382
+ buffer += decoder.decode(value, { stream: true });
383
+ // Split by two newlines to get distinct chunks from the stream
384
+ const lines = buffer.split('\n\n');
385
+ buffer = lines.pop(); // Keep the last potentially incomplete chunk
386
+
387
+ for (const line of lines) {
388
+ if (line.startsWith('data: ')) {
389
+ try {
390
+ const data = JSON.parse(line.substr(6));
391
+
392
+ if (data.mode) {
393
+ // Update loading indicator based on mode
394
+ if (data.mode === 'thinking') {
395
+ loadingIndicator.className = 'thinking-indicator';
396
+ loadingIndicator.innerHTML = '<i class="fas fa-brain indicator-icon"></i><span>Je réfléchis au problème...</span>';
397
+ } else if (data.mode === 'answering') {
398
+ loadingIndicator.className = 'answering-indicator';
399
+ loadingIndicator.innerHTML = '<i class="fas fa-pencil-alt indicator-icon"></i><span>Rédaction de la solution...</span>';
400
+ } else if (data.mode === 'executing_code') {
401
+ loadingIndicator.className = 'executing-indicator';
402
+ loadingIndicator.innerHTML = '<i class="fas fa-code indicator-icon"></i><span>Exécution de code pour la résolution...</span>';
403
+ } else if (data.mode === 'code_result') {
404
+ loadingIndicator.className = 'executing-indicator';
405
+ loadingIndicator.innerHTML = '<i class="fas fa-terminal indicator-icon"></i><span>Traitement des résultats...</span>';
406
+ }
407
+ }
408
+
409
+ if (data.content) {
410
+ const content = data.content;
411
+
412
+ // Create a container for this new content chunk
413
+ const contentContainer = document.createElement('div');
414
+
415
+ if (content.includes('```python')) {
416
+ // Code block
417
+ const codeHtml = content.replace(/```python\n([\s\S]*?)\n```/g, function(match, p1) {
418
+ // Use <pre> and <code> for Highlight.js
419
+ return `<div class="code-section">
420
+ <div class="code-header">
421
+ <span>Code Python</span>
422
+ </div>
423
+ <pre class="code-content"><code class="language-python">${p1}</code></pre>
424
+ </div>`;
425
+ });
426
+ contentContainer.innerHTML = codeHtml;
427
+ solution.appendChild(contentContainer);
428
+ // Apply syntax highlighting
429
+ contentContainer.querySelectorAll('pre code').forEach((block) => {
430
+ hljs.highlightElement(block);
431
+ });
432
+ } else if (content.includes('Résultat d\'exécution:')) {
433
+ // Code output block
434
+ const outputHtml = content.replace(/Résultat d'exécution:\n```\n([\s\S]*?)\n```/g, function(match, p1) {
435
+ return `<div class="output-section">${p1}</div>`;
436
+ });
437
+ contentContainer.innerHTML = outputHtml;
438
+ solution.appendChild(contentContainer);
439
+ } else {
440
+ // Regular text, might contain LaTeX.
441
+ // Add a class that MathJax is configured to process.
442
+ contentContainer.className = 'step-section';
443
+ contentContainer.innerHTML = content;
444
+ solution.appendChild(contentContainer);
445
+
446
+ // Tell MathJax to process the newly added content container
447
+ // MathJax.typesetPromise takes an array of elements or element IDs.
448
+ MathJax.typesetPromise([contentContainer]).catch(e => console.error('MathJax typesetting error:', e));
449
+ }
450
+ }
451
+
452
+ if (data.error) {
453
+ const errorDiv = document.createElement('div');
454
+ errorDiv.style.color = 'red';
455
+ errorDiv.style.margin = '15px 0';
456
+ errorDiv.style.padding = '10px';
457
+ errorDiv.style.background = '#ffeeee';
458
+ errorDiv.style.borderRadius = '5px';
459
+ errorDiv.textContent = `Erreur: ${data.error}`;
460
+ solution.appendChild(errorDiv);
461
+ loadingIndicator.style.display = 'none'; // Hide loading on error
462
+ }
463
+ } catch (e) {
464
+ console.error('Error parsing JSON from stream:', e, line);
465
+ }
466
+ }
467
+ }
468
+
469
+ // Scroll to bottom as new content arrives
470
+ window.scrollTo(0, document.body.scrollHeight);
471
+
472
+ // Read the next chunk from the stream
473
+ return reader.read().then(processStream);
474
+ }
475
+
476
+ // Start reading the stream
477
+ return reader.read().then(processStream);
478
+ })
479
+ .catch(error => {
480
+ const errorDiv = document.createElement('div');
481
+ errorDiv.style.color = 'red';
482
+ errorDiv.style.margin = '15px 0';
483
+ errorDiv.style.padding = '10px';
484
+ errorDiv.style.background = '#ffeeee';
485
+ errorDiv.style.borderRadius = '5px';
486
+ errorDiv.textContent = `Erreur de connexion ou du serveur: ${error}`;
487
+ solution.appendChild(errorDiv);
488
+ loadingIndicator.style.display = 'none'; // Hide loading on fetch error
489
+ console.error('Fetch error:', error);
490
+ });
491
+ });
492
+ </script>
493
  </body>
494
+ </html>