// AI Dashboard specific functions function initAIDashboard() { // Add event listeners for generation buttons document.getElementById('btnGenText')?.addEventListener('click', () => { console.log('Text generation requested'); // Implement text generation logic }); document.getElementById('btnGenImage')?.addEventListener('click', () => { console.log('Image generation requested'); // Implement image generation logic }); document.getElementById('btnGenVideo')?.addEventListener('click', () => { console.log('Video generation requested'); // Implement video generation logic }); } // Main application logic document.addEventListener('DOMContentLoaded', () => { // Initialize appropriate page based on current URL if (window.location.pathname.includes('ai-dashboard.html')) { initAIDashboard(); return; } // Initialize UI elements const chat = document.getElementById('chat'); const promptEl = document.getElementById('prompt'); const sendBtn = document.getElementById('btnSend'); const statusPill = document.getElementById('statusPill'); const codeEl = document.getElementById('code'); const previewFrame = document.getElementById('previewFrame'); const netStatus = document.getElementById('netStatus'); const mediaOut = document.getElementById('mediaOut'); const jobStatus = document.getElementById('jobStatus'); const retryPill = document.getElementById('retryPill'); // Check for Ollama backend first async function checkOllama() { try { const response = await fetch('http://localhost:11434/api/generate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'llama3.1', prompt: 'Test connection', stream: false }) }); return response.ok; } catch { return false; } } // UI helpers function addMsg(title, html) { const wrap = document.createElement('div'); wrap.className = "rounded-2xl border border-white/10 bg-white/5 p-4"; wrap.innerHTML = `
${title}
${html}
`; chat.appendChild(wrap); chat.scrollTop = chat.scrollHeight; } function setStatus(txt, type="idle") { statusPill.textContent = txt; statusPill.className = "px-2 py-1 rounded-lg border text-xs"; if (type === "ok") statusPill.classList.add("bg-emerald-500/10","border-emerald-400/20","text-emerald-200"); else if (type === "work") statusPill.classList.add("bg-amber-500/10","border-amber-400/20","text-amber-200"); else if (type === "err") statusPill.classList.add("bg-rose-500/10","border-rose-400/20","text-rose-200"); else statusPill.classList.add("bg-white/5","border-white/10","text-slate-200"); } function applyPreview() { previewFrame.srcdoc = codeEl.value; } // Tab switching function switchTab(tab) { document.querySelectorAll('.tabBtn').forEach(b => { const active = b.dataset.tab === tab; b.className = "tabBtn px-3 py-1.5 rounded-xl border text-xs " + (active ? "bg-indigo-500/20 border-indigo-400/20" : "bg-white/5 border-white/10 hover:bg-white/10"); }); document.getElementById('panel-code').classList.toggle('hidden', tab !== 'code'); document.getElementById('panel-preview').classList.toggle('hidden', tab !== 'preview'); document.getElementById('panel-media').classList.toggle('hidden', tab !== 'media'); } document.querySelectorAll('.tabBtn').forEach(b => { b.addEventListener('click', () => switchTab(b.dataset.tab)); }); // Button event listeners document.getElementById('btnApply').addEventListener('click', applyPreview); document.getElementById('btnReloadPreview').addEventListener('click', applyPreview); document.getElementById('btnRefresh').addEventListener('click', applyPreview); document.getElementById('btnCopy').addEventListener('click', async () => { try { await navigator.clipboard.writeText(codeEl.value); setStatus("Copied!", "ok"); setTimeout(() => setStatus("Ready", "ok"), 2000); } catch { setStatus("Copy failed", "err"); setTimeout(() => setStatus("Ready", "ok"), 2000); } }); document.getElementById('btnExport').addEventListener('click', () => { const blob = new Blob([codeEl.value], { type: "text/html;charset=utf-8" }); const a = document.createElement("a"); a.href = URL.createObjectURL(blob); a.download = "index.html"; a.click(); URL.revokeObjectURL(a.href); }); // Microphone functionality function micStart() { const SR = window.SpeechRecognition || window.webkitSpeechRecognition; if (!SR) { addMsg("System","Microphone not available. Use Chrome Desktop."); return; } const rec = new SR(); rec.lang = "en-US"; rec.interimResults = false; rec.maxAlternatives = 1; setStatus("Listening...","work"); rec.onresult = (e) => { const txt = e.results[0][0].transcript; promptEl.value = txt; setStatus("Ready","ok"); }; rec.onerror = () => setStatus("Mic error","err"); rec.onend = () => setStatus("Ready","ok"); rec.start(); } document.getElementById('btnMic').addEventListener('click', micStart); // Send message handler sendBtn.addEventListener('click', async () => { const v = promptEl.value.trim(); if (!v || sendBtn.disabled) return; promptEl.value = ""; addMsg("You", v); try { if (!await checkBackend()) { enableOfflineMode(); return; } setStatus("Traitement...", "work"); const response = await queryRosalinda(v); addMsg("Rosalinda", response); // Auto-apply AI suggestions for code if (response.startsWith("```") && response.endsWith("```")) { const code = response.slice(3, -3).trim(); codeEl.value = code; applyPreview(); } setStatus("Envoyé", "ok"); } catch (err) { console.error("Send error:", err); addMsg("System", `
❌ Échec de la requête
${escapeHtml(err.message)}
${err.message.includes('hors ligne') ? '
Veuillez vérifier votre connexion Internet.
' : ''} `); setStatus("Échec", "err"); if (err.message.includes('hors ligne') || err.message.includes('Failed to fetch')) { enableOfflineMode(); } } }); // Algorithm 3 - Anti-blockage input promptEl.addEventListener('keydown', async (e) => { if (e.key === "Enter") { e.preventDefault(); console.log("INPUT CAPTURED:", promptEl.value); sendBtn.click(); } }); // Real AI generation functions // Générateur d'images avec reprise document.getElementById('btnGenImg')?.addEventListener('click', async () => { setStatus("Génération d'image...", "work"); let retries = 0; while (retries < 3) { try { const response = await fetch('/api/generate/image', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: "Image créative haute qualité" }) }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); mediaOut.innerHTML = `
Image générée
Généré: ${new Date().toLocaleTimeString()}
`; setStatus("Image prête", "ok"); return; } catch (err) { retries++; console.error(`Tentative ${retries} échouée:`, err); if (retries >= 3) { setStatus("Échec de génération", "err"); addMsg("System", `❌ Échec après 3 tentatives: ${err.message}`); return; } await new Promise(resolve => setTimeout(resolve, 3000 * retries)); } } }); // Générateur de vidéos avec reprise document.getElementById('btnGenVid')?.addEventListener('click', async () => { setStatus("Génération de vidéo...", "work"); let retries = 0; while (retries < 3) { try { const response = await fetch('/api/generate/video', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: "Vidéo courte créative" }) }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); mediaOut.innerHTML = `
Généré: ${new Date().toLocaleTimeString()}
`; setStatus("Vidéo prête", "ok"); return; } catch (err) { retries++; console.error(`Tentative ${retries} échouée:`, err); if (retries >= 3) { setStatus("Échec de génération", "err"); addMsg("System", `❌ Échec après 3 tentatives: ${err.message}`); return; } await new Promise(resolve => setTimeout(resolve, 3000 * retries)); } } }); // Vérification améliorée du backend async function checkBackend() { let retries = 0; let lastError = null; while (retries < 3) { try { const response = await fetch('/api/health'); if (response.ok) { const data = await response.json(); netStatus.textContent = data.status === 'online' ? "En ligne" : "Maintenance"; netStatus.className = data.status === 'online' ? "text-emerald-400" : "text-amber-400"; jobStatus.textContent = data.status === 'online' ? "Prêt" : "Maintenance"; jobStatus.className = data.status === 'online' ? "text-emerald-400" : "text-amber-400"; if (data.status === 'online') { // Enable online features document.getElementById('btnSend').disabled = false; document.getElementById('btnMic').disabled = false; document.getElementById('btnGenImg')?.disabled = false; document.getElementById('btnGenVid')?.disabled = false; document.getElementById('prompt').placeholder = "Search or write..."; return true; } else { addMsg("System", `
⚠️ Maintenance en cours
Fonctionnalités limitées pendant la maintenance.
`); return false; } } throw new Error(`HTTP ${response.status}`); } catch (err) { retries++; lastError = err; if (retries >= 3) { throw lastError; // Let the caller handle the final error } await new Promise(resolve => setTimeout(resolve, 2000)); } } } // Intégration avec le serveur Rosalinda const ROSALINDA_API = "http://localhost:3000"; // Change to your public backend URL const ROSALINDA_TOKEN = "YOUR_SECRET_TOKEN"; // Change to match your backend token async function checkBackendAlive() { try { const res = await fetch(`${ROSALINDA_API}/health`, { cache: "no-store" }); if (!res.ok) return false; const data = await res.json(); return data?.status === "online"; } catch { return false; } } async function withTimeout(promise, ms = 8000) { return Promise.race([ promise, new Promise((_, reject) => setTimeout(() => reject(new Error("TIMEOUT IA")), ms) ) ]); } async function queryRosalinda(prompt) { setStatus("Traitement...", "work"); let retries = 0; // First try Ollama directly if available const ollamaAvailable = await checkOllama(); if (ollamaAvailable) { try { const response = await fetch('http://localhost:11434/api/generate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'llama3.1', prompt: `Tu es Rosalinda, IA privée. Réponds en français de façon professionnelle.\n\nUser: ${prompt}\nRosalinda:`, stream: false }) }); if (!response.ok) throw new Error(`Ollama error: ${response.status}`); const data = await response.json(); return data.response; } catch (err) { console.error("Ollama error:", err); // Fall through to try Rosalinda backend } } // Algorithm 1 - Anti-fake backend const alive = await checkBackendAlive(); if (!alive) { throw new Error("Backend IA indisponible"); } while (retries < 3) { try { // Algorithm 4 - Watchdog timeout const response = await withTimeout(fetch(`${ROSALINDA_API}/rosalinda/chat`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${ROSALINDA_TOKEN}` }, body: JSON.stringify({ message: prompt }) })); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData?.error || "Request failed"); } // Algorithm 2 - Proof of execution const data = await response.json(); console.log("EXECUTION OK:", data.execution_id); return data.reply; } catch (err) { retries++; console.error(`Attempt ${retries} failed:`, err); retryPill.textContent = `${retries} / 3`; if (retries >= 3) { throw new Error("Échec après 3 tentatives"); } await new Promise(resolve => setTimeout(resolve, 2000 * retries)); } } } // Initialize with default code codeEl.value = ` My App
🔥 New version!

I'm ready to work, Ask me anything.

`; // Initialisation Rosalinda async function initialize() { try { jobStatus.textContent = "Connecting..."; // First try Ollama if available const ollamaAvailable = await checkOllama(); if (ollamaAvailable) { netStatus.textContent = "Ollama Local"; netStatus.className = "text-emerald-400"; jobStatus.textContent = "Prêt"; addMsg("Rosalinda", "Bonjour ! Je suis Rosalinda en mode local (Ollama). Comment puis-je vous aider ?"); return; } // Then check Rosalinda backend health try { const response = await fetch(`${ROSALINDA_API}/health`); if (response.ok) { const data = await response.json(); netStatus.textContent = data.status === 'online' ? "En ligne" : "Maintenance"; netStatus.className = data.status === 'online' ? "text-emerald-400" : "text-amber-400"; jobStatus.textContent = "Prêt"; addMsg("Rosalinda", "Bonjour ! Je suis Rosalinda, votre assistante IA privée. Comment puis-je vous aider aujourd'hui ?"); return; } } catch (err) { console.error("Backend connection error:", err); enableOfflineMode(); } // Periodic health check setInterval(async () => { try { await fetch(`${ROSALINDA_API}/health`); netStatus.textContent = "En ligne"; netStatus.className = "text-emerald-400"; } catch (e) { enableOfflineMode(); } }, 30000); applyPreview(); switchTab('preview'); } catch (err) { console.error("Initialization error:", err); enableOfflineMode(); } } function enableOfflineMode() { jobStatus.textContent = "Hors ligne"; jobStatus.className = "text-rose-400"; netStatus.textContent = "Hors ligne"; netStatus.className = "text-rose-400"; setStatus("Mode hors ligne", "err"); // Algorithm 5 - Enterprise defense mode document.body.classList.add("locked"); addMsg("System", `
⚠️ Mode hors ligne activé
Certaines fonctionnalités sont désactivées :
Solutions locales: installer Ollama ou lancer le serveur Rosalinda.
`); // Enable features but they'll fail gracefully document.getElementById('btnSend').disabled = false; document.getElementById('btnMic').disabled = false; document.getElementById('prompt').placeholder = "Essayez de relancer le serveur Rosalinda"; } initialize(); applyPreview(); switchTab('preview'); }); // Utility functions function escapeHtml(s) { return String(s || "") .replaceAll("&","&") .replaceAll("<","<") .replaceAll(">",">"); } // Auto-retry for all fetch operations const originalFetch = window.fetch; window.fetch = async function(...args) { let retries = 3; while (retries > 0) { try { const response = await originalFetch(...args); if (response.ok) return response; throw new Error(`HTTP error ${response.status}`); } catch (err) { retries--; if (retries === 0) throw err; await new Promise(resolve => setTimeout(resolve, 2000)); } } };