Docfile commited on
Commit
dabdcd0
·
verified ·
1 Parent(s): ef81ad8

Update templates/math.html

Browse files
Files changed (1) hide show
  1. templates/math.html +84 -350
templates/math.html CHANGED
@@ -1,363 +1,97 @@
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
- <script src="https://cdn.tailwindcss.com"></script>
9
- <script defer src="https://cdnjs.cloudflare.com/ajax/libs/marked/9.1.6/marked.min.js"></script>
10
- <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
11
- <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
12
  <style>
13
- .dropzone { border: 2px dashed #4F46E5; transition: all 0.3s ease; }
14
- .dropzone:hover { border-color: #312E81; background-color: rgba(79, 70, 229, 0.1); }
15
- .loading { display: none; }
16
- .loading.active { display: flex; }
17
- .math-content { font-size: 1.1em; line-height: 1.6; overflow-x: auto; }
18
- .math-content p { margin-bottom: 1rem; white-space: pre-wrap; }
19
- .math-content .MathJax { overflow-x: auto; overflow-y: hidden; padding: 0.5rem 0; }
20
- @media (max-width: 640px) { .math-content .MathJax { font-size: 0.9em; } }
21
- .math-hidden { visibility: hidden; }
22
- .saved-response-header { cursor: pointer; display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 1rem; background-color: #f3f4f6; border-bottom: 1px solid #e5e7eb; }
23
- .saved-response-content { padding: 1rem; display: none; }
24
- .saved-response-item.open .saved-response-content { display: block; }
25
- </style>
26
- <script>
27
- window.MathJax = {
28
- tex: {
29
- inlineMath: [['$', '$'], ['\\(', '\\)']],
30
- displayMath: [['$$', '$$'], ['\\[', '\\]']],
31
- processEscapes: true,
32
- macros: { R: "{\\mathbb{R}}", N: "{\\mathbb{N}}", Z: "{\\mathbb{Z}}", vecv: ["\\begin{pmatrix}#1\\\\#2\\\\#3\\end{pmatrix}", 3] }
33
- },
34
- svg: { fontCache: 'global' },
35
- startup: { pageReady: () => { return Promise.resolve(); } },
36
- options: { renderActions: { addMenu: [], checkLoading: [150, () => { document.querySelectorAll('.math-content').forEach(el => { el.classList.remove('math-hidden'); }); }] } }
37
- };
38
- </script>
39
- <script>
40
- function loadMathJax() {
41
- return new Promise((resolve, reject) => {
42
- const script = document.createElement('script');
43
- script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js';
44
- script.async = true;
45
- script.id = 'MathJax-script';
46
- script.onload = resolve;
47
- script.onerror = reject;
48
- document.head.appendChild(script);
49
- });
50
  }
51
- loadMathJax().catch(console.error);
52
- </script>
53
- <script src="https://cdn.jsdelivr.net/npm/localforage@1.10.0/dist/localforage.min.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  </head>
55
-
56
- <body class="min-h-screen bg-gradient-to-br from-blue-50 to-white">
57
- <div class="container mx-auto px-4 py-8 max-w-4xl">
58
- <header class="text-center mb-12">
59
- <h1 class="text-4xl font-bold text-blue-800 mb-4">Résolution de Problèmes Mathématiques</h1>
60
- <p class="text-gray-600 text-lg">Soumettez une image de votre problème mathématique pour obtenir une solution détaillée</p>
61
- </header>
62
- <div class="mb-8">
63
- <form id="uploadForm" class="space-y-4">
64
- <div id="dropzone"
65
- class="dropzone rounded-lg p-8 text-center cursor-pointer bg-white shadow-sm hover:shadow-md transition-all">
66
- <input type="file" id="fileInput" class="hidden" accept="image/*">
67
- <div class="flex flex-col items-center space-y-4">
68
- <i class="fas fa-cloud-upload-alt text-4xl text-blue-600"></i>
69
- <div class="text-lg text-gray-700">
70
- Glissez votre image ici ou <span class="text-blue-600 font-semibold">cliquez pour sélectionner</span>
71
- </div>
72
- <p class="text-sm text-gray-500">Formats acceptés: PNG, JPG, JPEG</p>
73
- </div>
74
- </div>
75
-
76
- <div class="flex justify-center items-center space-x-4">
77
- <select id="modelChoice" name="model_choice" class="rounded-md border-gray-300 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50">
78
- <option value="mariam's">Mariam's(Rapide et performant)</option>
79
- <option value="qwen2">Qwen2(lent mais 2 +performant)</option>
80
- </select>
81
- <button type="submit"
82
- 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">
83
- <i class="fas fa-paper-plane"></i>
84
- <span>Analyser l'image</span>
85
- </button>
86
- </div>
87
- </form>
88
- </div>
89
-
90
- <div id="loading" class="loading flex-col items-center justify-center space-y-4 my-8">
91
- <div class="animate-spin rounded-full h-12 w-12 border-4 border-blue-200 border-t-blue-600"></div>
92
- <p class="text-gray-700 font-medium">Analyse en cours...</p>
93
- </div>
94
-
95
- <div id="response" class="hidden">
96
- <div class="bg-white rounded-lg shadow-lg p-6 mb-8">
97
- <h2 id="modelUsed" class="text-2xl font-semibold text-blue-800 mb-4">Solution (Modèle: <span id="modelName"></span>)</h2>
98
- <div id="latexContent" class="prose max-w-none math-content math-hidden"></div>
99
- </div>
100
- </div>
101
-
102
- <div id="savedResponsesSection" class="mt-8">
103
- <div class="flex justify-between items-center mb-4">
104
- <h2 class="text-2xl font-semibold text-blue-800">Réponses Sauvegardées</h2>
105
- <button id="clearSavedResponses" class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors duration-200">
106
- <i class="fas fa-trash-alt"></i> Effacer Tout
107
- </button>
108
- </div>
109
- <div id="savedResponses" class="space-y-2"></div>
110
- </div>
111
-
112
- <div id="errorMessage"
113
- class="hidden bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative my-4" role="alert">
114
- <strong class="font-bold">Erreur!</strong>
115
- <span class="block sm:inline" id="errorText"></span>
116
- </div>
117
  </div>
118
 
119
  <script>
120
- document.addEventListener('DOMContentLoaded', function () {
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
- const savedResponsesContainer = document.getElementById('savedResponses');
131
- const clearSavedResponsesButton = document.getElementById('clearSavedResponses');
132
- const modelChoiceSelect = document.getElementById('modelChoice');
133
- const modelNameSpan = document.getElementById('modelName');
134
-
135
- let mathJaxReady = false;
136
- window.MathJax.startup.promise.then(() => {
137
- mathJaxReady = true;
138
- });
139
-
140
- marked.setOptions({ breaks: true, gfm: true, pedantic: false, smartLists: true });
141
-
142
- function showError(message) {
143
- errorText.textContent = message;
144
- errorMessage.classList.remove('hidden');
145
- setTimeout(() => { errorMessage.classList.add('hidden'); }, 5000);
146
- }
147
-
148
- async function renderMathContent(text) {
149
- try {
150
- if (!mathJaxReady) {
151
- await window.MathJax.startup.promise;
152
- }
153
- latexContent.innerHTML = '';
154
- latexContent.classList.add('math-hidden');
155
- const htmlContent = marked.parse(text);
156
- latexContent.innerHTML = htmlContent;
157
- await MathJax.typesetPromise([latexContent]);
158
- response.classList.remove('hidden');
159
- latexContent.classList.remove('math-hidden');
160
- } catch (error) {
161
- console.error('Erreur lors du rendu:', error);
162
- showError('Erreur lors du rendu de la formule mathématique');
163
- latexContent.innerHTML = `
164
- <div class="text-red-600 mb-4">Une erreur s'est produite lors du rendu. Voici le texte brut :</div>
165
- <pre class="bg-gray-100 p-4 rounded-lg overflow-x-auto">${text}</pre>
166
- `;
167
- latexContent.classList.remove('math-hidden');
168
- }
169
- }
170
-
171
- function handleDragOver(e) { e.preventDefault(); e.stopPropagation(); dropzone.classList.add('bg-blue-50'); }
172
- function handleDragLeave(e) { e.preventDefault(); e.stopPropagation(); dropzone.classList.remove('bg-blue-50'); }
173
- function handleDrop(e) {
174
- e.preventDefault(); e.stopPropagation(); dropzone.classList.remove('bg-blue-50');
175
- const files = e.dataTransfer.files;
176
- if (files.length > 0 && files[0].type.startsWith('image/')) {
177
- fileInput.files = files;
178
- handleFileSelect(files[0]);
179
- } else {
180
- showError('Veuillez déposer une image valide');
181
- }
182
- }
183
 
184
- function handleFileSelect(file) {
185
- if (file && file.type.startsWith('image/')) {
186
- const reader = new FileReader();
187
- reader.onload = function (e) {
188
- const preview = document.createElement('img');
189
- preview.src = e.target.result;
190
- preview.classList.add('max-h-48', 'mx-auto', 'mt-4', 'rounded-lg');
191
- const oldPreview = dropzone.querySelector('img');
192
- if (oldPreview) oldPreview.remove();
193
- dropzone.appendChild(preview);
194
- submitButton.disabled = false;
195
- };
196
- reader.readAsDataURL(file);
197
- } else {
198
- showError('Veuillez sélectionner une image valide');
199
- }
200
- }
201
-
202
- dropzone.addEventListener('dragover', handleDragOver);
203
- dropzone.addEventListener('dragleave', handleDragLeave);
204
- dropzone.addEventListener('drop', handleDrop);
205
- dropzone.addEventListener('click', () => fileInput.click());
206
-
207
- fileInput.addEventListener('change', (e) => {
208
- if (e.target.files.length > 0) {
209
- handleFileSelect(e.target.files[0]);
210
- }
211
- });
212
-
213
- async function saveResponse(response, model) {
214
- const timestamp = new Date().getTime();
215
- const key = `response-${timestamp}-${model}`;
216
- try {
217
- await localforage.setItem(key, response);
218
- loadSavedResponses();
219
- } catch (error) {
220
- console.error('Erreur lors de la sauvegarde:', error);
221
- showError('Erreur lors de la sauvegarde de la réponse en local');
222
- }
223
- }
224
-
225
- async function clearSavedResponses() {
226
- Swal.fire({
227
- title: 'Êtes-vous sûr?',
228
- text: "Vous ne pourrez pas revenir en arrière!",
229
- icon: 'warning',
230
- showCancelButton: true,
231
- confirmButtonColor: '#d33',
232
- cancelButtonColor: '#3085d6',
233
- confirmButtonText: 'Oui, effacer!',
234
- cancelButtonText: 'Annuler'
235
- }).then(async (result) => {
236
- if (result.isConfirmed) {
237
- try {
238
- await localforage.clear();
239
- console.log('Réponses sauvegardées effacées');
240
- loadSavedResponses();
241
- Swal.fire(
242
- 'Effacé!',
243
- 'Les réponses ont été supprimées.',
244
- 'success'
245
- );
246
- } catch (error) {
247
- console.error('Erreur lors de l\'effacement des réponses sauvegardées:', error);
248
- showError('Erreur lors de l\'effacement des réponses sauvegardées');
249
- Swal.fire(
250
- 'Erreur!',
251
- 'Une erreur est survenue lors de la suppression.',
252
- 'error'
253
- );
254
- }
255
- }
256
- });
257
- }
258
-
259
- async function loadSavedResponses() {
260
- try {
261
- savedResponsesContainer.innerHTML = '';
262
- const keys = await localforage.keys();
263
- keys.sort((a, b) => parseInt(b.replace('response-', '').split('-')[0]) - parseInt(a.replace('response-', '').split('-')[0]));
264
-
265
- for (const key of keys) {
266
- const response = await localforage.getItem(key);
267
- const [ , timestamp, model ] = key.split('-');
268
- const responseItem = document.createElement('div');
269
- responseItem.className = 'saved-response-item bg-white rounded-lg shadow-md overflow-hidden';
270
-
271
- const header = document.createElement('div');
272
- header.className = 'saved-response-header';
273
- header.innerHTML = `
274
- <span class="text-blue-800 font-medium">Réponse du ${new Date(parseInt(timestamp)).toLocaleString()} (Modèle: ${model})</span>
275
- <div>
276
- <button class="toggle-content px-1 py-0.5 rounded-md text-xs bg-blue-500 hover:bg-blue-700 text-white mr-1"><i class="fas fa-chevron-down"></i></button>
277
- <button class="delete-response px-1 py-0.5 rounded-md text-xs bg-red-500 hover:bg-red-700 text-white"><i class="fas fa-trash-alt"></i></button>
278
- </div>
279
- `;
280
- responseItem.appendChild(header);
281
-
282
- const content = document.createElement('div');
283
- content.className = 'saved-response-content math-content math-hidden';
284
- content.innerHTML = marked.parse(response);
285
- responseItem.appendChild(content);
286
- savedResponsesContainer.appendChild(responseItem);
287
-
288
- header.querySelector('.toggle-content').addEventListener('click', () => {
289
- responseItem.classList.toggle('open');
290
- header.querySelector('i').classList.toggle('fa-chevron-down');
291
- header.querySelector('i').classList.toggle('fa-chevron-up');
292
- MathJax.typesetPromise([content]);
293
- content.classList.remove('math-hidden');
294
- });
295
-
296
- header.querySelector('.delete-response').addEventListener('click', async () => {
297
- try {
298
- await localforage.removeItem(key);
299
- responseItem.remove();
300
- } catch (error) {
301
- console.error('Erreur lors de la suppression de la réponse:', error);
302
- showError('Erreur lors de la suppression de la réponse');
303
- }
304
- });
305
-
306
- MathJax.typesetPromise([content]);
307
- content.classList.remove('math-hidden');
308
- }
309
- } catch (error) {
310
- console.error('Erreur lors du chargement des réponses sauvegardées:', error);
311
- showError('Erreur lors du chargement des réponses sauvegardées');
312
- }
313
- }
314
-
315
- uploadForm.addEventListener('submit', async (e) => {
316
- e.preventDefault();
317
-
318
- if (!fileInput.files.length) {
319
- showError('Veuillez sélectionner une image');
320
- return;
321
- }
322
-
323
- const formData = new FormData();
324
- formData.append('image', fileInput.files[0]);
325
- formData.append('model_choice', modelChoiceSelect.value);
326
-
327
- try {
328
- submitButton.disabled = true;
329
- loading.classList.add('active');
330
- response.classList.add('hidden');
331
- errorMessage.classList.add('hidden');
332
-
333
- const res = await fetch('/upload', {
334
- method: 'POST',
335
- body: formData
336
- });
337
-
338
- const data = await res.json();
339
-
340
- if (data.error) {
341
- throw new Error(data.error);
342
- }
343
-
344
- await renderMathContent(data.result);
345
- modelNameSpan.textContent = data.model;
346
- saveResponse(data.result, data.model);
347
-
348
- } catch (error) {
349
- console.error('Erreur:', error);
350
- showError(error.message || 'Une erreur est survenue lors du traitement');
351
- } finally {
352
- loading.classList.remove('active');
353
- submitButton.disabled = false;
354
- }
355
- });
356
-
357
- loadSavedResponses();
358
- clearSavedResponsesButton.addEventListener('click', clearSavedResponses);
359
- });
360
  </script>
361
  </body>
362
-
363
- </html>
 
1
  <!DOCTYPE html>
2
+ <html lang="en">
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Visualiseur de PDF</title>
 
 
 
 
7
  <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ margin: 0;
11
+ padding: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  }
13
+ #pdf-container {
14
+ height: 100vh;
15
+ overflow-y: auto;
16
+ padding: 10px;
17
+ background-color: #f8f9fa;
18
+ }
19
+ .page {
20
+ margin-bottom: 20px;
21
+ text-align: center;
22
+ border: 1px solid #ddd;
23
+ background-color: #fff;
24
+ padding: 10px;
25
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
26
+ }
27
+ .page img {
28
+ max-width: 100%;
29
+ height: auto;
30
+ }
31
+ .page button {
32
+ margin-top: 10px;
33
+ padding: 10px 15px;
34
+ background-color: #007bff;
35
+ color: white;
36
+ border: none;
37
+ border-radius: 4px;
38
+ cursor: pointer;
39
+ }
40
+ .page button:hover {
41
+ background-color: #0056b3;
42
+ }
43
+ </style>
44
  </head>
45
+ <body>
46
+ <div id="pdf-container">
47
+ <!-- Les pages PDF seront ajoutées ici dynamiquement -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  </div>
49
 
50
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ // Configuration de l'application
53
+ const totalPages = 210; // Changez ce nombre selon le nombre de pages de votre PDF
54
+ const lowResEndpoint = "/low_res/"; // Endpoint Flask pour les images basse résolution
55
+ const highResEndpoint = "/high_res/"; // Endpoint Flask pour les images haute résolution
56
+
57
+ // Référence au conteneur
58
+ const pdfContainer = document.getElementById("pdf-container");
59
+
60
+ // Fonction pour charger les pages PDF
61
+ function loadPages() {
62
+ for (let pageNumber = 1; pageNumber <= totalPages; pageNumber++) {
63
+ // Créer un conteneur pour chaque page
64
+ const pageDiv = document.createElement("div");
65
+ pageDiv.className = "page";
66
+ pageDiv.id = `page-${pageNumber}`;
67
+
68
+ // Ajouter une image basse résolution
69
+ const img = document.createElement("img");
70
+ img.src = `${lowResEndpoint}${pageNumber}`;
71
+ img.alt = `Page ${pageNumber}`;
72
+ pageDiv.appendChild(img);
73
+
74
+ // Ajouter un bouton pour la haute résolution
75
+ const button = document.createElement("button");
76
+ button.innerText = "Télécharger en haute résolution";
77
+ button.onclick = () => downloadHighRes(pageNumber);
78
+ pageDiv.appendChild(button);
79
+
80
+ // Ajouter la page au conteneur
81
+ pdfContainer.appendChild(pageDiv);
82
+ }
83
+ }
84
+
85
+ // Fonction pour télécharger une image en haute résolution
86
+ function downloadHighRes(pageNumber) {
87
+ const highResUrl = `${highResEndpoint}${pageNumber}`;
88
+ window.open(highResUrl, "_blank");
89
+ }
90
+
91
+ // Charger les pages PDF au chargement de la page
92
+ window.onload = loadPages;
93
+
94
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  </script>
96
  </body>
97
+ </html>