Docfile commited on
Commit
aaebe0a
·
verified ·
1 Parent(s): 3557cac

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +234 -394
templates/index.html CHANGED
@@ -3,15 +3,12 @@
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
- <!-- PAS BESOIN de marked.js pour cette approche -->
10
- <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.3.0/marked.min.js"></script> -->
11
- <!-- CSS pour KaTeX -->
12
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/katex.min.css">
13
  <style>
14
- /* --- Styles CSS (inchangés par rapport à la version précédente) --- */
15
  :root {
16
  --primary-color: #4a6fa5;
17
  --secondary-color: #166088;
@@ -38,411 +35,231 @@
38
  padding: 20px;
39
  }
40
 
41
- header {
 
42
  text-align: center;
43
- padding: 20px 0;
44
- margin-bottom: 30px;
45
  }
46
 
47
  .logo {
48
- font-size: 2.5rem;
49
- font-weight: bold;
50
- color: var(--primary-color);
51
- margin-bottom: 10px;
52
  }
53
-
54
  .subtitle {
55
- font-size: 1.2rem;
56
- color: var(--secondary-color);
57
- margin-bottom: 20px;
58
  }
59
-
60
  .content-box {
61
- background-color: white;
62
- border-radius: 10px;
63
- box-shadow: var(--box-shadow);
64
- padding: 30px;
65
- margin-bottom: 30px;
66
- /* text-align: center; enlevé pour que le contenu dynamique ne soit pas centré par défaut */
67
- }
68
-
69
- /* Ajustement pour le contenu généré */
70
- .content-box > h1, .content-box > p:not(#uploadStatus) {
71
- text-align: center;
72
- }
73
- .content-box .feature-list {
74
- text-align: left; /* Garder le texte des features aligné à gauche */
75
- max-width: 600px;
76
- margin: 30px auto;
77
- }
78
- .content-box .feature-list h2 {
79
- text-align: center;
80
- }
81
- .content-box .upload-section {
82
- text-align: center;
83
- margin-top: 30px; /* Ajouter de l'espace avant */
84
- }
85
- .content-box .upgrade-section {
86
- text-align: center;
87
- margin-top: 30px;
88
- padding: 20px;
89
- border-top: 1px solid #ddd;
90
- }
91
-
92
-
93
- h1 {
94
- color: var(--primary-color);
95
- margin-top: 0;
96
  }
 
97
 
98
  .feature-list {
99
- list-style-type: none;
100
- padding: 0;
101
- }
102
-
103
- .feature-list li {
104
- padding: 10px 0;
105
- margin-bottom: 10px;
106
- display: flex;
107
- align-items: center;
108
  }
109
-
 
110
  .feature-list i {
111
- color: var(--accent-color);
112
- margin-right: 10px;
113
- font-size: 1.2rem;
114
- width: 20px; /* Donner une largeur fixe pour l'alignement */
115
- text-align: center;
116
- }
117
- .feature-list .fa-times-circle {
118
- color: #aaa; /* Griser l'icône aussi */
119
  }
 
120
 
121
  .cta-button {
122
- display: inline-block;
123
- background-color: var(--primary-color);
124
- color: white;
125
- padding: 12px 25px;
126
- border-radius: 5px;
127
- text-decoration: none;
128
- font-weight: bold;
129
- transition: all 0.3s ease;
130
- margin: 10px; /* Ajustement marge */
131
- border: none;
132
- cursor: pointer;
133
  }
134
-
135
  .cta-button:hover {
136
- background-color: var(--secondary-color);
137
- transform: translateY(-2px);
138
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
139
  }
140
 
141
-
142
- footer {
143
- text-align: center;
144
- padding: 20px 0;
145
- color: #666;
146
- font-size: 0.9rem;
147
  }
 
148
 
149
- #solutionOutput {
150
- margin-top: 30px;
151
- text-align: left;
152
- display: none; /* Initialement caché */
153
- }
154
- #solutionOutput h3 {
155
- text-align: center; /* Centrer le titre "Solution :" */
156
- color: var(--primary-color);
157
- margin-bottom: 20px;
158
- }
159
-
160
- #solution {
161
- background: transparent; /* Le fond sera sur les divs enfants */
162
- padding: 0;
163
- border-radius: 8px;
164
- text-align: left;
165
- line-height: 1.8;
166
- font-size: 16px;
167
- box-shadow: var(--box-shadow);
168
- overflow: hidden; /* Pour que les border-radius s'appliquent aux enfants */
169
- margin-top: 20px; /* Espace entre indicateur et contenu */
170
- }
171
 
172
- /* Style de base pour tous les blocs dans #solution */
173
- /* Utiliser 'section' pour les blocs pour plus de sémantique */
174
- #solution > section {
175
- padding: 20px;
176
- margin: 0;
177
- border-radius: 0; /* Sera ajusté pour first/last child */
178
- overflow-x: auto; /* Permet le scroll horizontal si contenu trop large */
179
- background-color: #f9f9f9; /* Fond par défaut */
180
- border-bottom: 1px solid #eee; /* Séparateur par défaut */
181
- /* Ajout pour débordement horizontal */
182
- word-wrap: break-word; /* Pour casser les mots longs si nécessaire */
183
- overflow-wrap: break-word; /* Standard CSS */
184
- }
185
 
186
- .code-section {
187
- background-color: transparent !important; /* Le fond est géré par header/content */
188
- padding: 0 !important;
189
- border-bottom: none !important; /* Le content aura la bordure */
190
  }
191
 
192
- .output-section {
193
- background-color: var(--output-bg) !important;
194
- border-left: 4px solid var(--secondary-color); /* Distinction visuelle */
195
- padding-left: calc(20px - 4px);
196
  }
197
 
198
- .step-section {
199
- background-color: #ffffff; /* Fond blanc pour les étapes normales */
200
- border-left: 4px solid var(--primary-color);
201
- padding-left: calc(20px - 4px); /* Compenser la bordure */
202
- font-size: 16px;
203
- line-height: 1.8;
204
- }
205
 
206
- /* --- Amélioration du rendu KaTeX --- */
207
- .step-section .katex {
208
- font-size: 1.1em; /* Légèrement plus grand que le texte normal */
209
- line-height: normal; /* Laisser KaTeX gérer */
210
- text-indent: 0;
211
- /* text-rendering: optimizeLegibility; */ /* Peut améliorer mais coûteux */
212
- color: #333; /* Assurer la couleur du texte */
213
- /* display: inline-block; */ /* Peut causer des problèmes de wrapping */
214
- /* white-space: normal; */ /* Assurer le retour à la ligne si nécessaire */
 
215
  }
 
 
216
 
217
- .step-section .katex-display {
218
- display: block; /* Comportement block pour $$...$$ */
219
- text-align: center; /* Centrer les équations display */
220
- margin: 1em 0; /* Espacement vertical */
221
- overflow-x: auto; /* Permet le scroll horizontal si équation trop large */
222
- overflow-y: hidden;
223
- padding: 0.5em 0.2em; /* Un peu d'espace interne, même horizontal */
224
- background-color: #fdfdfd; /* Fond très légèrement différent pour les blocs */
225
- border-radius: 4px;
226
- }
227
- /* Conteneur interne créé par KaTeX */
228
- .step-section .katex-display > .katex {
229
- display: inline-block; /* Permet le centrage et évite la pleine largeur */
230
- text-align: initial; /* Texte de l'équation aligné à gauche par défaut */
231
- max-width: 100%;
232
- /* white-space: nowrap; */ /* Empêche le retour à la ligne DANS l'équation, utiliser scroll */
233
- }
234
- /* --- Fin Amélioration KaTeX --- */
235
 
236
  .code-header {
237
- background-color: #343a40;
238
- color: white;
239
- padding: 10px 15px;
240
- font-size: 14px;
241
- font-family: 'Courier New', monospace;
242
- display: flex;
243
- justify-content: space-between;
244
- align-items: center;
245
  }
246
-
247
  .code-content {
248
- margin: 0;
249
- padding: 15px;
250
- background-color: var(--code-bg);
251
- color: #e6e6e6;
252
- overflow-x: auto;
253
- font-family: 'Courier New', monospace;
254
- font-size: 14px;
255
- line-height: 1.5;
256
- border-bottom: 1px solid #444; /* Bordure sous le code */
257
  }
258
 
259
- /* --- Règles pour les coins arrondis (simplifié) --- */
260
  #solution > section:first-child,
261
  #solution > section.code-section:first-child .code-header {
262
- border-top-left-radius: 8px;
263
- border-top-right-radius: 8px;
264
  }
265
-
266
  #solution > section:last-child,
267
  #solution > section.code-section:last-child .code-content {
268
- border-bottom-left-radius: 8px;
269
- border-bottom-right-radius: 8px;
270
- border-bottom: none; /* Pas de bordure en bas du dernier élément */
271
  }
 
272
 
273
- #solution > section:only-child {
274
- border-radius: 8px;
275
- }
276
-
277
- /* --- Indicateurs --- */
278
  .thinking-indicator, .executing-indicator, .answering-indicator {
279
- display: flex;
280
- align-items: center;
281
- justify-content: center; /* Centrer le contenu */
282
- padding: 12px 15px;
283
- margin: 0 auto 20px auto; /* Centrer l'indicateur lui-même */
284
- border-radius: 8px;
285
- font-size: 0.95rem;
286
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
287
- max-width: 400px; /* Limiter la largeur */
288
  }
289
  .thinking-indicator { background-color: #e3f2fd; color: #1565c0; border: 1px solid #bbdefb; }
290
  .executing-indicator { background-color: #ede7f6; color: #5e35b1; border: 1px solid #d1c4e9; }
291
  .answering-indicator { background-color: #e8f5e9; color: #2e7d32; border: 1px solid #c8e6c9; }
292
 
293
- .indicator-icon {
294
- margin-right: 12px;
295
- animation: pulse 1.5s infinite ease-in-out;
296
- font-size: 1.1rem;
297
- }
298
- @keyframes pulse {
299
- 0% { opacity: 0.6; transform: scale(1); }
300
- 50% { opacity: 1; transform: scale(1.05); }
301
- 100% { opacity: 0.6; transform: scale(1); }
302
- }
303
 
304
- /* --- Classe pour les erreurs --- */
305
  .error-message {
306
- background-color: #fff0f0 !important;
307
- color: red !important;
308
- border-color: red !important;
309
- font-weight: bold;
310
- }
311
- .error-message code { /* Code dans les messages d'erreur */
312
- background-color: #fdd;
313
- color: #c00;
314
- padding: 2px 4px;
315
- border-radius: 3px;
316
- font-family: monospace;
317
  }
 
 
 
 
 
 
 
 
 
 
318
 
319
- /* Styles spécifiques pour le contenu sans Markdown (peut nécessiter ajustement) */
320
- .step-section p { /* Ajouter marge basique pour les paragraphes si pas de Markdown */
321
- margin-bottom: 1em;
322
- }
323
- .step-section p:last-child {
324
- margin-bottom: 0;
325
- }
326
 
327
  </style>
328
  </head>
329
  <body>
330
  <div class="container">
331
  <header>
332
- <div class="logo">Math Solver</div>
333
  <div class="subtitle">La solution intelligente pour vos problèmes mathématiques</div>
334
  </header>
335
 
336
  <div class="content-box">
337
- <h1>Version Gratuite</h1>
338
- <p>Vous utilisez actuellement la version gratuite de Math Solver qui vous permet de résoudre 3 problèmes par jour.</p>
339
-
340
- <div class="feature-list">
341
- <h2>Fonctionnalités disponibles :</h2>
342
- <!-- Liste des fonctionnalités -->
343
- <ul>
344
- <li><i class="fas fa-check-circle"></i> Résolution de problèmes mathématiques basiques</li>
345
- <li><i class="fas fa-check-circle"></i> 3 résolutions gratuites par jour</li>
346
- <li><i class="fas fa-check-circle"></i> Explication des étapes de résolution</li>
347
- <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Mode d'exécution de code avancé (version Pro)</span></li>
348
- <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Résolutions illimitées (version Pro)</span></li>
349
- <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Support prioritaire (version Pro)</span></li>
350
- </ul>
351
- </div>
352
-
353
- <div class="upload-section">
354
- <h2>Soumettez votre problème</h2>
355
- <form id="imageForm" enctype="multipart/form-data">
356
- <input type="file" id="imageInput" name="image" accept="image/*" style="display: none;">
357
- <button type="button" id="uploadButton" class="cta-button" onclick="document.getElementById('imageInput').click()">
358
- <i class="fas fa-upload"></i> Télécharger une image
359
- </button>
360
- <p id="uploadStatus" style="margin-top: 10px; font-size: 0.9em; color: #555; min-height: 1.2em;"></p>
361
- </form>
362
-
363
- <div id="imagePreview" style="display: none; margin: 20px auto; max-width: 400px; max-height: 300px; overflow: hidden; border: 1px solid #ddd; border-radius: 8px;">
364
- <img id="preview" style="display: block; width: 100%; height: auto; border-radius: 8px;">
365
- </div>
366
-
367
- <button id="solveButton" class="cta-button" style="display: none; background-color: var(--secondary-color);">
368
- <i class="fas fa-calculator"></i> Résoudre ce problème
369
- </button>
370
- </div>
371
-
372
- <!-- Section pour afficher la solution -->
373
- <div id="solutionOutput"> <!-- Initialement caché via CSS -->
374
- <h3>Solution :</h3>
375
- <div id="loadingIndicator" class="thinking-indicator" style="display: none;">
376
- <i class="fas fa-brain indicator-icon"></i>
377
- <span>Je réfléchis au problème...</span>
378
- </div>
379
- <!-- Container pour les blocs de contenu dynamiques -->
380
- <div id="solution">
381
- <!-- Le contenu (steps, code, output) sera ajouté ici par JS -->
382
- </div>
383
- </div>
384
-
385
- <div class="upgrade-section">
386
- <h2>Besoin de plus de puissance ?</h2>
387
- <p>Passez à la version Pro pour des fonctionnalités avancées et des résolutions illimitées.</p>
388
- <a href="#" class="cta-button">Passer à la version Pro</a>
389
- </div>
390
- </div>
391
-
392
- <footer>
393
- <p>© 2025 Math Solver. Tous droits réservés.</p>
394
- </footer>
395
- </div>
396
 
397
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
398
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
399
 
400
- <!-- KaTeX Scripts -->
401
- <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/katex.min.js"></script>
402
- <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/contrib/auto-render.min.js"></script>
403
-
404
  <script>
405
- // Configuration de KaTeX (options globales)
406
- const katexOptions = {
407
- delimiters: [
408
- {left: '$$', right: '$$', display: true},
409
- {left: '$', right: '$', display: false},
410
- {left: '\\(', right: '\\)', display: false},
411
- {left: '\\[', right: '\\]', display: true}
412
- ],
413
- throwOnError: false, // Ne pas bloquer toute la page en cas d'erreur LaTeX
414
- strict: (errorCode, errorMsg, token) => {
415
- // Log plus détaillé des erreurs KaTeX pour le débogage
416
- // console.warn(`KaTeX ${errorCode}: ${errorMsg}`, token);
417
- if (errorCode === 'unicodeTextInMathMode') {
418
- return 'ignore'; // Permet certains caractères unicode si besoin
419
- }
420
- return 'warn'; // Affiche les autres erreurs dans la console sans planter
421
- },
422
- // IMPORTANT: Pour autoriser le rendu dans différentes situations
423
- // trust: true peut être nécessaire si le contenu vient d'une source
424
- // non sûre et utilise des commandes spécifiques, mais essayons sans d'abord.
425
- // trust: true,
426
- output: 'htmlAndMathml' // Améliore l'accessibilité
427
  };
 
 
 
428
 
429
- // Fonction pour déclencher le rendu KaTeX sur un élément spécifique
430
- // En utilisant setTimeout pour s'assurer que le DOM est mis à jour
431
- function triggerKatexRender(element) {
432
- // Utiliser setTimeout pour décaler légèrement l'exécution
433
- setTimeout(() => {
434
- try {
435
- if (window.renderMathInElement) {
436
- window.renderMathInElement(element, katexOptions);
437
- } else {
438
- console.error("renderMathInElement n'est pas disponible. Vérifiez le chargement de KaTeX auto-render.");
439
- }
440
- } catch (e) {
441
- console.error('Erreur lors du rendu KaTeX sur élément:', e, element);
442
- }
443
- }, 0); // 0 ms de délai suffit généralement
444
- }
445
-
446
 
447
  document.getElementById('imageInput').addEventListener('change', function(event) {
448
  const file = event.target.files[0];
@@ -484,12 +301,40 @@
484
  const reader = response.body.getReader();
485
  const decoder = new TextDecoder();
486
  let buffer = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
 
488
  function processStream({ done, value }) {
489
  if (done) {
490
  loadingIndicator.style.display = 'none';
491
- // Passe finale de rendu KaTeX pour être sûr (peut-être redondant mais sûr)
492
- triggerKatexRender(solutionContainer);
493
  return;
494
  }
495
 
@@ -501,104 +346,103 @@
501
  if (message.startsWith('data: ')) {
502
  try {
503
  const data = JSON.parse(message.substring(6));
 
504
 
505
  // --- Gérer les mises à jour de mode ---
506
  if (data.mode) {
507
- const modes = {
508
- thinking: { icon: 'fa-brain', text: 'Je réfléchis...', class: 'thinking-indicator' },
509
- answering: { icon: 'fa-pencil-alt', text: 'Je rédige la réponse...', class: 'answering-indicator' },
510
- executing_code: { icon: 'fa-play', text: 'Exécution du code...', class: 'executing-indicator' },
511
- code_result: { icon: 'fa-terminal', text: 'Traitement des résultats...', class: 'executing-indicator' }
512
- };
513
  const modeInfo = modes[data.mode] || { icon: 'fa-sync-alt fa-spin', text: 'Traitement...', class: 'thinking-indicator' };
514
-
515
  loadingIndicator.className = `${modeInfo.class}`;
516
  loadingIndicator.innerHTML = `<i class="fas ${modeInfo.icon} indicator-icon"></i><span>${modeInfo.text}</span>`;
517
  loadingIndicator.style.display = 'flex';
518
  }
519
 
520
  // --- Gérer les blocs de contenu ---
521
- if (data.content !== undefined && data.content !== null) { // Vérifier existence et non-nullité
522
  loadingIndicator.style.display = 'none';
523
  const content = data.content;
524
-
525
- // Créer un élément conteneur générique (section)
526
- const blockElement = document.createElement('section');
527
-
528
- // Analyser le fragment HTML reçu pour détecter le type de bloc
529
  const tempDiv = document.createElement('div');
530
  tempDiv.innerHTML = content;
531
 
532
  const codeSection = tempDiv.querySelector('.code-section');
533
  const outputSection = tempDiv.querySelector('.output-section');
 
534
 
535
  if (codeSection) {
536
- // C'est une section de code Python dédiée
537
- // Remplacer le contenu de blockElement par codeSection
538
- blockElement.outerHTML = codeSection.outerHTML;
539
- // Il faut récupérer la référence au nouvel élément ajouté
540
- const addedCodeSection = solutionContainer.appendChild(blockElement.cloneNode(true));
541
- addedCodeSection.querySelectorAll('pre code').forEach((block) => {
542
  hljs.highlightElement(block);
543
  });
544
- // Déclencher KaTeX au cas il y aurait du LaTeX dans les commentaires du code (?)
545
- // triggerKatexRender(addedCodeSection); // Probablement pas nécessaire pour le code pur
546
 
547
  } else if (outputSection) {
548
- // C'est une section de sortie de code
549
- blockElement.outerHTML = outputSection.outerHTML;
550
- const addedOutputSection = solutionContainer.appendChild(blockElement.cloneNode(true));
551
- // Déclencher KaTeX si la sortie peut contenir du LaTeX
552
- triggerKatexRender(addedOutputSection);
553
 
554
  } else {
555
- // C'est une section d'étape (texte + LaTeX)
556
- // **Approche simplifiée : injecter le HTML brut**
557
- blockElement.className = 'step-section'; // Appliquer la classe pour le style
558
- blockElement.innerHTML = content; // Injecter directement
559
- solutionContainer.appendChild(blockElement);
560
-
561
- // **Déclencher le rendu KaTeX sur ce bloc spécifique**
562
- triggerKatexRender(blockElement);
563
  }
564
  }
565
 
566
-
567
  // --- Gérer les erreurs spécifiques ---
568
  if (data.error) {
569
  const errorElement = document.createElement('section');
570
- errorElement.className = 'step-section error-message'; // Utiliser classe d'erreur
571
- // Utiliser innerHTML pour interpréter d'éventuelles balises simples (gras, etc.)
572
- // ou juste textContent si l'erreur est toujours du texte brut.
573
  errorElement.innerHTML = `<strong>Erreur :</strong> ${data.error || 'Une erreur inconnue est survenue.'}`;
574
- solutionContainer.appendChild(errorElement);
575
  loadingIndicator.style.display = 'none';
 
576
  }
577
 
 
 
 
 
 
 
578
  } catch (e) {
579
  console.error('Erreur analyse JSON ou traitement message SSE:', e, message);
580
  const errorElement = document.createElement('section');
581
  errorElement.className = 'step-section error-message';
582
- errorElement.style.color = 'orange'; // Erreur de parsing client
583
- errorElement.style.backgroundColor = '#fff8e1';
584
- errorElement.style.borderColor = 'orange';
585
- errorElement.textContent = `Erreur de traitement du message reçu: ${message.substring(0, 150)}... (Voir console pour détails)`;
586
  solutionContainer.appendChild(errorElement);
587
  loadingIndicator.style.display = 'none';
588
  }
589
  }
590
  });
591
 
592
- // Défiler vers le bas pour voir le nouveau contenu au fur et à mesure
593
  solutionContainer.lastChild?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
594
 
595
-
596
  // Continuer à lire le flux
597
  return reader.read().then(processStream);
598
  }
599
 
600
  // Démarrer le traitement du flux
601
- reader.read().then(processStream);
 
 
 
 
 
 
 
 
 
 
 
602
  })
603
  .catch(error => {
604
  console.error('Erreur Fetch ou connexion:', error);
@@ -611,13 +455,9 @@
611
  });
612
  });
613
 
614
- // Premier rendu KaTeX au chargement (pour contenu statique éventuel)
615
- document.addEventListener('DOMContentLoaded', function() {
616
- // Inutile de le faire sur tout le body si le contenu est dynamique
617
- // Mais on peut le laisser au cas où il y aurait du LaTeX statique
618
- // triggerKatexRender(document.body);
619
- console.log("DOM chargé, KaTeX auto-render prêt.");
620
- });
621
  </script>
622
  </body>
623
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Math Solver (MathJax) - 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
+ <!-- PAS de CSS KaTeX -->
 
 
 
10
  <style>
11
+ /* --- Styles CSS (Largement inchangés, suppression des refs spécifiques à KaTeX) --- */
12
  :root {
13
  --primary-color: #4a6fa5;
14
  --secondary-color: #166088;
 
35
  padding: 20px;
36
  }
37
 
38
+ header, .content-box > h1, .content-box > p:not(#uploadStatus),
39
+ .upload-section h2, .upgrade-section, footer, #solutionOutput h3 {
40
  text-align: center;
 
 
41
  }
42
 
43
  .logo {
44
+ font-size: 2.5rem; font-weight: bold; color: var(--primary-color); margin-bottom: 10px;
 
 
 
45
  }
 
46
  .subtitle {
47
+ font-size: 1.2rem; color: var(--secondary-color); margin-bottom: 20px;
 
 
48
  }
 
49
  .content-box {
50
+ background-color: white; border-radius: 10px; box-shadow: var(--box-shadow);
51
+ padding: 30px; margin-bottom: 30px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  }
53
+ h1 { color: var(--primary-color); margin-top: 0; }
54
 
55
  .feature-list {
56
+ list-style-type: none; padding: 0; margin: 30px auto; max-width: 600px; text-align: left;
 
 
 
 
 
 
 
 
57
  }
58
+ .feature-list h2 { text-align: center; }
59
+ .feature-list li { padding: 10px 0; margin-bottom: 10px; display: flex; align-items: center; }
60
  .feature-list i {
61
+ color: var(--accent-color); margin-right: 10px; font-size: 1.2rem; width: 20px; text-align: center;
 
 
 
 
 
 
 
62
  }
63
+ .feature-list .fa-times-circle { color: #aaa; }
64
 
65
  .cta-button {
66
+ display: inline-block; background-color: var(--primary-color); color: white;
67
+ padding: 12px 25px; border-radius: 5px; text-decoration: none; font-weight: bold;
68
+ transition: all 0.3s ease; margin: 10px; border: none; cursor: pointer;
 
 
 
 
 
 
 
 
69
  }
 
70
  .cta-button:hover {
71
+ background-color: var(--secondary-color); transform: translateY(-2px);
 
72
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
73
  }
74
 
75
+ .upload-section { margin-top: 30px; }
76
+ #uploadStatus { margin-top: 10px; font-size: 0.9em; color: #555; min-height: 1.2em; }
77
+ #imagePreview {
78
+ display: none; margin: 20px auto; max-width: 400px; max-height: 300px;
79
+ overflow: hidden; border: 1px solid #ddd; border-radius: 8px;
 
80
  }
81
+ #preview { display: block; width: 100%; height: auto; border-radius: 8px; }
82
 
83
+ footer { padding: 20px 0; color: #666; font-size: 0.9rem; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
+ #solutionOutput { margin-top: 30px; text-align: left; display: none; }
86
+ #solutionOutput h3 { margin-bottom: 20px; }
 
 
 
 
 
 
 
 
 
 
 
87
 
88
+ #solution {
89
+ background: transparent; padding: 0; border-radius: 8px; text-align: left;
90
+ line-height: 1.8; font-size: 16px; box-shadow: var(--box-shadow);
91
+ overflow: hidden; margin-top: 20px;
92
  }
93
 
94
+ #solution > section { /* Utiliser section */
95
+ padding: 20px; margin: 0; border-radius: 0; overflow-x: auto;
96
+ background-color: #f9f9f9; border-bottom: 1px solid #eee;
97
+ word-wrap: break-word; overflow-wrap: break-word;
98
  }
99
 
100
+ .code-section { background-color: transparent !important; padding: 0 !important; border-bottom: none !important; }
101
+ .output-section { background-color: var(--output-bg) !important; border-left: 4px solid var(--secondary-color); padding-left: calc(20px - 4px); }
102
+ .step-section { background-color: #ffffff; border-left: 4px solid var(--primary-color); padding-left: calc(20px - 4px); }
 
 
 
 
103
 
104
+ /* Styles spécifiques pour MathJax (si nécessaire, souvent pas besoin au début) */
105
+ mjx-container[display="true"] { /* Cible les maths en mode display */
106
+ display: block;
107
+ overflow-x: auto; /* Scroll horizontal pour les équations longues */
108
+ overflow-y: hidden;
109
+ margin: 1em 0;
110
+ padding: 0.5em 0.2em;
111
+ background-color: #fdfdfd;
112
+ border-radius: 4px;
113
+ text-align: center; /* Centrer le conteneur */
114
  }
115
+ /* Pour s'assurer que le texte normal est bien aligné avec les maths inline */
116
+ mjx-container { line-height: 0; } /* MathJax ajuste souvent cela */
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
  .code-header {
120
+ background-color: #343a40; color: white; padding: 10px 15px; font-size: 14px;
121
+ font-family: 'Courier New', monospace; display: flex; justify-content: space-between; align-items: center;
 
 
 
 
 
 
122
  }
 
123
  .code-content {
124
+ margin: 0; padding: 15px; background-color: var(--code-bg); color: #e6e6e6;
125
+ overflow-x: auto; font-family: 'Courier New', monospace; font-size: 14px;
126
+ line-height: 1.5; border-bottom: 1px solid #444;
 
 
 
 
 
 
127
  }
128
 
 
129
  #solution > section:first-child,
130
  #solution > section.code-section:first-child .code-header {
131
+ border-top-left-radius: 8px; border-top-right-radius: 8px;
 
132
  }
 
133
  #solution > section:last-child,
134
  #solution > section.code-section:last-child .code-content {
135
+ border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; border-bottom: none;
 
 
136
  }
137
+ #solution > section:only-child { border-radius: 8px; }
138
 
 
 
 
 
 
139
  .thinking-indicator, .executing-indicator, .answering-indicator {
140
+ display: flex; align-items: center; justify-content: center; padding: 12px 15px;
141
+ margin: 0 auto 20px auto; border-radius: 8px; font-size: 0.95rem;
142
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); max-width: 400px;
 
 
 
 
 
 
143
  }
144
  .thinking-indicator { background-color: #e3f2fd; color: #1565c0; border: 1px solid #bbdefb; }
145
  .executing-indicator { background-color: #ede7f6; color: #5e35b1; border: 1px solid #d1c4e9; }
146
  .answering-indicator { background-color: #e8f5e9; color: #2e7d32; border: 1px solid #c8e6c9; }
147
 
148
+ .indicator-icon { margin-right: 12px; animation: pulse 1.5s infinite ease-in-out; font-size: 1.1rem; }
149
+ @keyframes pulse { 0% { opacity: 0.6; transform: scale(1); } 50% { opacity: 1; transform: scale(1.05); } 100% { opacity: 0.6; transform: scale(1); } }
 
 
 
 
 
 
 
 
150
 
 
151
  .error-message {
152
+ background-color: #fff0f0 !important; color: red !important; border-color: red !important; font-weight: bold;
 
 
 
 
 
 
 
 
 
 
153
  }
154
+ .error-message code { background-color: #fdd; color: #c00; padding: 2px 4px; border-radius: 3px; font-family: monospace; }
155
+
156
+ .step-section p { margin-bottom: 1em; }
157
+ .step-section p:last-child { margin-bottom: 0; }
158
+ /* Styles Markdown basiques si le serveur envoie du HTML simple pour listes/etc */
159
+ .step-section ul, .step-section ol { padding-left: 30px; margin-bottom: 1em; }
160
+ .step-section li { margin-bottom: 0.5em; }
161
+ .step-section code { font-family: monospace; background-color: #eee; padding: 2px 4px; border-radius: 3px; font-size: 0.9em; }
162
+ .step-section pre { background-color: #f0f0f0; border-radius: 4px; padding: 12px; overflow-x: auto; margin: 1em 0; border: 1px solid #ddd; }
163
+ .step-section pre code { background: transparent; padding: 0; border-radius: 0; font-size: 0.95em; }
164
 
 
 
 
 
 
 
 
165
 
166
  </style>
167
  </head>
168
  <body>
169
  <div class="container">
170
  <header>
171
+ <div class="logo">Math Solver (MathJax)</div>
172
  <div class="subtitle">La solution intelligente pour vos problèmes mathématiques</div>
173
  </header>
174
 
175
  <div class="content-box">
176
+ <h1>Version Gratuite</h1>
177
+ <p>Vous utilisez actuellement la version gratuite de Math Solver qui vous permet de résoudre 3 problèmes par jour.</p>
178
+
179
+ <div class="feature-list">
180
+ <h2>Fonctionnalités disponibles :</h2>
181
+ <ul>
182
+ <li><i class="fas fa-check-circle"></i> Résolution de problèmes mathématiques basiques</li>
183
+ <li><i class="fas fa-check-circle"></i> 3 résolutions gratuites par jour</li>
184
+ <li><i class="fas fa-check-circle"></i> Explication des étapes de résolution (avec MathJax)</li>
185
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Mode d'exécution de code avancé (version Pro)</span></li>
186
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Résolutions illimitées (version Pro)</span></li>
187
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Support prioritaire (version Pro)</span></li>
188
+ </ul>
189
+ </div>
190
+
191
+ <div class="upload-section">
192
+ <h2>Soumettez votre problème</h2>
193
+ <form id="imageForm" enctype="multipart/form-data">
194
+ <input type="file" id="imageInput" name="image" accept="image/*" style="display: none;">
195
+ <button type="button" id="uploadButton" class="cta-button" onclick="document.getElementById('imageInput').click()">
196
+ <i class="fas fa-upload"></i> Télécharger une image
197
+ </button>
198
+ <p id="uploadStatus"></p>
199
+ </form>
200
+
201
+ <div id="imagePreview"><img id="preview"></div>
202
+
203
+ <button id="solveButton" class="cta-button" style="display: none; background-color: var(--secondary-color);">
204
+ <i class="fas fa-calculator"></i> Résoudre ce problème
205
+ </button>
206
+ </div>
207
+
208
+ <div id="solutionOutput">
209
+ <h3>Solution :</h3>
210
+ <div id="loadingIndicator" class="thinking-indicator" style="display: none;">
211
+ <i class="fas fa-brain indicator-icon"></i>
212
+ <span>Je réfléchis au problème...</span>
213
+ </div>
214
+ <div id="solution">
215
+ <!-- Contenu dynamique ajouté ici -->
216
+ </div>
217
+ </div>
218
+
219
+ <div class="upgrade-section">
220
+ <h2>Besoin de plus de puissance ?</h2>
221
+ <p>Passez à la version Pro pour des fonctionnalités avancées et des résolutions illimitées.</p>
222
+ <a href="#" class="cta-button">Passer à la version Pro</a>
223
+ </div>
224
+ </div>
225
+
226
+ <footer>
227
+ <p>© 2025 Math Solver. Tous droits réservés.</p>
228
+ </footer>
229
+ </div>
 
 
 
 
 
230
 
231
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
232
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
233
 
234
+ <!-- Configuration MathJax (DOIT être avant le script principal) -->
 
 
 
235
  <script>
236
+ window.MathJax = {
237
+ tex: {
238
+ inlineMath: [['$', '$'], ['\\(', '\\)']], // Délimiteurs inline
239
+ displayMath: [['$$', '$$'], ['\\[', '\\]']], // Délimiteurs display
240
+ processEscapes: true, // Permet d'échapper les $ avec \$
241
+ tags: 'ams', // Numérotation des équations style AMS
242
+ packages: {'[+]': ['ams']} // Charger le package AMS pour plus de commandes
243
+ },
244
+ options: {
245
+ skipInitialTypeset: true, // Très important : on ne type pas la page au début
246
+ ignoreHtmlClass: 'tex2jax_ignore', // Classes à ignorer
247
+ processHtmlClass: 'tex2jax_process' // Classes à traiter explicitement (si besoin)
248
+ },
249
+ chtml: {
250
+ matchFontHeight: true, // Tente d'ajuster la taille à la police environnante
251
+ scale: 1.0 // Ajustement global de la taille (1.0 = normal)
252
+ },
253
+ loader: {
254
+ load: ['[tex]/ams'] // Assure le chargement du package AMS
255
+ }
 
 
256
  };
257
+ </script>
258
+ <!-- Script principal MathJax v3 -->
259
+ <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
260
 
261
+ <script>
262
+ // Pas besoin de config marked.js ici
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
 
264
  document.getElementById('imageInput').addEventListener('change', function(event) {
265
  const file = event.target.files[0];
 
301
  const reader = response.body.getReader();
302
  const decoder = new TextDecoder();
303
  let buffer = '';
304
+ let elementsToTypeset = []; // Pour regrouper les éléments à traiter par MathJax
305
+
306
+ // Fonction pour traiter les éléments en attente avec MathJax
307
+ function processPendingMathJax() {
308
+ if (elementsToTypeset.length > 0) {
309
+ // Copier et vider le tableau avant l'appel asynchrone
310
+ const elements = [...elementsToTypeset];
311
+ elementsToTypeset = [];
312
+ // Appeler MathJax.typesetPromise sur les éléments ajoutés
313
+ if (window.MathJax && window.MathJax.typesetPromise) {
314
+ window.MathJax.typesetPromise(elements).catch((err) => {
315
+ console.error('Erreur MathJax typesetting:', err);
316
+ // Afficher une erreur utilisateur si pertinent
317
+ elements.forEach(el => {
318
+ const errorDiv = document.createElement('div');
319
+ errorDiv.style.color = 'red';
320
+ errorDiv.textContent = '[Erreur MathJax]';
321
+ el.appendChild(errorDiv);
322
+ });
323
+ });
324
+ } else {
325
+ console.warn("MathJax n'est pas encore prêt ou typesetPromise n'existe pas.");
326
+ // Remettre les éléments dans la file d'attente pour un essai ultérieur ?
327
+ // elementsToTypeset.push(...elements); // Attention aux boucles infinies
328
+ }
329
+ }
330
+ }
331
+
332
 
333
  function processStream({ done, value }) {
334
  if (done) {
335
  loadingIndicator.style.display = 'none';
336
+ // Traiter les derniers éléments restants
337
+ processPendingMathJax();
338
  return;
339
  }
340
 
 
346
  if (message.startsWith('data: ')) {
347
  try {
348
  const data = JSON.parse(message.substring(6));
349
+ let blockAdded = null; // Référence au bloc ajouté
350
 
351
  // --- Gérer les mises à jour de mode ---
352
  if (data.mode) {
353
+ const modes = { /* ... (comme avant) ... */ };
 
 
 
 
 
354
  const modeInfo = modes[data.mode] || { icon: 'fa-sync-alt fa-spin', text: 'Traitement...', class: 'thinking-indicator' };
 
355
  loadingIndicator.className = `${modeInfo.class}`;
356
  loadingIndicator.innerHTML = `<i class="fas ${modeInfo.icon} indicator-icon"></i><span>${modeInfo.text}</span>`;
357
  loadingIndicator.style.display = 'flex';
358
  }
359
 
360
  // --- Gérer les blocs de contenu ---
361
+ if (data.content !== undefined && data.content !== null) {
362
  loadingIndicator.style.display = 'none';
363
  const content = data.content;
 
 
 
 
 
364
  const tempDiv = document.createElement('div');
365
  tempDiv.innerHTML = content;
366
 
367
  const codeSection = tempDiv.querySelector('.code-section');
368
  const outputSection = tempDiv.querySelector('.output-section');
369
+ let newElement = document.createElement('section'); // Conteneur par défaut
370
 
371
  if (codeSection) {
372
+ // Code Python dédié
373
+ newElement.outerHTML = codeSection.outerHTML; // Remplacer la section par le contenu du code
374
+ // On doit récupérer la référence APRES ajout au DOM
375
+ blockAdded = solutionContainer.appendChild(newElement.cloneNode(true));
376
+ blockAdded.querySelectorAll('pre code').forEach((block) => {
 
377
  hljs.highlightElement(block);
378
  });
379
+ // Pas de MathJax sur le code python a priori
 
380
 
381
  } else if (outputSection) {
382
+ // Sortie de code
383
+ newElement.outerHTML = outputSection.outerHTML;
384
+ blockAdded = solutionContainer.appendChild(newElement.cloneNode(true));
385
+ // Ajouter aux éléments à traiter par MathJax
386
+ if (blockAdded) elementsToTypeset.push(blockAdded);
387
 
388
  } else {
389
+ // Section d'étape (Texte + LaTeX potentiel)
390
+ newElement.className = 'step-section';
391
+ newElement.innerHTML = content; // Injecter le contenu HTML brut
392
+ blockAdded = solutionContainer.appendChild(newElement);
393
+ // Ajouter aux éléments à traiter par MathJax
394
+ if (blockAdded) elementsToTypeset.push(blockAdded);
 
 
395
  }
396
  }
397
 
 
398
  // --- Gérer les erreurs spécifiques ---
399
  if (data.error) {
400
  const errorElement = document.createElement('section');
401
+ errorElement.className = 'step-section error-message';
 
 
402
  errorElement.innerHTML = `<strong>Erreur :</strong> ${data.error || 'Une erreur inconnue est survenue.'}`;
403
+ blockAdded = solutionContainer.appendChild(errorElement);
404
  loadingIndicator.style.display = 'none';
405
+ // Pas besoin de MathJax sur les erreurs
406
  }
407
 
408
+ // Déclencher le rendu MathJax périodiquement ou après chaque message
409
+ // (Regrouper améliore un peu les perfs vs appeler à chaque fois)
410
+ // On pourrait utiliser un debounce ou juste après chaque message traité ici
411
+ processPendingMathJax();
412
+
413
+
414
  } catch (e) {
415
  console.error('Erreur analyse JSON ou traitement message SSE:', e, message);
416
  const errorElement = document.createElement('section');
417
  errorElement.className = 'step-section error-message';
418
+ errorElement.style.color = 'orange'; errorElement.style.backgroundColor = '#fff8e1'; errorElement.style.borderColor = 'orange';
419
+ errorElement.textContent = `Erreur traitement message: ${message.substring(0, 150)}...`;
 
 
420
  solutionContainer.appendChild(errorElement);
421
  loadingIndicator.style.display = 'none';
422
  }
423
  }
424
  });
425
 
426
+ // Défiler vers le bas
427
  solutionContainer.lastChild?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
428
 
 
429
  // Continuer à lire le flux
430
  return reader.read().then(processStream);
431
  }
432
 
433
  // Démarrer le traitement du flux
434
+ // S'assurer que MathJax est prêt avant de commencer (optionnel mais plus sûr)
435
+ if (window.MathJax && window.MathJax.startup) {
436
+ window.MathJax.startup.promise.then(() => {
437
+ console.log('MathJax prêt, démarrage du stream processing.');
438
+ reader.read().then(processStream);
439
+ });
440
+ } else {
441
+ // Fallback si MathJax n'est pas encore configuré (ne devrait pas arriver avec script async + config avant)
442
+ console.warn('MathJax pas encore prêt, démarrage direct du stream.');
443
+ reader.read().then(processStream);
444
+ }
445
+
446
  })
447
  .catch(error => {
448
  console.error('Erreur Fetch ou connexion:', error);
 
455
  });
456
  });
457
 
458
+ // Pas besoin d'event listener DOMContentLoaded pour MathJax avec skipInitialTypeset: true
459
+ console.log("Page chargée. MathJax configuré pour rendu manuel.");
460
+
 
 
 
 
461
  </script>
462
  </body>
463
  </html>