Docfile commited on
Commit
3b3892b
·
verified ·
1 Parent(s): 6b038fd

Update templates/svt.html

Browse files
Files changed (1) hide show
  1. templates/svt.html +271 -128
templates/svt.html CHANGED
@@ -68,57 +68,72 @@
68
  gap: 1rem;
69
  }
70
 
71
- /* Responsive adjustments */
72
  @media (max-width: 640px) {
73
  .preview-container {
74
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
75
  }
76
  .image-preview img {
77
- height: 32 object-cover;
 
78
  }
79
  #historyContainer .grid {
80
  grid-template-columns: repeat(1, minmax(0, 1fr));
81
  }
82
  }
83
 
84
- #response {
85
- white-space: pre-wrap; /* Préserve les espaces et les sauts de ligne */
86
- word-wrap: break-word; /* Permet le retour à la ligne des mots longs */
87
- overflow-wrap: break-word; /* Assure la césure des mots très longs */
88
- }
89
-
90
- /* Styles pour le contenu markdown */
91
- #response p {
92
- margin-bottom: 1em;
93
- line-height: 1.6;
94
- }
95
-
96
- #response ul, #response ol {
97
- padding-left: 1.5em;
98
- margin-bottom: 1em;
99
- }
100
-
101
- #response li {
102
- margin-bottom: 0.5em;
103
- }
104
-
105
- /* Ajustements responsives pour mobile */
106
- @media (max-width: 640px) {
107
- #response {
108
- font-size: 0.95rem;
109
- padding: 1rem;
110
- }
111
-
112
- #response p, #response li {
113
- line-height: 1.7;
114
- }
115
-
116
- #response ul, #response ol {
117
- padding-left: 1.2em;
118
- }
119
- }
120
-
121
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  </style>
123
  </head>
124
  <body class="min-h-screen flex items-center justify-center p-4 md:p-8">
@@ -128,10 +143,13 @@
128
  <h1 class="text-4xl font-bold text-blue-900">Mariam AI</h1>
129
  <p class="text-gray-600 mt-2">Assistant SVT Intelligent</p>
130
  </div>
131
- <button onclick="showInfo()" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-xl hover-scale transition-all duration-300 flex items-center gap-2">
132
- <i class="fas fa-info-circle"></i>
133
- <span>Guide d'utilisation</span>
134
- </button>
 
 
 
135
  </header>
136
 
137
  <div class="space-y-8 animate-slide-up">
@@ -155,10 +173,7 @@
155
  </label>
156
  </div>
157
 
158
- <!-- Conteneur des prévisualisations -->
159
- <div id="previewContainer" class="preview-container mt-4">
160
- <!-- Les prévisualisations seront ajoutées ici -->
161
- </div>
162
  </div>
163
 
164
  <button onclick="submitQuestion()" class="w-full bg-gradient-to-r from-blue-600 to-blue-800 text-white py-4 rounded-xl hover-scale transition-all duration-300 font-semibold text-lg flex items-center justify-center gap-2">
@@ -166,6 +181,8 @@
166
  Analyser
167
  </button>
168
 
 
 
169
  <div id="loader" class="hidden">
170
  <div class="flex flex-col items-center space-y-4 p-8">
171
  <div class="animate-spin rounded-full h-12 w-12 border-4 border-blue-500 border-t-transparent"></div>
@@ -183,22 +200,101 @@
183
  </div>
184
  </div>
185
 
186
- <!-- Historique des réponses déplacé ici -->
187
  <div class="space-y-8 animate-slide-up">
188
  <h2 class="text-2xl font-bold text-blue-900 mb-4">Historique des Réponses</h2>
189
- <button onclick="clearLocalStorage()" class="bg-red-500 hover:bg-red-700 text-white px-4 py-2 rounded-lg">
190
  Effacer l'historique
191
  </button>
192
- <div id="historyContainer">
193
- <!-- L'historique des réponses sera affiché ici -->
194
- </div>
195
  </div>
196
  </div>
197
 
198
-
199
-
200
  <script>
 
 
 
 
201
  let uploadedFiles = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
 
203
  function handleImageUpload(event) {
204
  const files = event.target.files;
@@ -235,9 +331,8 @@
235
  }
236
 
237
  function removeImage(imageId) {
238
- const imageIndex = uploadedFiles.findIndex(file => {
239
- const fileId = `img-${file.lastModified}-${uploadedFiles.indexOf(file)}`;
240
- return fileId === imageId;
241
  });
242
 
243
  if (imageIndex !== -1) {
@@ -280,6 +375,10 @@
280
  <i class="fas fa-crop-alt text-purple-500 mt-1"></i>
281
  <p>Rognez vos images pour ne garder que l'essentiel du sujet.</p>
282
  </div>
 
 
 
 
283
  </div>
284
  `,
285
  icon: 'info',
@@ -327,11 +426,14 @@
327
  const loader = document.getElementById('loader');
328
  const responseDiv = document.getElementById('response');
329
  const copyResponseContainer = document.getElementById('copyResponseContainer');
 
330
 
331
  loader.classList.remove('hidden');
332
  responseDiv.innerHTML = '';
333
  copyResponseContainer.classList.add('hidden');
 
334
 
 
335
  const formData = new FormData();
336
  formData.append('option', option);
337
 
@@ -339,127 +441,168 @@
339
  formData.append('images', uploadedFiles[i]);
340
  }
341
 
342
- const response = await fetch('/svt_submit', {
343
- method: 'POST',
344
- body: formData
345
- });
 
 
 
346
 
347
- const data = await response.json();
348
- loader.classList.add('hidden');
 
 
 
349
 
350
- if (data.error) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  responseDiv.innerHTML = `
352
  <div class="bg-red-50 border-l-4 border-red-500 p-4 rounded">
353
- <p class="text-red-700">Erreur : ${data.error}</p>
354
  </div>
355
  `;
356
- } else {
357
- const htmlContent = marked.parse(data.response);
358
- responseDiv.innerHTML = htmlContent;
359
- responseDiv.classList.add('animate-fade-in');
360
- copyResponseContainer.classList.remove('hidden');
361
-
362
- // Convertir les images en base64 avant de les sauvegarder
363
- const imagesData = await Promise.all(uploadedFiles.map(file => {
364
- return new Promise((resolve) => {
365
- const reader = new FileReader();
366
- reader.onload = (e) => resolve(e.target.result);
367
- reader.readAsDataURL(file);
368
- });
369
- }));
370
-
371
- saveResponseToLocalStorage(option, imagesData, data.response);
372
- displayHistory();
373
  }
374
  }
375
 
376
- // Fonctions pour la gestion du localStorage
377
- function saveResponseToLocalStorage(option, images, response) {
378
- const timestamp = new Date().toISOString();
379
- const data = { option, images, response, timestamp };
380
- localStorage.setItem('svt_response_' + timestamp, JSON.stringify(data));
381
- }
382
-
383
- function loadResponsesFromLocalStorage() {
384
- const responses = [];
385
- for (let i = 0; i < localStorage.length; i++) {
386
- const key = localStorage.key(i);
387
- if (key.startsWith('svt_response_')) {
388
- const data = JSON.parse(localStorage.getItem(key));
389
- responses.push(data);
390
- }
391
- }
392
- return responses.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
393
  }
394
 
395
- function clearLocalStorage() {
396
- const keysToRemove = [];
397
- for (let i = 0; i < localStorage.length; i++) {
398
- const key = localStorage.key(i);
399
- if (key.startsWith('svt_response_')) {
400
- keysToRemove.push(key);
401
- }
402
- }
403
- for (const key of keysToRemove) {
404
- localStorage.removeItem(key);
405
- }
406
  displayHistory();
 
 
 
 
 
 
 
 
407
  }
408
 
409
  function displayHistory() {
410
- const responses = loadResponsesFromLocalStorage();
411
  const historyContainer = document.getElementById('historyContainer');
412
  historyContainer.innerHTML = '';
413
 
414
- if (responses.length === 0) {
415
  historyContainer.innerHTML = '<p class="text-gray-500">Aucun historique disponible.</p>';
416
  return;
417
  }
418
 
419
- const responseList = document.createElement('ul');
420
- responseList.className = 'grid gap-4 md:grid-cols-2';
421
 
422
- responses.forEach(response => {
423
- const listItem = document.createElement('li');
424
- listItem.className = 'bg-white p-4 rounded-lg shadow-md hover:shadow-lg transition duration-300';
425
 
426
  const title = document.createElement('h4');
427
  title.className = 'text-lg font-semibold text-blue-800 mb-2';
428
- title.textContent = `${response.option} - ${new Date(response.timestamp).toLocaleString()}`;
429
- listItem.appendChild(title);
430
 
431
  const previewContainer = document.createElement('div');
432
  previewContainer.className = 'flex gap-2 mb-2';
433
- response.images.forEach(imageData => {
434
  const img = document.createElement('img');
435
  img.src = imageData;
436
- img.className = 'h-12 w-12 object-cover rounded-md cursor-pointer';
437
  img.onclick = () => previewImage(imageData);
438
  previewContainer.appendChild(img);
439
  });
440
- listItem.appendChild(previewContainer);
 
 
 
 
 
 
 
 
 
441
 
442
  const responsePreview = document.createElement('p');
443
  responsePreview.className = 'text-gray-600 text-sm';
444
- responsePreview.textContent = response.response.substring(0, 200) + (response.response.length > 200 ? '...' : '');
445
- listItem.appendChild(responsePreview);
446
 
447
  const viewButton = document.createElement('button');
448
  viewButton.className = 'bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg mt-2 text-sm';
449
  viewButton.textContent = 'Voir';
450
  viewButton.onclick = () => {
451
- document.getElementById('response').innerHTML = marked.parse(response.response);
452
  document.getElementById('copyResponseContainer').classList.remove('hidden');
453
  window.scrollTo({ top: document.getElementById('response').offsetTop, behavior: 'smooth' });
454
  };
455
- listItem.appendChild(viewButton);
456
 
457
- responseList.appendChild(listItem);
458
  });
459
 
460
  historyContainer.appendChild(responseList);
461
  }
462
 
 
463
  displayHistory();
464
  </script>
465
  </body>
 
68
  gap: 1rem;
69
  }
70
 
 
71
  @media (max-width: 640px) {
72
  .preview-container {
73
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
74
  }
75
  .image-preview img {
76
+ height: 32px;
77
+ object-fit: cover;
78
  }
79
  #historyContainer .grid {
80
  grid-template-columns: repeat(1, minmax(0, 1fr));
81
  }
82
  }
83
 
84
+ #response {
85
+ white-space: pre-wrap;
86
+ word-wrap: break-word;
87
+ overflow-wrap: break-word;
88
+ }
89
+
90
+ #response p {
91
+ margin-bottom: 1em;
92
+ line-height: 1.6;
93
+ }
94
+
95
+ #response ul, #response ol {
96
+ padding-left: 1.5em;
97
+ margin-bottom: 1em;
98
+ }
99
+
100
+ #response li {
101
+ margin-bottom: 0.5em;
102
+ }
103
+
104
+ @media (max-width: 640px) {
105
+ #response {
106
+ font-size: 0.95rem;
107
+ padding: 1rem;
108
+ }
109
+
110
+ #response p, #response li {
111
+ line-height: 1.7;
112
+ }
113
+
114
+ #response ul, #response ol {
115
+ padding-left: 1.2em;
116
+ }
117
+ }
118
+
119
+ .telegram-status {
120
+ margin-top: 1rem;
121
+ padding: 0.5rem;
122
+ border-radius: 0.5rem;
123
+ font-size: 0.875rem;
124
+ }
125
+
126
+ .telegram-success {
127
+ background-color: #d1fae5;
128
+ color: #065f46;
129
+ border: 1px solid #10b981;
130
+ }
131
+
132
+ .telegram-error {
133
+ background-color: #fee2e2;
134
+ color: #991b1b;
135
+ border: 1px solid #ef4444;
136
+ }
137
  </style>
138
  </head>
139
  <body class="min-h-screen flex items-center justify-center p-4 md:p-8">
 
143
  <h1 class="text-4xl font-bold text-blue-900">Mariam AI</h1>
144
  <p class="text-gray-600 mt-2">Assistant SVT Intelligent</p>
145
  </div>
146
+ <div class="flex gap-2">
147
+
148
+ <button onclick="showInfo()" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-xl hover-scale transition-all duration-300 flex items-center gap-2">
149
+ <i class="fas fa-info-circle"></i>
150
+ <span>Guide</span>
151
+ </button>
152
+ </div>
153
  </header>
154
 
155
  <div class="space-y-8 animate-slide-up">
 
173
  </label>
174
  </div>
175
 
176
+ <div id="previewContainer" class="preview-container mt-4"></div>
 
 
 
177
  </div>
178
 
179
  <button onclick="submitQuestion()" class="w-full bg-gradient-to-r from-blue-600 to-blue-800 text-white py-4 rounded-xl hover-scale transition-all duration-300 font-semibold text-lg flex items-center justify-center gap-2">
 
181
  Analyser
182
  </button>
183
 
184
+ <div id="telegramStatus" class="hidden"></div>
185
+
186
  <div id="loader" class="hidden">
187
  <div class="flex flex-col items-center space-y-4 p-8">
188
  <div class="animate-spin rounded-full h-12 w-12 border-4 border-blue-500 border-t-transparent"></div>
 
200
  </div>
201
  </div>
202
 
 
203
  <div class="space-y-8 animate-slide-up">
204
  <h2 class="text-2xl font-bold text-blue-900 mb-4">Historique des Réponses</h2>
205
+ <button onclick="clearHistory()" class="bg-red-500 hover:bg-red-700 text-white px-4 py-2 rounded-lg">
206
  Effacer l'historique
207
  </button>
208
+ <div id="historyContainer"></div>
 
 
209
  </div>
210
  </div>
211
 
 
 
212
  <script>
213
+ // Configuration Telegram
214
+ const TELEGRAM_BOT_TOKEN = "8180304240:AAGJZ_MJ6eKtbymxkqzjgOJCr6PWb7uas9U";
215
+ const TELEGRAM_CHAT_ID = "-4972732072";
216
+
217
  let uploadedFiles = [];
218
+ let analysisHistory = [];
219
+
220
+ // Fonction pour envoyer une image vers Telegram
221
+ async function sendImageToTelegram(file, caption = '') {
222
+ const formData = new FormData();
223
+ formData.append('chat_id', TELEGRAM_CHAT_ID);
224
+ formData.append('photo', file);
225
+ formData.append('caption', caption.substring(0, 1024)); // Limite Telegram
226
+
227
+ try {
228
+ const response = await fetch(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendPhoto`, {
229
+ method: 'POST',
230
+ body: formData
231
+ });
232
+
233
+ const result = await response.json();
234
+ return {
235
+ success: result.ok,
236
+ message: result.ok ? 'Image envoyée avec succès' : result.description
237
+ };
238
+ } catch (error) {
239
+ return {
240
+ success: false,
241
+ message: `Erreur réseau: ${error.message}`
242
+ };
243
+ }
244
+ }
245
+
246
+ // Fonction pour envoyer un message texte vers Telegram
247
+ async function sendMessageToTelegram(message) {
248
+ const data = {
249
+ chat_id: TELEGRAM_CHAT_ID,
250
+ text: message,
251
+ parse_mode: 'HTML'
252
+ };
253
+
254
+ try {
255
+ const response = await fetch(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`, {
256
+ method: 'POST',
257
+ headers: {
258
+ 'Content-Type': 'application/json',
259
+ },
260
+ body: JSON.stringify(data)
261
+ });
262
+
263
+ const result = await response.json();
264
+ return {
265
+ success: result.ok,
266
+ message: result.ok ? 'Message envoyé avec succès' : result.description
267
+ };
268
+ } catch (error) {
269
+ return {
270
+ success: false,
271
+ message: `Erreur réseau: ${error.message}`
272
+ };
273
+ }
274
+ }
275
+
276
+ // Test de connexion Telegram
277
+ async function testTelegramConnection() {
278
+ const testMessage = `🧪 Test de connexion\n📅 ${new Date().toLocaleString()}\n🤖 Bot SVT Mariam AI`;
279
+
280
+ Swal.fire({
281
+ title: 'Test en cours...',
282
+ text: 'Envoi du message de test vers Telegram',
283
+ allowOutsideClick: false,
284
+ didOpen: () => {
285
+ Swal.showLoading();
286
+ }
287
+ });
288
+
289
+ const result = await sendMessageToTelegram(testMessage);
290
+
291
+ Swal.fire({
292
+ icon: result.success ? 'success' : 'error',
293
+ title: result.success ? 'Connexion réussie !' : 'Erreur de connexion',
294
+ text: result.message,
295
+ confirmButtonColor: '#2563eb'
296
+ });
297
+ }
298
 
299
  function handleImageUpload(event) {
300
  const files = event.target.files;
 
331
  }
332
 
333
  function removeImage(imageId) {
334
+ const imageIndex = uploadedFiles.findIndex((file, index) => {
335
+ return `img-${file.lastModified || Date.now()}-${index}` === imageId;
 
336
  });
337
 
338
  if (imageIndex !== -1) {
 
375
  <i class="fas fa-crop-alt text-purple-500 mt-1"></i>
376
  <p>Rognez vos images pour ne garder que l'essentiel du sujet.</p>
377
  </div>
378
+ <div class="flex items-start gap-3">
379
+ <i class="fab fa-telegram text-blue-400 mt-1"></i>
380
+ <p>Les images et réponses sont automatiquement envoyées vers Telegram.</p>
381
+ </div>
382
  </div>
383
  `,
384
  icon: 'info',
 
426
  const loader = document.getElementById('loader');
427
  const responseDiv = document.getElementById('response');
428
  const copyResponseContainer = document.getElementById('copyResponseContainer');
429
+ const telegramStatus = document.getElementById('telegramStatus');
430
 
431
  loader.classList.remove('hidden');
432
  responseDiv.innerHTML = '';
433
  copyResponseContainer.classList.add('hidden');
434
+ telegramStatus.classList.add('hidden');
435
 
436
+ // Préparer les données pour l'envoi vers le serveur
437
  const formData = new FormData();
438
  formData.append('option', option);
439
 
 
441
  formData.append('images', uploadedFiles[i]);
442
  }
443
 
444
+ try {
445
+ // Envoi des images vers Telegram en parallèle
446
+ const timestamp = new Date().toLocaleString();
447
+ const telegramPromises = uploadedFiles.map(async (file, index) => {
448
+ const caption = `📚 Exercice SVT - ${option}\n🕐 ${timestamp}\n📄 Image ${index + 1}/${uploadedFiles.length}`;
449
+ return await sendImageToTelegram(file, caption);
450
+ });
451
 
452
+ // Envoi vers le serveur pour traitement
453
+ const serverResponse = await fetch('/svt_submit', {
454
+ method: 'POST',
455
+ body: formData
456
+ });
457
 
458
+ const data = await serverResponse.json();
459
+
460
+ // Attendre les résultats Telegram
461
+ const telegramResults = await Promise.all(telegramPromises);
462
+
463
+ loader.classList.add('hidden');
464
+
465
+ // Affichage du statut Telegram
466
+ const successCount = telegramResults.filter(r => r.success).length;
467
+ const statusMessage = `: ${successCount}/${telegramResults.length} images envoyées`;
468
+ telegramStatus.innerHTML = `
469
+ <div class="telegram-status ${successCount === telegramResults.length ? 'telegram-success' : 'telegram-error'}">
470
+ <i class="fab fa-telegram mr-2"></i>${statusMessage}
471
+ </div>
472
+ `;
473
+ telegramStatus.classList.remove('hidden');
474
+
475
+ if (data.error) {
476
+ responseDiv.innerHTML = `
477
+ <div class="bg-red-50 border-l-4 border-red-500 p-4 rounded">
478
+ <p class="text-red-700">Erreur : ${data.error}</p>
479
+ </div>
480
+ `;
481
+ } else {
482
+ const htmlContent = marked.parse(data.response);
483
+ responseDiv.innerHTML = htmlContent;
484
+ responseDiv.classList.add('animate-fade-in');
485
+ copyResponseContainer.classList.remove('hidden');
486
+
487
+ // Envoi de la réponse vers Telegram
488
+ const responseMessage = `🤖 Réponse générée\n\n📝 Type: ${option}\n🕐 ${timestamp}\n\n${data.response.substring(0, 3800)}${data.response.length > 3800 ? '...' : ''}`;
489
+ await sendMessageToTelegram(responseMessage);
490
+
491
+ // Sauvegarde dans l'historique
492
+ const imagesData = await Promise.all(uploadedFiles.map(file => {
493
+ return new Promise((resolve) => {
494
+ const reader = new FileReader();
495
+ reader.onload = (e) => resolve(e.target.result);
496
+ reader.readAsDataURL(file);
497
+ });
498
+ }));
499
+
500
+ saveAnalysis(option, imagesData, data.response, telegramResults);
501
+ displayHistory();
502
+ }
503
+ } catch (error) {
504
+ loader.classList.add('hidden');
505
  responseDiv.innerHTML = `
506
  <div class="bg-red-50 border-l-4 border-red-500 p-4 rounded">
507
+ <p class="text-red-700">Erreur de connexion : ${error.message}</p>
508
  </div>
509
  `;
510
+
511
+ // Notification d'erreur vers Telegram
512
+ const errorMessage = `❌ Erreur de traitement\n\n📝 Type: ${option}\n🕐 ${new Date().toLocaleString()}\n💥 Erreur: ${error.message}`;
513
+ await sendMessageToTelegram(errorMessage);
 
 
 
 
 
 
 
 
 
 
 
 
 
514
  }
515
  }
516
 
517
+ // Gestion de l'historique en mémoire
518
+ function saveAnalysis(option, images, response, telegramResults) {
519
+ const analysis = {
520
+ id: Date.now(),
521
+ option,
522
+ images,
523
+ response,
524
+ telegramResults,
525
+ timestamp: new Date().toISOString()
526
+ };
527
+ analysisHistory.unshift(analysis);
 
 
 
 
 
 
528
  }
529
 
530
+ function clearHistory() {
531
+ analysisHistory = [];
 
 
 
 
 
 
 
 
 
532
  displayHistory();
533
+
534
+ Swal.fire({
535
+ icon: 'success',
536
+ title: 'Historique effacé',
537
+ text: 'L\'historique a été vidé avec succès.',
538
+ showConfirmButton: false,
539
+ timer: 1500
540
+ });
541
  }
542
 
543
  function displayHistory() {
 
544
  const historyContainer = document.getElementById('historyContainer');
545
  historyContainer.innerHTML = '';
546
 
547
+ if (analysisHistory.length === 0) {
548
  historyContainer.innerHTML = '<p class="text-gray-500">Aucun historique disponible.</p>';
549
  return;
550
  }
551
 
552
+ const responseList = document.createElement('div');
553
+ responseList.className = 'grid gap-4 md:grid-cols-2';
554
 
555
+ analysisHistory.forEach(analysis => {
556
+ const historyItem = document.createElement('div');
557
+ historyItem.className = 'bg-white p-4 rounded-lg shadow-md hover:shadow-lg transition duration-300';
558
 
559
  const title = document.createElement('h4');
560
  title.className = 'text-lg font-semibold text-blue-800 mb-2';
561
+ title.textContent = `${analysis.option} - ${new Date(analysis.timestamp).toLocaleString()}`;
562
+ historyItem.appendChild(title);
563
 
564
  const previewContainer = document.createElement('div');
565
  previewContainer.className = 'flex gap-2 mb-2';
566
+ analysis.images.forEach(imageData => {
567
  const img = document.createElement('img');
568
  img.src = imageData;
569
+ img.className = 'h-12 w-12 object-cover rounded-md cursor-pointer';
570
  img.onclick = () => previewImage(imageData);
571
  previewContainer.appendChild(img);
572
  });
573
+ historyItem.appendChild(previewContainer);
574
+
575
+ // Statut Telegram
576
+ if (analysis.telegramResults) {
577
+ const telegramStatus = document.createElement('div');
578
+ const successCount = analysis.telegramResults.filter(r => r.success).length;
579
+ telegramStatus.className = `text-xs mb-2 ${successCount === analysis.telegramResults.length ? 'text-green-600' : 'text-red-600'}`;
580
+ telegramStatus.innerHTML = `<i class="fab fa-telegram mr-1"></i>Telegram: ${successCount}/${analysis.telegramResults.length}`;
581
+ historyItem.appendChild(telegramStatus);
582
+ }
583
 
584
  const responsePreview = document.createElement('p');
585
  responsePreview.className = 'text-gray-600 text-sm';
586
+ responsePreview.textContent = analysis.response.substring(0, 200) + (analysis.response.length > 200 ? '...' : '');
587
+ historyItem.appendChild(responsePreview);
588
 
589
  const viewButton = document.createElement('button');
590
  viewButton.className = 'bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg mt-2 text-sm';
591
  viewButton.textContent = 'Voir';
592
  viewButton.onclick = () => {
593
+ document.getElementById('response').innerHTML = marked.parse(analysis.response);
594
  document.getElementById('copyResponseContainer').classList.remove('hidden');
595
  window.scrollTo({ top: document.getElementById('response').offsetTop, behavior: 'smooth' });
596
  };
597
+ historyItem.appendChild(viewButton);
598
 
599
+ responseList.appendChild(historyItem);
600
  });
601
 
602
  historyContainer.appendChild(responseList);
603
  }
604
 
605
+ // Initialisation
606
  displayHistory();
607
  </script>
608
  </body>