/* Cosmic Chatbot - Scripts JavaScript */ // Attendre que le DOM soit complètement chargé document.addEventListener('DOMContentLoaded', function() { // Éléments DOM const messagesDiv = document.getElementById('messages'); const chatInput = document.getElementById('chatInput'); const sendButton = document.getElementById('sendButton'); const fileInput = document.getElementById('fileInput'); const filePreviewArea = document.getElementById('filePreviewArea'); const themeToggle = document.getElementById('themeToggle'); const featureToggle = document.getElementById('featureToggle'); const featureShowcase = document.getElementById('featureShowcase'); const starsContainer = document.getElementById('starsContainer'); const particlesContainer = document.getElementById('particlesContainer'); // Variables globales let currentTheme = 'dark'; let selectedFile = null; // Initialisation initializeStars(); initializeParticles(); initializeEventListeners(); // Fonctions d'initialisation function initializeStars() { // Créer des étoiles avec des positions et tailles aléatoires for (let i = 0; i < 100; i++) { const star = document.createElement('div'); star.className = 'star'; // Position aléatoire const x = Math.random() * 100; const y = Math.random() * 100; // Taille aléatoire const size = Math.random() * 2 + 1; // Délai d'animation aléatoire const delay = Math.random() * 3; // Appliquer les styles star.style.left = `${x}%`; star.style.top = `${y}%`; star.style.width = `${size}px`; star.style.height = `${size}px`; star.style.animationDelay = `${delay}s`; starsContainer.appendChild(star); } } function initializeParticles() { // Créer des particules flottantes for (let i = 0; i < 15; i++) { const particle = document.createElement('div'); particle.className = 'particle'; // Position aléatoire const x = Math.random() * 100; const y = Math.random() * 100; // Taille aléatoire const size = Math.random() * 50 + 20; // Délai d'animation aléatoire const delay = Math.random() * 5; // Appliquer les styles particle.style.left = `${x}%`; particle.style.top = `${y}%`; particle.style.width = `${size}px`; particle.style.height = `${size}px`; particle.style.animationDelay = `${delay}s`; particlesContainer.appendChild(particle); } } function initializeEventListeners() { // Événement d'envoi de message sendButton.addEventListener('click', processInput); chatInput.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); processInput(); } }); // Événement de changement de thème themeToggle.addEventListener('click', toggleTheme); // Événement d'affichage des fonctionnalités featureToggle.addEventListener('click', toggleFeatureShowcase); // Événement de sélection de fichier fileInput.addEventListener('change', handleFileSelection); // Événement de clic sur une carte de fonctionnalité document.querySelectorAll('.feature-card').forEach(card => { card.addEventListener('click', () => { const feature = card.getAttribute('data-feature'); suggestFeaturePrompt(feature); }); }); } // Fonctions de gestion des événements function toggleTheme() { const body = document.body; const icon = themeToggle.querySelector('i'); if (currentTheme === 'dark') { // Passer au thème clair body.classList.add('light-theme'); icon.className = 'bx bx-sun'; currentTheme = 'light'; } else { // Passer au thème sombre body.classList.remove('light-theme'); icon.className = 'bx bx-moon'; currentTheme = 'dark'; } // Ajouter une classe pour la transition body.classList.add('theme-transition'); // Supprimer la classe après la transition setTimeout(() => { body.classList.remove('theme-transition'); }, 500); } function toggleFeatureShowcase() { featureShowcase.classList.toggle('active'); // Changer l'icône et le texte du bouton if (featureShowcase.classList.contains('active')) { featureToggle.innerHTML = ' Fermer'; } else { featureToggle.innerHTML = ' Fonctionnalités'; } } function handleFileSelection(e) { const file = e.target.files[0]; if (!file) return; selectedFile = file; // Afficher l'aperçu du fichier filePreviewArea.innerHTML = ''; const preview = document.createElement('div'); preview.className = 'file-preview'; // Déterminer l'icône en fonction du type de fichier let iconClass = 'bx-file'; if (file.type.startsWith('image/')) { iconClass = 'bx-image'; } else if (file.name.endsWith('.pdf')) { iconClass = 'bx-file-pdf'; } else if (file.name.endsWith('.xlsx') || file.name.endsWith('.xls')) { iconClass = 'bx-spreadsheet'; } else if (file.name.endsWith('.docx') || file.name.endsWith('.doc')) { iconClass = 'bx-file-doc'; } preview.innerHTML = `
${file.name}
`; filePreviewArea.appendChild(preview); // Ajouter un événement pour supprimer l'aperçu preview.querySelector('.file-preview-remove').addEventListener('click', () => { filePreviewArea.innerHTML = ''; fileInput.value = ''; selectedFile = null; }); } function suggestFeaturePrompt(feature) { let prompt = ''; switch (feature) { case 'summarize': prompt = 'Pouvez-vous résumer ce document pour moi ?'; break; case 'image-caption': chatInput.value = ''; fileInput.click(); return; case 'qa': prompt = 'Pouvez-vous répondre à cette question : '; break; case 'vqa': prompt = 'Que pouvez-vous me dire sur cette image ?'; fileInput.click(); break; case 'visualization': prompt = 'Générez un graphique à partir de ces données Excel'; fileInput.click(); return; case 'translate': prompt = 'Traduisez ce texte en français : '; break; } chatInput.value = prompt; chatInput.focus(); // Placer le curseur à la fin du texte const len = chatInput.value.length; chatInput.setSelectionRange(len, len); // Fermer le showcase featureShowcase.classList.remove('active'); featureToggle.innerHTML = ' Fonctionnalités'; } // Fonctions de traitement des messages async function processInput() { const text = chatInput.value.trim(); const file = selectedFile; if (!text && !file) return; // Ajouter le message de l'utilisateur if (text) { addMessage(text, true); } if (file) { addMessage(`📄 ${file.name}`, true); filePreviewArea.innerHTML = ''; } // Effacer les entrées chatInput.value = ''; selectedFile = null; // Afficher l'indicateur de frappe showTyping(); try { const formData = new FormData(); if (file) formData.append('file', file); if (text) formData.append('text', text); const response = await fetch('/process', { method: 'POST', body: formData }); if (!response.ok) throw new Error('Erreur serveur'); const data = await response.json(); // Supprimer l'indicateur de frappe document.getElementById('typingIndicator')?.remove(); // Formater la réponse en fonction du type let responseText = data.response; if (data.type === 'visualization_code') { responseText = `Voici le code de visualisation :\n\`\`\`python\n${data.response}\n\`\`\``; } else if (data.type === 'caption' && file && file.type.startsWith('image/')) { // Pour les images, afficher l'image avec la légende const reader = new FileReader(); reader.onload = function(e) { const imgPreview = `Image téléchargée`; addMessage(`${imgPreview}

${responseText}

`, false, true); }; reader.readAsDataURL(file); return; } addMessage(responseText); } catch (error) { document.getElementById('typingIndicator')?.remove(); addMessage(`Erreur: ${error.message}`); } } function addMessage(content, isUser = false, isHTML = false) { const msgDiv = document.createElement('div'); msgDiv.className = `message ${isUser ? 'user-message' : 'bot-message'}`; // Ajouter l'avatar const avatar = document.createElement('div'); avatar.className = 'message-avatar'; avatar.innerHTML = isUser ? '' : ''; msgDiv.appendChild(avatar); // Ajouter l'heure const time = document.createElement('div'); time.className = 'message-time'; time.textContent = formatTime(new Date()); // Formater le contenu if (isHTML) { // Si le contenu est du HTML (pour les images) msgDiv.innerHTML += content; } else if (content.includes('```')) { // Formater les blocs de code const contentDiv = document.createElement('div'); contentDiv.className = 'markdown-content'; const parts = content.split(/```([\s\S]*?)```/); parts.forEach((part, i) => { if (i % 2 === 1) { // Bloc de code const pre = document.createElement('div'); pre.className = 'code-block'; pre.textContent = part.trim(); // Bouton de copie const copyBtn = document.createElement('button'); copyBtn.className = 'copy-code'; copyBtn.textContent = 'Copier'; copyBtn.addEventListener('click', () => { navigator.clipboard.writeText(part.trim()); copyBtn.textContent = 'Copié !'; setTimeout(() => { copyBtn.textContent = 'Copier'; }, 2000); }); pre.appendChild(copyBtn); contentDiv.appendChild(pre); } else if (part.trim()) { // Texte normal const p = document.createElement('p'); p.textContent = part.trim(); contentDiv.appendChild(p); } }); msgDiv.appendChild(contentDiv); } else { // Texte normal avec formatage Markdown basique const contentDiv = document.createElement('div'); contentDiv.className = 'markdown-content'; // Convertir les listes let formattedContent = content; if (content.includes('\n- ')) { const listItems = content.split('\n- '); formattedContent = listItems[0]; if (listItems.length > 1) { const ul = document.createElement('ul'); for (let i = 1; i < listItems.length; i++) { const li = document.createElement('li'); li.textContent = listItems[i].trim(); ul.appendChild(li); } contentDiv.innerHTML = `

${formattedContent}

`; contentDiv.appendChild(ul); msgDiv.appendChild(contentDiv); } else { contentDiv.textContent = formattedContent; msgDiv.appendChild(contentDiv); } } else { contentDiv.textContent = formattedContent; msgDiv.appendChild(contentDiv); } } msgDiv.appendChild(time); messagesDiv.appendChild(msgDiv); messagesDiv.scrollTop = messagesDiv.scrollHeight; return msgDiv; } function showTyping() { const typingDiv = document.createElement('div'); typingDiv.className = 'typing'; typingDiv.id = 'typingIndicator'; for (let i = 0; i < 3; i++) { const dot = document.createElement('div'); dot.className = 'typing-dot'; typingDiv.appendChild(dot); } messagesDiv.appendChild(typingDiv); messagesDiv.scrollTop = messagesDiv.scrollHeight; } // Fonctions utilitaires function formatTime(date) { const hours = date.getHours().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, '0'); return `${hours}:${minutes}`; } });