Docfile commited on
Commit
5dd2816
·
verified ·
1 Parent(s): 15ed921

Update templates/maj.html

Browse files
Files changed (1) hide show
  1. templates/maj.html +522 -361
templates/maj.html CHANGED
@@ -3,9 +3,10 @@
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 (MathJax)</title>
7
- <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/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 +14,17 @@
13
  --accent-color: #4fc3f7;
14
  --background-color: #f8f9fa;
15
  --text-color: #333;
16
- --box-shadow: 0 4px 8px 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,36 +32,34 @@
25
  padding: 0;
26
  background-color: var(--background-color);
27
  color: var(--text-color);
28
- font-size: 16px;
29
  }
30
-
31
  .container {
 
32
  max-width: 1000px;
33
  margin: 0 auto;
34
  padding: 20px;
35
- box-sizing: border-box;
36
  }
37
-
38
  header {
39
  text-align: center;
40
  padding: 20px 0;
41
  margin-bottom: 30px;
42
- border-bottom: 1px solid #eee;
43
  }
44
-
45
  .logo {
46
- font-size: 2.2rem;
47
  font-weight: bold;
48
  color: var(--primary-color);
49
- margin-bottom: 5px;
50
  }
51
-
52
  .subtitle {
53
- font-size: 1.1rem;
54
  color: var(--secondary-color);
55
  margin-bottom: 20px;
56
  }
57
-
58
  .content-box {
59
  background-color: white;
60
  border-radius: 10px;
@@ -63,112 +68,289 @@
63
  margin-bottom: 30px;
64
  text-align: center;
65
  }
66
-
67
- h1 { color: var(--primary-color); margin-top: 0; margin-bottom: 15px; font-size: 1.8rem; }
68
- h2 { color: var(--secondary-color); margin-top: 25px; margin-bottom: 15px; font-size: 1.5rem; }
69
- h3 { color: var(--primary-color); margin-top: 20px; margin-bottom: 10px; font-size: 1.3rem; text-align: left; }
70
-
71
- .feature-list { list-style-type: none; padding: 0; margin: 20px 0 30px 0; text-align: left; display: inline-block; }
72
- .feature-list li { padding: 8px 0; margin-bottom: 8px; display: flex; align-items: center; font-size: 1rem; }
73
- .feature-list i { color: var(--accent-color); margin-right: 12px; font-size: 1.2rem; width: 20px; text-align: center; }
74
- .feature-list li .fa-times-circle { color: #aaa; }
75
- .feature-list li span { color: #777; }
76
-
77
- .cta-button { display: inline-block; background-color: var(--primary-color); color: white; padding: 12px 25px; border-radius: 5px; text-decoration: none; font-weight: bold; transition: all 0.3s ease; margin: 10px 5px; border: none; cursor: pointer; font-size: 1rem; text-align: center; }
78
- .cta-button:hover { background-color: var(--secondary-color); transform: translateY(-2px); box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15); }
79
- .cta-button i { margin-right: 8px; }
80
-
81
- .upload-section, .upgrade-section { margin-top: 30px; padding-top: 20px; border-top: 1px solid #eee; }
82
-
83
- footer { text-align: center; padding: 30px 0 20px 0; color: #666; font-size: 0.9rem; border-top: 1px solid #eee; margin-top: 40px; }
84
-
85
- #solutionOutput { margin-top: 30px; text-align: left; display: none; }
86
- #solution { background: #fff; padding: 20px; border-radius: 8px; text-align: left; line-height: 1.8; font-size: 1rem; border: 1px solid #eee; margin-top: 15px; overflow-x: hidden; }
87
-
88
- .code-section { margin: 20px 0; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
89
- .code-header { background-color: #343a40; color: white; padding: 10px 15px; font-size: 0.9em; font-family: 'Courier New', monospace; }
90
- .code-content { margin: 0; padding: 15px; background-color: var(--code-bg); color: #e6e6e6; overflow-x: auto; font-family: 'Courier New', monospace; font-size: 0.9em; line-height: 1.5; }
91
- .code-content pre, .code-content code { margin: 0; padding: 0; background: none; white-space: pre; }
92
-
93
- .output-section { background-color: var(--output-bg); padding: 15px; margin: 15px 0; border-radius: 8px; border: 1px solid #d6e0e2; color: #333; font-family: 'Courier New', monospace; font-size: 0.9em; white-space: pre-wrap; overflow-x: auto; box-shadow: inset 0 1px 3px rgba(0,0,0,0.05); }
94
-
95
- .step-section { margin: 20px 0; padding: 15px; background-color: #fdfdfd; border-left: 4px solid var(--accent-color); border-radius: 0 5px 5px 0; overflow-wrap: break-word; }
96
- .step-section:first-child { margin-top: 0; }
97
- .step-section:last-child { margin-bottom: 0; }
98
-
99
- .indicator { display: flex; align-items: center; padding: 12px 15px; margin: 15px 0; border-radius: 8px; font-size: 0.95rem; border: 1px solid transparent; }
100
- .indicator.thinking-indicator { background-color: #e3f2fd; color: #1565c0; border-color: #bde0fe; }
101
- .indicator.executing-indicator { background-color: #ede7f6; color: #5e35b1; border-color: #d1c4e9; }
102
- .indicator.answering-indicator { background-color: #e8f5e9; color: #2e7d32; border-color: #c8e6c9; }
103
- .indicator i { margin-right: 10px; font-size: 1.1em; animation: pulse 1.5s infinite ease-in-out; }
104
- @keyframes pulse { 0%, 100% { opacity: 0.7; } 50% { opacity: 1; } }
105
-
106
- .mjx-chtml {
107
- overflow-x: auto;
108
- overflow-y: hidden;
109
- }
110
- mjx-container[display="true"] {
111
- display: block;
112
- margin: 1em 0;
113
- text-align: center;
114
- }
115
- mjx-container[display="true"] > .mjx-chtml {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  overflow-x: auto;
117
- overflow-y: hidden;
118
- padding: 0.2em 0;
119
- }
120
-
121
- @media (max-width: 992px) { .container { max-width: 90%; } }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  @media (max-width: 768px) {
123
- .container { padding: 15px; }
124
- .logo { font-size: 2rem; }
125
- .subtitle { font-size: 1rem; }
126
- h1 { font-size: 1.6rem; } h2 { font-size: 1.3rem; } h3 { font-size: 1.2rem; }
127
- .content-box { padding: 20px; }
128
- .feature-list { display: block; text-align: left; margin-left: auto; margin-right: auto; }
129
- .upload-section, .upgrade-section { padding-top: 15px; }
130
- #imagePreview { max-width: 100%; }
131
- #imagePreview img { max-width: 100%; height: auto; }
132
- }
133
- @media (max-width: 576px) {
134
- body { font-size: 15px; }
135
- .logo { font-size: 1.8rem; }
136
- .cta-button { display: block; width: 100%; margin: 10px 0; box-sizing: border-box; }
137
- #solveButton { margin-top: 15px; }
138
- .content-box { padding: 15px; }
139
- #solution { padding: 15px; }
140
- .code-header, .code-content, .output-section { font-size: 0.85em; }
141
- .mjx-chtml {
142
- font-size: 0.95em;
143
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  }
145
  </style>
146
-
147
- <script>
148
- window.MathJax = {
149
- tex: {
150
- inlineMath: [['$', '$'], ['\\(', '\\)']],
151
- displayMath: [['$$', '$$'], ['\\[', '\\]']],
152
- processEscapes: true,
153
- tags: 'ams',
154
- macros: {}
155
- },
156
- chtml: {
157
- matchFontHeight: true,
158
- scale: 1.0
159
- },
160
- options: {
161
- ignoreHtmlClass: 'tex2jax_ignore',
162
- processHtmlClass: 'tex2jax_process',
163
- skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
164
- },
165
- startup: {
166
- typeset: false,
167
- }
168
- };
169
- </script>
170
- <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
171
-
172
  </head>
173
  <body>
174
  <div class="container">
@@ -176,279 +358,258 @@
176
  <div class="logo">Math Solver</div>
177
  <div class="subtitle">La solution intelligente pour vos problèmes mathématiques</div>
178
  </header>
179
-
180
  <div class="content-box">
181
  <h1>Version Gratuite</h1>
182
  <p>Vous utilisez actuellement la version gratuite de Math Solver qui vous permet de résoudre 3 problèmes par jour.</p>
183
-
184
- <h2>Fonctionnalités disponibles :</h2>
185
- <ul class="feature-list">
186
- <li><i class="fas fa-check-circle"></i> Résolution de problèmes mathématiques</li>
187
- <li><i class="fas fa-check-circle"></i> 3 résolutions gratuites par jour</li>
188
- <li><i class="fas fa-check-circle"></i> Explication des étapes de résolution</li>
189
- <li><i class="fas fa-check-circle"></i> Support du format LaTeX (MathJax)</li>
190
- <li><i class="fas fa-times-circle"></i> <span>Exécution de code Python (Pro)</span></li>
191
- <li><i class="fas fa-times-circle"></i> <span>Résolutions illimitées (Pro)</span></li>
192
- <li><i class="fas fa-times-circle"></i> <span>Support prioritaire (Pro)</span></li>
193
- </ul>
194
-
 
195
  <div class="upload-section">
196
- <h2>Soumettre un problème</h2>
197
- <form id="imageForm" enctype="multipart/form-data">
198
- <input type="file" id="imageInput" name="image" accept="image/*" style="display: none;">
199
- <button type="button" class="cta-button" onclick="document.getElementById('imageInput').click()">
200
- <i class="fas fa-upload"></i> Télécharger une image
201
- </button>
202
- </form>
203
-
204
- <p id="uploadStatus" style="margin-top: 15px; font-size: 0.9em; color: #555;"></p>
205
- <div id="imagePreview" style="display: none; margin: 20px auto; max-width: 400px;">
206
- <img id="preview" style="display: block; width: 100%; border-radius: 8px; box-shadow: var(--box-shadow);">
207
- </div>
208
-
209
- <button id="solveButton" class="cta-button" style="display: none; background-color: var(--secondary-color);">
210
- <i class="fas fa-calculator"></i> Résoudre ce problème
211
- </button>
212
- </div>
213
-
214
- <div id="solutionOutput" style="display: none;">
215
- <h3>Solution Détaillée :</h3>
216
- <div id="loadingIndicator" class="indicator" style="display: none;">
217
  </div>
218
- <div id="solution">
219
- </div>
220
- <div id="mathjaxProcessingIndicator" class="indicator answering-indicator" style="display: none; margin-top: 10px;">
221
- <i class="fas fa-magic indicator-icon"></i><span>Mise en forme des équations...</span>
 
 
 
 
 
 
 
222
  </div>
 
223
  </div>
224
-
225
  <div class="upgrade-section">
226
- <h2>Besoin de plus ?</h2>
227
  <p>Passez à la version Pro pour des fonctionnalités avancées et des résolutions illimitées.</p>
228
- <a href="#" class="cta-button">Passer à la version Pro <i class="fas fa-arrow-right"></i></a>
229
  </div>
230
  </div>
231
-
232
  <footer>
233
- <p 2025 Math Solver. Tous droits réservés.</p>
234
  </footer>
235
  </div>
236
-
237
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
238
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
239
-
 
 
240
  <script>
241
- document.addEventListener('DOMContentLoaded', (event) => {
242
-
243
- const imageInput = document.getElementById('imageInput');
244
- const uploadStatus = document.getElementById('uploadStatus');
245
- const imagePreview = document.getElementById('imagePreview');
246
- const preview = document.getElementById('preview');
247
- const solveButton = document.getElementById('solveButton');
248
- const imageForm = document.getElementById('imageForm');
249
- const solutionOutput = document.getElementById('solutionOutput');
250
- const loadingIndicator = document.getElementById('loadingIndicator');
251
- const solutionDiv = document.getElementById('solution');
252
- const mathjaxIndicator = document.getElementById('mathjaxProcessingIndicator');
253
-
254
- imageInput.addEventListener('change', function(event) {
255
- const file = event.target.files[0];
256
- if (file) {
257
- const reader = new FileReader();
258
- reader.onload = function(e) {
259
- preview.src = e.target.result;
260
- imagePreview.style.display = 'block';
261
- solveButton.style.display = 'inline-block';
262
- uploadStatus.textContent = `Image sélectionnée : ${file.name}`;
263
- solutionOutput.style.display = 'none';
264
- solutionDiv.innerHTML = '';
265
- mathjaxIndicator.style.display = 'none';
266
- }
267
- reader.onerror = function(e) {
268
- console.error("FileReader error:", e);
269
- uploadStatus.textContent = "Erreur lors de la lecture de l'image.";
270
- imagePreview.style.display = 'none';
271
- solveButton.style.display = 'none';
272
- }
273
- reader.readAsDataURL(file);
274
- } else {
275
- uploadStatus.textContent = '';
276
- imagePreview.style.display = 'none';
277
- solveButton.style.display = 'none';
278
- preview.src = '';
279
- }
280
- });
281
-
282
- solveButton.addEventListener('click', function() {
283
- if (!imageInput.files || imageInput.files.length === 0) {
284
- alert("Veuillez d'abord sélectionner une image.");
285
- return;
286
  }
 
 
287
 
288
- if (!imageForm) {
289
- alert("Erreur interne: Le formulaire d'upload est introuvable.");
290
- return;
 
 
 
 
291
  }
292
- const formData = new FormData(imageForm);
 
 
 
293
 
294
- const fileData = formData.get('image');
295
- if (!fileData || fileData.size === 0) {
296
- alert("Erreur lors de la préparation de l'image pour l'envoi.");
297
- return;
 
 
 
 
 
 
298
  }
299
-
300
- solutionOutput.style.display = 'block';
301
- loadingIndicator.style.display = 'flex';
302
- loadingIndicator.className = 'indicator thinking-indicator';
303
- loadingIndicator.innerHTML = '<i class="fas fa-brain indicator-icon"></i><span>Préparation de la requête...</span>';
304
- solutionDiv.innerHTML = '';
305
- mathjaxIndicator.style.display = 'none';
306
-
307
- fetch('/solved', {
308
- method: 'POST',
309
- body: formData
310
- })
311
- .then(response => {
312
- if (!response.ok) { throw new Error(`Erreur HTTP: ${response.status}`); }
313
- if (!response.body) { throw new Error("La réponse ne contient pas de corps."); }
314
-
315
- const reader = response.body.getReader();
316
- const decoder = new TextDecoder();
317
- let buffer = '';
318
-
319
- function processStream({ done, value }) {
320
- if (done) {
321
- loadingIndicator.style.display = 'none';
322
-
323
- if (buffer.trim()) {
324
- const finalStepDiv = document.createElement('div');
325
- finalStepDiv.className = 'step-section';
326
- finalStepDiv.innerHTML = buffer;
327
- solutionDiv.appendChild(finalStepDiv);
328
- }
329
-
330
- if (typeof MathJax !== 'undefined' && MathJax.typesetPromise) {
331
- mathjaxIndicator.style.display = 'flex';
332
- MathJax.typesetPromise([solutionDiv])
333
- .then(() => {
334
- mathjaxIndicator.style.display = 'none';
335
- })
336
- .catch((err) => {
337
- console.error('Erreur de rendu MathJax:', err);
338
- mathjaxIndicator.style.display = 'none';
339
- solutionDiv.innerHTML += `<div style="color: orange; margin-top: 10px;">Erreur lors de l'affichage des formules mathématiques (MathJax).</div>`;
340
- })
341
- .finally(() => {
342
- solutionOutput.scrollIntoView({ behavior: 'smooth', block: 'start' });
343
- });
344
- } else {
345
- console.warn("MathJax n'est pas prêt ou n'a pas pu être chargé.");
346
- solutionDiv.innerHTML += `<div style="color: orange; margin-top: 10px;">Impossible de charger le module d'affichage mathématique (MathJax).</div>`;
347
- solutionOutput.scrollIntoView({ behavior: 'smooth', block: 'start' });
348
- }
349
- return;
350
- }
351
-
352
- buffer += decoder.decode(value, { stream: true });
353
- const parts = buffer.split('\n\n');
354
- buffer = parts.pop() || '';
355
-
356
- parts.forEach(part => {
357
- if (part.startsWith('data: ')) {
358
- try {
359
- const jsonData = JSON.parse(part.substring(6));
360
-
361
- if (jsonData.mode) {
362
- loadingIndicator.style.display = 'flex';
363
- if (jsonData.mode === 'thinking') {
364
- loadingIndicator.className = 'indicator thinking-indicator';
365
- loadingIndicator.innerHTML = '<i class="fas fa-brain indicator-icon"></i><span>Je réfléchis au problème...</span>';
366
- } else if (jsonData.mode === 'answering') {
367
- loadingIndicator.className = 'indicator answering-indicator';
368
- loadingIndicator.innerHTML = '<i class="fas fa-pencil-alt indicator-icon"></i><span>Rédaction de la solution...</span>';
369
- } else if (jsonData.mode === 'executing_code') {
370
- loadingIndicator.className = 'indicator executing-indicator';
371
- loadingIndicator.innerHTML = '<i class="fas fa-code indicator-icon"></i><span>Exécution du code Python...</span>';
372
- } else if (jsonData.mode === 'code_result') {
373
- loadingIndicator.className = 'indicator executing-indicator';
374
- loadingIndicator.innerHTML = '<i class="fas fa-terminal indicator-icon"></i><span>Traitement des résultats du code...</span>';
375
- }
376
- }
377
-
378
- if (jsonData.content) {
379
- const content = jsonData.content;
380
- let elementToAppend;
381
-
382
- if (content.startsWith('```python')) {
383
- const code = content.replace(/^```python\n?([\s\S]*?)\n?```$/, '$1');
384
- elementToAppend = document.createElement('div');
385
- elementToAppend.className = 'code-section';
386
- elementToAppend.innerHTML = `
387
- <div class="code-header">Code Python</div>
388
- <div class="code-content"><pre><code class="language-python tex2jax_ignore">${escapeHtml(code)}</code></pre></div>
389
- `;
390
- solutionDiv.appendChild(elementToAppend);
391
- const codeBlock = elementToAppend.querySelector('code');
392
- if (codeBlock && hljs) { hljs.highlightElement(codeBlock); }
393
-
394
- } else if (content.startsWith('Résultat d\'exécution:\n```')) {
395
- const output = content.replace(/^Résultat d'exécution:\n```\n?([\s\S]*?)\n?```$/, '$1');
396
- elementToAppend = document.createElement('div');
397
- elementToAppend.className = 'output-section tex2jax_ignore';
398
- elementToAppend.textContent = output;
399
- solutionDiv.appendChild(elementToAppend);
400
-
401
- } else {
402
- elementToAppend = document.createElement('div');
403
- elementToAppend.className = 'step-section';
404
- elementToAppend.innerHTML = content;
405
- solutionDiv.appendChild(elementToAppend);
406
- }
407
- }
408
-
409
- if (jsonData.error) {
410
- const errorDiv = document.createElement('div');
411
- errorDiv.style.cssText = 'color: red; margin: 15px 0; padding: 10px; background: #ffeeee; border: 1px solid #ffdddd; border-radius: 5px;';
412
- errorDiv.textContent = `Erreur: ${jsonData.error}`;
413
- solutionDiv.appendChild(errorDiv);
414
- loadingIndicator.style.display = 'none';
415
  }
416
-
417
- } catch (e) {
418
- console.error('Erreur de parsing JSON ou traitement:', e, 'Part:', part);
419
  }
 
 
 
 
 
 
 
420
  }
421
- });
422
-
423
- solutionDiv.lastChild?.scrollIntoView({ behavior: 'smooth', block: 'end' });
424
-
425
- return reader.read().then(processStream);
426
  }
427
-
 
 
 
 
 
 
428
  return reader.read().then(processStream);
429
- })
430
- .catch(error => {
431
- console.error('Erreur lors de la requête fetch:', error);
432
- loadingIndicator.style.display = 'none';
433
- const errorDiv = document.createElement('div');
434
- errorDiv.style.cssText = 'color: red; margin: 15px 0; padding: 10px; background: #ffeeee; border: 1px solid #ffdddd; border-radius: 5px;';
435
- errorDiv.textContent = `Erreur de communication avec le serveur: ${error.message}`;
436
- solutionDiv.appendChild(errorDiv);
437
- mathjaxIndicator.style.display = 'none';
438
- solutionOutput.scrollIntoView({ behavior: 'smooth', block: 'start' });
439
- });
440
  });
441
-
442
- function escapeHtml(unsafe) {
443
- return unsafe
444
- .replace(/&/g, "&")
445
- .replace(/</g, "<")
446
- .replace(/>/g, ">")
447
- .replace(/"/g, """)
448
- .replace(/'/g, "'");
449
- }
450
  });
451
- </script>
452
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
453
  </body>
454
  </html>
 
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
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/katex.min.css">
10
  <style>
11
  :root {
12
  --primary-color: #4a6fa5;
 
14
  --accent-color: #4fc3f7;
15
  --background-color: #f8f9fa;
16
  --text-color: #333;
17
+ --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
18
  --code-bg: #2c323c;
19
  --output-bg: #f1f8f9;
20
  }
21
+
22
+ * {
23
+ box-sizing: border-box;
24
+ margin: 0;
25
+ padding: 0;
26
+ }
27
+
28
  body {
29
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
30
  line-height: 1.6;
 
32
  padding: 0;
33
  background-color: var(--background-color);
34
  color: var(--text-color);
 
35
  }
36
+
37
  .container {
38
+ width: 100%;
39
  max-width: 1000px;
40
  margin: 0 auto;
41
  padding: 20px;
 
42
  }
43
+
44
  header {
45
  text-align: center;
46
  padding: 20px 0;
47
  margin-bottom: 30px;
 
48
  }
49
+
50
  .logo {
51
+ font-size: 2.5rem;
52
  font-weight: bold;
53
  color: var(--primary-color);
54
+ margin-bottom: 10px;
55
  }
56
+
57
  .subtitle {
58
+ font-size: 1.2rem;
59
  color: var(--secondary-color);
60
  margin-bottom: 20px;
61
  }
62
+
63
  .content-box {
64
  background-color: white;
65
  border-radius: 10px;
 
68
  margin-bottom: 30px;
69
  text-align: center;
70
  }
71
+
72
+ h1 {
73
+ color: var(--primary-color);
74
+ margin-top: 0;
75
+ margin-bottom: 1rem;
76
+ }
77
+
78
+ h2 {
79
+ color: var(--secondary-color);
80
+ margin: 1.5rem 0 1rem;
81
+ }
82
+
83
+ h3 {
84
+ color: var(--secondary-color);
85
+ margin: 1rem 0;
86
+ }
87
+
88
+ .feature-list {
89
+ list-style-type: none;
90
+ padding: 0;
91
+ margin: 20px 0;
92
+ text-align: left;
93
+ }
94
+
95
+ .feature-list li {
96
+ padding: 10px 0;
97
+ margin-bottom: 10px;
98
+ display: flex;
99
+ align-items: center;
100
+ }
101
+
102
+ .feature-list i {
103
+ color: var(--accent-color);
104
+ margin-right: 10px;
105
+ font-size: 1.2rem;
106
+ flex-shrink: 0;
107
+ }
108
+
109
+ .cta-button {
110
+ display: inline-block;
111
+ background-color: var(--primary-color);
112
+ color: white;
113
+ padding: 12px 25px;
114
+ border-radius: 5px;
115
+ text-decoration: none;
116
+ font-weight: bold;
117
+ transition: all 0.3s ease;
118
+ margin: 20px 10px;
119
+ border: none;
120
+ cursor: pointer;
121
+ }
122
+
123
+ .cta-button:hover {
124
+ background-color: var(--secondary-color);
125
+ transform: translateY(-2px);
126
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
127
+ }
128
+
129
+ .upgrade-section {
130
+ margin-top: 30px;
131
+ padding: 20px;
132
+ border-top: 1px solid #ddd;
133
+ }
134
+
135
+ footer {
136
+ text-align: center;
137
+ padding: 20px 0;
138
+ color: #666;
139
+ font-size: 0.9rem;
140
+ }
141
+
142
+ #solution {
143
+ background: #fff;
144
+ padding: 20px;
145
+ border-radius: 8px;
146
+ text-align: left;
147
+ line-height: 1.8;
148
+ font-size: 16px;
149
  overflow-x: auto;
150
+ }
151
+
152
+ .code-section {
153
+ margin: 20px 0;
154
+ border-radius: 8px;
155
+ overflow: hidden;
156
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
157
+ }
158
+
159
+ .code-header {
160
+ background-color: #343a40;
161
+ color: white;
162
+ padding: 8px 15px;
163
+ font-size: 14px;
164
+ font-family: 'Courier New', monospace;
165
+ display: flex;
166
+ justify-content: space-between;
167
+ align-items: center;
168
+ }
169
+
170
+ .code-content,
171
+ pre code {
172
+ margin: 0;
173
+ padding: 15px;
174
+ background-color: var(--code-bg);
175
+ color: #e6e6e6;
176
+ overflow-x: auto;
177
+ font-family: 'Courier New', monospace;
178
+ font-size: 14px;
179
+ line-height: 1.5;
180
+ width: 100%;
181
+ }
182
+
183
+ .output-section {
184
+ background-color: var(--output-bg);
185
+ padding: 15px;
186
+ border-radius: 0 0 8px 8px;
187
+ border-top: 1px solid #ddd;
188
+ color: #333;
189
+ font-family: 'Courier New', monospace;
190
+ font-size: 14px;
191
+ white-space: pre-wrap;
192
+ overflow-x: auto;
193
+ }
194
+
195
+ .step-section {
196
+ margin: 25px 0;
197
+ padding: 15px;
198
+ background-color: #f9f9f9;
199
+ border-left: 4px solid var(--primary-color);
200
+ border-radius: 0 8px 8px 0;
201
+ overflow-x: auto;
202
+ }
203
+
204
+ .math-display {
205
+ overflow-x: auto;
206
+ padding: 10px 0;
207
+ text-align: center;
208
+ }
209
+
210
+ .thinking-indicator,
211
+ .executing-indicator,
212
+ .answering-indicator {
213
+ display: flex;
214
+ align-items: center;
215
+ padding: 10px;
216
+ margin: 10px 0;
217
+ border-radius: 8px;
218
+ font-size: 0.9rem;
219
+ }
220
+
221
+ .thinking-indicator {
222
+ background-color: #e3f2fd;
223
+ color: #1565c0;
224
+ }
225
+
226
+ .executing-indicator {
227
+ background-color: #ede7f6;
228
+ color: #5e35b1;
229
+ }
230
+
231
+ .answering-indicator {
232
+ background-color: #e8f5e9;
233
+ color: #2e7d32;
234
+ }
235
+
236
+ .indicator-icon {
237
+ margin-right: 10px;
238
+ animation: pulse 1.5s infinite ease-in-out;
239
+ }
240
+
241
+ @keyframes pulse {
242
+ 0% { opacity: 0.6; }
243
+ 50% { opacity: 1; }
244
+ 100% { opacity: 0.6; }
245
+ }
246
+
247
+ .katex-display {
248
+ overflow-x: auto;
249
+ padding: 8px 0;
250
+ }
251
+
252
+ #imagePreview {
253
+ max-width: 100%;
254
+ margin: 20px auto;
255
+ }
256
+
257
+ #preview {
258
+ max-width: 100%;
259
+ height: auto;
260
+ border-radius: 8px;
261
+ box-shadow: var(--box-shadow);
262
+ }
263
+
264
+ #uploadStatus {
265
+ margin: 10px 0;
266
+ font-size: 0.9rem;
267
+ color: #666;
268
+ }
269
+
270
+ /* Responsive design adjustments */
271
  @media (max-width: 768px) {
272
+ .container {
273
+ padding: 10px;
274
+ }
275
+
276
+ .content-box {
277
+ padding: 15px;
278
+ margin-bottom: 20px;
279
+ }
280
+
281
+ .logo {
282
+ font-size: 2rem;
283
+ }
284
+
285
+ .subtitle {
286
+ font-size: 1rem;
287
+ }
288
+
289
+ .cta-button {
290
+ padding: 10px 20px;
291
+ font-size: 0.9rem;
292
+ margin: 15px 5px;
293
+ width: 100%;
294
+ max-width: 300px;
295
+ }
296
+
297
+ h1 {
298
+ font-size: 1.8rem;
299
+ }
300
+
301
+ h2 {
302
+ font-size: 1.4rem;
303
+ }
304
+
305
+ .feature-list li {
306
+ padding: 8px 0;
307
+ }
308
+
309
+ #solution {
310
+ padding: 15px;
311
+ font-size: 15px;
312
+ }
313
+
314
+ .step-section {
315
+ padding: 12px;
316
+ margin: 20px 0;
317
+ }
318
+ }
319
+
320
+ @media (max-width: 480px) {
321
+ .logo {
322
+ font-size: 1.8rem;
323
+ }
324
+
325
+ .subtitle {
326
+ font-size: 0.9rem;
327
+ }
328
+
329
+ h1 {
330
+ font-size: 1.6rem;
331
+ }
332
+
333
+ h2 {
334
+ font-size: 1.3rem;
335
+ }
336
+
337
+ .content-box {
338
+ padding: 12px;
339
+ }
340
+
341
+ .cta-button {
342
+ padding: 8px 16px;
343
+ font-size: 0.85rem;
344
+ }
345
+
346
+ #solution,
347
+ .code-content,
348
+ pre code,
349
+ .output-section {
350
+ font-size: 13px;
351
+ }
352
  }
353
  </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  </head>
355
  <body>
356
  <div class="container">
 
358
  <div class="logo">Math Solver</div>
359
  <div class="subtitle">La solution intelligente pour vos problèmes mathématiques</div>
360
  </header>
361
+
362
  <div class="content-box">
363
  <h1>Version Gratuite</h1>
364
  <p>Vous utilisez actuellement la version gratuite de Math Solver qui vous permet de résoudre 3 problèmes par jour.</p>
365
+
366
+ <div>
367
+ <h2>Fonctionnalités disponibles :</h2>
368
+ <ul class="feature-list">
369
+ <li><i class="fas fa-check-circle"></i> Résolution de problèmes mathématiques basiques</li>
370
+ <li><i class="fas fa-check-circle"></i> 3 résolutions gratuites par jour</li>
371
+ <li><i class="fas fa-check-circle"></i> Explication des étapes de résolution</li>
372
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Mode d'exécution de code avancé (version Pro)</span></li>
373
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Résolutions illimitées (version Pro)</span></li>
374
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Support prioritaire (version Pro)</span></li>
375
+ </ul>
376
+ </div>
377
+
378
  <div class="upload-section">
379
+ <form id="imageForm" enctype="multipart/form-data">
380
+ <input type="file" id="imageInput" name="image" accept="image/*" style="display: none;">
381
+ <button type="button" id="uploadButton" class="cta-button" onclick="document.getElementById('imageInput').click()">
382
+ <i class="fas fa-upload"></i> Télécharger une image
383
+ </button>
384
+ </form>
385
+
386
+ <p id="uploadStatus"></p>
387
+ <div id="imagePreview" style="display: none;">
388
+ <img id="preview" style="width: 100%;">
 
 
 
 
 
 
 
 
 
 
 
389
  </div>
390
+
391
+ <button id="solveButton" class="cta-button" style="display: none; background-color: var(--secondary-color);">
392
+ <i class="fas fa-calculator"></i> Résoudre ce problème
393
+ </button>
394
+ </div>
395
+
396
+ <div id="solutionOutput" style="margin-top: 30px; text-align: left; display: none;">
397
+ <h3>Solution :</h3>
398
+ <div id="loadingIndicator" class="thinking-indicator" style="display: none;">
399
+ <i class="fas fa-brain indicator-icon"></i>
400
+ <span>Je réfléchis au problème...</span>
401
  </div>
402
+ <div id="solution"></div>
403
  </div>
404
+
405
  <div class="upgrade-section">
406
+ <h2>Besoin de plus de puissance ?</h2>
407
  <p>Passez à la version Pro pour des fonctionnalités avancées et des résolutions illimitées.</p>
408
+ <a href="#" class="cta-button">Passer à la version Pro</a>
409
  </div>
410
  </div>
411
+
412
  <footer>
413
+ <p>&copy; 2025 Math Solver. Tous droits réservés.</p>
414
  </footer>
415
  </div>
416
+
417
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
418
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
419
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/katex.min.js"></script>
420
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/contrib/auto-render.min.js"></script>
421
+
422
  <script>
423
+ // Configuration globale pour KaTeX
424
+ document.addEventListener("DOMContentLoaded", function() {
425
+ // Définir les options pour renderMathInElement
426
+ window.renderMathConfig = {
427
+ delimiters: [
428
+ {left: '$$', right: '$$', display: true},
429
+ {left: '$', right: '$', display: false},
430
+ {left: '\\(', right: '\\)', display: false},
431
+ {left: '\\[', right: '\\]', display: true},
432
+ {left: '\\begin{equation}', right: '\\end{equation}', display: true},
433
+ {left: '\\begin{align}', right: '\\end{align}', display: true},
434
+ {left: '\\begin{alignat}', right: '\\end{alignat}', display: true},
435
+ {left: '\\begin{gather}', right: '\\end{gather}', display: true},
436
+ {left: '\\begin{CD}', right: '\\end{CD}', display: true}
437
+ ],
438
+ throwOnError: false,
439
+ strict: false,
440
+ trust: true,
441
+ macros: {
442
+ "\\R": "\\mathbb{R}",
443
+ "\\N": "\\mathbb{N}",
444
+ "\\Z": "\\mathbb{Z}",
445
+ "\\Q": "\\mathbb{Q}",
446
+ "\\C": "\\mathbb{C}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
  }
448
+ };
449
+ });
450
 
451
+ // Fonction pour rendre LaTeX
452
+ function renderLatex(element) {
453
+ if (typeof renderMathInElement === 'function') {
454
+ try {
455
+ renderMathInElement(element, window.renderMathConfig);
456
+ } catch (e) {
457
+ console.error('Erreur lors du rendu LaTeX:', e);
458
  }
459
+ } else {
460
+ console.warn('La fonction renderMathInElement n\'est pas disponible');
461
+ }
462
+ }
463
 
464
+ // Gestion de l'upload d'image
465
+ document.getElementById('imageInput').addEventListener('change', function(event) {
466
+ const file = event.target.files[0];
467
+ if (file) {
468
+ const reader = new FileReader();
469
+ reader.onload = function(e) {
470
+ document.getElementById('preview').src = e.target.result;
471
+ document.getElementById('imagePreview').style.display = 'block';
472
+ document.getElementById('solveButton').style.display = 'inline-block';
473
+ document.getElementById('uploadStatus').textContent = `Image sélectionnée : ${file.name}`;
474
  }
475
+ reader.readAsDataURL(file);
476
+ }
477
+ });
478
+
479
+ // Fonction pour résoudre le problème
480
+ document.getElementById('solveButton').addEventListener('click', function() {
481
+ const formData = new FormData(document.getElementById('imageForm'));
482
+ const solutionOutput = document.getElementById('solutionOutput');
483
+ const loadingIndicator = document.getElementById('loadingIndicator');
484
+ const solution = document.getElementById('solution');
485
+
486
+ solutionOutput.style.display = 'block';
487
+ loadingIndicator.style.display = 'flex';
488
+ solution.innerHTML = '';
489
+
490
+ // Simuler un streaming pour l'exemple
491
+ // Dans un environnement réel, ceci serait remplacé par un vrai appel fetch
492
+ fetch('/solved', {
493
+ method: 'POST',
494
+ body: formData
495
+ })
496
+ .then(response => {
497
+ const reader = response.body.getReader();
498
+ const decoder = new TextDecoder();
499
+ let buffer = '';
500
+
501
+ function processStream({ done, value }) {
502
+ if (done) {
503
+ loadingIndicator.style.display = 'none';
504
+ // Rendu final de LaTeX
505
+ renderLatex(solution);
506
+ return;
507
+ }
508
+
509
+ buffer += decoder.decode(value, { stream: true });
510
+ const lines = buffer.split('\n\n');
511
+ buffer = lines.pop(); // Garder le morceau incomplet pour la prochaine fois
512
+
513
+ for (const line of lines) {
514
+ if (line.startsWith('data: ')) {
515
+ try {
516
+ const data = JSON.parse(line.substr(6));
517
+
518
+ // Mettre à jour l'indicateur
519
+ if (data.mode === 'thinking') {
520
+ loadingIndicator.className = 'thinking-indicator';
521
+ loadingIndicator.innerHTML = '<i class="fas fa-brain indicator-icon"></i><span>Je réfléchis au problème...</span>';
522
+ } else if (data.mode === 'answering') {
523
+ loadingIndicator.className = 'answering-indicator';
524
+ loadingIndicator.innerHTML = '<i class="fas fa-pencil-alt indicator-icon"></i><span>Rédaction de la solution...</span>';
525
+ } else if (data.mode === 'executing_code') {
526
+ loadingIndicator.className = 'executing-indicator';
527
+ loadingIndicator.innerHTML = '<i class="fas fa-code indicator-icon"></i><span>Exécution de code pour la résolution...</span>';
528
+ } else if (data.mode === 'code_result') {
529
+ loadingIndicator.className = 'executing-indicator';
530
+ loadingIndicator.innerHTML = '<i class="fas fa-terminal indicator-icon"></i><span>Traitement des résultats...</span>';
531
+ }
532
+
533
+ // Traiter le contenu
534
+ if (data.content) {
535
+ const content = data.content;
536
+
537
+ // Détecter si c'est du code ou une sortie et formater en conséquence
538
+ if (content.includes('```python')) {
539
+ // C'est du code
540
+ const code = content.replace(/```python\n([\s\S]*?)\n```/g, function(match, p1) {
541
+ return `<div class="code-section">
542
+ <div class="code-header">
543
+ <span>Code Python</span>
544
+ </div>
545
+ <pre><code class="language-python">${p1}</code></pre>
546
+ </div>`;
547
+ });
548
+ solution.innerHTML += code;
549
+
550
+ // Appliquer la coloration syntaxique
551
+ document.querySelectorAll('pre code').forEach((block) => {
552
+ hljs.highlightElement(block);
553
+ });
554
+ }
555
+ else if (content.includes('Résultat d\'exécution:')) {
556
+ // C'est une sortie de code
557
+ const output = content.replace(/Résultat d'exécution:\n```\n([\s\S]*?)\n```/g, function(match, p1) {
558
+ return `<div class="output-section">${p1}</div>`;
559
+ });
560
+ solution.innerHTML += output;
561
+ }
562
+ else {
563
+ // Texte normal, peut contenir du LaTeX
564
+ solution.innerHTML += `<div class="step-section">${content}</div>`;
565
+
566
+ // Rendu LaTeX incrémental
567
+ renderLatex(solution.lastElementChild);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
568
  }
 
 
 
569
  }
570
+
571
+ if (data.error) {
572
+ solution.innerHTML += `<div style="color: red; margin: 15px 0; padding: 10px; background: #ffeeee; border-radius: 5px;">Erreur: ${data.error}</div>`;
573
+ loadingIndicator.style.display = 'none';
574
+ }
575
+ } catch (e) {
576
+ console.error('Erreur d\'analyse JSON:', e, line);
577
  }
578
+ }
 
 
 
 
579
  }
580
+
581
+ // Défiler automatiquement vers le bas
582
+ window.scrollTo({
583
+ top: document.body.scrollHeight,
584
+ behavior: 'smooth'
585
+ });
586
+
587
  return reader.read().then(processStream);
588
+ }
589
+
590
+ return reader.read().then(processStream);
591
+ })
592
+ .catch(error => {
593
+ solution.innerHTML += `<div style="color: red; margin: 15px 0; padding: 10px; background: #ffeeee; border-radius: 5px;">Erreur de connexion: ${error}</div>`;
594
+ loadingIndicator.style.display = 'none';
 
 
 
 
595
  });
 
 
 
 
 
 
 
 
 
596
  });
 
597
 
598
+ // Vérifier si les appareils sont de petite taille pour adapter l'interface
599
+ function checkMobileDevice() {
600
+ if (window.innerWidth <= 768) {
601
+ // Ajustements spécifiques pour mobile si nécessaire
602
+ const buttons = document.querySelectorAll('.cta-button');
603
+ buttons.forEach(button => {
604
+ button.style.display = 'block';
605
+ button.style.margin = '15px auto';
606
+ });
607
+ }
608
+ }
609
+
610
+ // Exécuter au chargement et lors du redimensionnement
611
+ window.addEventListener('load', checkMobileDevice);
612
+ window.addEventListener('resize', checkMobileDevice);
613
+ </script>
614
  </body>
615
  </html>