Spaces:
Running
Running
| // CONFIGURATION PROFESSIONNELLE | |
| const LaBaleineIA = { | |
| token: "hf_votre_token_gratuit", // À configurer sur HuggingFace | |
| endpoints: { | |
| image: "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0", | |
| video: "https://api-inference.huggingface.co/models/cerspense/zeroscope_v2_576w" | |
| }, | |
| // Initialisation | |
| init: function() { | |
| console.log("🐋 La Baleine IA initialisée"); | |
| this.setupEventListeners(); | |
| }, | |
| // Configuration des événements | |
| setupEventListeners: function() { | |
| // Récupère la zone de saisie existante | |
| const inputField = document.querySelector('input[placeholder*="Écrivez votre message"], input[placeholder*="écrire"]'); | |
| if (inputField) { | |
| inputField.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter' && e.target.value.trim()) { | |
| this.processerDemande(e.target.value); | |
| e.target.value = ''; | |
| } | |
| }); | |
| } | |
| // Bouton d'envoi (si existant) | |
| const sendButton = document.querySelector('button:contains("Envoyer"), button:contains("Send")'); | |
| if (sendButton) { | |
| sendButton.addEventListener('click', () => { | |
| const input = document.querySelector('input[placeholder*="Écrivez votre message"], input[placeholder*="écrire"]'); | |
| if (input && input.value.trim()) { | |
| this.processerDemande(input.value); | |
| input.value = ''; | |
| } | |
| }); | |
| } | |
| }, | |
| // Traiter la demande utilisateur | |
| processerDemande: async function(demande) { | |
| // 1. Afficher le message utilisateur | |
| this.afficherMessage('utilisateur', demande); | |
| // 2. Réponse initiale de La Baleine | |
| this.afficherMessage('ia', `J'ai bien reçu : "${demande}". Je commence la génération...`); | |
| // 3. Analyser la demande pour le type | |
| const type = this.analyserTypeDemande(demande); | |
| // 4. Expliquer les étapes | |
| this.afficherExplication(`Étape 1/3 : Analyse de votre demande...`); | |
| await this.delay(800); | |
| this.afficherExplication(`Étape 2/3 : Préparation de la génération ${type === 'image' ? 'd\'image' : 'de vidéo'}...`); | |
| await this.delay(800); | |
| // 5. Génération | |
| try { | |
| this.afficherExplication(`Étape 3/3 : Génération en cours avec les modèles IA...`); | |
| if (type === 'image') { | |
| await this.genererImage(demande); | |
| } else { | |
| await this.genererVideo(demande); | |
| } | |
| this.afficherMessage('ia', `✅ Génération terminée ! Consultez la colonne de droite pour voir le résultat.`); | |
| this.afficherExplication(`Processus complet terminé avec succès.`); | |
| } catch (error) { | |
| this.afficherMessage('ia', `❌ Désolée, une erreur est survenue : ${error.message}`); | |
| } | |
| }, | |
| // Générer une image | |
| genererImage: async function(prompt) { | |
| const response = await fetch(this.endpoints.image, { | |
| method: 'POST', | |
| headers: { | |
| 'Authorization': `Bearer ${this.token}`, | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ | |
| inputs: prompt, | |
| parameters: { | |
| num_inference_steps: 30, | |
| guidance_scale: 7.5 | |
| } | |
| }) | |
| }); | |
| if (!response.ok) throw new Error(`Erreur API: ${response.status}`); | |
| const blob = await response.blob(); | |
| const urlImage = URL.createObjectURL(blob); | |
| // Afficher dans la colonne droite | |
| this.afficherResultatVisuel('image', urlImage, prompt); | |
| // Sauvegarder pour téléchargement | |
| this.mediaCourant = { type: 'image', url: urlImage, nom: `baleine_${Date.now()}.png` }; | |
| }, | |
| // Afficher le résultat visuel | |
| afficherResultatVisuel: function(type, url, prompt) { | |
| const section = document.getElementById('apercu-section'); | |
| const statut = document.getElementById('statut-generation'); | |
| const resultat = document.getElementById('resultat-visuel'); | |
| const controles = document.getElementById('controles-generation'); | |
| if (statut) statut.textContent = `✅ ${type === 'image' ? 'Image générée' : 'Vidéo générée'}`; | |
| if (resultat) { | |
| if (type === 'image') { | |
| resultat.innerHTML = ` | |
| <h5 style="color: #fff; margin-bottom: 15px;">"${prompt}"</h5> | |
| <img src="${url}" alt="Généré par La Baleine" | |
| style="max-width: 100%; border-radius: 10px; box-shadow: 0 5px 20px rgba(0,0,0,0.5);"> | |
| `; | |
| } else { | |
| resultat.innerHTML = ` | |
| <h5 style="color: #fff; margin-bottom: 15px;">"${prompt}"</h5> | |
| <video src="${url}" controls autoplay | |
| style="max-width: 100%; border-radius: 10px; box-shadow: 0 5px 20px rgba(0,0,0,0.5);"> | |
| </video> | |
| `; | |
| } | |
| } | |
| if (controles) controles.style.display = 'block'; | |
| // Scroll automatique | |
| section.scrollTop = section.scrollHeight; | |
| }, | |
| // Afficher un message dans le chat | |
| afficherMessage: function(auteur, contenu) { | |
| const chat = document.getElementById('assistant-ia'); | |
| if (!chat) return; | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `message-${auteur}`; | |
| messageDiv.style.cssText = ` | |
| padding: 12px; | |
| border-radius: 12px; | |
| margin-bottom: 15px; | |
| max-width: 80%; | |
| ${auteur === 'utilisateur' ? | |
| 'background: #007bff; color: white; margin-left: auto;' : | |
| 'background: #e3f2fd; color: #333;'} | |
| `; | |
| messageDiv.innerHTML = `<strong>${auteur === 'utilisateur' ? '👤 Vous' : '🐋 La Baleine'}:</strong> ${contenu}`; | |
| chat.appendChild(messageDiv); | |
| chat.scrollTop = chat.scrollHeight; | |
| }, | |
| // Afficher une explication technique | |
| afficherExplication: function(texte) { | |
| const chat = document.getElementById('assistant-ia'); | |
| if (!chat) return; | |
| const explicationDiv = document.createElement('div'); | |
| explicationDiv.style.cssText = ` | |
| padding: 10px; | |
| border-radius: 8px; | |
| margin: 5px 0; | |
| background: #f5f5f5; | |
| border-left: 4px solid #4fc3f7; | |
| font-size: 14px; | |
| color: #555; | |
| `; | |
| explicationDiv.innerHTML = `⚙️ ${texte}`; | |
| chat.appendChild(explicationDiv); | |
| chat.scrollTop = chat.scrollHeight; | |
| }, | |
| // Analyser le type de demande | |
| analyserTypeDemande: function(demande) { | |
| const motsVideo = ['vidéo', 'film', 'animation', 'mouvement', 'cinéma']; | |
| const contientVideo = motsVideo.some(mot => demande.toLowerCase().includes(mot)); | |
| return contientVideo ? 'video' : 'image'; | |
| }, | |
| // Fonction d'attente | |
| delay: function(ms) { | |
| return new Promise(resolve => setTimeout(resolve, ms)); | |
| } | |
| }; | |
| // Fonctions de contrôle | |
| function telechargerMedia() { | |
| if (LaBaleineIA.mediaCourant) { | |
| const a = document.createElement('a'); | |
| a.href = LaBaleineIA.mediaCourant.url; | |
| a.download = LaBaleineIA.mediaCourant.nom; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| } | |
| } | |
| function genererNouvelleVersion() { | |
| const dernierMessage = document.querySelector('.message-utilisateur:last-child'); | |
| if (dernierMessage) { | |
| const texte = dernierMessage.textContent.replace('👤 Vous:', '').trim(); | |
| if (texte) LaBaleineIA.processerDemande(texte); | |
| } | |
| } | |
| document.addEventListener('DOMContentLoaded', () => { | |
| LaBaleineIA.init(); | |
| // Initialize tooltips for icons | |
| const initTooltips = () => { | |
| const buttons = document.querySelectorAll('button'); | |
| buttons.forEach(button => { | |
| const icon = button.querySelector('[data-feather]'); | |
| if (icon) { | |
| const iconName = icon.getAttribute('data-feather'); | |
| button.setAttribute('title', iconName.charAt(0).toUpperCase() + iconName.slice(1)); | |
| } | |
| }); | |
| }; | |
| // Handle message sending and AI responses | |
| const setupMessageInput = () => { | |
| const input = document.querySelector('main input'); | |
| const sendBtn = document.querySelector('main button:disabled'); | |
| const micBtn = document.querySelector('main button[data-feather="mic"]'); | |
| const plusBtn = document.querySelector('main button[data-feather="plus"]'); | |
| const paperclipBtn = document.querySelector('main button[data-feather="paperclip"]'); | |
| const messageContainer = document.querySelector('.flex-1.flex.items-center.justify-center'); | |
| // AI response logic | |
| const getAIResponse = (message) => { | |
| const lowerMsg = message.toLowerCase(); | |
| if (lowerMsg.includes('image') || lowerMsg.includes('photo') || lowerMsg.includes('picture')) { | |
| return `Je peux générer des images pour toi. Voici un exemple : | |
| <a href="baleine.html" class="text-blue-400 hover:underline">Ouvrir le générateur d'images La Baleine IA</a>`; | |
| } | |
| else if (lowerMsg.includes('vidéo') || lowerMsg.includes('video')) { | |
| return "Pour les vidéos, je peux te conseiller sur le format, la durée et le style. Quel type de vidéo veux-tu créer ?"; | |
| } | |
| else if (lowerMsg.includes('thème') || lowerMsg.includes('theme')) { | |
| return "Je peux t'aider à concevoir un thème. Dis-moi pour quelle plateforme (Shopify, WordPress, etc.) et quel style tu recherches."; | |
| } | |
| else if (lowerMsg.includes('plugin')) { | |
| return "Les plugins peuvent étendre les fonctionnalités. Quel type de plugin veux-tu développer ? (pour WordPress, Shopify, etc.)"; | |
| } | |
| else { | |
| return "Je peux t'aider avec des images, vidéos, thèmes et plugins. Dis-moi plus précisément ce que tu veux créer !"; | |
| } | |
| }; | |
| // Display message in chat | |
| const displayMessage = (text, isUser = false) => { | |
| if (!messageContainer) return; | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `p-4 mb-2 rounded-lg max-w-[80%] ${isUser ? 'ml-auto bg-blue-900/30 text-blue-100' : 'bg-gray-700/50 text-gray-100'}`; | |
| messageDiv.innerHTML = text; | |
| if (isUser) { | |
| messageContainer.insertBefore(messageDiv, messageContainer.firstChild); | |
| } else { | |
| messageContainer.appendChild(messageDiv); | |
| } | |
| }; | |
| // Handle send message | |
| const handleSend = () => { | |
| const message = input.value.trim(); | |
| if (!message) return; | |
| displayMessage(message, true); | |
| input.value = ''; | |
| sendBtn.disabled = true; | |
| // Simulate AI thinking | |
| setTimeout(() => { | |
| const response = getAIResponse(message); | |
| displayMessage(response); | |
| }, 1000); | |
| }; | |
| // Event listeners | |
| input.addEventListener('keydown', (e) => { | |
| if (e.key === 'Enter') handleSend(); | |
| }); | |
| sendBtn.addEventListener('click', handleSend); | |
| // Microphone functionality using Web Speech API | |
| if (micBtn) { | |
| micBtn.addEventListener('click', async () => { | |
| try { | |
| const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; | |
| if (!SpeechRecognition) { | |
| statusEl.textContent = "Micro: non supporté"; | |
| return; | |
| } | |
| const recognition = new SpeechRecognition(); | |
| recognition.lang = 'fr-FR'; | |
| recognition.interimResults = false; | |
| recognition.onresult = (event) => { | |
| let transcript = ''; | |
| for (let i = event.resultIndex; i < event.results.length; i++) { | |
| transcript += event.results[i][0].transcript; | |
| } | |
| inp.value = transcript; | |
| // Only send if the result is final | |
| if (event.results[0].isFinal) { | |
| handleSend(); | |
| } | |
| }; | |
| recognition.onerror = (event) => { | |
| console.error('Erreur de reconnaissance vocale:', event.error); | |
| statusEl.textContent = "Micro: erreur - " + event.error; | |
| }; | |
| statusEl.textContent = "Micro: écoute..."; | |
| await navigator.mediaDevices.getUserMedia({ audio: true }); | |
| recognition.start(); | |
| micBtn.innerHTML = '<i data-feather="mic-off" class="w-5 h-5"></i>'; | |
| feather.replace(); | |
| recognition.onend = () => { | |
| micBtn.innerHTML = '<i data-feather="mic" class="w-5 h-5"></i>'; | |
| feather.replace(); | |
| statusEl.textContent = "Micro: prêt"; | |
| }; | |
| } catch (err) { | |
| console.error('Erreur microphone:', err); | |
| statusEl.textContent = "Micro: permission refusée"; | |
| } | |
| }); | |
| } | |
| // File attachment functionality | |
| if (paperclipBtn) { | |
| // Create hidden file input | |
| const fileInput = document.createElement('input'); | |
| fileInput.type = 'file'; | |
| fileInput.style.display = 'none'; | |
| document.body.appendChild(fileInput); | |
| paperclipBtn.addEventListener('click', () => { | |
| fileInput.click(); | |
| }); | |
| fileInput.addEventListener('change', (e) => { | |
| const file = e.target.files[0]; | |
| if (!file) return; | |
| // Handle different file types | |
| if (file.type.startsWith('image/')) { | |
| const reader = new FileReader(); | |
| reader.onload = (event) => { | |
| const img = document.createElement('img'); | |
| img.src = event.target.result; | |
| img.classList.add('max-w-xs', 'max-h-40', 'rounded-lg', 'mt-2'); | |
| const message = `Fichier image: ${file.name}`; | |
| displayMessage(`${message}<br>`); | |
| messageContainer.appendChild(img); | |
| }; | |
| reader.readAsDataURL(file); | |
| } else { | |
| displayMessage(`Fichier joint: ${file.name} (${(file.size / 1024).toFixed(1)} KB)`); | |
| } | |
| }); | |
| } | |
| }; | |
| // Initialize all functionality | |
| const init = () => { | |
| initTooltips(); | |
| setupMessageInput(); | |
| }; | |
| init(); | |
| }); | |