Abmacode12's picture
zone-ai/
4ed3b55 verified
// 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("&","&amp;")
.replaceAll("<","&lt;")
.replaceAll(">","&gt;");
}
// 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));
}
}
};