Docfile commited on
Commit
b79d861
·
verified ·
1 Parent(s): 1731ca9

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +108 -432
templates/index.html CHANGED
@@ -4,509 +4,185 @@
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Mariam AI - Analyse d'Image</title>
7
- <link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
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/sweetalert2/11.7.32/sweetalert2.all.min.js"></script>
10
  <style>
 
11
  .loader {
12
  width: 48px;
13
  height: 48px;
14
- border: 5px solid #FFF;
15
- border-bottom-color: #6366F1;
16
  border-radius: 50%;
17
- display: inline-block;
18
- box-sizing: border-box;
19
- animation: rotation 1s linear infinite;
20
  }
21
 
22
- @keyframes rotation {
23
- 0% { transform: rotate(0deg); }
24
- 100% { transform: rotate(360deg); }
 
25
  }
26
 
 
27
  .fade-in {
28
- animation: fadeIn 0.5s ease-in;
29
  }
30
 
31
  @keyframes fadeIn {
32
- 0% { opacity: 0; }
33
- 100% { opacity: 1; }
34
- }
35
-
36
- .upload-zone {
37
- border: 2px dashed #6366F1;
38
- transition: all 0.3s ease;
39
- }
40
-
41
- .upload-zone:hover {
42
- border-color: #4F46E5;
43
- background-color: #EEF2FF;
44
- }
45
-
46
- .upload-zone.drag-over {
47
- background-color: #EEF2FF;
48
- border-color: #4F46E5;
49
- transform: scale(1.02);
50
- }
51
-
52
- .preview-image {
53
- max-height: 300px;
54
- width: auto;
55
- object-fit: contain;
56
- }
57
-
58
- /* Styles pour le tableau avec scroll horizontal */
59
- .markdown-content {
60
- overflow-x: auto;
61
- padding-bottom: 1rem;
62
- }
63
-
64
- .markdown-content table {
65
- border-collapse: collapse;
66
- min-width: 100%;
67
- width: max-content;
68
- margin: 1rem 0;
69
- }
70
-
71
- .markdown-content th,
72
- .markdown-content td {
73
- border: 1px solid #e5e7eb;
74
- padding: 0.75rem;
75
- text-align: left;
76
- white-space: nowrap;
77
- min-width: 150px;
78
- }
79
-
80
- .markdown-content th {
81
- background-color: #f9fafb;
82
- position: sticky;
83
- top: 0;
84
- z-index: 10;
85
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
86
- }
87
-
88
- /* Styles pour la scrollbar */
89
- .custom-scrollbar::-webkit-scrollbar {
90
- height: 8px;
91
- width: 8px;
92
- }
93
-
94
- .custom-scrollbar::-webkit-scrollbar-track {
95
- background: #f1f1f1;
96
- border-radius: 4px;
97
- }
98
-
99
- .custom-scrollbar::-webkit-scrollbar-thumb {
100
- background: #6366F1;
101
- border-radius: 4px;
102
- }
103
-
104
- .custom-scrollbar::-webkit-scrollbar-thumb:hover {
105
- background: #4F46E5;
106
- }
107
-
108
- /* Progress bar */
109
- .progress-bar {
110
- height: 4px;
111
- background-color: #E5E7EB;
112
- border-radius: 2px;
113
- overflow: hidden;
114
- }
115
-
116
- .progress-value {
117
- height: 100%;
118
- background-color: #6366F1;
119
- transition: width 0.3s ease;
120
  }
121
  </style>
122
  </head>
123
- <body class="bg-gray-50">
124
- <div class="min-h-screen">
125
- <!-- Header -->
126
- <header class="bg-white shadow-sm">
127
- <div class="max-w-7xl mx-auto px-4 py-4 sm:px-6 lg:px-8">
128
- <h1 class="text-3xl font-bold text-indigo-600">Mariam AI</h1>
129
- <p class="mt-1 text-sm text-gray-500">Assistant pour commentaire composé</p>
130
- </div>
131
- </header>
 
 
 
 
132
 
133
- <!-- Main content -->
134
- <main class="max-w-7xl mx-auto px-4 py-8 sm:px-6 lg:px-8">
135
  <!-- Upload Section -->
136
- <div class="bg-white rounded-lg shadow p-6 mb-8">
137
- <form id="uploadForm" class="space-y-6">
138
- <div class="upload-zone rounded-lg p-8 text-center relative">
139
- <input type="file" id="imageInput" accept="image/*" required class="hidden">
140
- <label for="imageInput" class="cursor-pointer block">
141
- <div id="dropZone" class="space-y-4">
142
- <!-- Icon container -->
143
- <div id="uploadIcon" class="transition-all duration-200">
144
- <svg class="mx-auto h-12 w-12 text-indigo-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
145
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
146
- 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"/>
147
- </svg>
148
- <p id="fileName" class="mt-2 text-sm text-gray-500">
149
- Cliquez ou glissez une image ici
150
- </p>
151
- </div>
152
-
153
- <!-- Preview container -->
154
- <div id="previewContainer" class="hidden flex flex-col items-center space-y-4">
155
- <img id="imagePreview" class="preview-image rounded-lg shadow-md" src="" alt="Prévisualisation">
156
- <button type="button" id="removeImage" class="text-sm text-red-500 hover:text-red-700">
157
- Supprimer l'image
158
- </button>
159
- </div>
160
- </div>
161
  </label>
162
  </div>
163
 
164
- <!-- Progress bar -->
165
- <div id="progressContainer" class="hidden">
166
- <div class="flex justify-between text-sm text-gray-600 mb-1">
167
- <span>Progression</span>
168
- <span id="progressText">0%</span>
169
- </div>
170
- <div class="progress-bar">
171
- <div id="progressValue" class="progress-value" style="width: 0%"></div>
172
- </div>
173
  </div>
174
 
175
- <div class="flex justify-center">
176
- <button type="submit" id="analyzeButton" disabled
177
- class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-gray-400 cursor-not-allowed transition-colors duration-200">
178
  Analyser l'image
179
  </button>
180
  </div>
181
  </form>
182
  </div>
183
 
184
- <!-- Loading indicator -->
185
- <div id="loading" class="hidden">
186
- <div class="flex flex-col items-center justify-center space-y-4">
187
- <span class="loader"></span>
188
- <p class="text-gray-500">Analyse en cours, veuillez patienter...</p>
189
- </div>
190
  </div>
191
 
192
  <!-- Results Section -->
193
- <div id="results" class="space-y-8 hidden">
194
- <div class="flex justify-center space-x-4">
195
- <button id="showTableau"
196
- class="px-6 py-3 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 transition-colors duration-200">
 
 
 
 
 
197
  Voir le tableau d'analyse
198
  </button>
199
- <button id="downloadPDF"
200
- class="px-6 py-3 bg-green-600 text-white rounded-md hover:bg-green-700 transition-colors duration-200">
201
- Télécharger en PDF
202
- </button>
203
- </div>
204
-
205
- <!-- Dissertation -->
206
- <div class="bg-white rounded-lg shadow p-6">
207
- <h2 class="text-2xl font-bold text-gray-900 mb-4">Dissertation</h2>
208
- <div id="dissertationResult" class="prose max-w-none markdown-content custom-scrollbar">
209
- </div>
210
  </div>
211
  </div>
212
- </main>
213
- </div>
214
 
215
  <script>
216
  let tableauContent = '';
217
- const dropZone = document.getElementById('dropZone');
218
- const imageInput = document.getElementById('imageInput');
219
- const fileName = document.getElementById('fileName');
220
- const uploadIcon = document.getElementById('uploadIcon');
221
- const previewContainer = document.getElementById('previewContainer');
222
- const imagePreview = document.getElementById('imagePreview');
223
- const removeImage = document.getElementById('removeImage');
224
- const analyzeButton = document.getElementById('analyzeButton');
225
- const progressContainer = document.getElementById('progressContainer');
226
- const progressValue = document.getElementById('progressValue');
227
- const progressText = document.getElementById('progressText');
228
 
229
- // Fonctions de drag & drop
230
- ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
231
- dropZone.addEventListener(eventName, preventDefaults, false);
232
- document.body.addEventListener(eventName, preventDefaults, false);
233
- });
234
-
235
- ['dragenter', 'dragover'].forEach(eventName => {
236
- dropZone.addEventListener(eventName, highlight, false);
237
- });
238
-
239
- ['dragleave', 'drop'].forEach(eventName => {
240
- dropZone.addEventListener(eventName, unhighlight, false);
241
- });
242
-
243
- dropZone.addEventListener('drop', handleDrop, false);
244
-
245
- function preventDefaults(e) {
246
- e.preventDefault();
247
- e.stopPropagation();
248
- }
249
-
250
- function highlight(e) {
251
- dropZone.classList.add('drag-over');
252
- }
253
-
254
- function unhighlight(e) {
255
- dropZone.classList.remove('drag-over');
256
- }
257
-
258
- function handleDrop(e) {
259
- const dt = e.dataTransfer;
260
- const files = dt.files;
261
-
262
- if (files.length > 0 && files[0].type.startsWith('image/')) {
263
- imageInput.files = files;
264
- updateImagePreview(files[0]);
265
  } else {
266
- Swal.fire({
267
- icon: 'error',
268
- title: 'Type de fichier non valide',
269
- text: 'Veuillez sélectionner une image'
270
- });
271
- }
272
- }
273
-
274
- // Gestion de la prévisualisation
275
- imageInput.addEventListener('change', (e) => {
276
- if (e.target.files.length > 0) {
277
- updateImagePreview(e.target.files[0]);
278
- }
279
- });
280
-
281
- function updateImagePreview(file) {
282
- if (file.type.startsWith('image/')) {
283
- const reader = new FileReader();
284
- reader.onload = (e) => {
285
- imagePreview.src = e.target.result;
286
- uploadIcon.classList.add('hidden');
287
- previewContainer.classList.remove('hidden');
288
- analyzeButton.disabled = false;
289
- analyzeButton.classList.remove('bg
290
-
291
- -gray-400', 'cursor-not-allowed');
292
- analyzeButton.classList.add('bg-indigo-600', 'hover:bg-indigo-700');
293
- };
294
- reader.readAsDataURL(file);
295
  }
296
  }
297
 
298
- removeImage.addEventListener('click', (e) => {
299
- e.preventDefault();
300
- imageInput.value = '';
301
- imagePreview.src = '';
302
- uploadIcon.classList.remove('hidden');
303
- previewContainer.classList.add('hidden');
304
- analyzeButton.disabled = true;
305
- analyzeButton.classList.remove('bg-indigo-600', 'hover:bg-indigo-700');
306
- analyzeButton.classList.add('bg-gray-400', 'cursor-not-allowed');
 
307
  });
308
 
309
- // Gestion de l'upload et de l'analyse
310
  document.getElementById('uploadForm').addEventListener('submit', async (e) => {
311
  e.preventDefault();
312
-
313
  const loading = document.getElementById('loading');
314
  const results = document.getElementById('results');
315
  const dissertationResult = document.getElementById('dissertationResult');
316
-
317
  const formData = new FormData();
318
- formData.append('image', imageInput.files[0]);
319
-
320
  loading.classList.remove('hidden');
321
  results.classList.add('hidden');
322
- progressContainer.classList.remove('hidden');
323
-
324
  try {
325
  const response = await fetch('/analyze', {
326
  method: 'POST',
327
- body: formData,
328
- onUploadProgress: (progressEvent) => {
329
- const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
330
- progressValue.style.width = `${percentCompleted}%`;
331
- progressText.textContent = `${percentCompleted}%`;
332
- }
333
  });
334
-
335
  const data = await response.json();
336
-
337
  if (response.ok) {
338
  tableauContent = data.tableau;
339
  dissertationResult.innerHTML = marked.parse(data.dissertation);
340
  results.classList.remove('hidden');
341
- results.classList.add('fade-in');
342
  } else {
343
- Swal.fire({
344
- icon: 'error',
345
- title: 'Erreur',
346
- text: data.error || 'Une erreur est survenue lors de l\'analyse'
347
- });
348
  }
349
  } catch (error) {
350
- Swal.fire({
351
- icon: 'error',
352
- title: 'Erreur',
353
- text: 'Une erreur est survenue lors de l\'analyse'
354
- });
355
  } finally {
356
  loading.classList.add('hidden');
357
- progressContainer.classList.add('hidden');
358
- progressValue.style.width = '0%';
359
- progressText.textContent = '0%';
360
  }
361
  });
362
-
363
- // Gestion de l'affichage du tableau
364
- document.getElementById('showTableau').addEventListener('click', () => {
365
- Swal.fire({
366
- title: 'Tableau d\'analyse',
367
- html: marked.parse(tableauContent),
368
- width: '90%',
369
- customClass: {
370
- htmlContainer: 'markdown-content custom-scrollbar'
371
- },
372
- didRender: () => {
373
- const container = document.querySelector('.markdown-content');
374
- if (container.scrollWidth > container.clientWidth) {
375
- // Ajouter des indicateurs de défilement
376
- const scrollIndicator = document.createElement('div');
377
- scrollIndicator.className = 'fixed bottom-4 right-4 bg-indigo-600 text-white px-3 py-2 rounded-md shadow-lg opacity-0 transition-opacity duration-300';
378
- scrollIndicator.textContent = '← Faites défiler →';
379
- document.body.appendChild(scrollIndicator);
380
-
381
- // Gérer la visibilité de l'indicateur de défilement
382
- let scrollTimeout;
383
- container.addEventListener('scroll', () => {
384
- scrollIndicator.style.opacity = '1';
385
- clearTimeout(scrollTimeout);
386
- scrollTimeout = setTimeout(() => {
387
- scrollIndicator.style.opacity = '0';
388
- }, 1500);
389
- });
390
-
391
- // Ajouter des ombres de défilement
392
- function updateScrollShadows() {
393
- const maxScroll = container.scrollWidth - container.clientWidth;
394
- const leftShadow = container.scrollLeft > 0 ?
395
- 'inset 10px 0 5px -5px rgba(0,0,0,0.1)' : '';
396
- const rightShadow = container.scrollLeft < maxScroll ?
397
- 'inset -10px 0 5px -5px rgba(0,0,0,0.1)' : '';
398
-
399
- container.style.boxShadow = [leftShadow, rightShadow]
400
- .filter(Boolean)
401
- .join(', ');
402
- }
403
-
404
- container.addEventListener('scroll', updateScrollShadows);
405
- updateScrollShadows(); // Initial call
406
- }
407
- }
408
- });
409
- });
410
-
411
- // Gestion du téléchargement PDF
412
- document.getElementById('downloadPDF').addEventListener('click', async () => {
413
- try {
414
- const loadingText = document.createElement('div');
415
- loadingText.className = 'fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white p-6 rounded-lg shadow-xl z-50';
416
- loadingText.innerHTML = `
417
- <div class="flex flex-col items-center space-y-4">
418
- <span class="loader"></span>
419
- <p class="text-gray-600">Génération du PDF en cours...</p>
420
- </div>
421
- `;
422
- document.body.appendChild(loadingText);
423
-
424
- // Préparer les données pour le PDF
425
- const pdfData = {
426
- dissertation: marked.parse(document.getElementById('dissertationResult').innerHTML),
427
- tableau: tableauContent,
428
- imageData: imagePreview.src
429
- };
430
-
431
- // Appel à l'API pour générer le PDF
432
- const response = await fetch('/generate-pdf', {
433
- method: 'POST',
434
- headers: {
435
- 'Content-Type': 'application/json',
436
- },
437
- body: JSON.stringify(pdfData)
438
- });
439
-
440
- if (!response.ok) throw new Error('Erreur lors de la génération du PDF');
441
-
442
- // Télécharger le PDF
443
- const blob = await response.blob();
444
- const url = window.URL.createObjectURL(blob);
445
- const a = document.createElement('a');
446
- a.href = url;
447
- a.download = 'analyse-mariam-ai.pdf';
448
- document.body.appendChild(a);
449
- a.click();
450
- document.body.removeChild(a);
451
- window.URL.revokeObjectURL(url);
452
-
453
- Swal.fire({
454
- icon: 'success',
455
- title: 'PDF généré avec succès',
456
- text: 'Le téléchargement devrait commencer automatiquement'
457
- });
458
- } catch (error) {
459
- Swal.fire({
460
- icon: 'error',
461
- title: 'Erreur',
462
- text: 'Une erreur est survenue lors de la génération du PDF'
463
- });
464
- } finally {
465
- const loadingText = document.querySelector('.fixed.top-1/2');
466
- if (loadingText) document.body.removeChild(loadingText);
467
- }
468
- });
469
-
470
- // Amélioration de l'accessibilité
471
- const setupAccessibility = () => {
472
- // Ajouter des attributs ARIA
473
- const dropZone = document.querySelector('.upload-zone');
474
- dropZone.setAttribute('role', 'button');
475
- dropZone.setAttribute('aria-label', 'Zone de dépôt d\'image. Cliquez ou glissez une image ici.');
476
-
477
- // Gestion du clavier
478
- dropZone.addEventListener('keydown', (e) => {
479
- if (e.key === 'Enter' || e.key === ' ') {
480
- e.preventDefault();
481
- imageInput.click();
482
- }
483
- });
484
-
485
- // Messages d'aide pour les lecteurs d'écran
486
- const addAriaLive = () => {
487
- const liveRegion = document.createElement('div');
488
- liveRegion.setAttribute('aria-live', 'polite');
489
- liveRegion.setAttribute('aria-atomic', 'true');
490
- liveRegion.className = 'sr-only';
491
- document.body.appendChild(liveRegion);
492
-
493
- return (message) => {
494
- liveRegion.textContent = message;
495
- };
496
- };
497
-
498
- const announce = addAriaLive();
499
-
500
- // Annoncer les événements importants
501
- imageInput.addEventListener('change', () => {
502
- if (imageInput.files.length > 0) {
503
- announce('Image sélectionnée : ' + imageInput.files[0].name);
504
- }
505
- });
506
- };
507
-
508
- // Initialisation de l'accessibilité au chargement
509
- document.addEventListener('DOMContentLoaded', setupAccessibility);
510
  </script>
511
  </body>
512
  </html>
 
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Mariam AI - Analyse d'Image</title>
7
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/3.3.2/tailwind.min.css" rel="stylesheet">
8
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/9.1.6/marked.min.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
10
  <style>
11
+ /* Animation de loader */
12
  .loader {
13
  width: 48px;
14
  height: 48px;
15
+ border: 5px solid #e5e7eb;
16
+ border-top-color: #4f46e5;
17
  border-radius: 50%;
18
+ animation: spin 1s linear infinite;
 
 
19
  }
20
 
21
+ @keyframes spin {
22
+ to {
23
+ transform: rotate(360deg);
24
+ }
25
  }
26
 
27
+ /* Animation de fade-in */
28
  .fade-in {
29
+ animation: fadeIn 0.5s ease-in-out;
30
  }
31
 
32
  @keyframes fadeIn {
33
+ from {
34
+ opacity: 0;
35
+ }
36
+ to {
37
+ opacity: 1;
38
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  }
40
  </style>
41
  </head>
42
+ <body class="bg-gray-50 text-gray-800 min-h-screen flex flex-col">
43
+
44
+ <!-- Header -->
45
+ <header class="bg-white shadow-md">
46
+ <div class="max-w-7xl mx-auto px-4 py-6">
47
+ <h1 class="text-4xl font-extrabold text-indigo-600">Mariam AI</h1>
48
+ <p class="mt-2 text-sm text-gray-500">Un assistant intelligent pour l'analyse d'image et la rédaction de dissertations.</p>
49
+ </div>
50
+ </header>
51
+
52
+ <!-- Main Content -->
53
+ <main class="flex-1 flex items-center justify-center px-4 py-8">
54
+ <div class="bg-white shadow-lg rounded-lg w-full max-w-3xl p-8 space-y-8">
55
 
 
 
56
  <!-- Upload Section -->
57
+ <div>
58
+ <h2 class="text-2xl font-semibold text-gray-900">Téléversez votre image</h2>
59
+ <p class="text-sm text-gray-500">Glissez et déposez une image ou cliquez pour choisir un fichier à analyser.</p>
60
+ <form id="uploadForm" class="space-y-4 mt-4">
61
+ <div class="upload-zone border-2 border-dashed border-indigo-500 rounded-lg p-6 text-center transition hover:bg-indigo-50">
62
+ <input type="file" id="imageInput" accept="image/*" required class="hidden" onchange="handleImageUpload()">
63
+ <label for="imageInput" class="cursor-pointer">
64
+ <svg xmlns="http://www.w3.org/2000/svg" class="mx-auto h-12 w-12 text-indigo-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
65
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 16l4-4a3 3 0 014 0l4 4m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
66
+ </svg>
67
+ <span id="fileName" class="block mt-2 text-sm text-gray-600">Cliquez ou glissez une image ici</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  </label>
69
  </div>
70
 
71
+ <!-- Image Preview -->
72
+ <div id="imagePreviewContainer" class="hidden mt-4 text-center">
73
+ <h3 class="text-lg font-semibold text-gray-800 mb-2">Aperçu de l'image :</h3>
74
+ <img id="imagePreview" src="" alt="Aperçu de l'image" class="mx-auto max-w-xs rounded-lg shadow">
 
 
 
 
 
75
  </div>
76
 
77
+ <div class="text-center">
78
+ <button type="submit" class="w-full sm:w-auto px-6 py-3 bg-indigo-600 text-white font-medium rounded-md hover:bg-indigo-700 transition">
 
79
  Analyser l'image
80
  </button>
81
  </div>
82
  </form>
83
  </div>
84
 
85
+ <!-- Loading Indicator -->
86
+ <div id="loading" class="hidden text-center space-y-4">
87
+ <div class="loader mx-auto"></div>
88
+ <p class="text-gray-500">Analyse en cours, veuillez patienter...</p>
 
 
89
  </div>
90
 
91
  <!-- Results Section -->
92
+ <div id="results" class="hidden space-y-6 fade-in">
93
+ <!-- Dissertation -->
94
+ <div class="bg-gray-50 rounded-lg p-6 shadow">
95
+ <h2 class="text-xl font-bold text-gray-800">Dissertation</h2>
96
+ <div id="dissertationResult" class="prose prose-indigo max-w-none mt-4"></div>
97
+ </div>
98
+ <!-- Tableau Button -->
99
+ <div class="text-center">
100
+ <button id="showTableau" class="px-6 py-3 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 transition">
101
  Voir le tableau d'analyse
102
  </button>
 
 
 
 
 
 
 
 
 
 
 
103
  </div>
104
  </div>
105
+ </div>
106
+ </main>
107
 
108
  <script>
109
  let tableauContent = '';
 
 
 
 
 
 
 
 
 
 
 
110
 
111
+ // Met à jour le nom du fichier téléversé et affiche un aperçu de l'image
112
+ function handleImageUpload() {
113
+ const input = document.getElementById('imageInput');
114
+ const fileName = document.getElementById('fileName');
115
+ const previewContainer = document.getElementById('imagePreviewContainer');
116
+ const imagePreview = document.getElementById('imagePreview');
117
+
118
+ if (input.files.length > 0) {
119
+ const file = input.files[0];
120
+ fileName.textContent = file.name;
121
+
122
+ // Vérifie si le fichier est une image et génère l'aperçu
123
+ if (file.type.startsWith('image/')) {
124
+ const reader = new FileReader();
125
+ reader.onload = (e) => {
126
+ imagePreview.src = e.target.result;
127
+ previewContainer.classList.remove('hidden');
128
+ };
129
+ reader.readAsDataURL(file);
130
+ } else {
131
+ previewContainer.classList.add('hidden');
132
+ imagePreview.src = '';
133
+ Swal.fire('Erreur', 'Veuillez téléverser un fichier image valide.', 'error');
134
+ }
 
 
 
 
 
 
 
 
 
 
 
 
135
  } else {
136
+ previewContainer.classList.add('hidden');
137
+ imagePreview.src = '';
138
+ fileName.textContent = 'Cliquez ou glissez une image ici';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  }
140
  }
141
 
142
+ // Affiche le tableau dans une popup
143
+ document.getElementById('showTableau').addEventListener('click', () => {
144
+ Swal.fire({
145
+ title: 'Tableau d\'analyse',
146
+ html: marked.parse(tableauContent),
147
+ width: '80%',
148
+ customClass: {
149
+ htmlContainer: 'prose prose-indigo max-w-none'
150
+ }
151
+ });
152
  });
153
 
154
+ // Gestion du formulaire de téléversement
155
  document.getElementById('uploadForm').addEventListener('submit', async (e) => {
156
  e.preventDefault();
 
157
  const loading = document.getElementById('loading');
158
  const results = document.getElementById('results');
159
  const dissertationResult = document.getElementById('dissertationResult');
 
160
  const formData = new FormData();
161
+ formData.append('image', document.getElementById('imageInput').files[0]);
162
+
163
  loading.classList.remove('hidden');
164
  results.classList.add('hidden');
165
+
 
166
  try {
167
  const response = await fetch('/analyze', {
168
  method: 'POST',
169
+ body: formData
 
 
 
 
 
170
  });
171
+
172
  const data = await response.json();
 
173
  if (response.ok) {
174
  tableauContent = data.tableau;
175
  dissertationResult.innerHTML = marked.parse(data.dissertation);
176
  results.classList.remove('hidden');
 
177
  } else {
178
+ Swal.fire('Erreur', data.error, 'error');
 
 
 
 
179
  }
180
  } catch (error) {
181
+ Swal.fire('Erreur', 'Une erreur est survenue lors de l\'analyse.', 'error');
 
 
 
 
182
  } finally {
183
  loading.classList.add('hidden');
 
 
 
184
  }
185
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  </script>
187
  </body>
188
  </html>