home23 / static /scripts.js
Hadiil's picture
Upload 12 files
7dd65a7 verified
raw
history blame
15 kB
/* 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 = '<i class="bx bx-x"></i> Fermer';
} else {
featureToggle.innerHTML = '<i class="bx bx-bulb"></i> 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 = `
<div class="file-preview-icon"><i class="bx ${iconClass}"></i></div>
<div class="file-preview-name">${file.name}</div>
<button class="file-preview-remove"><i class="bx bx-x"></i></button>
`;
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 = '<i class="bx bx-bulb"></i> 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 = `<img src="${e.target.result}" alt="Image téléchargée" class="image-preview">`;
addMessage(`${imgPreview}<p>${responseText}</p>`, 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 ? '<i class="bx bx-user"></i>' : '<i class="bx bx-bot"></i>';
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 = `<p>${formattedContent}</p>`;
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}`;
}
});