Docfile commited on
Commit
13f8f31
·
verified ·
1 Parent(s): f7aa851

Delete templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +0 -558
templates/index.html DELETED
@@ -1,558 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="fr">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Mariam M-0 | Solution Mathématique</title>
7
- <!-- Tailwind CSS -->
8
- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
9
-
10
- <!-- Configuration optimisée de MathJax avec support complet LaTeX -->
11
- <script>
12
- window.MathJax = {
13
- tex: {
14
- inlineMath: [['$', '$'], ['\\(', '\\)']],
15
- displayMath: [['$$', '$$'], ['\\[', '\\]']],
16
- processEscapes: true,
17
- processEnvironments: true,
18
- // Extension des macros et commandes disponibles
19
- macros: {
20
- // Ajoutez ici des macros personnalisées si nécessaire
21
- R: '{\\mathbb{R}}',
22
- N: '{\\mathbb{N}}',
23
- Z: '{\\mathbb{Z}}',
24
- C: '{\\mathbb{C}}',
25
- Q: '{\\mathbb{Q}}'
26
- },
27
- // Chargement automatique de packages avancés
28
- packages: {
29
- '[+]': [
30
- 'autoload',
31
- 'ams',
32
- 'noerrors',
33
- 'physics',
34
- 'colorv2',
35
- 'bbox',
36
- 'boldsymbol',
37
- 'cancel',
38
- 'enclose',
39
- 'mhchem'
40
- ]
41
- }
42
- },
43
- svg: {
44
- fontCache: 'global',
45
- scale: 1.2 // Améliore la taille des formules
46
- },
47
- chtml: {
48
- scale: 1.2, // Améliore la taille des formules
49
- matchFontHeight: false
50
- },
51
- options: {
52
- enableMenu: true, // Activer le menu contextuel pour faciliter le débogage
53
- renderActions: {
54
- addMenu: [],
55
- checkLoading: []
56
- },
57
- ignoreHtmlClass: 'tex2jax_ignore',
58
- processHtmlClass: 'tex2jax_process',
59
- skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'],
60
- messageStyle: 'none'
61
- },
62
- loader: {
63
- load: ['[tex]/physics', '[tex]/colorv2', '[tex]/bbox', '[tex]/boldsymbol', '[tex]/cancel', '[tex]/enclose', '[tex]/mhchem']
64
- },
65
- startup: {
66
- pageReady: () => {
67
- console.log('MathJax est complètement chargé.');
68
- window.mathJaxReady = true;
69
-
70
- // Notification d'événement pour les écouteurs externes
71
- const event = new CustomEvent('mathjax-ready');
72
- document.dispatchEvent(event);
73
- }
74
- }
75
- };
76
- </script>
77
- <!-- Utilisation de la version complète pour un meilleur support des expressions complexes -->
78
- <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js" id="MathJax-script" async></script>
79
- <script src="https://cdn.jsdelivr.net/npm/marked/lib/marked.umd.min.js"></script>
80
-
81
- <style>
82
- @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;700&display=swap');
83
-
84
- body {
85
- font-family: 'Space Grotesk', sans-serif;
86
- }
87
-
88
- .uploadArea {
89
- background: #f3f4f6;
90
- border: 2px dashed #d1d5db;
91
- transition: border-color 0.2s ease;
92
- }
93
- .uploadArea:hover {
94
- border-color: #3b82f6;
95
- }
96
-
97
- .blue-button {
98
- background: #3b82f6;
99
- transition: background-color 0.2s ease;
100
- }
101
- .blue-button:hover {
102
- background: #2563eb;
103
- }
104
-
105
- .loader {
106
- width: 48px;
107
- height: 48px;
108
- border: 3px solid #3b82f6;
109
- border-bottom-color: transparent;
110
- border-radius: 50%;
111
- display: inline-block;
112
- animation: rotation 1s linear infinite;
113
- }
114
- @keyframes rotation {
115
- 0% { transform: rotate(0deg); }
116
- 100% { transform: rotate(360deg); }
117
- }
118
-
119
- .thought-box {
120
- transition: max-height 0.3s ease-out;
121
- max-height: 0;
122
- overflow: hidden;
123
- }
124
- .thought-box.open {
125
- max-height: 500px;
126
- }
127
-
128
- #thoughtsContent, #answerContent {
129
- max-height: 500px;
130
- overflow-y: auto;
131
- scroll-behavior: smooth;
132
- white-space: pre-wrap;
133
- }
134
-
135
- .preview-image {
136
- max-width: 300px;
137
- max-height: 300px;
138
- object-fit: contain;
139
- }
140
-
141
- .timestamp {
142
- color: #3b82f6;
143
- font-size: 0.9em;
144
- margin-left: 8px;
145
- }
146
-
147
- /* Styles améliorés pour tableaux */
148
- table {
149
- border-collapse: collapse;
150
- width: 100%;
151
- margin: 1rem 0;
152
- }
153
- th, td {
154
- border: 1px solid #d1d5db;
155
- padding: 0.75rem;
156
- text-align: left;
157
- }
158
- th {
159
- background-color: #f3f4f6;
160
- font-weight: 600;
161
- }
162
- .table-responsive {
163
- overflow-x: auto;
164
- margin-bottom: 1rem;
165
- }
166
-
167
- /* Styles spécifiques pour les équations */
168
- .mjx-chtml {
169
- margin: 10px 0 !important;
170
- min-width: auto !important;
171
- }
172
- mjx-container {
173
- overflow-x: auto;
174
- overflow-y: hidden;
175
- max-width: 100%;
176
- padding: 5px 0;
177
- }
178
- /* Amélioration des styles pour les fractions et matrices */
179
- mjx-mtable {
180
- min-width: auto !important;
181
- }
182
- </style>
183
- </head>
184
- <body class="p-4">
185
- <div class="max-w-4xl mx-auto">
186
- <header class="p-6 text-center mb-8">
187
- <h1 class="text-4xl font-bold text-blue-600">Mariam M-0</h1>
188
- <p class="text-gray-600">Solution Mathématique/Physique/Chimie Intelligente</p>
189
- </header>
190
-
191
- <main>
192
- <form id="problemForm" class="space-y-6" novalidate>
193
- <!-- Zone de dépôt et sélection d'image -->
194
- <div class="uploadArea p-8 text-center relative" aria-label="Zone de dépôt d'image">
195
- <input type="file" id="imageInput" accept="image/*" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer" aria-label="Choisir une image">
196
- <div class="space-y-3">
197
- <div class="w-16 h-16 mx-auto border-2 border-blue-400 rounded-full flex items-center justify-center">
198
- <svg class="w-8 h-8 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
199
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
200
- d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
201
- </svg>
202
- </div>
203
- <p class="text-gray-700 font-medium">Déposez votre image ici</p>
204
- <p class="text-gray-500 text-sm">ou cliquez pour sélectionner</p>
205
- </div>
206
- </div>
207
-
208
- <!-- Aperçu de l'image -->
209
- <div id="imagePreview" class="hidden text-center">
210
- <img id="previewImage" class="preview-image mx-auto" alt="Prévisualisation de l'image sélectionnée">
211
- </div>
212
-
213
- <button type="submit" class="blue-button w-full py-3 text-white font-medium rounded-lg">
214
- Résoudre le problème
215
- </button>
216
- </form>
217
-
218
- <!-- Loader d'analyse -->
219
- <div id="loader" class="hidden mt-8 text-center">
220
- <span class="loader"></span>
221
- <p class="mt-4 text-gray-600">Analyse en cours...</p>
222
- </div>
223
-
224
- <!-- Affichage de la solution -->
225
- <section id="solution" class="hidden mt-8 space-y-6">
226
- <div class="border-t pt-4">
227
- <button id="thoughtsToggle" type="button" class="w-full flex justify-between items-center p-2">
228
- <span class="font-medium text-gray-700">Processus de Réflexion</span>
229
- <span id="timestamp" class="timestamp"></span>
230
- </button>
231
- <div id="thoughtsBox" class="thought-box">
232
- <div id="thoughtsContent" class="p-4 text-gray-600"></div>
233
- </div>
234
- </div>
235
- <div class="border-t pt-6">
236
- <h3 class="text-xl font-bold text-gray-800 mb-4">Solution</h3>
237
- <div id="answerContent" class="text-gray-700 table-responsive"></div>
238
- </div>
239
- </section>
240
- </main>
241
- </div>
242
-
243
- <script>
244
- document.addEventListener('DOMContentLoaded', () => {
245
- // Récupération des éléments DOM
246
- const form = document.getElementById('problemForm');
247
- const imageInput = document.getElementById('imageInput');
248
- const loader = document.getElementById('loader');
249
- const solutionSection = document.getElementById('solution');
250
- const thoughtsContent = document.getElementById('thoughtsContent');
251
- const answerContent = document.getElementById('answerContent');
252
- const thoughtsToggle = document.getElementById('thoughtsToggle');
253
- const thoughtsBox = document.getElementById('thoughtsBox');
254
- const imagePreview = document.getElementById('imagePreview');
255
- const previewImage = document.getElementById('previewImage');
256
- const timestamp = document.getElementById('timestamp');
257
-
258
- let startTime = null;
259
- let timerInterval = null;
260
- let thoughtsBuffer = '';
261
- let answerBuffer = '';
262
- let currentMode = null;
263
- let updateTimeout = null;
264
- let mathJaxQueue = Promise.resolve(); // File d'attente pour les opérations MathJax
265
-
266
- // Mise à jour de l'affichage du temps écoulé
267
- const updateTimestamp = () => {
268
- if (startTime) {
269
- const seconds = Math.floor((Date.now() - startTime) / 1000);
270
- timestamp.textContent = `${seconds}s`;
271
- }
272
- };
273
-
274
- const startTimer = () => {
275
- startTime = Date.now();
276
- timerInterval = setInterval(updateTimestamp, 1000);
277
- updateTimestamp();
278
- };
279
-
280
- const stopTimer = () => {
281
- clearInterval(timerInterval);
282
- startTime = null;
283
- timestamp.textContent = '';
284
- };
285
-
286
- // Gestion de la sélection ou du dépôt de l'image
287
- const handleFileSelect = file => {
288
- if (!file) return;
289
- const reader = new FileReader();
290
- reader.onload = e => {
291
- previewImage.src = e.target.result;
292
- imagePreview.classList.remove('hidden');
293
- };
294
- reader.readAsDataURL(file);
295
- };
296
-
297
- // Toggle pour afficher/cacher le processus de réflexion
298
- thoughtsToggle.addEventListener('click', () => {
299
- thoughtsBox.classList.toggle('open');
300
- });
301
-
302
- imageInput.addEventListener('change', e => handleFileSelect(e.target.files[0]));
303
-
304
- // Gestion des événements de glisser-déposer
305
- const dropZone = document.querySelector('.uploadArea');
306
- dropZone.addEventListener('dragover', e => {
307
- e.preventDefault();
308
- dropZone.classList.add('border-blue-400');
309
- });
310
- dropZone.addEventListener('dragleave', e => {
311
- e.preventDefault();
312
- dropZone.classList.remove('border-blue-400');
313
- });
314
- dropZone.addEventListener('drop', e => {
315
- e.preventDefault();
316
- dropZone.classList.remove('border-blue-400');
317
- handleFileSelect(e.dataTransfer.files[0]);
318
- });
319
-
320
- // Fonction améliorée pour le rendu MathJax avec gestion des erreurs
321
- const typesetMathJax = async (element) => {
322
- // Si MathJax n'est pas prêt, attendre
323
- if (!window.mathJaxReady) {
324
- return new Promise((resolve) => {
325
- document.addEventListener('mathjax-ready', () => {
326
- typesetMathJax(element).then(resolve);
327
- }, { once: true });
328
- });
329
- }
330
-
331
- try {
332
- // Ajouter à la file d'attente pour éviter les rendus simultanés
333
- return mathJaxQueue = mathJaxQueue.then(async () => {
334
- MathJax.startup.document.elements = [element];
335
- await MathJax.typesetPromise([element])
336
- .catch(err => {
337
- console.warn('Erreur MathJax:', err);
338
- // Tenter de régler certaines erreurs courantes
339
- const texElements = element.querySelectorAll('.tex2jax_process');
340
- texElements.forEach(el => {
341
- el.innerHTML = el.innerHTML
342
- .replace(/\\{/g, '\\lbrace ')
343
- .replace(/\\}/g, '\\rbrace ');
344
- });
345
- return MathJax.typesetPromise([element]);
346
- });
347
- return true;
348
- });
349
- } catch (error) {
350
- console.error('Erreur fatale de rendu MathJax:', error);
351
- return false;
352
- }
353
- };
354
-
355
- // Préparation du contenu markdown avec traitement spécifique pour LaTeX
356
- const prepareMarkdown = (content) => {
357
- // Protéger les délimiteurs LaTeX pendant le parsing markdown
358
- const placeholders = [];
359
-
360
- // Remplacer les blocs LaTeX par des placeholders
361
- let protectedContent = content.replace(/(\$\$[\s\S]*?\$\$|\$[\s\S]*?\$|\\begin\{[\s\S]*?\\end\{[a-z]*\})/g, (match, latex) => {
362
- const placeholder = `__LATEX_PLACEHOLDER_${placeholders.length}__`;
363
- placeholders.push(latex);
364
- return placeholder;
365
- });
366
-
367
- // Parser le markdown
368
- let htmlContent = marked.parse(protectedContent);
369
-
370
- // Restaurer les expressions LaTeX
371
- placeholders.forEach((latex, index) => {
372
- htmlContent = htmlContent.replace(`__LATEX_PLACEHOLDER_${index}__`, latex);
373
- });
374
-
375
- return htmlContent;
376
- };
377
-
378
- // Fonction pour déclencher la mise à jour de l'affichage
379
- const updateDisplay = async () => {
380
- // Préparation du contenu markdown avec protection LaTeX
381
- thoughtsContent.innerHTML = prepareMarkdown(thoughtsBuffer);
382
- answerContent.innerHTML = prepareMarkdown(answerBuffer);
383
-
384
- // Activer le traitement LaTeX pour les deux sections
385
- await typesetMathJax(thoughtsContent);
386
- await typesetMathJax(answerContent);
387
-
388
- // Faire défiler vers le bas
389
- if (currentMode === 'thinking') {
390
- thoughtsContent.scrollTop = thoughtsContent.scrollHeight;
391
- } else if (currentMode === 'answering') {
392
- answerContent.scrollTop = answerContent.scrollHeight;
393
- }
394
-
395
- // Réinitialiser le timeout
396
- updateTimeout = null;
397
- };
398
-
399
- // Fonction pour planifier la mise à jour (dé-bounce)
400
- const scheduleUpdate = () => {
401
- if (updateTimeout) {
402
- clearTimeout(updateTimeout);
403
- }
404
- updateTimeout = setTimeout(updateDisplay, 300); // Augmentation du délai pour réduire les rendus trop fréquents
405
- };
406
-
407
- // Configuration de marked avec support du mode GFM et options étendues
408
- marked.setOptions({
409
- gfm: true,
410
- breaks: true,
411
- pedantic: false,
412
- sanitize: false,
413
- smartLists: true,
414
- smartypants: true
415
- });
416
-
417
- // Soumission du formulaire
418
- form.addEventListener('submit', async e => {
419
- e.preventDefault();
420
- const file = imageInput.files[0];
421
- if (!file) {
422
- alert('Veuillez sélectionner une image.');
423
- return;
424
- }
425
-
426
- // Initialisation de l'affichage et des variables
427
- startTimer();
428
- loader.classList.remove('hidden');
429
- solutionSection.classList.add('hidden');
430
- thoughtsContent.innerHTML = '';
431
- answerContent.innerHTML = '';
432
- thoughtsBuffer = '';
433
- answerBuffer = '';
434
- currentMode = null;
435
- thoughtsBox.classList.add('open');
436
-
437
- const formData = new FormData();
438
- formData.append('image', file);
439
-
440
- try {
441
- // Envoi de la requête au serveur
442
- const response = await fetch('/solve', {
443
- method: 'POST',
444
- body: formData
445
- });
446
-
447
- if (!response.ok) {
448
- throw new Error(`Erreur HTTP: ${response.status}`);
449
- }
450
-
451
- const reader = response.body.getReader();
452
- const decoder = new TextDecoder();
453
- let buffer = '';
454
-
455
- // Traitement d'un chunk de données
456
- const processChunk = async chunk => {
457
- buffer += decoder.decode(chunk, { stream: true });
458
- // Recherche des délimiteurs de message complets (évite de couper les expressions LaTeX)
459
- const lines = [];
460
- let startPos = 0;
461
- let endPos;
462
-
463
- while ((endPos = buffer.indexOf('\n\n', startPos)) !== -1) {
464
- lines.push(buffer.substring(startPos, endPos));
465
- startPos = endPos + 2;
466
- }
467
-
468
- // Conserver la dernière partie potentiellement incomplète
469
- buffer = buffer.substring(startPos);
470
-
471
- for (const line of lines) {
472
- if (!line.startsWith('data:')) continue;
473
- try {
474
- const data = JSON.parse(line.slice(5));
475
-
476
- if (data.mode) {
477
- currentMode = data.mode;
478
- loader.classList.add('hidden');
479
- solutionSection.classList.remove('hidden');
480
- }
481
- if (data.content) {
482
- if (currentMode === 'thinking') {
483
- thoughtsBuffer += data.content;
484
- } else if (currentMode === 'answering') {
485
- answerBuffer += data.content;
486
- }
487
- }
488
- } catch (error) {
489
- console.error('Erreur de parsing JSON:', error, line);
490
- }
491
- }
492
-
493
- // Planifier la mise à jour
494
- scheduleUpdate();
495
- };
496
-
497
- // Lecture du flux de réponse
498
- while (true) {
499
- const { done, value } = await reader.read();
500
- if (done) {
501
- // Traitement du contenu restant dans le buffer si nécessaire
502
- if (buffer.length > 5 && buffer.startsWith('data:')) {
503
- try {
504
- const data = JSON.parse(buffer.slice(5));
505
- if (data.content) {
506
- if (currentMode === 'thinking') {
507
- thoughtsBuffer += data.content;
508
- } else if (currentMode === 'answering') {
509
- answerBuffer += data.content;
510
- }
511
- }
512
- } catch (e) {
513
- console.warn('Impossible de parser le dernier fragment:', e);
514
- }
515
- }
516
-
517
- // Forcer une dernière mise à jour synchrone avant de terminer
518
- if (updateTimeout) {
519
- clearTimeout(updateTimeout);
520
- updateTimeout = null;
521
- }
522
- await updateDisplay();
523
- break;
524
- }
525
- await processChunk(value);
526
- }
527
- stopTimer();
528
- } catch (error) {
529
- console.error('Erreur:', error);
530
- alert(`Une erreur est survenue: ${error.message}`);
531
- loader.classList.add('hidden');
532
- stopTimer();
533
- }
534
- });
535
-
536
- // Ajouter un écouteur d'événements pour détecter quand MathJax est prêt
537
- document.addEventListener('mathjax-ready', () => {
538
- console.log('Event: MathJax est prêt à l\'utilisation');
539
- });
540
-
541
- // Test de diagnostic MathJax
542
- window.testMathJax = (expression) => {
543
- const testDiv = document.createElement('div');
544
- testDiv.style.display = 'none';
545
- testDiv.innerHTML = expression;
546
- document.body.appendChild(testDiv);
547
-
548
- return typesetMathJax(testDiv)
549
- .then(success => {
550
- const result = {success, rendered: testDiv.innerHTML};
551
- document.body.removeChild(testDiv);
552
- return result;
553
- });
554
- };
555
- });
556
- </script>
557
- </body>
558
- </html>