Docfile commited on
Commit
8f9eea8
·
verified ·
1 Parent(s): 063d916

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +44 -60
templates/index.html CHANGED
@@ -136,11 +136,10 @@
136
  <span class="text-sm text-gray-700 group-hover:text-indigo-600">Document iconographique (Image, Photo, Dessin...) avec méthodologie.</span>
137
  </label>
138
  <label class="relative flex items-center group cursor-pointer p-3 border border-gray-200 rounded-lg hover:bg-indigo-50 transition-colors w-full">
139
- <input type="radio" name="fileType" value="text_image" <!-- MODIFIED: value to distinguish if needed, or keep "text" if backend logic depends on it -->
140
  class="peer sr-only file-type-radio">
141
  <div class="w-5 h-5 mr-3 border-2 border-gray-300 rounded-full flex-shrink-0 peer-checked:border-indigo-500 peer-checked:bg-indigo-500 transition-all"></div>
142
- <!-- MODIFIED LABEL -->
143
- <span class="text-sm text-gray-700 group-hover:text-indigo-600">Image d'un document textuel (ex: capture d'écran de texte) avec méthodologie.</span>
144
  </label>
145
  </div>
146
  </div>
@@ -149,7 +148,7 @@
149
  <div class="mb-6">
150
  <label class="block text-base font-medium text-gray-700 mb-3">2. Sélectionnez votre fichier</label>
151
  <div id="upload-zone" class="upload-zone border-2 border-dashed border-gray-300 rounded-xl p-6 text-center cursor-pointer transition-all duration-300 relative overflow-hidden">
152
- <input id="file-upload" name="file" type="file" class="sr-only" accept="image/*"> <!-- Default accept to image/* -->
153
  <div class="space-y-3">
154
  <div class="w-16 h-16 mx-auto rounded-full bg-indigo-100 flex items-center justify-center border-4 border-white shadow-sm">
155
  <svg class="w-8 h-8 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -163,7 +162,7 @@
163
  <span class="text-gray-500"> ou </span>
164
  <label for="file-upload" class="cursor-pointer text-indigo-600 hover:text-indigo-500 font-medium">cliquez pour sélectionner</label>
165
  </div>
166
- <p class="text-xs text-gray-500" id="file-types-info">Images (PNG, JPG, GIF, WEBP) - Max 16MB</p> <!-- Default info text -->
167
  </div>
168
  </div>
169
  </div>
@@ -173,7 +172,7 @@
173
  <h3 class="text-base font-medium text-gray-800 mb-3">Aperçu</h3>
174
  <div class="preview-container border rounded-lg p-4 bg-gray-50 max-h-72 overflow-auto relative">
175
  <img id="image-preview" class="max-w-full h-auto hidden rounded block mx-auto" alt="Aperçu Image">
176
- <pre id="text-preview" class="text-sm text-gray-700 whitespace-pre-wrap hidden bg-white p-3 rounded shadow-inner"></pre> <!-- Kept for potential future use, but will be hidden for text_image -->
177
  <p id="file-info" class="text-xs text-gray-500 mt-2 text-center"></p>
178
  <button id="remove-file-button" class="absolute top-2 right-2 bg-red-100 text-red-600 hover:bg-red-200 rounded-full p-1 text-xs hidden" title="Retirer le fichier">
179
  <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
@@ -228,7 +227,7 @@
228
  const fileInput = document.getElementById('file-upload');
229
  const preview = document.getElementById('preview');
230
  const imagePreview = document.getElementById('image-preview');
231
- const textPreview = document.getElementById('text-preview'); // Still used for clearing
232
  const fileInfo = document.getElementById('file-info');
233
  const removeFileButton = document.getElementById('remove-file-button');
234
  const submitButton = document.getElementById('submit-button');
@@ -241,10 +240,7 @@
241
  const fileTypesInfo = document.getElementById('file-types-info');
242
 
243
  let selectedFile = null;
244
- const imageMimeTypes = "image/png, image/jpeg, image/gif, image/webp";
245
- const imageInfoText = "Images (PNG, JPG, GIF, WEBP) - Max 16MB";
246
 
247
- // Configure marked with Prism check
248
  marked.setOptions({
249
  breaks: true,
250
  gfm: true,
@@ -256,14 +252,13 @@
256
  return Prism.highlight(code, Prism.languages[lang], lang);
257
  } catch (error) {
258
  console.warn(`Prism highlighting failed for language ${lang}:`, error)
259
- return code;
260
  }
261
  }
262
  return code;
263
  }
264
  });
265
 
266
- // --- Helper Functions ---
267
  function showLoading(isLoading) {
268
  if (isLoading) {
269
  submitButtonText.classList.add('hidden');
@@ -281,57 +276,49 @@
281
  fileInput.value = '';
282
  preview.classList.add('hidden');
283
  imagePreview.classList.add('hidden');
284
- textPreview.classList.add('hidden');
285
  imagePreview.src = '#';
286
- textPreview.textContent = '';
287
  fileInfo.textContent = '';
288
  removeFileButton.classList.add('hidden');
289
  results.classList.add('hidden');
290
  analysisContent.innerHTML = '<p class="text-gray-500">L\'analyse apparaîtra ici...</p>';
291
  submitButton.disabled = true;
292
  showLoading(false);
293
- updateAcceptAttribute(); // Ensure accept attribute is correct on reset
294
  }
295
 
296
  function updateAcceptAttribute() {
297
- const selectedType = document.querySelector('input[name="fileType"]:checked').value;
298
- // MODIFICATION: Both options now accept images
299
- fileInput.accept = imageMimeTypes;
300
- fileTypesInfo.textContent = imageInfoText;
301
 
302
  if (selectedFile) {
303
- // Now, both types expect an image. If a file was selected, it must be an image.
304
  const isImage = selectedFile.type.startsWith('image/');
305
- if(!isImage) {
 
 
306
  resetUI();
307
  Swal.fire({
308
  icon: 'warning',
309
  title: 'Type de fichier incompatible',
310
- text: 'Seuls les fichiers images sont acceptés. Veuillez resélectionner votre fichier.',
311
  });
312
  }
313
  }
314
  }
315
 
316
-
317
- // --- Event Listeners ---
318
  fileTypeRadios.forEach(radio => {
319
  radio.addEventListener('change', () => {
320
- // No need to call updateAcceptAttribute if it always accepts images,
321
- // but if you changed the radio value to be different, you might re-evaluate.
322
- // For now, we'll just check if a file is selected and if it's still valid (image)
323
- // Or, more simply, just reset if type changes and a file is loaded, to force re-selection
324
- if (selectedFile) {
325
- resetUI();
326
- Swal.fire({
327
- icon: 'info',
328
- title: 'Type de document changé',
329
- text: 'Le type de méthodologie a été modifié. Veuillez resélectionner votre fichier image.',
330
- });
331
- }
332
- updateAcceptAttribute(); // Still useful to call for consistency, though its effect is now static on accept types
333
  });
334
  });
 
335
  uploadZone.addEventListener('click', () => fileInput.click());
336
  uploadZone.addEventListener('dragover', (e) => {
337
  e.preventDefault();
@@ -357,10 +344,8 @@
357
  copyAnalysisButton.addEventListener('click', copyAnalysisToClipboard);
358
 
359
 
360
- // --- Core Logic Functions ---
361
-
362
  function handleFileSelection(file) {
363
- // const fileType = document.querySelector('input[name="fileType"]:checked').value; // fileType radio value
364
  const maxFileSize = 16 * 1024 * 1024;
365
 
366
  if (file.size > maxFileSize) {
@@ -375,11 +360,11 @@
375
 
376
  const allowedImageTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/webp'];
377
 
378
- // MODIFICATION: Always validate as image
379
  if (!allowedImageTypes.includes(file.type)) {
380
  const isImageTypeByName = /\.(jpe?g|png|gif|webp)$/i.test(file.name);
381
- if (!isImageTypeByName) {
382
- Swal.fire({
383
  icon: 'error',
384
  title: 'Type de fichier invalide',
385
  text: 'Veuillez sélectionner une image (PNG, JPG, GIF, WEBP).'
@@ -389,6 +374,7 @@
389
  }
390
  }
391
 
 
392
  selectedFile = file;
393
  preview.classList.remove('hidden');
394
  preview.classList.add('fade-in');
@@ -397,30 +383,29 @@
397
  fileInfo.textContent = `${file.name} (${(file.size / 1024).toFixed(1)} Ko)`;
398
  removeFileButton.classList.remove('hidden');
399
 
400
- // MODIFICATION: Always show image preview
401
  imagePreview.classList.remove('hidden');
402
  textPreview.classList.add('hidden'); // Ensure text preview is hidden
403
  textPreview.textContent = ''; // Clear any old text preview content
 
404
  const reader = new FileReader();
405
  reader.onload = (e) => imagePreview.src = e.target.result;
406
  reader.readAsDataURL(file);
407
-
408
  submitButton.disabled = false;
409
  }
410
 
411
  function handleSubmit() {
412
  if (!selectedFile) {
413
- Swal.fire('Aucun fichier', 'Veuillez sélectionner un fichier image avant de lancer l\'analyse.', 'warning');
414
  return;
415
  }
416
 
417
- // This 'fileType' value ('image' or 'text_image') will be sent to the backend.
418
- // The backend can use this to apply different analysis methodologies
419
- // even though the uploaded file is always an image.
420
  const fileTypeForBackend = document.querySelector('input[name="fileType"]:checked').value;
421
  const formData = new FormData();
422
- formData.append('file', selectedFile);
423
- formData.append('fileType', fileTypeForBackend); // Send the selected radio value
424
 
425
  showLoading(true);
426
  results.classList.add('hidden');
@@ -467,7 +452,8 @@
467
  text: error.message || 'Une erreur inconnue est survenue.',
468
  });
469
  console.error('Error during analysis:', error);
470
- submitButton.disabled = false;
 
471
  });
472
  }
473
 
@@ -487,9 +473,9 @@
487
  .replace(/<\/p>/gi, '\n')
488
  .replace(/<\/li>/gi, '\n')
489
  .replace(/<\/(h[1-6])>/gi, '\n\n')
490
- .replace(/<pre.*?><code.*?>([\s\S]*?)<\/code><\/pre>/gi, '\n```\n$1\n```\n')
491
- .replace(/<[^>]+>/g, '')
492
- .replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&')
493
  .trim();
494
 
495
  navigator.clipboard.writeText(textToCopy)
@@ -498,8 +484,8 @@
498
  icon: 'success',
499
  title: 'Copié !',
500
  text: 'L\'analyse a été copiée dans le presse-papiers.',
501
- timer: 1500,
502
- showConfirmButton: false
503
  });
504
  })
505
  .catch(err => {
@@ -512,9 +498,7 @@
512
  });
513
  }
514
 
515
- // --- Initial Setup ---
516
- updateAcceptAttribute(); // Call once to set initial state
517
- resetUI(); // Call resetUI which also calls updateAcceptAttribute
518
 
519
  }); // End DOMContentLoaded
520
  </script>
 
136
  <span class="text-sm text-gray-700 group-hover:text-indigo-600">Document iconographique (Image, Photo, Dessin...) avec méthodologie.</span>
137
  </label>
138
  <label class="relative flex items-center group cursor-pointer p-3 border border-gray-200 rounded-lg hover:bg-indigo-50 transition-colors w-full">
139
+ <input type="radio" name="fileType" value="text"
140
  class="peer sr-only file-type-radio">
141
  <div class="w-5 h-5 mr-3 border-2 border-gray-300 rounded-full flex-shrink-0 peer-checked:border-indigo-500 peer-checked:bg-indigo-500 transition-all"></div>
142
+ <span class="text-sm text-gray-700 group-hover:text-indigo-600">Analyse de texte à partir d'une image (Image, Photo de texte...) avec méthodologie.</span>
 
143
  </label>
144
  </div>
145
  </div>
 
148
  <div class="mb-6">
149
  <label class="block text-base font-medium text-gray-700 mb-3">2. Sélectionnez votre fichier</label>
150
  <div id="upload-zone" class="upload-zone border-2 border-dashed border-gray-300 rounded-xl p-6 text-center cursor-pointer transition-all duration-300 relative overflow-hidden">
151
+ <input id="file-upload" name="file" type="file" class="sr-only" accept="image/*">
152
  <div class="space-y-3">
153
  <div class="w-16 h-16 mx-auto rounded-full bg-indigo-100 flex items-center justify-center border-4 border-white shadow-sm">
154
  <svg class="w-8 h-8 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
 
162
  <span class="text-gray-500"> ou </span>
163
  <label for="file-upload" class="cursor-pointer text-indigo-600 hover:text-indigo-500 font-medium">cliquez pour sélectionner</label>
164
  </div>
165
+ <p class="text-xs text-gray-500" id="file-types-info">Images (PNG, JPG, GIF, WEBP) - Max 16MB</p>
166
  </div>
167
  </div>
168
  </div>
 
172
  <h3 class="text-base font-medium text-gray-800 mb-3">Aperçu</h3>
173
  <div class="preview-container border rounded-lg p-4 bg-gray-50 max-h-72 overflow-auto relative">
174
  <img id="image-preview" class="max-w-full h-auto hidden rounded block mx-auto" alt="Aperçu Image">
175
+ <pre id="text-preview" class="text-sm text-gray-700 whitespace-pre-wrap hidden bg-white p-3 rounded shadow-inner"></pre>
176
  <p id="file-info" class="text-xs text-gray-500 mt-2 text-center"></p>
177
  <button id="remove-file-button" class="absolute top-2 right-2 bg-red-100 text-red-600 hover:bg-red-200 rounded-full p-1 text-xs hidden" title="Retirer le fichier">
178
  <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
 
227
  const fileInput = document.getElementById('file-upload');
228
  const preview = document.getElementById('preview');
229
  const imagePreview = document.getElementById('image-preview');
230
+ const textPreview = document.getElementById('text-preview'); // Still keep the element for completeness
231
  const fileInfo = document.getElementById('file-info');
232
  const removeFileButton = document.getElementById('remove-file-button');
233
  const submitButton = document.getElementById('submit-button');
 
240
  const fileTypesInfo = document.getElementById('file-types-info');
241
 
242
  let selectedFile = null;
 
 
243
 
 
244
  marked.setOptions({
245
  breaks: true,
246
  gfm: true,
 
252
  return Prism.highlight(code, Prism.languages[lang], lang);
253
  } catch (error) {
254
  console.warn(`Prism highlighting failed for language ${lang}:`, error)
255
+ return code;
256
  }
257
  }
258
  return code;
259
  }
260
  });
261
 
 
262
  function showLoading(isLoading) {
263
  if (isLoading) {
264
  submitButtonText.classList.add('hidden');
 
276
  fileInput.value = '';
277
  preview.classList.add('hidden');
278
  imagePreview.classList.add('hidden');
279
+ textPreview.classList.add('hidden'); // Ensure text preview is hidden
280
  imagePreview.src = '#';
281
+ textPreview.textContent = ''; // Clear text preview content
282
  fileInfo.textContent = '';
283
  removeFileButton.classList.add('hidden');
284
  results.classList.add('hidden');
285
  analysisContent.innerHTML = '<p class="text-gray-500">L\'analyse apparaîtra ici...</p>';
286
  submitButton.disabled = true;
287
  showLoading(false);
288
+ updateAcceptAttribute(); // Call this to set initial accept types
289
  }
290
 
291
  function updateAcceptAttribute() {
292
+ // Both options now accept images
293
+ fileInput.accept = "image/png, image/jpeg, image/gif, image/webp";
294
+ fileTypesInfo.textContent = "Images (PNG, JPG, GIF, WEBP) - Max 16MB";
 
295
 
296
  if (selectedFile) {
297
+ // Check if the currently selected file is an image
298
  const isImage = selectedFile.type.startsWith('image/');
299
+ if (!isImage) {
300
+ // If a non-image file was somehow selected (e.g., before this logic was in place, or if user bypasses JS)
301
+ // and then the radio changes, reset.
302
  resetUI();
303
  Swal.fire({
304
  icon: 'warning',
305
  title: 'Type de fichier incompatible',
306
+ text: 'Seuls les fichiers image (PNG, JPG, GIF, WEBP) sont acceptés. Veuillez resélectionner votre fichier.',
307
  });
308
  }
309
  }
310
  }
311
 
 
 
312
  fileTypeRadios.forEach(radio => {
313
  radio.addEventListener('change', () => {
314
+ // Update accept attribute (though it's always images now)
315
+ updateAcceptAttribute();
316
+ // If a file is selected, and it's not an image (which shouldn't happen with current validation),
317
+ // the updateAcceptAttribute will handle resetting.
318
+ // Otherwise, no need to clear selection if it's already an image.
 
 
 
 
 
 
 
 
319
  });
320
  });
321
+
322
  uploadZone.addEventListener('click', () => fileInput.click());
323
  uploadZone.addEventListener('dragover', (e) => {
324
  e.preventDefault();
 
344
  copyAnalysisButton.addEventListener('click', copyAnalysisToClipboard);
345
 
346
 
 
 
347
  function handleFileSelection(file) {
348
+ // const intendedAnalysisType = document.querySelector('input[name="fileType"]:checked').value; // For future use if needed
349
  const maxFileSize = 16 * 1024 * 1024;
350
 
351
  if (file.size > maxFileSize) {
 
360
 
361
  const allowedImageTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/webp'];
362
 
363
+ // Both radio options now expect an image
364
  if (!allowedImageTypes.includes(file.type)) {
365
  const isImageTypeByName = /\.(jpe?g|png|gif|webp)$/i.test(file.name);
366
+ if (!isImageTypeByName) { // Check by extension as a fallback
367
+ Swal.fire({
368
  icon: 'error',
369
  title: 'Type de fichier invalide',
370
  text: 'Veuillez sélectionner une image (PNG, JPG, GIF, WEBP).'
 
374
  }
375
  }
376
 
377
+ // If validation passes:
378
  selectedFile = file;
379
  preview.classList.remove('hidden');
380
  preview.classList.add('fade-in');
 
383
  fileInfo.textContent = `${file.name} (${(file.size / 1024).toFixed(1)} Ko)`;
384
  removeFileButton.classList.remove('hidden');
385
 
386
+ // Always show image preview
387
  imagePreview.classList.remove('hidden');
388
  textPreview.classList.add('hidden'); // Ensure text preview is hidden
389
  textPreview.textContent = ''; // Clear any old text preview content
390
+
391
  const reader = new FileReader();
392
  reader.onload = (e) => imagePreview.src = e.target.result;
393
  reader.readAsDataURL(file);
394
+
395
  submitButton.disabled = false;
396
  }
397
 
398
  function handleSubmit() {
399
  if (!selectedFile) {
400
+ Swal.fire('Aucun fichier', 'Veuillez sélectionner un fichier avant de lancer l\'analyse.', 'warning');
401
  return;
402
  }
403
 
404
+ // This 'fileTypeForBackend' is crucial for the backend
 
 
405
  const fileTypeForBackend = document.querySelector('input[name="fileType"]:checked').value;
406
  const formData = new FormData();
407
+ formData.append('file', selectedFile); // This will always be an image file
408
+ formData.append('fileType', fileTypeForBackend); // This will be 'image' or 'text' based on radio
409
 
410
  showLoading(true);
411
  results.classList.add('hidden');
 
452
  text: error.message || 'Une erreur inconnue est survenue.',
453
  });
454
  console.error('Error during analysis:', error);
455
+ // Do not re-enable button if there was a selected file, let user reset or try again with same file
456
+ // submitButton.disabled = (selectedFile === null);
457
  });
458
  }
459
 
 
473
  .replace(/<\/p>/gi, '\n')
474
  .replace(/<\/li>/gi, '\n')
475
  .replace(/<\/(h[1-6])>/gi, '\n\n')
476
+ .replace(/<pre.*?><code.*?>([\s\S]*?)<\/code><\/pre>/gi, '\n```\n$1\n```\n')
477
+ .replace(/<[^>]+>/g, '')
478
+ .replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&')
479
  .trim();
480
 
481
  navigator.clipboard.writeText(textToCopy)
 
484
  icon: 'success',
485
  title: 'Copié !',
486
  text: 'L\'analyse a été copiée dans le presse-papiers.',
487
+ timer: 1500,
488
+ showConfirmButton: false
489
  });
490
  })
491
  .catch(err => {
 
498
  });
499
  }
500
 
501
+ resetUI(); // Initial setup call
 
 
502
 
503
  }); // End DOMContentLoaded
504
  </script>