Docfile commited on
Commit
5c8a3c4
·
verified ·
1 Parent(s): 027e14a

Update templates/math.html

Browse files
Files changed (1) hide show
  1. templates/math.html +166 -71
templates/math.html CHANGED
@@ -4,13 +4,23 @@
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
  <script src="https://cdn.tailwindcss.com"></script>
8
- <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/9.1.6/marked.min.js"></script>
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.js"></script>
10
- <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/contrib/auto-render.min.js"></script>
 
 
11
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css">
 
 
 
 
12
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
 
13
  <style>
 
14
  .dropzone {
15
  border: 2px dashed #4F46E5;
16
  transition: all 0.3s ease;
@@ -28,13 +38,30 @@
28
  .math-content {
29
  font-size: 1.1em;
30
  line-height: 1.6;
 
31
  }
32
  .math-content p {
33
  margin-bottom: 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
35
  </style>
36
  </head>
 
37
  <body class="min-h-screen bg-gradient-to-br from-blue-50 to-white">
 
38
  <div class="container mx-auto px-4 py-8 max-w-4xl">
39
  <!-- En-tête -->
40
  <header class="text-center mb-12">
@@ -45,7 +72,7 @@
45
  <!-- Zone de dépôt d'image -->
46
  <div class="mb-8">
47
  <form id="uploadForm" class="space-y-4">
48
- <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer">
49
  <input type="file" id="fileInput" class="hidden" accept="image/*">
50
  <div class="flex flex-col items-center space-y-4">
51
  <i class="fas fa-cloud-upload-alt text-4xl text-blue-600"></i>
@@ -55,17 +82,20 @@
55
  <p class="text-sm text-gray-500">Formats acceptés: PNG, JPG, JPEG</p>
56
  </div>
57
  </div>
58
- <button type="submit" class="w-full md:w-auto px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors duration-200 flex items-center justify-center space-x-2">
59
- <i class="fas fa-paper-plane"></i>
60
- <span>Analyser l'image</span>
61
- </button>
 
 
 
62
  </form>
63
  </div>
64
 
65
  <!-- Indicateur de chargement -->
66
  <div id="loading" class="loading flex-col items-center justify-center space-y-4 my-8">
67
- <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
68
- <p class="text-gray-700">Analyse en cours...</p>
69
  </div>
70
 
71
  <!-- Zone de réponse -->
@@ -73,70 +103,149 @@
73
  <div class="bg-white rounded-lg shadow-lg p-6 mb-8">
74
  <h2 class="text-2xl font-semibold text-blue-800 mb-4">Solution</h2>
75
  <div id="latexContent" class="prose max-w-none math-content">
76
- <!-- Le contenu LaTeX sera inséré ici -->
77
  </div>
78
  </div>
79
  </div>
 
 
 
 
 
 
80
  </div>
81
 
82
  <script>
83
  document.addEventListener('DOMContentLoaded', function() {
 
84
  const dropzone = document.getElementById('dropzone');
85
  const fileInput = document.getElementById('fileInput');
86
  const uploadForm = document.getElementById('uploadForm');
87
  const loading = document.getElementById('loading');
88
  const response = document.getElementById('response');
89
  const latexContent = document.getElementById('latexContent');
 
 
 
90
 
91
- // Configuration de marked pour le Markdown
92
  marked.setOptions({
93
  breaks: true,
94
- gfm: true
 
 
95
  });
96
 
97
- // Configuration de KaTeX
98
- const renderMathInElement = function(element) {
99
- renderMathInElementOptions = {
100
- delimiters: [
101
- {left: "$$", right: "$$", display: true},
102
- {left: "$", right: "$", display: false},
103
- ],
104
- throwOnError: false,
105
- output: 'html'
106
- };
107
- renderMathInElement(element, renderMathInElementOptions);
108
- };
109
-
110
- // Fonction pour traiter le contenu avec Markdown et LaTeX
111
- function processContent(text) {
112
- // Convertir d'abord le Markdown en HTML
113
- const htmlContent = marked.parse(text);
114
- latexContent.innerHTML = htmlContent;
115
-
116
- // Puis rendre les expressions mathématiques
117
- renderMathInElement(latexContent);
118
  }
119
 
120
- // Gestion du drag & drop
121
- dropzone.addEventListener('click', () => fileInput.click());
122
-
123
- dropzone.addEventListener('dragover', (e) => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  e.preventDefault();
 
125
  dropzone.classList.add('bg-blue-50');
126
- });
127
 
128
- dropzone.addEventListener('dragleave', () => {
 
 
129
  dropzone.classList.remove('bg-blue-50');
130
- });
131
 
132
- dropzone.addEventListener('drop', (e) => {
133
  e.preventDefault();
 
134
  dropzone.classList.remove('bg-blue-50');
135
 
136
- if (e.dataTransfer.files.length) {
137
- fileInput.files = e.dataTransfer.files;
138
- const event = new Event('change');
139
- fileInput.dispatchEvent(event);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
141
  });
142
 
@@ -144,12 +253,19 @@
144
  uploadForm.addEventListener('submit', async (e) => {
145
  e.preventDefault();
146
 
 
 
 
 
 
147
  const formData = new FormData();
148
  formData.append('image', fileInput.files[0]);
149
 
150
  try {
 
151
  loading.classList.add('active');
152
  response.classList.add('hidden');
 
153
 
154
  const res = await fetch('/upload', {
155
  method: 'POST',
@@ -162,35 +278,14 @@
162
  throw new Error(data.error);
163
  }
164
 
165
- // Traiter le contenu avec Markdown et LaTeX
166
- processContent(data.result);
167
- response.classList.remove('hidden');
168
 
169
  } catch (error) {
170
- alert('Erreur: ' + error.message);
 
171
  } finally {
172
  loading.classList.remove('active');
173
- }
174
- });
175
-
176
- // Aperçu de l'image sélectionnée
177
- fileInput.addEventListener('change', function() {
178
- if (this.files && this.files[0]) {
179
- const reader = new FileReader();
180
- reader.onload = function(e) {
181
- const preview = document.createElement('img');
182
- preview.src = e.target.result;
183
- preview.classList.add('max-h-48', 'mx-auto', 'mt-4', 'rounded-lg');
184
-
185
- // Supprimer l'aperçu précédent s'il existe
186
- const oldPreview = dropzone.querySelector('img');
187
- if (oldPreview) {
188
- oldPreview.remove();
189
- }
190
-
191
- dropzone.appendChild(preview);
192
- }
193
- reader.readAsDataURL(this.files[0]);
194
  }
195
  });
196
  });
 
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
+ <!-- KaTeX pour le LaTeX -->
15
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css">
16
+ <script defer src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.js"></script>
17
+ <script defer src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/contrib/auto-render.min.js"></script>
18
+
19
+ <!-- Font Awesome pour les icônes -->
20
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
21
+
22
  <style>
23
+ /* Styles personnalisés */
24
  .dropzone {
25
  border: 2px dashed #4F46E5;
26
  transition: all 0.3s ease;
 
38
  .math-content {
39
  font-size: 1.1em;
40
  line-height: 1.6;
41
+ overflow-x: auto;
42
  }
43
  .math-content p {
44
  margin-bottom: 1rem;
45
+ white-space: pre-wrap;
46
+ }
47
+ .math-content .katex-display {
48
+ overflow-x: auto;
49
+ overflow-y: hidden;
50
+ padding: 0.5rem 0;
51
+ }
52
+ .math-content .katex {
53
+ font-size: 1.1em;
54
+ }
55
+ @media (max-width: 640px) {
56
+ .math-content .katex {
57
+ font-size: 0.9em;
58
+ }
59
  }
60
  </style>
61
  </head>
62
+
63
  <body class="min-h-screen bg-gradient-to-br from-blue-50 to-white">
64
+ <!-- Container principal -->
65
  <div class="container mx-auto px-4 py-8 max-w-4xl">
66
  <!-- En-tête -->
67
  <header class="text-center mb-12">
 
72
  <!-- Zone de dépôt d'image -->
73
  <div class="mb-8">
74
  <form id="uploadForm" class="space-y-4">
75
+ <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer bg-white shadow-sm hover:shadow-md transition-all">
76
  <input type="file" id="fileInput" class="hidden" accept="image/*">
77
  <div class="flex flex-col items-center space-y-4">
78
  <i class="fas fa-cloud-upload-alt text-4xl text-blue-600"></i>
 
82
  <p class="text-sm text-gray-500">Formats acceptés: PNG, JPG, JPEG</p>
83
  </div>
84
  </div>
85
+
86
+ <div class="flex justify-center">
87
+ <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">
88
+ <i class="fas fa-paper-plane"></i>
89
+ <span>Analyser l'image</span>
90
+ </button>
91
+ </div>
92
  </form>
93
  </div>
94
 
95
  <!-- Indicateur de chargement -->
96
  <div id="loading" class="loading flex-col items-center justify-center space-y-4 my-8">
97
+ <div class="animate-spin rounded-full h-12 w-12 border-4 border-blue-200 border-t-blue-600"></div>
98
+ <p class="text-gray-700 font-medium">Analyse en cours...</p>
99
  </div>
100
 
101
  <!-- Zone de réponse -->
 
103
  <div class="bg-white rounded-lg shadow-lg p-6 mb-8">
104
  <h2 class="text-2xl font-semibold text-blue-800 mb-4">Solution</h2>
105
  <div id="latexContent" class="prose max-w-none math-content">
106
+ <!-- Le contenu sera inséré ici -->
107
  </div>
108
  </div>
109
  </div>
110
+
111
+ <!-- Message d'erreur -->
112
+ <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">
113
+ <strong class="font-bold">Erreur!</strong>
114
+ <span class="block sm:inline" id="errorText"></span>
115
+ </div>
116
  </div>
117
 
118
  <script>
119
  document.addEventListener('DOMContentLoaded', function() {
120
+ // Éléments DOM
121
  const dropzone = document.getElementById('dropzone');
122
  const fileInput = document.getElementById('fileInput');
123
  const uploadForm = document.getElementById('uploadForm');
124
  const loading = document.getElementById('loading');
125
  const response = document.getElementById('response');
126
  const latexContent = document.getElementById('latexContent');
127
+ const errorMessage = document.getElementById('errorMessage');
128
+ const errorText = document.getElementById('errorText');
129
+ const submitButton = uploadForm.querySelector('button[type="submit"]');
130
 
131
+ // Configuration de marked
132
  marked.setOptions({
133
  breaks: true,
134
+ gfm: true,
135
+ pedantic: false,
136
+ smartLists: true
137
  });
138
 
139
+ // Fonction pour afficher les erreurs
140
+ function showError(message) {
141
+ errorText.textContent = message;
142
+ errorMessage.classList.remove('hidden');
143
+ setTimeout(() => {
144
+ errorMessage.classList.add('hidden');
145
+ }, 5000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  }
147
 
148
+ // Fonction pour rendre le contenu mathématique
149
+ async function renderMathContent(text) {
150
+ try {
151
+ // Nettoyer le contenu précédent
152
+ latexContent.innerHTML = '';
153
+
154
+ // Convertir le Markdown en HTML
155
+ const htmlContent = marked.parse(text);
156
+ latexContent.innerHTML = htmlContent;
157
+
158
+ // Rendre les formules mathématiques
159
+ await renderMathInElement(latexContent, {
160
+ delimiters: [
161
+ {left: "$$", right: "$$", display: true},
162
+ {left: "$", right: "$", display: false},
163
+ {left: "\\[", right: "\\]", display: true},
164
+ {left: "\\(", right: "\\)", display: false}
165
+ ],
166
+ throwOnError: false,
167
+ errorColor: '#cc0000',
168
+ strict: false,
169
+ trust: true,
170
+ macros: {
171
+ "\\R": "\\mathbb{R}",
172
+ "\\N": "\\mathbb{N}",
173
+ "\\Z": "\\mathbb{Z}"
174
+ }
175
+ });
176
+
177
+ // Afficher le résultat
178
+ response.classList.remove('hidden');
179
+
180
+ } catch (error) {
181
+ console.error('Erreur lors du rendu:', error);
182
+ showError('Erreur lors du rendu de la formule mathématique');
183
+
184
+ // Afficher le texte brut en cas d'erreur
185
+ latexContent.innerHTML = `
186
+ <div class="text-red-600 mb-4">Une erreur s'est produite lors du rendu. Voici le texte brut :</div>
187
+ <pre class="bg-gray-100 p-4 rounded-lg overflow-x-auto">${text}</pre>
188
+ `;
189
+ }
190
+ }
191
+
192
+ // Gestionnaire de drag & drop
193
+ function handleDragOver(e) {
194
  e.preventDefault();
195
+ e.stopPropagation();
196
  dropzone.classList.add('bg-blue-50');
197
+ }
198
 
199
+ function handleDragLeave(e) {
200
+ e.preventDefault();
201
+ e.stopPropagation();
202
  dropzone.classList.remove('bg-blue-50');
203
+ }
204
 
205
+ function handleDrop(e) {
206
  e.preventDefault();
207
+ e.stopPropagation();
208
  dropzone.classList.remove('bg-blue-50');
209
 
210
+ const files = e.dataTransfer.files;
211
+ if (files.length > 0 && files[0].type.startsWith('image/')) {
212
+ fileInput.files = files;
213
+ handleFileSelect(files[0]);
214
+ } else {
215
+ showError('Veuillez déposer une image valide');
216
+ }
217
+ }
218
+
219
+ // Gestion de la sélection de fichier
220
+ function handleFileSelect(file) {
221
+ if (file && file.type.startsWith('image/')) {
222
+ const reader = new FileReader();
223
+ reader.onload = function(e) {
224
+ const preview = document.createElement('img');
225
+ preview.src = e.target.result;
226
+ preview.classList.add('max-h-48', 'mx-auto', 'mt-4', 'rounded-lg');
227
+
228
+ const oldPreview = dropzone.querySelector('img');
229
+ if (oldPreview) oldPreview.remove();
230
+
231
+ dropzone.appendChild(preview);
232
+ submitButton.disabled = false;
233
+ };
234
+ reader.readAsDataURL(file);
235
+ } else {
236
+ showError('Veuillez sélectionner une image valide');
237
+ }
238
+ }
239
+
240
+ // Gestionnaires d'événements
241
+ dropzone.addEventListener('dragover', handleDragOver);
242
+ dropzone.addEventListener('dragleave', handleDragLeave);
243
+ dropzone.addEventListener('drop', handleDrop);
244
+ dropzone.addEventListener('click', () => fileInput.click());
245
+
246
+ fileInput.addEventListener('change', (e) => {
247
+ if (e.target.files.length > 0) {
248
+ handleFileSelect(e.target.files[0]);
249
  }
250
  });
251
 
 
253
  uploadForm.addEventListener('submit', async (e) => {
254
  e.preventDefault();
255
 
256
+ if (!fileInput.files.length) {
257
+ showError('Veuillez sélectionner une image');
258
+ return;
259
+ }
260
+
261
  const formData = new FormData();
262
  formData.append('image', fileInput.files[0]);
263
 
264
  try {
265
+ submitButton.disabled = true;
266
  loading.classList.add('active');
267
  response.classList.add('hidden');
268
+ errorMessage.classList.add('hidden');
269
 
270
  const res = await fetch('/upload', {
271
  method: 'POST',
 
278
  throw new Error(data.error);
279
  }
280
 
281
+ await renderMathContent(data.result);
 
 
282
 
283
  } catch (error) {
284
+ console.error('Erreur:', error);
285
+ showError(error.message || 'Une erreur est survenue lors du traitement');
286
  } finally {
287
  loading.classList.remove('active');
288
+ submitButton.disabled = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  }
290
  });
291
  });