Docfile commited on
Commit
a04e8b6
·
verified ·
1 Parent(s): 3258c39

Update templates/maj.html

Browse files
Files changed (1) hide show
  1. templates/maj.html +479 -269
templates/maj.html CHANGED
@@ -4,8 +4,10 @@
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;
@@ -13,11 +15,11 @@
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;
@@ -25,33 +27,36 @@
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;
@@ -60,32 +65,58 @@
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);
@@ -95,143 +126,238 @@
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
- }
179
-
180
- .math-display {
181
- overflow-x: auto;
182
- padding: 10px 0;
183
- text-align: center;
184
  }
185
-
186
- .thinking-indicator, .executing-indicator, .answering-indicator {
 
 
 
 
 
 
 
187
  display: flex;
188
  align-items: center;
189
- padding: 10px;
190
- margin: 10px 0;
191
  border-radius: 8px;
192
- font-size: 0.9rem;
 
193
  }
194
-
195
- .thinking-indicator {
196
- background-color: #e3f2fd;
197
- color: #1565c0;
198
  }
199
-
200
- .executing-indicator {
201
- background-color: #ede7f6;
202
- color: #5e35b1;
203
  }
204
-
205
- .answering-indicator {
206
- background-color: #e8f5e9;
207
- color: #2e7d32;
208
  }
209
-
210
- .indicator-icon {
211
  margin-right: 10px;
 
212
  animation: pulse 1.5s infinite ease-in-out;
213
  }
214
-
215
  @keyframes pulse {
216
- 0% { opacity: 0.6; }
217
  50% { opacity: 1; }
218
- 100% { opacity: 0.6; }
219
  }
220
-
 
221
  .katex-display {
222
- overflow-x: auto;
223
- padding: 8px 0;
 
224
  }
225
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  @media (max-width: 768px) {
227
  .container {
228
  padding: 15px;
229
  }
230
-
 
 
 
 
 
 
 
 
 
231
  .content-box {
232
  padding: 20px;
233
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  </style>
236
  </head>
237
  <body>
@@ -240,218 +366,302 @@
240
  <div class="logo">Math Solver</div>
241
  <div class="subtitle">La solution intelligente pour vos problèmes mathématiques</div>
242
  </header>
243
-
244
  <div class="content-box">
245
  <h1>Version Gratuite</h1>
246
  <p>Vous utilisez actuellement la version gratuite de Math Solver qui vous permet de résoudre 3 problèmes par jour.</p>
247
-
248
- <div class="feature-list">
249
- <h2>Fonctionnalités disponibles :</h2>
250
- <ul class="feature-list">
251
- <li><i class="fas fa-check-circle"></i> Résolution de problèmes mathématiques basiques</li>
252
- <li><i class="fas fa-check-circle"></i> 3 résolutions gratuites par jour</li>
253
- <li><i class="fas fa-check-circle"></i> Explication des étapes de résolution</li>
254
- <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Mode d'exécution de code avancé (version Pro)</span></li>
255
- <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Résolutions illimitées (version Pro)</span></li>
256
- <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Support prioritaire (version Pro)</span></li>
257
- </ul>
258
- </div>
259
-
260
  <div class="upload-section">
261
- <form id="imageForm" enctype="multipart/form-data">
262
- <input type="file" id="imageInput" name="image" accept="image/*" style="display: none;">
263
- <button type="button" id="uploadButton" class="cta-button" onclick="document.getElementById('imageInput').click()">
264
- <i class="fas fa-upload"></i> Télécharger une image
265
- </button>
266
- </form>
267
-
268
- <p id="uploadStatus"></p>
269
- <div id="imagePreview" style="display: none; margin: 20px auto; max-width: 500px;">
270
- <img id="preview" style="width: 100%; border-radius: 8px; box-shadow: var(--box-shadow);">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  </div>
272
-
273
- <button id="solveButton" class="cta-button" style="display: none; background-color: var(--secondary-color);">
274
- <i class="fas fa-calculator"></i> Résoudre ce problème
275
- </button>
276
- </div>
277
-
278
- <div id="solutionOutput" style="margin-top: 30px; text-align: left; display: none;">
279
- <h3>Solution :</h3>
280
- <div id="loadingIndicator" class="thinking-indicator" style="display: none;">
281
- <i class="fas fa-brain indicator-icon"></i>
282
- <span>Je réfléchis au problème...</span>
283
  </div>
284
- <div id="solution" style="background: #fff; padding: 20px; border-radius: 8px;"></div>
285
  </div>
286
-
 
287
  <div class="upgrade-section">
288
- <h2>Besoin de plus de puissance ?</h2>
289
  <p>Passez à la version Pro pour des fonctionnalités avancées et des résolutions illimitées.</p>
290
- <a href="#" class="cta-button">Passer à la version Pro</a>
291
  </div>
292
  </div>
293
-
294
  <footer>
295
- <p>&copy; 2025 Math Solver. Tous droits réservés.</p>
296
  </footer>
297
  </div>
298
-
 
299
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
300
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
 
 
 
 
 
 
301
  <script>
302
- document.getElementById('imageInput').addEventListener('change', function(event) {
303
- const file = event.target.files[0];
304
- if (file) {
305
- const reader = new FileReader();
306
- reader.onload = function(e) {
307
- document.getElementById('preview').src = e.target.result;
308
- document.getElementById('imagePreview').style.display = 'block';
309
- document.getElementById('solveButton').style.display = 'inline-block';
310
- document.getElementById('uploadStatus').textContent = `Image sélectionnée : ${file.name}`;
311
- }
312
- reader.readAsDataURL(file);
313
- }
314
- });
315
-
316
- document.getElementById('solveButton').addEventListener('click', function() {
317
- const formData = new FormData(document.getElementById('imageForm'));
318
  const solutionOutput = document.getElementById('solutionOutput');
319
  const loadingIndicator = document.getElementById('loadingIndicator');
320
- const solution = document.getElementById('solution');
321
-
322
- solutionOutput.style.display = 'block';
323
- loadingIndicator.style.display = 'flex';
324
- solution.innerHTML = '';
325
-
326
- fetch('/solved', {
327
- method: 'POST',
328
- body: formData
329
- })
330
- .then(response => {
331
- const reader = response.body.getReader();
332
- const decoder = new TextDecoder();
333
- let buffer = '';
334
-
335
- function processStream({ done, value }) {
336
- if (done) {
337
- loadingIndicator.style.display = 'none';
338
- // Render any remaining LaTeX once stream is complete
339
- try {
340
- renderMathInElement(solution, {
341
- delimiters: [
342
- {left: '$$', right: '$$', display: true},
343
- {left: '$', right: '$', display: false},
344
- {left: '\\(', right: '\\)', display: false},
345
- {left: '\\[', right: '\\]', display: true}
346
- ],
347
- throwOnError: false
348
- });
349
- } catch (e) {
350
- console.error('Error rendering LaTeX:', e);
351
- }
352
- return;
353
  }
354
-
355
- buffer += decoder.decode(value, { stream: true });
356
- const lines = buffer.split('\n\n');
357
- buffer = lines.pop(); // Keep the incomplete chunk for next time
358
-
359
- for (const line of lines) {
360
- if (line.startsWith('data: ')) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  try {
362
- const data = JSON.parse(line.substr(6));
363
-
364
- if (data.mode === 'thinking') {
365
- loadingIndicator.className = 'thinking-indicator';
366
- loadingIndicator.innerHTML = '<i class="fas fa-brain indicator-icon"></i><span>Je réfléchis au problème...</span>';
367
- } else if (data.mode === 'answering') {
368
- loadingIndicator.className = 'answering-indicator';
369
- loadingIndicator.innerHTML = '<i class="fas fa-pencil-alt indicator-icon"></i><span>Rédaction de la solution...</span>';
370
- } else if (data.mode === 'executing_code') {
371
- loadingIndicator.className = 'executing-indicator';
372
- loadingIndicator.innerHTML = '<i class="fas fa-code indicator-icon"></i><span>Exécution de code pour la résolution...</span>';
373
- } else if (data.mode === 'code_result') {
374
- loadingIndicator.className = 'executing-indicator';
375
- loadingIndicator.innerHTML = '<i class="fas fa-terminal indicator-icon"></i><span>Traitement des résultats...</span>';
376
  }
377
-
378
- if (data.content) {
379
- const content = data.content;
380
-
381
- // Detect if this is code or output and format appropriately
382
- if (content.includes('```python')) {
383
- // This is code
384
- const code = content.replace(/```python\n([\s\S]*?)\n```/g, function(match, p1) {
385
- return `<div class="code-section">
386
- <div class="code-header">
387
- <span>Code Python</span>
388
- </div>
389
- <pre><code class="language-python">${p1}</code></pre>
390
- </div>`;
391
- });
392
- solution.innerHTML += code;
393
-
394
- // Apply syntax highlighting
395
- document.querySelectorAll('pre code').forEach((block) => {
396
- hljs.highlightElement(block);
397
- });
398
- }
399
- else if (content.includes('Résultat d\'exécution:')) {
400
- // This is code output
401
- const output = content.replace(/Résultat d'exécution:\n```\n([\s\S]*?)\n```/g, function(match, p1) {
402
- return `<div class="output-section">${p1}</div>`;
403
- });
404
- solution.innerHTML += output;
405
- }
406
- else {
407
- // Regular text, might contain LaTeX
408
- solution.innerHTML += `<div class="step-section">${content}</div>`;
409
-
410
- // Render LaTeX incrementally
411
- try {
412
- renderMathInElement(solution, {
413
- delimiters: [
414
- {left: '$$', right: '$$', display: true},
415
- {left: '$', right: '$', display: false},
416
- {left: '\\(', right: '\\)', display: false},
417
- {left: '\\[', right: '\\]', display: true}
418
- ],
419
- throwOnError: false
420
- });
421
- } catch (e) {
422
- console.error('Error rendering LaTeX:', e);
423
  }
424
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
  }
426
-
427
- if (data.error) {
428
- solution.innerHTML += `<div style="color: red; margin: 15px 0; padding: 10px; background: #ffeeee; border-radius: 5px;">Erreur: ${data.error}</div>`;
429
- loadingIndicator.style.display = 'none';
430
- }
431
- } catch (e) {
432
- console.error('Error parsing JSON:', e, line);
433
  }
434
- }
 
 
 
 
 
 
 
 
435
  }
436
-
437
- // Scroll to bottom automatically
438
- window.scrollTo(0, document.body.scrollHeight);
439
-
440
  return reader.read().then(processStream);
441
- }
442
-
443
- return reader.read().then(processStream);
444
- })
445
- .catch(error => {
446
- solution.innerHTML += `<div style="color: red; margin: 15px 0; padding: 10px; background: #ffeeee; border-radius: 5px;">Erreur de connexion: ${error}</div>`;
447
- loadingIndicator.style.display = 'none';
 
 
 
448
  });
449
- });
 
 
 
 
 
 
 
 
 
 
450
  </script>
451
-
452
- <!-- KaTeX pour le rendu LaTeX (plus rapide et plus léger que MathJax) -->
453
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/katex.min.css">
454
- <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/katex.min.js"></script>
455
- <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/contrib/auto-render.min.js"></script>
456
  </body>
457
  </html>
 
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.4.0/css/all.min.css" rel="stylesheet"> <!-- Updated Font Awesome -->
8
  <link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css" rel="stylesheet">
9
+ <!-- KaTeX CSS -->
10
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-n8MVd4RsNIU0tAv4ct0nTaAbDJwPJzDEaqSD1tBCETAMZN+vtEQFPxfujAHU4/mz" crossorigin="anonymous">
11
  <style>
12
  :root {
13
  --primary-color: #4a6fa5;
 
15
  --accent-color: #4fc3f7;
16
  --background-color: #f8f9fa;
17
  --text-color: #333;
18
+ --box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Slightly enhanced shadow */
19
  --code-bg: #2c323c;
20
  --output-bg: #f1f8f9;
21
  }
22
+
23
  body {
24
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
25
  line-height: 1.6;
 
27
  padding: 0;
28
  background-color: var(--background-color);
29
  color: var(--text-color);
30
+ font-size: 16px; /* Base font size */
31
  }
32
+
33
  .container {
34
  max-width: 1000px;
35
  margin: 0 auto;
36
  padding: 20px;
37
+ box-sizing: border-box; /* Include padding in width */
38
  }
39
+
40
  header {
41
  text-align: center;
42
  padding: 20px 0;
43
  margin-bottom: 30px;
44
+ border-bottom: 1px solid #eee;
45
  }
46
+
47
  .logo {
48
+ font-size: 2.2rem; /* Adjusted size */
49
  font-weight: bold;
50
  color: var(--primary-color);
51
+ margin-bottom: 5px;
52
  }
53
+
54
  .subtitle {
55
+ font-size: 1.1rem; /* Adjusted size */
56
  color: var(--secondary-color);
57
  margin-bottom: 20px;
58
  }
59
+
60
  .content-box {
61
  background-color: white;
62
  border-radius: 10px;
 
65
  margin-bottom: 30px;
66
  text-align: center;
67
  }
68
+
69
  h1 {
70
  color: var(--primary-color);
71
  margin-top: 0;
72
+ margin-bottom: 15px;
73
+ font-size: 1.8rem;
74
+ }
75
+
76
+ h2 {
77
+ color: var(--secondary-color);
78
+ margin-top: 25px;
79
+ margin-bottom: 15px;
80
+ font-size: 1.5rem;
81
  }
82
+ h3 {
83
+ color: var(--primary-color);
84
+ margin-top: 20px;
85
+ margin-bottom: 10px;
86
+ font-size: 1.3rem;
87
+ text-align: left; /* Align solution heading left */
88
+ }
89
+
90
  .feature-list {
91
  list-style-type: none;
92
  padding: 0;
93
+ margin: 20px 0 30px 0;
94
  text-align: left;
95
+ display: inline-block; /* Center the list block itself */
96
  }
97
+
98
  .feature-list li {
99
+ padding: 8px 0;
100
+ margin-bottom: 8px;
101
  display: flex;
102
  align-items: center;
103
+ font-size: 1rem;
104
  }
105
+
106
  .feature-list i {
107
  color: var(--accent-color);
108
+ margin-right: 12px;
109
  font-size: 1.2rem;
110
+ width: 20px; /* Ensure alignment */
111
+ text-align: center;
112
  }
113
+ .feature-list li .fa-times-circle {
114
+ color: #aaa; /* Dimmer color for unavailable features */
115
+ }
116
+ .feature-list li span {
117
+ color: #777; /* Style the descriptive text */
118
+ }
119
+
120
  .cta-button {
121
  display: inline-block;
122
  background-color: var(--primary-color);
 
126
  text-decoration: none;
127
  font-weight: bold;
128
  transition: all 0.3s ease;
129
+ margin: 10px 5px; /* Adjusted margin */
130
  border: none;
131
  cursor: pointer;
132
+ font-size: 1rem;
133
+ text-align: center;
134
  }
135
+
136
  .cta-button:hover {
137
  background-color: var(--secondary-color);
138
  transform: translateY(-2px);
139
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
140
  }
141
+ .cta-button i {
142
+ margin-right: 8px;
143
+ }
144
+
145
+ .upload-section, .upgrade-section {
146
  margin-top: 30px;
147
+ padding-top: 20px;
148
+ border-top: 1px solid #eee;
149
  }
150
+
151
  footer {
152
  text-align: center;
153
+ padding: 30px 0 20px 0;
154
  color: #666;
155
  font-size: 0.9rem;
156
+ border-top: 1px solid #eee;
157
+ margin-top: 40px;
158
+ }
159
+
160
+ #solutionOutput {
161
+ margin-top: 30px;
162
+ text-align: left;
163
+ display: none; /* Initially hidden */
164
  }
165
+
166
  #solution {
167
+ background: #fff; /* White background for readability */
168
  padding: 20px;
169
  border-radius: 8px;
170
  text-align: left;
171
  line-height: 1.8;
172
+ font-size: 1rem; /* Ensure consistent font size */
173
+ border: 1px solid #eee; /* Subtle border */
174
+ margin-top: 15px;
175
+ overflow-x: auto; /* Allow horizontal scroll if needed */
176
  }
177
+
178
+ /* Code Block Styling */
179
  .code-section {
180
  margin: 20px 0;
181
  border-radius: 8px;
182
+ overflow: hidden; /* Important for border radius */
183
  box-shadow: 0 2px 5px rgba(0,0,0,0.1);
184
  }
185
+
186
  .code-header {
187
  background-color: #343a40;
188
  color: white;
189
+ padding: 10px 15px;
190
+ font-size: 0.9em;
191
  font-family: 'Courier New', monospace;
 
 
 
192
  }
193
+
194
  .code-content {
195
  margin: 0;
196
  padding: 15px;
197
  background-color: var(--code-bg);
198
  color: #e6e6e6;
199
+ overflow-x: auto; /* Essential for long code lines */
200
  font-family: 'Courier New', monospace;
201
+ font-size: 0.9em;
202
  line-height: 1.5;
203
  }
204
+ /* Ensure pre/code take full advantage */
205
+ .code-content pre, .code-content code {
206
+ margin: 0;
207
+ padding: 0;
208
+ background: none;
209
+ white-space: pre; /* Let overflow-x handle wrapping */
210
+ }
211
+
212
+ /* Output Block Styling */
213
  .output-section {
214
  background-color: var(--output-bg);
215
  padding: 15px;
216
+ margin: 15px 0; /* Spacing */
217
+ border-radius: 8px;
218
+ border: 1px solid #d6e0e2; /* Subtle border */
219
  color: #333;
220
  font-family: 'Courier New', monospace;
221
+ font-size: 0.9em;
222
+ white-space: pre-wrap; /* Wrap text */
223
+ overflow-x: auto; /* Scroll if needed */
224
+ box-shadow: inset 0 1px 3px rgba(0,0,0,0.05);
225
  }
226
+
227
+ /* Step Styling */
228
  .step-section {
229
+ margin: 20px 0;
230
  padding: 15px;
231
+ background-color: #fdfdfd; /* Slightly off-white */
232
+ border-left: 4px solid var(--accent-color); /* Use accent color */
233
+ border-radius: 0 5px 5px 0;
234
+ overflow-wrap: break-word; /* Break long words/URLs */
 
 
 
 
 
235
  }
236
+ .step-section:first-child {
237
+ margin-top: 0;
238
+ }
239
+ .step-section:last-child {
240
+ margin-bottom: 0;
241
+ }
242
+
243
+ /* Indicator Styling */
244
+ .indicator {
245
  display: flex;
246
  align-items: center;
247
+ padding: 12px 15px;
248
+ margin: 15px 0;
249
  border-radius: 8px;
250
+ font-size: 0.95rem;
251
+ border: 1px solid transparent;
252
  }
253
+ .indicator.thinking-indicator {
254
+ background-color: #e3f2fd; color: #1565c0; border-color: #bde0fe;
 
 
255
  }
256
+ .indicator.executing-indicator {
257
+ background-color: #ede7f6; color: #5e35b1; border-color: #d1c4e9;
 
 
258
  }
259
+ .indicator.answering-indicator {
260
+ background-color: #e8f5e9; color: #2e7d32; border-color: #c8e6c9;
 
 
261
  }
262
+ .indicator i {
 
263
  margin-right: 10px;
264
+ font-size: 1.1em;
265
  animation: pulse 1.5s infinite ease-in-out;
266
  }
 
267
  @keyframes pulse {
268
+ 0%, 100% { opacity: 0.7; }
269
  50% { opacity: 1; }
 
270
  }
271
+
272
+ /* KaTeX Display adjustments */
273
  .katex-display {
274
+ overflow-x: auto; /* Allow scrolling for wide equations */
275
+ overflow-y: hidden;
276
+ padding: 8px 0; /* Add some vertical padding */
277
  }
278
+ .katex {
279
+ font-size: 1.1em; /* Slightly larger math font */
280
+ text-align: left; /* Default math alignment */
281
+ }
282
+ .katex-display > .katex {
283
+ text-align: center; /* Center display math */
284
+ display: block; /* Ensure it takes block space */
285
+ }
286
+
287
+
288
+ /* --- Responsive Design --- */
289
+
290
+ /* Smaller Desktops / Large Tablets */
291
+ @media (max-width: 992px) {
292
+ .container {
293
+ max-width: 90%;
294
+ }
295
+ }
296
+
297
+ /* Tablets and smaller */
298
  @media (max-width: 768px) {
299
  .container {
300
  padding: 15px;
301
  }
302
+ .logo {
303
+ font-size: 2rem;
304
+ }
305
+ .subtitle {
306
+ font-size: 1rem;
307
+ }
308
+ h1 { font-size: 1.6rem; }
309
+ h2 { font-size: 1.3rem; }
310
+ h3 { font-size: 1.2rem; }
311
+
312
  .content-box {
313
  padding: 20px;
314
  }
315
+ .feature-list {
316
+ display: block; /* Stack list items */
317
+ text-align: left; /* Align text left on mobile */
318
+ margin-left: auto; /* Keep centering effect if desired */
319
+ margin-right: auto;
320
+ }
321
+ .upload-section, .upgrade-section {
322
+ padding-top: 15px;
323
+ }
324
+ #imagePreview {
325
+ max-width: 100%; /* Ensure preview fits */
326
+ }
327
+ #imagePreview img {
328
+ max-width: 100%; /* Scale image within preview */
329
+ height: auto; /* Maintain aspect ratio */
330
+ }
331
  }
332
+
333
+ /* Mobile phones */
334
+ @media (max-width: 576px) {
335
+ body {
336
+ font-size: 15px; /* Slightly smaller base font */
337
+ }
338
+ .logo {
339
+ font-size: 1.8rem;
340
+ }
341
+ .cta-button {
342
+ display: block; /* Stack buttons */
343
+ width: 100%;
344
+ margin: 10px 0; /* Adjust margin for stacked buttons */
345
+ box-sizing: border-box; /* Include padding in width */
346
+ }
347
+ #solveButton {
348
+ margin-top: 15px;
349
+ }
350
+ .content-box {
351
+ padding: 15px;
352
+ }
353
+ #solution {
354
+ padding: 15px;
355
+ }
356
+ .code-header, .code-content, .output-section {
357
+ font-size: 0.85em; /* Smaller code font on mobile */
358
+ }
359
+ }
360
+
361
  </style>
362
  </head>
363
  <body>
 
366
  <div class="logo">Math Solver</div>
367
  <div class="subtitle">La solution intelligente pour vos problèmes mathématiques</div>
368
  </header>
369
+
370
  <div class="content-box">
371
  <h1>Version Gratuite</h1>
372
  <p>Vous utilisez actuellement la version gratuite de Math Solver qui vous permet de résoudre 3 problèmes par jour.</p>
373
+
374
+ <h2>Fonctionnalités disponibles :</h2>
375
+ <ul class="feature-list">
376
+ <li><i class="fas fa-check-circle"></i> Résolution de problèmes mathématiques</li>
377
+ <li><i class="fas fa-check-circle"></i> 3 résolutions gratuites par jour</li>
378
+ <li><i class="fas fa-check-circle"></i> Explication des étapes de résolution</li>
379
+ <li><i class="fas fa-check-circle"></i> Support du format LaTeX</li>
380
+ <li><i class="fas fa-times-circle"></i> <span>Exécution de code Python (Pro)</span></li>
381
+ <li><i class="fas fa-times-circle"></i> <span>Résolutions illimitées (Pro)</span></li>
382
+ <li><i class="fas fa-times-circle"></i> <span>Support prioritaire (Pro)</span></li>
383
+ </ul>
384
+
 
385
  <div class="upload-section">
386
+ <h2>Soumettre un problème</h2>
387
+ <form id="imageForm" enctype="multipart/form-data">
388
+ <!-- Hide the actual input -->
389
+ <input type="file" id="imageInput" name="image" accept="image/*" style="display: none;">
390
+ <!-- Style a button to trigger the input -->
391
+ <button type="button" class="cta-button" onclick="document.getElementById('imageInput').click()">
392
+ <i class="fas fa-upload"></i> Télécharger une image
393
+ </button>
394
+ </form>
395
+
396
+ <p id="uploadStatus" style="margin-top: 15px; font-size: 0.9em; color: #555;"></p>
397
+ <div id="imagePreview" style="display: none; margin: 20px auto; max-width: 400px;"> <!-- Adjusted max-width -->
398
+ <img id="preview" style="display: block; width: 100%; border-radius: 8px; box-shadow: var(--box-shadow);">
399
+ </div>
400
+
401
+ <button id="solveButton" class="cta-button" style="display: none; background-color: var(--secondary-color);">
402
+ <i class="fas fa-calculator"></i> Résoudre ce problème
403
+ </button>
404
+ </div>
405
+
406
+ <div id="solutionOutput" style="display: none;"> <!-- Container for the whole solution section -->
407
+ <h3>Solution Détaillée :</h3>
408
+ <div id="loadingIndicator" class="indicator" style="display: none;">
409
+ <!-- Content set by JS -->
410
  </div>
411
+ <div id="solution">
412
+ <!-- Solution content will be injected here -->
 
 
 
 
 
 
 
 
 
413
  </div>
 
414
  </div>
415
+
416
+
417
  <div class="upgrade-section">
418
+ <h2>Besoin de plus ?</h2>
419
  <p>Passez à la version Pro pour des fonctionnalités avancées et des résolutions illimitées.</p>
420
+ <a href="#" class="cta-button">Passer à la version Pro <i class="fas fa-arrow-right"></i></a>
421
  </div>
422
  </div>
423
+
424
  <footer>
425
+ <p 2025 Math Solver. Tous droits réservés.</p>
426
  </footer>
427
  </div>
428
+
429
+ <!-- Dependencies: Highlight.js -->
430
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
431
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
432
+
433
+ <!-- Dependencies: KaTeX -->
434
+ <!-- The loading of KaTeX is deferred to speed up page rendering -->
435
+ <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js" integrity="sha384-XjKyOOlGwcjNTAIQHIpgOno0Hl1YQqzUOEleOLALmuqehneUG+vnGctmUb0ZY0l8" crossorigin="anonymous"></script>
436
+ <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"></script>
437
+
438
  <script>
439
+ document.addEventListener('DOMContentLoaded', (event) => {
440
+
441
+ const imageInput = document.getElementById('imageInput');
442
+ const uploadStatus = document.getElementById('uploadStatus');
443
+ const imagePreview = document.getElementById('imagePreview');
444
+ const preview = document.getElementById('preview');
445
+ const solveButton = document.getElementById('solveButton');
446
+ const imageForm = document.getElementById('imageForm');
 
 
 
 
 
 
 
 
447
  const solutionOutput = document.getElementById('solutionOutput');
448
  const loadingIndicator = document.getElementById('loadingIndicator');
449
+ const solutionDiv = document.getElementById('solution'); // Renamed for clarity
450
+
451
+ imageInput.addEventListener('change', function(event) {
452
+ const file = event.target.files[0];
453
+ if (file) {
454
+ const reader = new FileReader();
455
+ reader.onload = function(e) {
456
+ preview.src = e.target.result;
457
+ imagePreview.style.display = 'block';
458
+ solveButton.style.display = 'inline-block'; // Or 'block' based on mobile styles
459
+ uploadStatus.textContent = `Image sélectionnée : ${file.name}`;
460
+ solutionOutput.style.display = 'none'; // Hide previous solution
461
+ solutionDiv.innerHTML = ''; // Clear previous solution
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
  }
463
+ reader.readAsDataURL(file);
464
+ } else {
465
+ // Reset if no file selected
466
+ uploadStatus.textContent = '';
467
+ imagePreview.style.display = 'none';
468
+ solveButton.style.display = 'none';
469
+ preview.src = '';
470
+ }
471
+ });
472
+
473
+ solveButton.addEventListener('click', function() {
474
+ const formData = new FormData(imageForm);
475
+ if (!imageInput.files[0]) {
476
+ alert("Veuillez d'abord sélectionner une image.");
477
+ return;
478
+ }
479
+
480
+ solutionOutput.style.display = 'block'; // Show the solution area
481
+ loadingIndicator.style.display = 'flex'; // Show loading
482
+ loadingIndicator.className = 'indicator thinking-indicator'; // Reset class
483
+ loadingIndicator.innerHTML = '<i class="fas fa-brain indicator-icon"></i><span>Préparation de la requête...</span>';
484
+ solutionDiv.innerHTML = ''; // Clear previous solution content
485
+
486
+ fetch('/solved', { // Make sure this endpoint matches your backend
487
+ method: 'POST',
488
+ body: formData
489
+ })
490
+ .then(response => {
491
+ if (!response.ok) {
492
+ throw new Error(`Erreur HTTP: ${response.status}`);
493
+ }
494
+ if (!response.body) {
495
+ throw new Error("La réponse ne contient pas de corps.");
496
+ }
497
+
498
+ const reader = response.body.getReader();
499
+ const decoder = new TextDecoder();
500
+ let buffer = '';
501
+ let accumulatedContent = ''; // Store all content for final rendering
502
+
503
+ function processStream({ done, value }) {
504
+ if (done) {
505
+ loadingIndicator.style.display = 'none';
506
+ // Process any remaining buffer
507
+ if (buffer.trim()) {
508
+ // This assumes the last part is regular text/LaTeX
509
+ // Might need adjustment if code/output can be the last chunk
510
+ const finalStepDiv = document.createElement('div');
511
+ finalStepDiv.className = 'step-section';
512
+ finalStepDiv.innerHTML = buffer; // Use innerHTML to allow potential HTML tags in the last chunk
513
+ solutionDiv.appendChild(finalStepDiv);
514
+ accumulatedContent += buffer;
515
+ }
516
+
517
+ // FINAL LaTeX Rendering
518
  try {
519
+ // Check if KaTeX is loaded
520
+ if (window.renderMathInElement) {
521
+ renderMathInElement(solutionDiv, {
522
+ delimiters: [
523
+ {left: '$$', right: '$$', display: true},
524
+ {left: '$', right: '$', display: false},
525
+ {left: '\\(', right: '\\)', display: false},
526
+ {left: '\\[', right: '\\]', display: true}
527
+ ],
528
+ throwOnError: false // Don't stop rendering on single error
529
+ });
530
+ } else {
531
+ console.warn("KaTeX auto-render not loaded yet.");
532
+ // Optionally add a message or retry mechanism
533
  }
534
+ } catch (e) {
535
+ console.error('Erreur lors du rendu final de LaTeX:', e);
536
+ solutionDiv.innerHTML += `<div style="color: orange; margin-top: 10px;">Erreur lors de l'affichage de certaines formules mathématiques.</div>`;
537
+ }
538
+
539
+ // Final Highlight.js call (optional, could rely on per-block)
540
+ // hljs.highlightAll(); // Or just rely on highlightElement below
541
+
542
+ // Scroll to the solution area
543
+ solutionOutput.scrollIntoView({ behavior: 'smooth', block: 'start' });
544
+ return;
545
+ }
546
+
547
+ buffer += decoder.decode(value, { stream: true });
548
+ // Split by double newline, assuming that separates messages
549
+ const parts = buffer.split('\n\n');
550
+ buffer = parts.pop() || ''; // Keep incomplete part for next chunk
551
+
552
+ parts.forEach(part => {
553
+ if (part.startsWith('data: ')) {
554
+ try {
555
+ const jsonData = JSON.parse(part.substring(6)); // Remove 'data: '
556
+ accumulatedContent += jsonData.content || ''; // Add to total content
557
+
558
+ // Update Indicator
559
+ if (jsonData.mode) {
560
+ loadingIndicator.style.display = 'flex'; // Ensure visible
561
+ if (jsonData.mode === 'thinking') {
562
+ loadingIndicator.className = 'indicator thinking-indicator';
563
+ loadingIndicator.innerHTML = '<i class="fas fa-brain indicator-icon"></i><span>Je réfléchis au problème...</span>';
564
+ } else if (jsonData.mode === 'answering') {
565
+ loadingIndicator.className = 'indicator answering-indicator';
566
+ loadingIndicator.innerHTML = '<i class="fas fa-pencil-alt indicator-icon"></i><span>Rédaction de la solution...</span>';
567
+ } else if (jsonData.mode === 'executing_code') {
568
+ loadingIndicator.className = 'indicator executing-indicator';
569
+ loadingIndicator.innerHTML = '<i class="fas fa-code indicator-icon"></i><span>Exécution du code Python...</span>';
570
+ } else if (jsonData.mode === 'code_result') {
571
+ loadingIndicator.className = 'indicator executing-indicator'; // Keep same style?
572
+ loadingIndicator.innerHTML = '<i class="fas fa-terminal indicator-icon"></i><span>Traitement des résultats du code...</span>';
 
 
 
 
 
 
 
573
  }
574
  }
575
+
576
+ // Append Content
577
+ if (jsonData.content) {
578
+ const content = jsonData.content;
579
+ let elementToAppend;
580
+
581
+ if (content.startsWith('```python')) {
582
+ const code = content.replace(/^```python\n?([\s\S]*?)\n?```$/, '$1');
583
+ elementToAppend = document.createElement('div');
584
+ elementToAppend.className = 'code-section';
585
+ elementToAppend.innerHTML = `
586
+ <div class="code-header">Code Python</div>
587
+ <div class="code-content"><pre><code class="language-python">${escapeHtml(code)}</code></pre></div>
588
+ `;
589
+ solutionDiv.appendChild(elementToAppend);
590
+ // Highlight this specific block
591
+ const codeBlock = elementToAppend.querySelector('code');
592
+ if (codeBlock && hljs) {
593
+ hljs.highlightElement(codeBlock);
594
+ }
595
+ } else if (content.startsWith('Résultat d\'exécution:\n```')) {
596
+ const output = content.replace(/^Résultat d'exécution:\n```\n?([\s\S]*?)\n?```$/, '$1');
597
+ elementToAppend = document.createElement('div');
598
+ elementToAppend.className = 'output-section';
599
+ elementToAppend.textContent = output; // Use textContent for plain output
600
+ solutionDiv.appendChild(elementToAppend);
601
+ } else {
602
+ // Regular text, potentially with inline LaTeX
603
+ elementToAppend = document.createElement('div');
604
+ elementToAppend.className = 'step-section';
605
+ // Use innerHTML carefully, assuming backend sanitizes or it's trusted markdown/html
606
+ elementToAppend.innerHTML = content;
607
+ solutionDiv.appendChild(elementToAppend);
608
+ // We wait until the end to render LaTeX
609
+ }
610
+ }
611
+
612
+ if (jsonData.error) {
613
+ const errorDiv = document.createElement('div');
614
+ errorDiv.style.cssText = 'color: red; margin: 15px 0; padding: 10px; background: #ffeeee; border: 1px solid #ffdddd; border-radius: 5px;';
615
+ errorDiv.textContent = `Erreur: ${jsonData.error}`;
616
+ solutionDiv.appendChild(errorDiv);
617
+ loadingIndicator.style.display = 'none'; // Hide loading on error display
618
+ }
619
+
620
+ } catch (e) {
621
+ console.error('Erreur de parsing JSON ou traitement:', e, 'Part:', part);
622
+ // Append raw part if parsing fails, for debugging?
623
+ // const errorDiv = document.createElement('div');
624
+ // errorDiv.style.color = 'orange';
625
+ // errorDiv.textContent = `Donnée brute non traitée: ${part}`;
626
+ // solutionDiv.appendChild(errorDiv);
627
  }
 
 
 
 
 
 
 
628
  }
629
+ });
630
+
631
+ // Scroll down automatically as content arrives
632
+ // window.scrollTo(0, document.body.scrollHeight);
633
+ solutionDiv.lastChild?.scrollIntoView({ behavior: 'smooth', block: 'end' });
634
+
635
+
636
+ // Continue reading the stream
637
+ return reader.read().then(processStream);
638
  }
639
+
640
+ // Start processing the stream
 
 
641
  return reader.read().then(processStream);
642
+ })
643
+ .catch(error => {
644
+ console.error('Erreur lors de la requête fetch:', error);
645
+ loadingIndicator.style.display = 'none'; // Hide loading
646
+ const errorDiv = document.createElement('div');
647
+ errorDiv.style.cssText = 'color: red; margin: 15px 0; padding: 10px; background: #ffeeee; border: 1px solid #ffdddd; border-radius: 5px;';
648
+ errorDiv.textContent = `Erreur de communication avec le serveur: ${error.message}`;
649
+ solutionDiv.appendChild(errorDiv);
650
+ solutionOutput.scrollIntoView({ behavior: 'smooth', block: 'start' });
651
+ });
652
  });
653
+
654
+ // Helper function to escape HTML for code blocks
655
+ function escapeHtml(unsafe) {
656
+ return unsafe
657
+ .replace(/&/g, "&")
658
+ .replace(/</g, "<")
659
+ .replace(/>/g, ">")
660
+ .replace(/"/g, """)
661
+ .replace(/'/g, "'");
662
+ }
663
+ }); // End DOMContentLoaded
664
  </script>
665
+
 
 
 
 
666
  </body>
667
  </html>