Download script.js from Abmacode12/codeflow-station-anti-stop-engine: direct link, hf CLI and curl.
- Browser
- Download file 19.4 kB
-
https://huggingface.co/spaces/Abmacode12/codeflow-station-anti-stop-engine/resolve/main/script.js
- Command line
-
hf download hf://spaces/Abmacode12/codeflow-station-anti-stop-engine/script.js
-
curl -L -o script.js https://huggingface.co/spaces/Abmacode12/codeflow-station-anti-stop-engine/resolve/main/script.js
19.4 kB
| // 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 = ` | |
| <div class="text-xs text-slate-400 mb-2">${title}</div> | |
| <div class="text-sm text-slate-200 leading-6">${html}</div> | |
| `; | |
| 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", ` | |
| <div class="text-rose-400">❌ Échec de la requête</div> | |
| <div class="mt-1 text-sm">${escapeHtml(err.message)}</div> | |
| ${err.message.includes('hors ligne') ? | |
| '<div class="mt-1 text-xs">Veuillez vérifier votre connexion Internet.</div>' : ''} | |
| `); | |
| 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 = ` | |
| <div class="rounded-xl overflow-hidden border border-white/10"> | |
| <img src="${data.url}" class="w-full" alt="Image générée"> | |
| <div class="p-2 text-xs text-slate-400">Généré: ${new Date().toLocaleTimeString()}</div> | |
| <button class="w-full px-3 py-1 bg-indigo-500/20 hover:bg-indigo-500/30 text-xs" | |
| onclick="document.getElementById('code').value += '\\n<img src=\\'${data.url}\\' alt=\\'Image générée\\'>\\n'; applyPreview()"> | |
| Insérer dans le code | |
| </button> | |
| </div> | |
| `; | |
| 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 = ` | |
| <div class="rounded-xl overflow-hidden border border-white/10"> | |
| <video controls class="w-full"> | |
| <source src="${data.url}" type="video/mp4"> | |
| </video> | |
| <div class="p-2 text-xs text-slate-400">Généré: ${new Date().toLocaleTimeString()}</div> | |
| <button class="w-full px-3 py-1 bg-indigo-500/20 hover:bg-indigo-500/30 text-xs" | |
| onclick="document.getElementById('code').value += '\\n<video controls>\\n <source src=\\'${data.url}\\' type=\\'video/mp4\\'>\\n</video>\\n'; applyPreview()"> | |
| Insérer dans le code | |
| </button> | |
| </div> | |
| `; | |
| 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", ` | |
| <div class="text-amber-400">⚠️ Maintenance en cours</div> | |
| <div class="mt-1 text-sm">Fonctionnalités limitées pendant la maintenance.</div> | |
| `); | |
| 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 = `<!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>My App</title> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <meta charset="utf-8"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| </head> | |
| <body class="flex justify-center items-center h-screen overflow-hidden bg-white font-sans text-center px-6"> | |
| <div class="w-full"> | |
| <span class="text-xs rounded-full mb-2 inline-block px-2 py-1 border border-amber-500/15 bg-amber-500/15 text-amber-500">🔥 New version!</span> | |
| <h1 class="text-4xl lg:text-6xl font-bold font-sans"> | |
| <span class="text-2xl lg:text-4xl text-gray-400 block font-medium">I'm ready to work,</span> | |
| Ask me anything. | |
| </h1> | |
| </div> | |
| </body> | |
| </html>`; | |
| // 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", ` | |
| <div class="text-amber-400">⚠️ Mode hors ligne activé</div> | |
| <div class="mt-2 text-sm">Certaines fonctionnalités sont désactivées :</div> | |
| <ul class="mt-1 text-xs space-y-1"> | |
| <li>• Vérifiez que le serveur Rosalinda est en marche</li> | |
| <li>• Si local: <code class="bg-black/20 px-1">node server.js</code></li> | |
| <li>• Pour Ollama: <code class="bg-black/20 px-1">ollama serve</code></li> | |
| <li>• Si cloud: vérifiez l'URL de l'espace HF</li> | |
| </ul> | |
| <div class="mt-2 text-xs">Solutions locales: installer Ollama ou lancer le serveur Rosalinda.</div> | |
| `); | |
| // 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)); | |
| } | |
| } | |
| }; | |