Docfile commited on
Commit
c00a085
·
verified ·
1 Parent(s): 5928c56

Update templates/math.html

Browse files
Files changed (1) hide show
  1. templates/math.html +148 -27
templates/math.html CHANGED
@@ -1,66 +1,81 @@
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>Résolution de Problèmes Mathématiques</title>
7
-
8
  <!-- Tailwind CSS -->
9
  <script src="https://cdn.tailwindcss.com"></script>
10
-
11
  <!-- Marked.js pour le Markdown -->
12
  <script defer src="https://cdnjs.cloudflare.com/ajax/libs/marked/9.1.6/marked.min.js"></script>
13
-
14
  <!-- Font Awesome pour les icônes -->
15
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
16
-
17
  <style>
18
  /* Styles personnalisés */
19
  .dropzone {
20
  border: 2px dashed #4F46E5;
21
  transition: all 0.3s ease;
22
  }
 
23
  .dropzone:hover {
24
  border-color: #312E81;
25
  background-color: rgba(79, 70, 229, 0.1);
26
  }
 
27
  .loading {
28
  display: none;
29
  }
 
30
  .loading.active {
31
  display: flex;
32
  }
 
33
  .math-content {
34
  font-size: 1.1em;
35
  line-height: 1.6;
36
  overflow-x: auto;
37
  }
 
38
  .math-content p {
39
  margin-bottom: 1rem;
40
  white-space: pre-wrap;
41
  }
 
42
  .math-content .MathJax {
43
  overflow-x: auto;
44
  overflow-y: hidden;
45
  padding: 0.5rem 0;
46
  }
 
47
  @media (max-width: 640px) {
48
  .math-content .MathJax {
49
  font-size: 0.9em;
50
  }
51
  }
 
52
  /* Style pour masquer le contenu pendant le chargement de MathJax */
53
  .math-hidden {
54
  visibility: hidden;
55
  }
56
  </style>
57
-
58
  <!-- Configuration de MathJax -->
59
  <script>
60
  window.MathJax = {
61
  tex: {
62
- inlineMath: [['$', '$'], ['\\(', '\\)']],
63
- displayMath: [['$$', '$$'], ['\\[', '\\]']],
 
 
 
 
 
 
64
  processEscapes: true,
65
  macros: {
66
  R: "{\\mathbb{R}}",
@@ -89,7 +104,7 @@
89
  }
90
  };
91
  </script>
92
-
93
  <!-- Chargement de MathJax -->
94
  <script>
95
  function loadMathJax() {
@@ -107,6 +122,9 @@
107
  // Charger MathJax immédiatement
108
  loadMathJax().catch(console.error);
109
  </script>
 
 
 
110
  </head>
111
 
112
  <body class="min-h-screen bg-gradient-to-br from-blue-50 to-white">
@@ -115,25 +133,29 @@
115
  <!-- En-tête -->
116
  <header class="text-center mb-12">
117
  <h1 class="text-4xl font-bold text-blue-800 mb-4">Résolution de Problèmes Mathématiques</h1>
118
- <p class="text-gray-600 text-lg">Soumettez une image de votre problème mathématique pour obtenir une solution détaillée</p>
 
119
  </header>
120
 
121
  <!-- Zone de dépôt d'image -->
122
  <div class="mb-8">
123
  <form id="uploadForm" class="space-y-4">
124
- <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer bg-white shadow-sm hover:shadow-md transition-all">
 
125
  <input type="file" id="fileInput" class="hidden" accept="image/*">
126
  <div class="flex flex-col items-center space-y-4">
127
  <i class="fas fa-cloud-upload-alt text-4xl text-blue-600"></i>
128
  <div class="text-lg text-gray-700">
129
- Glissez votre image ici ou <span class="text-blue-600 font-semibold">cliquez pour sélectionner</span>
 
130
  </div>
131
  <p class="text-sm text-gray-500">Formats acceptés: PNG, JPG, JPEG</p>
132
  </div>
133
  </div>
134
-
135
  <div class="flex justify-center">
136
- <button type="submit" class="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors duration-200 flex items-center space-x-2 disabled:opacity-50 disabled:cursor-not-allowed">
 
137
  <i class="fas fa-paper-plane"></i>
138
  <span>Analyser l'image</span>
139
  </button>
@@ -157,15 +179,27 @@
157
  </div>
158
  </div>
159
 
 
 
 
 
 
 
 
 
 
 
 
160
  <!-- Message d'erreur -->
161
- <div id="errorMessage" class="hidden bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative my-4" role="alert">
 
162
  <strong class="font-bold">Erreur!</strong>
163
  <span class="block sm:inline" id="errorText"></span>
164
  </div>
165
  </div>
166
 
167
  <script>
168
- document.addEventListener('DOMContentLoaded', function() {
169
  // Éléments DOM
170
  const dropzone = document.getElementById('dropzone');
171
  const fileInput = document.getElementById('fileInput');
@@ -176,6 +210,8 @@
176
  const errorMessage = document.getElementById('errorMessage');
177
  const errorText = document.getElementById('errorText');
178
  const submitButton = uploadForm.querySelector('button[type="submit"]');
 
 
179
 
180
  // Attendre que MathJax soit complètement chargé
181
  let mathJaxReady = false;
@@ -211,22 +247,22 @@
211
  // Nettoyer le contenu précédent
212
  latexContent.innerHTML = '';
213
  latexContent.classList.add('math-hidden');
214
-
215
  // Convertir le Markdown en HTML
216
  const htmlContent = marked.parse(text);
217
  latexContent.innerHTML = htmlContent;
218
 
219
  // Rendre les formules mathématiques avec MathJax
220
  await MathJax.typesetPromise([latexContent]);
221
-
222
  // Afficher le contenu
223
  response.classList.remove('hidden');
224
  latexContent.classList.remove('math-hidden');
225
-
226
  } catch (error) {
227
  console.error('Erreur lors du rendu:', error);
228
  showError('Erreur lors du rendu de la formule mathématique');
229
-
230
  latexContent.innerHTML = `
231
  <div class="text-red-600 mb-4">Une erreur s'est produite lors du rendu. Voici le texte brut :</div>
232
  <pre class="bg-gray-100 p-4 rounded-lg overflow-x-auto">${text}</pre>
@@ -252,7 +288,7 @@
252
  e.preventDefault();
253
  e.stopPropagation();
254
  dropzone.classList.remove('bg-blue-50');
255
-
256
  const files = e.dataTransfer.files;
257
  if (files.length > 0 && files[0].type.startsWith('image/')) {
258
  fileInput.files = files;
@@ -266,14 +302,14 @@
266
  function handleFileSelect(file) {
267
  if (file && file.type.startsWith('image/')) {
268
  const reader = new FileReader();
269
- reader.onload = function(e) {
270
  const preview = document.createElement('img');
271
  preview.src = e.target.result;
272
  preview.classList.add('max-h-48', 'mx-auto', 'mt-4', 'rounded-lg');
273
-
274
  const oldPreview = dropzone.querySelector('img');
275
  if (oldPreview) oldPreview.remove();
276
-
277
  dropzone.appendChild(preview);
278
  submitButton.disabled = false;
279
  };
@@ -288,17 +324,90 @@
288
  dropzone.addEventListener('dragleave', handleDragLeave);
289
  dropzone.addEventListener('drop', handleDrop);
290
  dropzone.addEventListener('click', () => fileInput.click());
291
-
292
  fileInput.addEventListener('change', (e) => {
293
  if (e.target.files.length > 0) {
294
  handleFileSelect(e.target.files[0]);
295
  }
296
  });
297
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  // Gestion du formulaire
299
  uploadForm.addEventListener('submit', async (e) => {
300
  e.preventDefault();
301
-
302
  if (!fileInput.files.length) {
303
  showError('Veuillez sélectionner une image');
304
  return;
@@ -326,15 +435,27 @@
326
 
327
  await renderMathContent(data.result);
328
 
 
 
 
329
  } catch (error) {
330
  console.error('Erreur:', error);
331
- showError(error.message || 'Une erreur est survenue lors du traitement');
332
  } finally {
333
  loading.classList.remove('active');
334
  submitButton.disabled = false;
335
  }
336
  });
 
 
 
 
 
 
337
  });
 
338
  </script>
339
  </body>
340
- </html>
 
 
 
1
  <!DOCTYPE html>
2
  <html lang="fr">
3
+
4
  <head>
5
  <meta charset="UTF-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
  <title>Résolution de Problèmes Mathématiques</title>
8
+
9
  <!-- Tailwind CSS -->
10
  <script src="https://cdn.tailwindcss.com"></script>
11
+
12
  <!-- Marked.js pour le Markdown -->
13
  <script defer src="https://cdnjs.cloudflare.com/ajax/libs/marked/9.1.6/marked.min.js"></script>
14
+
15
  <!-- Font Awesome pour les icônes -->
16
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
17
+
18
  <style>
19
  /* Styles personnalisés */
20
  .dropzone {
21
  border: 2px dashed #4F46E5;
22
  transition: all 0.3s ease;
23
  }
24
+
25
  .dropzone:hover {
26
  border-color: #312E81;
27
  background-color: rgba(79, 70, 229, 0.1);
28
  }
29
+
30
  .loading {
31
  display: none;
32
  }
33
+
34
  .loading.active {
35
  display: flex;
36
  }
37
+
38
  .math-content {
39
  font-size: 1.1em;
40
  line-height: 1.6;
41
  overflow-x: auto;
42
  }
43
+
44
  .math-content p {
45
  margin-bottom: 1rem;
46
  white-space: pre-wrap;
47
  }
48
+
49
  .math-content .MathJax {
50
  overflow-x: auto;
51
  overflow-y: hidden;
52
  padding: 0.5rem 0;
53
  }
54
+
55
  @media (max-width: 640px) {
56
  .math-content .MathJax {
57
  font-size: 0.9em;
58
  }
59
  }
60
+
61
  /* Style pour masquer le contenu pendant le chargement de MathJax */
62
  .math-hidden {
63
  visibility: hidden;
64
  }
65
  </style>
66
+
67
  <!-- Configuration de MathJax -->
68
  <script>
69
  window.MathJax = {
70
  tex: {
71
+ inlineMath: [
72
+ ['$', '$'],
73
+ ['\\(', '\\)']
74
+ ],
75
+ displayMath: [
76
+ ['$$', '$$'],
77
+ ['\\[', '\\]']
78
+ ],
79
  processEscapes: true,
80
  macros: {
81
  R: "{\\mathbb{R}}",
 
104
  }
105
  };
106
  </script>
107
+
108
  <!-- Chargement de MathJax -->
109
  <script>
110
  function loadMathJax() {
 
122
  // Charger MathJax immédiatement
123
  loadMathJax().catch(console.error);
124
  </script>
125
+
126
+ <!-- localForage pour le stockage local -->
127
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/localforage.min.js"></script>
128
  </head>
129
 
130
  <body class="min-h-screen bg-gradient-to-br from-blue-50 to-white">
 
133
  <!-- En-tête -->
134
  <header class="text-center mb-12">
135
  <h1 class="text-4xl font-bold text-blue-800 mb-4">Résolution de Problèmes Mathématiques</h1>
136
+ <p class="text-gray-600 text-lg">Soumettez une image de votre problème mathématique pour obtenir une solution
137
+ détaillée</p>
138
  </header>
139
 
140
  <!-- Zone de dépôt d'image -->
141
  <div class="mb-8">
142
  <form id="uploadForm" class="space-y-4">
143
+ <div id="dropzone"
144
+ class="dropzone rounded-lg p-8 text-center cursor-pointer bg-white shadow-sm hover:shadow-md transition-all">
145
  <input type="file" id="fileInput" class="hidden" accept="image/*">
146
  <div class="flex flex-col items-center space-y-4">
147
  <i class="fas fa-cloud-upload-alt text-4xl text-blue-600"></i>
148
  <div class="text-lg text-gray-700">
149
+ Glissez votre image ici ou <span class="text-blue-600 font-semibold">cliquez pour
150
+ sélectionner</span>
151
  </div>
152
  <p class="text-sm text-gray-500">Formats acceptés: PNG, JPG, JPEG</p>
153
  </div>
154
  </div>
155
+
156
  <div class="flex justify-center">
157
+ <button type="submit"
158
+ class="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors duration-200 flex items-center space-x-2 disabled:opacity-50 disabled:cursor-not-allowed">
159
  <i class="fas fa-paper-plane"></i>
160
  <span>Analyser l'image</span>
161
  </button>
 
179
  </div>
180
  </div>
181
 
182
+ <!-- Réponses sauvegardées -->
183
+ <div id="savedResponsesSection" class="mt-8">
184
+ <h2 class="text-2xl font-semibold text-blue-800 mb-4">Réponses Sauvegardées</h2>
185
+ <div id="savedResponses" class="space-y-4">
186
+ <!-- Les réponses sauvegardées seront affichées ici -->
187
+ </div>
188
+ <button id="clearSavedResponses" class="mt-4 px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors duration-200">
189
+ Effacer les réponses sauvegardées
190
+ </button>
191
+ </div>
192
+
193
  <!-- Message d'erreur -->
194
+ <div id="errorMessage"
195
+ class="hidden bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative my-4" role="alert">
196
  <strong class="font-bold">Erreur!</strong>
197
  <span class="block sm:inline" id="errorText"></span>
198
  </div>
199
  </div>
200
 
201
  <script>
202
+ document.addEventListener('DOMContentLoaded', function () {
203
  // Éléments DOM
204
  const dropzone = document.getElementById('dropzone');
205
  const fileInput = document.getElementById('fileInput');
 
210
  const errorMessage = document.getElementById('errorMessage');
211
  const errorText = document.getElementById('errorText');
212
  const submitButton = uploadForm.querySelector('button[type="submit"]');
213
+ const savedResponsesContainer = document.getElementById('savedResponses');
214
+ const clearSavedResponsesButton = document.getElementById('clearSavedResponses');
215
 
216
  // Attendre que MathJax soit complètement chargé
217
  let mathJaxReady = false;
 
247
  // Nettoyer le contenu précédent
248
  latexContent.innerHTML = '';
249
  latexContent.classList.add('math-hidden');
250
+
251
  // Convertir le Markdown en HTML
252
  const htmlContent = marked.parse(text);
253
  latexContent.innerHTML = htmlContent;
254
 
255
  // Rendre les formules mathématiques avec MathJax
256
  await MathJax.typesetPromise([latexContent]);
257
+
258
  // Afficher le contenu
259
  response.classList.remove('hidden');
260
  latexContent.classList.remove('math-hidden');
261
+
262
  } catch (error) {
263
  console.error('Erreur lors du rendu:', error);
264
  showError('Erreur lors du rendu de la formule mathématique');
265
+
266
  latexContent.innerHTML = `
267
  <div class="text-red-600 mb-4">Une erreur s'est produite lors du rendu. Voici le texte brut :</div>
268
  <pre class="bg-gray-100 p-4 rounded-lg overflow-x-auto">${text}</pre>
 
288
  e.preventDefault();
289
  e.stopPropagation();
290
  dropzone.classList.remove('bg-blue-50');
291
+
292
  const files = e.dataTransfer.files;
293
  if (files.length > 0 && files[0].type.startsWith('image/')) {
294
  fileInput.files = files;
 
302
  function handleFileSelect(file) {
303
  if (file && file.type.startsWith('image/')) {
304
  const reader = new FileReader();
305
+ reader.onload = function (e) {
306
  const preview = document.createElement('img');
307
  preview.src = e.target.result;
308
  preview.classList.add('max-h-48', 'mx-auto', 'mt-4', 'rounded-lg');
309
+
310
  const oldPreview = dropzone.querySelector('img');
311
  if (oldPreview) oldPreview.remove();
312
+
313
  dropzone.appendChild(preview);
314
  submitButton.disabled = false;
315
  };
 
324
  dropzone.addEventListener('dragleave', handleDragLeave);
325
  dropzone.addEventListener('drop', handleDrop);
326
  dropzone.addEventListener('click', () => fileInput.click());
327
+
328
  fileInput.addEventListener('change', (e) => {
329
  if (e.target.files.length > 0) {
330
  handleFileSelect(e.target.files[0]);
331
  }
332
  });
333
 
334
+ // Fonction pour sauvegarder la réponse
335
+ async function saveResponse(response) {
336
+ const timestamp = new Date().getTime();
337
+ const key = `response-${timestamp}`;
338
+ try {
339
+ await localforage.setItem(key, response);
340
+ console.log('Réponse sauvegardée avec la clé:', key);
341
+ // Recharger les réponses affichées après la sauvegarde
342
+ loadSavedResponses();
343
+ } catch (error) {
344
+ console.error('Erreur lors de la sauvegarde:', error);
345
+ showError('Erreur lors de la sauvegarde de la réponse en local');
346
+ }
347
+ }
348
+
349
+ // Fonction pour effacer toutes les réponses sauvegardées
350
+ async function clearSavedResponses() {
351
+ try {
352
+ await localforage.clear();
353
+ console.log('Réponses sauvegardées effacées');
354
+ // Recharger les réponses affichées après l'effacement
355
+ loadSavedResponses();
356
+ } catch (error) {
357
+ console.error('Erreur lors de l\'effacement des réponses sauvegardées:', error);
358
+ showError('Erreur lors de l\'effacement des réponses sauvegardées');
359
+ }
360
+ }
361
+
362
+ // Fonction pour charger et afficher les réponses sauvegardées
363
+ async function loadSavedResponses() {
364
+ try {
365
+ savedResponsesContainer.innerHTML = ''; // Effacer les réponses précédentes
366
+ const keys = await localforage.keys();
367
+ keys.sort((a, b) => parseInt(b.replace('response-', '')) - parseInt(a.replace('response-', '')));
368
+
369
+ for (const key of keys) {
370
+ const response = await localforage.getItem(key);
371
+ const responseDiv = document.createElement('div');
372
+ responseDiv.className = 'bg-white rounded-lg shadow-md p-4';
373
+
374
+ const responseContent = document.createElement('div');
375
+ responseContent.className = 'math-content math-hidden';
376
+ responseContent.innerHTML = marked.parse(response);
377
+ responseDiv.appendChild(responseContent);
378
+
379
+ // Bouton de suppression pour chaque réponse
380
+ const deleteButton = document.createElement('button');
381
+ deleteButton.innerHTML = '<i class="fas fa-trash"></i>'; // Icône Font Awesome pour la poubelle
382
+ deleteButton.className = 'mt-2 px-2 py-1 bg-red-500 hover:bg-red-700 text-white rounded-sm text-xs';
383
+ deleteButton.onclick = async function () {
384
+ try {
385
+ await localforage.removeItem(key);
386
+ console.log('Réponse supprimée:', key);
387
+ responseDiv.remove(); // Supprimer la réponse de l'affichage
388
+ } catch (error) {
389
+ console.error('Erreur lors de la suppression de la réponse:', error);
390
+ showError('Erreur lors de la suppression de la réponse');
391
+ }
392
+ };
393
+ responseDiv.appendChild(deleteButton); // Ajouter le bouton de suppression à la réponse
394
+
395
+ await MathJax.typesetPromise([responseContent]);
396
+ responseContent.classList.remove('math-hidden');
397
+
398
+ savedResponsesContainer.appendChild(responseDiv);
399
+
400
+ }
401
+ } catch (error) {
402
+ console.error('Erreur lors du chargement des réponses sauvegardées:', error);
403
+ showError('Erreur lors du chargement des réponses sauvegardées');
404
+ }
405
+ }
406
+
407
  // Gestion du formulaire
408
  uploadForm.addEventListener('submit', async (e) => {
409
  e.preventDefault();
410
+
411
  if (!fileInput.files.length) {
412
  showError('Veuillez sélectionner une image');
413
  return;
 
435
 
436
  await renderMathContent(data.result);
437
 
438
+ // Sauvegarder la réponse après le rendu
439
+ saveResponse(data.result);
440
+
441
  } catch (error) {
442
  console.error('Erreur:', error);
443
+ showError(error.message || 'Une erreur est survenue lors du traitement');
444
  } finally {
445
  loading.classList.remove('active');
446
  submitButton.disabled = false;
447
  }
448
  });
449
+
450
+ // Charger les réponses sauvegardées au chargement de la page
451
+ loadSavedResponses();
452
+
453
+ // Gestionnaire d'événement pour effacer les réponses sauvegardées
454
+ clearSavedResponsesButton.addEventListener('click', clearSavedResponses);
455
  });
456
+
457
  </script>
458
  </body>
459
+
460
+ </html>
461
+