console.log("Interface Espace Codage chargée."); // ===== Configuration API OpenAI ===== const OPENAI_API_KEY = "sk-votre_cle_api_ici"; // Remplacez par votre clé API // ===== Thème (light/dark) ===== const themeToggle = document.getElementById('themeToggle'); const prefersDark = window.matchMedia('(prefers-color-scheme: dark)'); const storedTheme = localStorage.getItem('theme'); // 'dark' | 'light' | null const setTheme = (mode) => { const html = document.documentElement; if (mode === 'dark') { html.classList.add('dark'); localStorage.setItem('theme', 'dark'); themeToggle.innerHTML = ''; } else { html.classList.remove('dark'); localStorage.setItem('theme', 'light'); themeToggle.innerHTML = ''; } }; setTheme(storedTheme ? storedTheme : (prefersDark.matches ? 'dark' : 'light')); themeToggle.addEventListener('click', () => { const current = document.documentElement.classList.contains('dark') ? 'dark' : 'light'; setTheme(current === 'dark' ? 'light' : 'dark'); }); prefersDark.addEventListener('change', (e) => { if (!localStorage.getItem('theme')) { setTheme(e.matches ? 'dark' : 'light'); } }); // ===== Éléments du DOM ===== const projectList = document.getElementById('projectList'); const chatMessages = document.getElementById('chatMessages'); const chatInput = document.getElementById('chatInput'); const sendBtn = document.getElementById('sendBtn'); const micBtn = document.getElementById('micBtn'); const connectBtn = document.getElementById('connectBtn'); const attachBtn = document.getElementById('attachBtn'); const codeOutput = document.getElementById('codeOutput').querySelector('code'); const aiActivityText = document.getElementById('aiActivityText'); const aiActivityDot = document.getElementById('aiActivityDot'); const tabButtons = document.querySelectorAll('.tab-btn'); // ===== Gestion des projets ===== let projects = JSON.parse(localStorage.getItem('projects') || '[]'); function saveProjects() { localStorage.setItem('projects', JSON.stringify(projects)); } function renderProjects() { projectList.innerHTML = ''; if (projects.length === 0) { const li = document.createElement('li'); li.className = 'text-slate-500'; li.textContent = 'Aucun projet. Cliquez sur "Nouvelle tâche" pour commencer.'; projectList.appendChild(li); return; } projects.forEach((p, idx) => { const li = document.createElement('li'); li.innerHTML = ` ${p} `; projectList.appendChild(li); }); } function addProject(name) { if (!name) return; projects.push(name); saveProjects(); renderProjects(); } function renameProject(index) { const newName = prompt('Nouveau nom du projet:', projects[index]); if (newName && newName.trim()) { projects[index] = newName.trim(); saveProjects(); renderProjects(); } } function deleteProject(index) { if (confirm('Supprimer ce projet ?')) { projects.splice(index, 1); saveProjects(); renderProjects(); } } projectList.addEventListener('click', (e) => { const btn = e.target.closest('button[data-action]'); if (!btn) return; const idx = Number(btn.dataset.index); if (btn.dataset.action === 'rename') renameProject(idx); if (btn.dataset.action === 'delete') deleteProject(idx); }); document.getElementById('newTaskBtn').addEventListener('click', () => { const name = prompt('Nom du nouveau projet:'); if (name) addProject(name.trim()); }); document.getElementById('searchBtn').addEventListener('click', () => { alert('Fonction "Rechercher" à implémenter.'); }); document.getElementById('libraryBtn').addEventListener('click', () => { alert('Fonction "Bibliothèque" à implémenter.'); }); renderProjects(); // ===== Chat (Rosalinda) ===== function setAIActivity(text, active = true) { aiActivityText.textContent = text; aiActivityDot.style.background = active ? 'rgb(34,197,94)' : 'rgb(100,116,139)'; // emerald vs slate } function getChatHistory() { const messages = []; const nodes = chatMessages.querySelectorAll('.msg'); nodes.forEach(node => { const role = node.classList.contains('msg-user') ? 'user' : 'assistant'; const text = node.querySelector('.bubble').textContent.trim(); messages.push({ role, content: text }); }); return messages; } function addMessage(role, content) { const msg = document.createElement('div'); msg.className = 'msg ' + (role === 'user' ? 'msg-user' : 'msg-ai'); if (role === 'user') { msg.innerHTML = `
${escapeHTML(content)}
`; } else { msg.innerHTML = `
${content}
`; } chatMessages.appendChild(msg); chatMessages.scrollTop = chatMessages.scrollHeight; } function escapeHTML(str) { return str.replace(/[&<>"']/g, (m) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[m])); } async function sendMessage() { const text = chatInput.value.trim(); if (!text) return; addMessage('user', text); chatInput.value = ''; setAIActivity('Rosalinda réfléchit...', true); try { const response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${OPENAI_API_KEY}` }, body: JSON.stringify({ model: 'gpt-3.5-turbo', messages: [ { role: 'system', content: 'Tu es Rosalinda, une assistante IA utiles et concise.' }, ...getChatHistory(), { role: 'user', content: text } ], temperature: 0.7 }) }); if (!response.ok) { throw new Error(`Erreur API: ${response.status} ${response.statusText}`); } const data = await response.json(); const assistantMessage = data.choices?.[0]?.message?.content ?? 'Désolé, aucune réponse.'; setAIActivity('IA en veille', false); addMessage('ai', assistantMessage); codeOutput.textContent = assistantMessage; } catch (error) { console.error(error); setAIActivity('IA en veille', false); addMessage('ai', 'Une erreur est survenue lors de la communication avec l\'IA.'); } } sendBtn.addEventListener('click', sendMessage); chatInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') sendMessage(); }); const micBtn = document.getElementById('micBtn'); const languageSelect = document.createElement('select'); languageSelect.id = 'languageSelect'; languageSelect.style.marginLeft = '8px'; languageSelect.style.padding = '6px 8px'; languageSelect.style.borderRadius = '6px'; languageSelect.style.border = '1px solid rgb(226 232 240)'; languageSelect.style.background = 'rgb(248 250 252)'; languageSelect.style.color = 'inherit'; languageSelect.innerHTML = ` `; const chatInputParent = chatInput.parentElement; if (chatInputParent && !document.getElementById('languageSelect')) { chatInputParent.insertBefore(languageSelect, chatInput); } let isListening = false; let recognition = null; let interimTranscript = ''; let lastFinalTranscript = ''; const SpeechRecognitionAPI = window.SpeechRecognition || window.webkitSpeechRecognition; function initSpeechRecognition() { if (!SpeechRecognitionAPI) { aiActivityText.textContent = 'Reconnaissance vocale non supportée'; aiActivityDot.style.background = 'rgb(239,68,68)'; micBtn.disabled = true; micBtn.title = 'Navigateur non compatible'; micBtn.style.opacity = '0.6'; micBtn.style.cursor = 'not-allowed'; return; } recognition = new SpeechRecognitionAPI(); recognition.lang = languageSelect.value; recognition.continuous = true; recognition.interimResults = true; recognition.maxAlternatives = 1; recognition.onstart = () => { isListening = true; micBtn.classList.add('listening'); micBtn.innerHTML = ''; aiActivityText.textContent = 'Écoute en cours...'; aiActivityDot.style.background = 'rgb(234,179,8)'; setAIActivity('Écoute en cours...', true); }; recognition.onend = () => { isListening = false; micBtn.classList.remove('listening'); micBtn.innerHTML = ''; aiActivityText.textContent = 'IA en veille'; aiActivityDot.style.background = 'rgb(100,116,139)'; setAIActivity('IA en veille', false); interimTranscript = ''; }; recognition.onerror = (event) => { console.error('SpeechRecognition error:', event.error); let message = 'Erreur de reconnaissance vocale.'; switch (event.error) { case 'no-speech': message = 'Aucune parole détectée. Essayez de parler plus fort.'; break; case 'audio-capture': message = 'Aucun microphone détecté.'; break; case 'not-allowed': message = 'Accès au microphone refusé.'; break; case 'network': message = 'Erreur réseau.'; break; } addMessage('ai', message); recognition.stop(); }; recognition.onresult = (event) => { interimTranscript = ''; for (let i = event.resultIndex; i < event.results.length; i++) { const transcript = event.results[i][0].transcript.trim(); if (event.results[i].isFinal) { lastFinalTranscript = transcript; addMessage('user', transcript); setAIActivity('Rosalinda réfléchit...', true); sendToAI(transcript); } else { interimTranscript += transcript + ' '; } } if (interimTranscript) { codeOutput.textContent = `// En écoute...\n${interimTranscript}`; } }; } function sendToAI(text) { fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${OPENAI_API_KEY}` }, body: JSON.stringify({ model: 'gpt-3.5-turbo', messages: [ { role: 'system', content: 'Tu es Rosalinda, une assistante IA utile et concise.' }, ...getChatHistory(), { role: 'user', content: text } ], temperature: 0.7 }) }) .then(response => { if (!response.ok) throw new Error(`Erreur API: ${response.status}`); return response.json(); }) .then(data => { const assistantMessage = data.choices?.[0]?.message?.content ?? 'Désolé, aucune réponse.'; addMessage('ai', assistantMessage); codeOutput.textContent = assistantMessage; }) .catch(error => { console.error(error); addMessage('ai', 'Une erreur est survenue lors de la communication avec l\'IA.'); }) .finally(() => { setAIActivity('IA en veille', false); }); } async function toggleListening() { if (!recognition) initSpeechRecognition(); if (!recognition) return; try { if (isListening) { recognition.stop(); } else { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }).catch(() => null); if (!stream) { addMessage('ai', 'Impossible d\'accéder au microphone. Vérifiez les permissions.'); return; } stream.getTracks().forEach(t => t.stop()); recognition.start(); } } catch (err) { console.error(err); addMessage('ai', 'Erreur lors du démarrage de la reconnaissance vocale.'); } } function stopListening() { if (recognition && isListening) recognition.stop(); } micBtn.addEventListener('click', toggleListening); languageSelect.addEventListener('change', () => { if (recognition) recognition.lang = languageSelect.value; }); document.addEventListener('keydown', (e) => { if (e.code === 'Space' && (e.ctrlKey || e.metaKey)) { e.preventDefault(); toggleListening(); } if (e.key === 'Escape' && isListening) { stopListening(); } }); // Stop listening on tab change to avoid dangling permissions document.addEventListener('visibilitychange', () => { if (document.hidden) stopListening(); }); connectBtn.addEventListener('click', () => { alert('Fonction "Connexion" à implémenter (OAuth, clés API, etc.).'); }); attachBtn.addEventListener('click', () => { alert('Fonction "Ajouter un fichier" à implémenter (FileReader, uploads, etc.).'); }); // ===== Onglets ===== tabButtons.forEach(btn => { btn.addEventListener('click', () => { tabButtons.forEach(b => b.classList.remove('active')); btn.classList.add('active'); const tab = btn.dataset.tab; const demo = { code: '// Code généré s’affichera ici...', dashboard: 'Tableau de bord (graphiques, KPIs)...', db: 'Visualisation base de données (tables, requêtes)...', storage: 'Gestion du stockage (fichiers, objets)...', settings: 'Paramètres (thème, clés API, intégrations)...' }; codeOutput.textContent = demo[tab] || '// ...'; }); }); // Surveillance anti-modification non autorisée du résultat setInterval(() => { const codeActuel = document.getElementById('resultat').innerText; if (!codeActuel.includes('Résultat final')) { alert('⚠️ Alerte : Modification non autorisée détectée. Restauration...'); location.reload(); } }, 5000);