Spaces:
Sleeping
Sleeping
Update templates/index.html
Browse files- templates/index.html +35 -44
templates/index.html
CHANGED
@@ -127,26 +127,26 @@
|
|
127 |
<div class="bg-white rounded-2xl shadow-xl p-6 md:p-8 mb-8 slide-up">
|
128 |
<!-- File Type Selection -->
|
129 |
<div class="mb-6">
|
130 |
-
<label class="block text-base font-medium text-gray-700 mb-3">1. Choisissez le type de document</label>
|
131 |
<div class="flex flex-col sm:flex-row gap-4">
|
132 |
<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">
|
133 |
<input type="radio" name="fileType" value="image" checked
|
134 |
class="peer sr-only file-type-radio">
|
135 |
<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>
|
136 |
-
<span class="text-sm text-gray-700 group-hover:text-indigo-600">
|
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="
|
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">
|
143 |
</label>
|
144 |
</div>
|
145 |
</div>
|
146 |
|
147 |
<!-- Upload Zone -->
|
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">
|
@@ -172,7 +172,7 @@
|
|
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,7 +227,7 @@
|
|
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'); //
|
231 |
const fileInfo = document.getElementById('file-info');
|
232 |
const removeFileButton = document.getElementById('remove-file-button');
|
233 |
const submitButton = document.getElementById('submit-button');
|
@@ -276,9 +276,9 @@
|
|
276 |
fileInput.value = '';
|
277 |
preview.classList.add('hidden');
|
278 |
imagePreview.classList.add('hidden');
|
279 |
-
textPreview.classList.add('hidden');
|
280 |
imagePreview.src = '#';
|
281 |
-
textPreview.textContent = '';
|
282 |
fileInfo.textContent = '';
|
283 |
removeFileButton.classList.add('hidden');
|
284 |
results.classList.add('hidden');
|
@@ -289,36 +289,33 @@
|
|
289 |
}
|
290 |
|
291 |
function updateAcceptAttribute() {
|
|
|
292 |
// Both options now accept images
|
293 |
fileInput.accept = "image/png, image/jpeg, image/gif, image/webp";
|
294 |
-
|
|
|
|
|
|
|
|
|
|
|
295 |
|
296 |
if (selectedFile) {
|
297 |
-
// Check if the currently selected file is an image
|
298 |
const isImage = selectedFile.type.startsWith('image/');
|
299 |
-
if
|
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
|
306 |
-
text: 'Seuls les fichiers
|
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();
|
@@ -343,9 +340,8 @@
|
|
343 |
submitButton.addEventListener('click', handleSubmit);
|
344 |
copyAnalysisButton.addEventListener('click', copyAnalysisToClipboard);
|
345 |
|
346 |
-
|
347 |
function handleFileSelection(file) {
|
348 |
-
|
349 |
const maxFileSize = 16 * 1024 * 1024;
|
350 |
|
351 |
if (file.size > maxFileSize) {
|
@@ -360,10 +356,10 @@
|
|
360 |
|
361 |
const allowedImageTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/webp'];
|
362 |
|
363 |
-
// Both
|
364 |
if (!allowedImageTypes.includes(file.type)) {
|
365 |
const isImageTypeByName = /\.(jpe?g|png|gif|webp)$/i.test(file.name);
|
366 |
-
if (!isImageTypeByName) {
|
367 |
Swal.fire({
|
368 |
icon: 'error',
|
369 |
title: 'Type de fichier invalide',
|
@@ -374,7 +370,6 @@
|
|
374 |
}
|
375 |
}
|
376 |
|
377 |
-
// If validation passes:
|
378 |
selectedFile = file;
|
379 |
preview.classList.remove('hidden');
|
380 |
preview.classList.add('fade-in');
|
@@ -383,15 +378,13 @@
|
|
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 |
|
@@ -401,11 +394,11 @@
|
|
401 |
return;
|
402 |
}
|
403 |
|
404 |
-
|
405 |
-
const fileTypeForBackend = document.querySelector('input[name="fileType"]:checked').value;
|
406 |
const formData = new FormData();
|
407 |
-
formData.append('file', selectedFile);
|
408 |
-
|
|
|
409 |
|
410 |
showLoading(true);
|
411 |
results.classList.add('hidden');
|
@@ -438,7 +431,6 @@
|
|
438 |
} else {
|
439 |
console.warn("Prism n'est pas chargé, impossible de colorer la syntaxe.");
|
440 |
}
|
441 |
-
|
442 |
results.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
443 |
} else {
|
444 |
throw new Error(data.error || "L'analyse n'a pas pu être générée.");
|
@@ -452,8 +444,7 @@
|
|
452 |
text: error.message || 'Une erreur inconnue est survenue.',
|
453 |
});
|
454 |
console.error('Error during analysis:', error);
|
455 |
-
|
456 |
-
// submitButton.disabled = (selectedFile === null);
|
457 |
});
|
458 |
}
|
459 |
|
@@ -475,7 +466,7 @@
|
|
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)
|
@@ -498,9 +489,9 @@
|
|
498 |
});
|
499 |
}
|
500 |
|
501 |
-
|
502 |
-
|
503 |
-
});
|
504 |
</script>
|
505 |
</body>
|
506 |
</html>
|
|
|
127 |
<div class="bg-white rounded-2xl shadow-xl p-6 md:p-8 mb-8 slide-up">
|
128 |
<!-- File Type Selection -->
|
129 |
<div class="mb-6">
|
130 |
+
<label class="block text-base font-medium text-gray-700 mb-3">1. Choisissez le type de document et la méthodologie</label>
|
131 |
<div class="flex flex-col sm:flex-row gap-4">
|
132 |
<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">
|
133 |
<input type="radio" name="fileType" value="image" checked
|
134 |
class="peer sr-only file-type-radio">
|
135 |
<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>
|
136 |
+
<span class="text-sm text-gray-700 group-hover:text-indigo-600">Image (Photo, Dessin...) avec méthodologie iconographique.</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_method_image_input"
|
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">Image (Photo, Dessin...) avec méthodologie textuelle.</span>
|
143 |
</label>
|
144 |
</div>
|
145 |
</div>
|
146 |
|
147 |
<!-- Upload Zone -->
|
148 |
<div class="mb-6">
|
149 |
+
<label class="block text-base font-medium text-gray-700 mb-3">2. Sélectionnez votre fichier image</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">
|
|
|
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> <!-- Keep for potential future text use, but hide -->
|
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'); // Keep reference, but won't be used for 2nd option
|
231 |
const fileInfo = document.getElementById('file-info');
|
232 |
const removeFileButton = document.getElementById('remove-file-button');
|
233 |
const submitButton = document.getElementById('submit-button');
|
|
|
276 |
fileInput.value = '';
|
277 |
preview.classList.add('hidden');
|
278 |
imagePreview.classList.add('hidden');
|
279 |
+
textPreview.classList.add('hidden');
|
280 |
imagePreview.src = '#';
|
281 |
+
textPreview.textContent = '';
|
282 |
fileInfo.textContent = '';
|
283 |
removeFileButton.classList.add('hidden');
|
284 |
results.classList.add('hidden');
|
|
|
289 |
}
|
290 |
|
291 |
function updateAcceptAttribute() {
|
292 |
+
const selectedType = document.querySelector('input[name="fileType"]:checked').value;
|
293 |
// Both options now accept images
|
294 |
fileInput.accept = "image/png, image/jpeg, image/gif, image/webp";
|
295 |
+
|
296 |
+
if (selectedType === 'image') {
|
297 |
+
fileTypesInfo.textContent = "Images (PNG, JPG, GIF, WEBP) pour analyse iconographique - Max 16MB";
|
298 |
+
} else if (selectedType === 'text_method_image_input') {
|
299 |
+
fileTypesInfo.textContent = "Images (PNG, JPG, GIF, WEBP) pour analyse textuelle - Max 16MB";
|
300 |
+
}
|
301 |
|
302 |
if (selectedFile) {
|
303 |
+
// Check if the currently selected file is an image, regardless of radio button choice
|
304 |
const isImage = selectedFile.type.startsWith('image/');
|
305 |
+
if(!isImage) {
|
|
|
|
|
306 |
resetUI();
|
307 |
Swal.fire({
|
308 |
icon: 'warning',
|
309 |
+
title: 'Type de fichier changé ou invalide',
|
310 |
+
text: 'Seuls les fichiers images sont acceptés. Veuillez resélectionner votre fichier.',
|
311 |
});
|
312 |
}
|
313 |
}
|
314 |
}
|
315 |
|
316 |
fileTypeRadios.forEach(radio => {
|
317 |
+
radio.addEventListener('change', updateAcceptAttribute);
|
|
|
|
|
|
|
|
|
|
|
|
|
318 |
});
|
|
|
319 |
uploadZone.addEventListener('click', () => fileInput.click());
|
320 |
uploadZone.addEventListener('dragover', (e) => {
|
321 |
e.preventDefault();
|
|
|
340 |
submitButton.addEventListener('click', handleSubmit);
|
341 |
copyAnalysisButton.addEventListener('click', copyAnalysisToClipboard);
|
342 |
|
|
|
343 |
function handleFileSelection(file) {
|
344 |
+
const fileTypeOption = document.querySelector('input[name="fileType"]:checked').value; // To know which methodology
|
345 |
const maxFileSize = 16 * 1024 * 1024;
|
346 |
|
347 |
if (file.size > maxFileSize) {
|
|
|
356 |
|
357 |
const allowedImageTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/webp'];
|
358 |
|
359 |
+
// Both options now expect an image
|
360 |
if (!allowedImageTypes.includes(file.type)) {
|
361 |
const isImageTypeByName = /\.(jpe?g|png|gif|webp)$/i.test(file.name);
|
362 |
+
if (!isImageTypeByName) {
|
363 |
Swal.fire({
|
364 |
icon: 'error',
|
365 |
title: 'Type de fichier invalide',
|
|
|
370 |
}
|
371 |
}
|
372 |
|
|
|
373 |
selectedFile = file;
|
374 |
preview.classList.remove('hidden');
|
375 |
preview.classList.add('fade-in');
|
|
|
378 |
fileInfo.textContent = `${file.name} (${(file.size / 1024).toFixed(1)} Ko)`;
|
379 |
removeFileButton.classList.remove('hidden');
|
380 |
|
381 |
+
// Always show image preview now
|
382 |
imagePreview.classList.remove('hidden');
|
383 |
textPreview.classList.add('hidden'); // Ensure text preview is hidden
|
|
|
|
|
384 |
const reader = new FileReader();
|
385 |
reader.onload = (e) => imagePreview.src = e.target.result;
|
386 |
reader.readAsDataURL(file);
|
387 |
+
|
388 |
submitButton.disabled = false;
|
389 |
}
|
390 |
|
|
|
394 |
return;
|
395 |
}
|
396 |
|
397 |
+
const fileTypeForAnalysis = document.querySelector('input[name="fileType"]:checked').value;
|
|
|
398 |
const formData = new FormData();
|
399 |
+
formData.append('file', selectedFile);
|
400 |
+
// This 'fileType' will tell the backend which prompt/methodology to use
|
401 |
+
formData.append('fileType', fileTypeForAnalysis);
|
402 |
|
403 |
showLoading(true);
|
404 |
results.classList.add('hidden');
|
|
|
431 |
} else {
|
432 |
console.warn("Prism n'est pas chargé, impossible de colorer la syntaxe.");
|
433 |
}
|
|
|
434 |
results.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
435 |
} else {
|
436 |
throw new Error(data.error || "L'analyse n'a pas pu être générée.");
|
|
|
444 |
text: error.message || 'Une erreur inconnue est survenue.',
|
445 |
});
|
446 |
console.error('Error during analysis:', error);
|
447 |
+
submitButton.disabled = (selectedFile === null);
|
|
|
448 |
});
|
449 |
}
|
450 |
|
|
|
466 |
.replace(/<\/(h[1-6])>/gi, '\n\n')
|
467 |
.replace(/<pre.*?><code.*?>([\s\S]*?)<\/code><\/pre>/gi, '\n```\n$1\n```\n')
|
468 |
.replace(/<[^>]+>/g, '')
|
469 |
+
.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&') // Basic decoding
|
470 |
.trim();
|
471 |
|
472 |
navigator.clipboard.writeText(textToCopy)
|
|
|
489 |
});
|
490 |
}
|
491 |
|
492 |
+
updateAcceptAttribute(); // Initial call
|
493 |
+
resetUI(); // Initial reset
|
494 |
+
});
|
495 |
</script>
|
496 |
</body>
|
497 |
</html>
|