Update templates/index.html
Browse files- templates/index.html +202 -77
templates/index.html
CHANGED
@@ -186,23 +186,66 @@
|
|
186 |
.message-bubble:hover .copy-btn {
|
187 |
opacity: 1;
|
188 |
}
|
|
|
189 |
.file-preview {
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
|
|
196 |
}
|
197 |
-
.file-preview
|
198 |
-
|
199 |
}
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
.chip {
|
207 |
display: inline-flex;
|
208 |
align-items: center;
|
@@ -416,6 +459,17 @@
|
|
416 |
#send-button i {
|
417 |
font-size: 0.9rem;
|
418 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
419 |
}
|
420 |
/* Container pour le textarea et le bouton */
|
421 |
.input-wrapper {
|
@@ -497,7 +551,7 @@
|
|
497 |
</div>
|
498 |
<!-- Zone de prévisualisation -->
|
499 |
<div id="preview-area" class="px-4 py-2 bg-gray-50 dark:bg-gray-800/50 hidden">
|
500 |
-
<div id="file-preview" class="hidden"></div>
|
501 |
</div>
|
502 |
<!-- Barre d'options -->
|
503 |
<div class="flex items-center justify-between flex-wrap gap-y-2 px-4 py-2 bg-gray-100 dark:bg-gray-800/80 text-sm text-gray-600 dark:text-gray-300">
|
@@ -523,23 +577,22 @@
|
|
523 |
<span class="tooltip-text">Raisonnement avancé (1 fois/min)</span>
|
524 |
</label>
|
525 |
</div>
|
|
|
526 |
<div class="flex items-center space-x-2">
|
527 |
-
|
528 |
-
|
529 |
<label for="file_upload" class="cursor-pointer flex items-center text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300 tooltip">
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
</label>
|
535 |
|
536 |
-
|
537 |
<div id="file-chip" class="chip hidden">
|
538 |
-
<i class="fa-solid fa-
|
539 |
<span id="file-name" class="truncate max-w-[100px] sm:max-w-[120px]"></span>
|
540 |
<i id="clear-file" class="fa-solid fa-xmark chip-close"></i>
|
541 |
</div>
|
542 |
</div>
|
|
|
543 |
</div>
|
544 |
<!-- Formulaire de chat -->
|
545 |
<form id="chat-form" class="p-3 sm:p-4 bg-white dark:bg-gray-900">
|
@@ -604,6 +657,7 @@
|
|
604 |
const MOBILE_BREAKPOINT = 640;
|
605 |
let advancedToggleCooldownEndTime = 0;
|
606 |
let isComposing = false;
|
|
|
607 |
|
608 |
// Gestion du thème
|
609 |
function initializeTheme() {
|
@@ -757,12 +811,13 @@
|
|
757 |
scrollToBottom();
|
758 |
}
|
759 |
function escapeHtml(unsafe) {
|
|
|
760 |
return unsafe
|
761 |
-
.replace(/&/g, "&
|
762 |
-
.replace(/</g, "
|
763 |
-
.replace(/>/g, "
|
764 |
-
.replace(/"/g, "
|
765 |
-
.replace(/'/g, "
|
766 |
}
|
767 |
|
768 |
// Gestion du cooldown pour le raisonnement avancé
|
@@ -829,55 +884,97 @@
|
|
829 |
}
|
830 |
}
|
831 |
|
832 |
-
//
|
833 |
function clearFileInput() {
|
834 |
-
fileUpload.value = '';
|
835 |
fileChip.classList.add('hidden');
|
836 |
fileNameSpan.textContent = '';
|
837 |
fileNameSpan.title = '';
|
838 |
-
filePreview.innerHTML = '';
|
839 |
filePreview.classList.add('hidden');
|
840 |
previewArea.classList.add('hidden');
|
|
|
841 |
}
|
|
|
|
|
|
|
842 |
fileUpload.addEventListener('change', () => {
|
843 |
if (fileUpload.files.length > 0) {
|
844 |
-
|
845 |
-
const name = file.name;
|
846 |
-
fileNameSpan.textContent = name;
|
847 |
-
fileNameSpan.title = name;
|
848 |
-
fileChip.classList.remove('hidden');
|
849 |
filePreview.innerHTML = '';
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
856 |
</div>`;
|
857 |
-
filePreview.
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
-
|
865 |
-
|
866 |
-
|
867 |
-
filePreview.innerHTML = `
|
868 |
-
<div class="flex items-center justify-center p-3">
|
869 |
-
<div class="bg-gray-100 dark:bg-gray-800 p-3 rounded-lg text-center">
|
870 |
-
<i class="fa-solid ${getFileIcon(file.type)} text-3xl text-gray-500 dark:text-gray-400 mb-2"></i>
|
871 |
-
<p class="text-xs text-gray-500 dark:text-gray-400">${formatFileSize(file.size)}</p>
|
872 |
-
</div>
|
873 |
-
</div>`;
|
874 |
-
filePreview.classList.remove('hidden');
|
875 |
-
previewArea.classList.remove('hidden');
|
876 |
}
|
|
|
|
|
|
|
877 |
} else {
|
878 |
clearFileInput();
|
879 |
}
|
880 |
});
|
|
|
|
|
881 |
function getFileIcon(fileType) {
|
882 |
if (!fileType) return 'fa-file';
|
883 |
if (fileType.includes('pdf')) return 'fa-file-pdf';
|
@@ -905,14 +1002,16 @@
|
|
905 |
setTimeout(() => adjustTextareaHeight(promptInput), 0);
|
906 |
} else if (!isMobile && !e.shiftKey) {
|
907 |
e.preventDefault();
|
908 |
-
|
|
|
909 |
chatForm.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
|
910 |
}
|
911 |
} else if (e.shiftKey) {
|
912 |
setTimeout(() => adjustTextareaHeight(promptInput), 0);
|
913 |
if (isMobile) {
|
914 |
e.preventDefault();
|
915 |
-
|
|
|
916 |
chatForm.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
|
917 |
}
|
918 |
}
|
@@ -926,19 +1025,23 @@
|
|
926 |
});
|
927 |
adjustTextareaHeight(promptInput);
|
928 |
|
929 |
-
//
|
930 |
chatForm.addEventListener('submit', async (e) => {
|
931 |
e.preventDefault();
|
932 |
const prompt = promptInput.value.trim();
|
933 |
-
const file = fileUpload.files[0];
|
934 |
const useWebSearch = webSearchToggle.checked;
|
935 |
const useAdvanced = advancedToggle.checked;
|
|
|
936 |
if (sendButton.disabled) return;
|
937 |
-
|
|
|
938 |
promptInput.focus();
|
939 |
return;
|
940 |
}
|
|
|
941 |
errorMessageDiv.classList.add('hidden');
|
|
|
|
|
942 |
if (useAdvanced) {
|
943 |
const now = Date.now();
|
944 |
if (advancedToggleCooldownEndTime > 0 && now < advancedToggleCooldownEndTime) {
|
@@ -947,37 +1050,57 @@
|
|
947 |
return;
|
948 |
}
|
949 |
}
|
|
|
|
|
950 |
let userMessageText = prompt;
|
951 |
-
if (
|
952 |
-
|
|
|
|
|
|
|
|
|
|
|
953 |
}
|
|
|
954 |
addMessageToChat('user', userMessageText);
|
|
|
|
|
955 |
const formData = new FormData();
|
956 |
formData.append('prompt', prompt);
|
957 |
formData.append('web_search', useWebSearch);
|
958 |
formData.append('advanced_reasoning', useAdvanced);
|
959 |
-
|
960 |
-
|
961 |
-
|
|
|
|
|
|
|
|
|
962 |
promptInput.value = '';
|
963 |
adjustTextareaHeight(promptInput);
|
964 |
-
clearFileInput();
|
|
|
965 |
if (useAdvanced) {
|
966 |
startAdvancedCooldownTimer();
|
967 |
advancedToggle.checked = false;
|
968 |
}
|
969 |
webSearchToggle.checked = false;
|
970 |
showLoading(true);
|
|
|
|
|
971 |
try {
|
972 |
const response = await fetch(API_CHAT_ENDPOINT, { method: 'POST', body: formData });
|
973 |
const data = await response.json();
|
974 |
if (!response.ok) {
|
975 |
-
|
976 |
}
|
977 |
if (data.success && data.message) {
|
978 |
addMessageToChat('assistant', data.message, true);
|
979 |
-
} else {
|
980 |
-
|
|
|
|
|
|
|
981 |
}
|
982 |
} catch (error) {
|
983 |
console.error("Chat Error:", error);
|
@@ -987,6 +1110,7 @@
|
|
987 |
promptInput.focus();
|
988 |
}
|
989 |
});
|
|
|
990 |
|
991 |
// Effacement de la conversation
|
992 |
clearForm.addEventListener('submit', async (e) => {
|
@@ -1021,7 +1145,7 @@
|
|
1021 |
clearButton.disabled = true;
|
1022 |
clearButton.innerHTML = '<i class="fa-solid fa-spinner fa-spin mr-1.5"></i><span class="hidden sm:inline">Effacement...</span>';
|
1023 |
try {
|
1024 |
-
const response = await fetch(CLEAR_ENDPOINT, {
|
1025 |
method: 'POST',
|
1026 |
headers: {
|
1027 |
'X-Requested-With': 'XMLHttpRequest'
|
@@ -1033,6 +1157,7 @@
|
|
1033 |
messagesToRemove.forEach(el => el.remove());
|
1034 |
addMessageToChat('assistant', "Conversation effacée. Comment puis-je vous aider maintenant ?", true);
|
1035 |
errorMessageDiv.classList.add('hidden');
|
|
|
1036 |
} else {
|
1037 |
throw new Error(data.error || "Impossible d'effacer la conversation.");
|
1038 |
}
|
@@ -1093,4 +1218,4 @@
|
|
1093 |
});
|
1094 |
</script>
|
1095 |
</body>
|
1096 |
-
</html>
|
|
|
186 |
.message-bubble:hover .copy-btn {
|
187 |
opacity: 1;
|
188 |
}
|
189 |
+
/* START: CSS for multi-file preview */
|
190 |
.file-preview {
|
191 |
+
max-height: 200px; /* Adjusted max-height for multi previews */
|
192 |
+
overflow-y: auto;
|
193 |
+
scrollbar-width: thin;
|
194 |
+
padding: 0.5rem; /* Add some padding */
|
195 |
+
background-color: rgba(243, 244, 246, 0.5); /* Light background */
|
196 |
+
border-radius: 0.5rem;
|
197 |
+
margin-top: 0.5rem;
|
198 |
}
|
199 |
+
.dark .file-preview {
|
200 |
+
background-color: rgba(30, 41, 59, 0.5); /* Darker background for dark mode */
|
201 |
}
|
202 |
+
|
203 |
+
.file-preview-item {
|
204 |
+
background-color: rgba(255, 255, 255, 0.7);
|
205 |
+
transition: all 0.2s ease-in-out;
|
206 |
+
margin-bottom: 0.5rem;
|
207 |
+
padding: 0.5rem;
|
208 |
+
border: 1px solid #e5e7eb;
|
209 |
+
border-radius: 0.375rem;
|
210 |
+
display: flex;
|
211 |
+
align-items: center;
|
212 |
+
}
|
213 |
+
|
214 |
+
.dark .file-preview-item {
|
215 |
+
background-color: rgba(51, 65, 85, 0.5);
|
216 |
+
border-color: rgba(71, 85, 105, 0.5);
|
217 |
+
}
|
218 |
+
|
219 |
+
.file-preview-item:hover {
|
220 |
+
background-color: rgba(255, 255, 255, 1);
|
221 |
+
}
|
222 |
+
|
223 |
+
.dark .file-preview-item:hover {
|
224 |
+
background-color: rgba(51, 65, 85, 0.8);
|
225 |
+
}
|
226 |
+
|
227 |
+
#file-preview::-webkit-scrollbar {
|
228 |
+
width: 5px;
|
229 |
}
|
230 |
+
|
231 |
+
#file-preview::-webkit-scrollbar-thumb {
|
232 |
+
background-color: rgba(156, 163, 175, 0.5);
|
233 |
+
border-radius: 3px;
|
234 |
+
}
|
235 |
+
|
236 |
+
#file-preview::-webkit-scrollbar-track {
|
237 |
+
background-color: rgba(229, 231, 235, 0.3);
|
238 |
+
}
|
239 |
+
|
240 |
+
.dark #file-preview::-webkit-scrollbar-thumb {
|
241 |
+
background-color: rgba(75, 85, 99, 0.5);
|
242 |
+
}
|
243 |
+
|
244 |
+
.dark #file-preview::-webkit-scrollbar-track {
|
245 |
+
background-color: rgba(31, 41, 55, 0.3);
|
246 |
+
}
|
247 |
+
/* END: CSS for multi-file preview */
|
248 |
+
|
249 |
.chip {
|
250 |
display: inline-flex;
|
251 |
align-items: center;
|
|
|
459 |
#send-button i {
|
460 |
font-size: 0.9rem;
|
461 |
}
|
462 |
+
/* Smaller file previews on mobile */
|
463 |
+
.file-preview-item {
|
464 |
+
padding: 0.375rem;
|
465 |
+
}
|
466 |
+
.file-preview-item .w-12 { width: 2.5rem; }
|
467 |
+
.file-preview-item .h-12 { height: 2.5rem; }
|
468 |
+
.file-preview-item .w-10 { width: 2rem; }
|
469 |
+
.file-preview-item .h-10 { height: 2rem; }
|
470 |
+
.file-preview-item .text-xs { font-size: 0.7rem; }
|
471 |
+
.file-preview { max-height: 150px; }
|
472 |
+
|
473 |
}
|
474 |
/* Container pour le textarea et le bouton */
|
475 |
.input-wrapper {
|
|
|
551 |
</div>
|
552 |
<!-- Zone de prévisualisation -->
|
553 |
<div id="preview-area" class="px-4 py-2 bg-gray-50 dark:bg-gray-800/50 hidden">
|
554 |
+
<div id="file-preview" class="hidden"></div> <!-- Container for multiple previews -->
|
555 |
</div>
|
556 |
<!-- Barre d'options -->
|
557 |
<div class="flex items-center justify-between flex-wrap gap-y-2 px-4 py-2 bg-gray-100 dark:bg-gray-800/80 text-sm text-gray-600 dark:text-gray-300">
|
|
|
577 |
<span class="tooltip-text">Raisonnement avancé (1 fois/min)</span>
|
578 |
</label>
|
579 |
</div>
|
580 |
+
<!-- START: Modified HTML for file input and chip -->
|
581 |
<div class="flex items-center space-x-2">
|
|
|
|
|
582 |
<label for="file_upload" class="cursor-pointer flex items-center text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300 tooltip">
|
583 |
+
<i class="fa-solid fa-paperclip"></i>
|
584 |
+
<span class="ml-1.5 hidden sm:inline">Fichiers</span>
|
585 |
+
<input type="file" id="file_upload" name="file[]" class="hidden" accept=".txt,.pdf,.png,.jpg,.jpeg" multiple>
|
586 |
+
<span class="tooltip-text">Joindre plusieurs fichiers (txt, pdf, image)</span>
|
587 |
+
</label>
|
588 |
|
|
|
589 |
<div id="file-chip" class="chip hidden">
|
590 |
+
<i class="fa-solid fa-files chip-icon"></i> <!-- Changed icon to fa-files -->
|
591 |
<span id="file-name" class="truncate max-w-[100px] sm:max-w-[120px]"></span>
|
592 |
<i id="clear-file" class="fa-solid fa-xmark chip-close"></i>
|
593 |
</div>
|
594 |
</div>
|
595 |
+
<!-- END: Modified HTML for file input and chip -->
|
596 |
</div>
|
597 |
<!-- Formulaire de chat -->
|
598 |
<form id="chat-form" class="p-3 sm:p-4 bg-white dark:bg-gray-900">
|
|
|
657 |
const MOBILE_BREAKPOINT = 640;
|
658 |
let advancedToggleCooldownEndTime = 0;
|
659 |
let isComposing = false;
|
660 |
+
const filesList = []; // Pour stocker les fichiers sélectionnés
|
661 |
|
662 |
// Gestion du thème
|
663 |
function initializeTheme() {
|
|
|
811 |
scrollToBottom();
|
812 |
}
|
813 |
function escapeHtml(unsafe) {
|
814 |
+
if (typeof unsafe !== 'string') return '';
|
815 |
return unsafe
|
816 |
+
.replace(/&/g, "&")
|
817 |
+
.replace(/</g, "<")
|
818 |
+
.replace(/>/g, ">")
|
819 |
+
.replace(/"/g, """)
|
820 |
+
.replace(/'/g, "'");
|
821 |
}
|
822 |
|
823 |
// Gestion du cooldown pour le raisonnement avancé
|
|
|
884 |
}
|
885 |
}
|
886 |
|
887 |
+
// START: Modified clearFileInput function
|
888 |
function clearFileInput() {
|
889 |
+
fileUpload.value = ''; // Clear the input element
|
890 |
fileChip.classList.add('hidden');
|
891 |
fileNameSpan.textContent = '';
|
892 |
fileNameSpan.title = '';
|
893 |
+
filePreview.innerHTML = ''; // Clear previews
|
894 |
filePreview.classList.add('hidden');
|
895 |
previewArea.classList.add('hidden');
|
896 |
+
filesList.length = 0; // Vider la liste des fichiers
|
897 |
}
|
898 |
+
// END: Modified clearFileInput function
|
899 |
+
|
900 |
+
// START: Replaced fileUpload event listener for multiple files
|
901 |
fileUpload.addEventListener('change', () => {
|
902 |
if (fileUpload.files.length > 0) {
|
903 |
+
// Vider les prévisualisations précédentes et la liste
|
|
|
|
|
|
|
|
|
904 |
filePreview.innerHTML = '';
|
905 |
+
fileChip.classList.add('hidden'); // Hide chip initially
|
906 |
+
filesList.length = 0;
|
907 |
+
|
908 |
+
// Mettre à jour la liste des fichiers
|
909 |
+
for (let i = 0; i < fileUpload.files.length; i++) {
|
910 |
+
filesList.push(fileUpload.files[i]);
|
911 |
+
}
|
912 |
+
|
913 |
+
// Afficher le nombre total de fichiers dans la puce
|
914 |
+
fileNameSpan.textContent = `${filesList.length} fichier${filesList.length > 1 ? 's' : ''}`;
|
915 |
+
fileNameSpan.title = filesList.map(f => f.name).join(', ');
|
916 |
+
fileChip.classList.remove('hidden');
|
917 |
+
|
918 |
+
// Créer des prévisualisations pour chaque fichier (jusqu'à un maximum raisonnable)
|
919 |
+
const maxPreviews = 5;
|
920 |
+
const filesToPreview = filesList.slice(0, maxPreviews);
|
921 |
+
|
922 |
+
filesToPreview.forEach(file => {
|
923 |
+
const previewItem = document.createElement('div');
|
924 |
+
// Added dark mode classes and adjusted structure
|
925 |
+
previewItem.className = 'file-preview-item mb-2 p-2 border rounded dark:border-gray-600 bg-white dark:bg-gray-700';
|
926 |
+
|
927 |
+
if (file.type.startsWith('image/')) {
|
928 |
+
const reader = new FileReader();
|
929 |
+
reader.onload = (e) => {
|
930 |
+
previewItem.innerHTML = `
|
931 |
+
<div class="flex items-center w-full">
|
932 |
+
<div class="w-12 h-12 flex-shrink-0 mr-2">
|
933 |
+
<img src="${e.target.result}" alt="Aperçu" class="h-full w-full object-cover rounded">
|
934 |
+
</div>
|
935 |
+
<div class="overflow-hidden flex-grow">
|
936 |
+
<p class="text-xs font-medium truncate text-gray-800 dark:text-gray-200">${escapeHtml(file.name)}</p>
|
937 |
+
<p class="text-xs text-gray-500 dark:text-gray-400">${formatFileSize(file.size)}</p>
|
938 |
+
</div>
|
939 |
+
</div>`;
|
940 |
+
filePreview.appendChild(previewItem);
|
941 |
+
};
|
942 |
+
reader.onerror = () => {
|
943 |
+
previewItem.innerHTML = `<p class="text-red-500 dark:text-red-400 text-xs p-2">Erreur lecture image: ${escapeHtml(file.name)}</p>`;
|
944 |
+
filePreview.appendChild(previewItem);
|
945 |
+
};
|
946 |
+
reader.readAsDataURL(file);
|
947 |
+
} else {
|
948 |
+
previewItem.innerHTML = `
|
949 |
+
<div class="flex items-center w-full">
|
950 |
+
<div class="w-10 h-10 flex-shrink-0 mr-2 bg-gray-100 dark:bg-gray-800 rounded flex items-center justify-center">
|
951 |
+
<i class="fa-solid ${getFileIcon(file.type)} text-gray-500 dark:text-gray-400 text-lg"></i>
|
952 |
+
</div>
|
953 |
+
<div class="overflow-hidden flex-grow">
|
954 |
+
<p class="text-xs font-medium truncate text-gray-800 dark:text-gray-200">${escapeHtml(file.name)}</p>
|
955 |
+
<p class="text-xs text-gray-500 dark:text-gray-400">${formatFileSize(file.size)}</p>
|
956 |
+
</div>
|
957 |
</div>`;
|
958 |
+
filePreview.appendChild(previewItem);
|
959 |
+
}
|
960 |
+
});
|
961 |
+
|
962 |
+
// Afficher un message si d'autres fichiers ne sont pas prévisualisés
|
963 |
+
if (filesList.length > maxPreviews) {
|
964 |
+
const moreInfo = document.createElement('p');
|
965 |
+
moreInfo.className = 'text-xs text-gray-500 dark:text-gray-400 text-center mt-1 px-2';
|
966 |
+
moreInfo.textContent = `+ ${filesList.length - maxPreviews} autre${filesList.length - maxPreviews > 1 ? 's' : ''} fichier${filesList.length - maxPreviews > 1 ? 's' : ''}`;
|
967 |
+
filePreview.appendChild(moreInfo);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
968 |
}
|
969 |
+
|
970 |
+
filePreview.classList.remove('hidden');
|
971 |
+
previewArea.classList.remove('hidden');
|
972 |
} else {
|
973 |
clearFileInput();
|
974 |
}
|
975 |
});
|
976 |
+
// END: Replaced fileUpload event listener
|
977 |
+
|
978 |
function getFileIcon(fileType) {
|
979 |
if (!fileType) return 'fa-file';
|
980 |
if (fileType.includes('pdf')) return 'fa-file-pdf';
|
|
|
1002 |
setTimeout(() => adjustTextareaHeight(promptInput), 0);
|
1003 |
} else if (!isMobile && !e.shiftKey) {
|
1004 |
e.preventDefault();
|
1005 |
+
// Modified condition to check filesList
|
1006 |
+
if (!sendButton.disabled && (promptInput.value.trim() || filesList.length > 0)) {
|
1007 |
chatForm.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
|
1008 |
}
|
1009 |
} else if (e.shiftKey) {
|
1010 |
setTimeout(() => adjustTextareaHeight(promptInput), 0);
|
1011 |
if (isMobile) {
|
1012 |
e.preventDefault();
|
1013 |
+
// Modified condition to check filesList
|
1014 |
+
if (!sendButton.disabled && (promptInput.value.trim() || filesList.length > 0)) {
|
1015 |
chatForm.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
|
1016 |
}
|
1017 |
}
|
|
|
1025 |
});
|
1026 |
adjustTextareaHeight(promptInput);
|
1027 |
|
1028 |
+
// START: Modified chatForm submit listener
|
1029 |
chatForm.addEventListener('submit', async (e) => {
|
1030 |
e.preventDefault();
|
1031 |
const prompt = promptInput.value.trim();
|
|
|
1032 |
const useWebSearch = webSearchToggle.checked;
|
1033 |
const useAdvanced = advancedToggle.checked;
|
1034 |
+
|
1035 |
if (sendButton.disabled) return;
|
1036 |
+
// Check against filesList instead of fileUpload.files
|
1037 |
+
if (!prompt && filesList.length === 0) {
|
1038 |
promptInput.focus();
|
1039 |
return;
|
1040 |
}
|
1041 |
+
|
1042 |
errorMessageDiv.classList.add('hidden');
|
1043 |
+
|
1044 |
+
// Vérification du cooldown pour le raisonnement avancé
|
1045 |
if (useAdvanced) {
|
1046 |
const now = Date.now();
|
1047 |
if (advancedToggleCooldownEndTime > 0 && now < advancedToggleCooldownEndTime) {
|
|
|
1050 |
return;
|
1051 |
}
|
1052 |
}
|
1053 |
+
|
1054 |
+
// Création du message utilisateur avec potentiellement plusieurs fichiers
|
1055 |
let userMessageText = prompt;
|
1056 |
+
if (filesList.length > 0) {
|
1057 |
+
const fileNames = filesList.map(f => f.name).join(', ');
|
1058 |
+
const filesText = filesList.length === 1
|
1059 |
+
? `[Fichier joint: ${escapeHtml(fileNames)}]`
|
1060 |
+
: `[${filesList.length} fichiers joints: ${escapeHtml(fileNames)}]`;
|
1061 |
+
|
1062 |
+
userMessageText = prompt ? `${prompt}\n${filesText}` : filesText;
|
1063 |
}
|
1064 |
+
|
1065 |
addMessageToChat('user', userMessageText);
|
1066 |
+
|
1067 |
+
// Préparation des données à envoyer
|
1068 |
const formData = new FormData();
|
1069 |
formData.append('prompt', prompt);
|
1070 |
formData.append('web_search', useWebSearch);
|
1071 |
formData.append('advanced_reasoning', useAdvanced);
|
1072 |
+
|
1073 |
+
// Ajout de tous les fichiers au formData avec la clé 'file[]'
|
1074 |
+
filesList.forEach(file => {
|
1075 |
+
formData.append('file[]', file);
|
1076 |
+
});
|
1077 |
+
|
1078 |
+
// Réinitialisation des champs et gestion des paramètres
|
1079 |
promptInput.value = '';
|
1080 |
adjustTextareaHeight(promptInput);
|
1081 |
+
clearFileInput(); // Clears filesList as well now
|
1082 |
+
|
1083 |
if (useAdvanced) {
|
1084 |
startAdvancedCooldownTimer();
|
1085 |
advancedToggle.checked = false;
|
1086 |
}
|
1087 |
webSearchToggle.checked = false;
|
1088 |
showLoading(true);
|
1089 |
+
|
1090 |
+
// Envoi de la requête et gestion de la réponse (aucun changement nécessaire ici)
|
1091 |
try {
|
1092 |
const response = await fetch(API_CHAT_ENDPOINT, { method: 'POST', body: formData });
|
1093 |
const data = await response.json();
|
1094 |
if (!response.ok) {
|
1095 |
+
throw new Error(data.error || `Erreur serveur (${response.status}): ${response.statusText}`);
|
1096 |
}
|
1097 |
if (data.success && data.message) {
|
1098 |
addMessageToChat('assistant', data.message, true);
|
1099 |
+
} else if (data.error) {
|
1100 |
+
throw new Error(data.error);
|
1101 |
+
}
|
1102 |
+
else {
|
1103 |
+
throw new Error("Réponse invalide ou vide du serveur.");
|
1104 |
}
|
1105 |
} catch (error) {
|
1106 |
console.error("Chat Error:", error);
|
|
|
1110 |
promptInput.focus();
|
1111 |
}
|
1112 |
});
|
1113 |
+
// END: Modified chatForm submit listener
|
1114 |
|
1115 |
// Effacement de la conversation
|
1116 |
clearForm.addEventListener('submit', async (e) => {
|
|
|
1145 |
clearButton.disabled = true;
|
1146 |
clearButton.innerHTML = '<i class="fa-solid fa-spinner fa-spin mr-1.5"></i><span class="hidden sm:inline">Effacement...</span>';
|
1147 |
try {
|
1148 |
+
const response = await fetch(CLEAR_ENDPOINT, {
|
1149 |
method: 'POST',
|
1150 |
headers: {
|
1151 |
'X-Requested-With': 'XMLHttpRequest'
|
|
|
1157 |
messagesToRemove.forEach(el => el.remove());
|
1158 |
addMessageToChat('assistant', "Conversation effacée. Comment puis-je vous aider maintenant ?", true);
|
1159 |
errorMessageDiv.classList.add('hidden');
|
1160 |
+
clearFileInput(); // Also clear any lingering file selections
|
1161 |
} else {
|
1162 |
throw new Error(data.error || "Impossible d'effacer la conversation.");
|
1163 |
}
|
|
|
1218 |
});
|
1219 |
</script>
|
1220 |
</body>
|
1221 |
+
</html>
|