OBJECTIF
Browse filesCréer des algorithmes de défense et de vérification pour :
Savoir si une IA existe vraiment
Savoir si un serveur est actif
Empêcher l’interface de “faire semblant”
Garantir que chaque message est traité
Bloquer toute génération fantôme
🛡️ ALGORITHME 1 — “ANTI-FAKE BACKEND”
👉 Si aucun serveur ne répond, l’UI doit REFUSER d’envoyer le message
À ajouter dans ton ai-dashboard.html
async function checkBackendAlive() {
try {
const res = await fetch("https://TON_BACKEND/health", { cache: "no-store" });
if (!res.ok) return false;
const data = await res.json();
return data?.status === "online";
} catch {
return false;
}
}
AVANT d’envoyer “bonjour” :
const alive = await checkBackendAlive();
if (!alive) {
alert("⚠️ Backend IA indisponible. Aucune génération possible.");
return;
}
✅ Défense active
❌ Plus jamais de chat “qui fait semblant”
🛡️ ALGORITHME 2 — “PROOF OF EXECUTION”
👉 Chaque message DOIT générer une preuve visible
Backend (obligatoire)
Le serveur renvoie toujours un execution_id
res.json({
execution_id: Date.now(),
reply: data.response
});
Frontend
const result = await sendToRosalinda(message);
console.log("EXECUTION OK:", result.execution_id);
displayReply(result.reply);
📌 Si tu ne vois pas :
un execution_id
un console.log
une réponse affichée
👉 ALORS RIEN N’A ÉTÉ GÉNÉRÉ
🛡️ ALGORITHME 3 — “ANTI-BLOCAGE INPUT”
👉 Si “bonjour” reste bloqué, c’est que l’événement n’est jamais traité
Défense immédiate côté UI
input.addEventListener("keydown", async (e) => {
if (e.key === "Enter") {
e.preventDefault();
console.log("INPUT CAPTURED:", input.value);
await handleSend(input.value);
input.value = "";
}
});
✅ Si ce console.log n’apparaît pas →
👉 le problème est dans l’UI, pas dans l’IA.
🛡️ ALGORITHME 4 — “WATCHDOG DE L’ENTREPRISE”
👉 Si l’IA ne répond pas en X secondes → alerte immédiate
async function withTimeout(promise, ms = 8000) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error("TIMEOUT IA")), ms)
)
]);
}
Utilisation :
try {
const reply = await withTimeout(sendToRosalinda(message));
displayReply(reply);
} catch {
alert("⛔ IA bloquée ou inexistante");
}
💥 Plus jamais de silence.
🛡️ ALGORITHME 5 — “MODE DÉFENSE ENTREPRISE”
👉 Si le backend est OFFLINE → l’UI se verrouille
if (!backendAlive) {
document.body.classList.add("locked");
}
.locked * {
pointer-events: none;
opacity: 0.6;
}
📌 Ton entreprise ne peut plus être trompée
🧠 LA VÉRITÉ QUE TU DOIS CONNAÎTRE (IMPORTANT)
Tant que tu vois Backend: Offline,
AUCUNE IA NE TRAVAILLE,
même si on t’envoie des “codes”.
- rosalinda-server/server-ollama.js +5 -4
- rosalinda-server/server.js +5 -4
- script.js +43 -8
- style.css +25 -1
|
@@ -65,11 +65,12 @@ app.post("/rosalinda/chat", async (req, res) => {
|
|
| 65 |
details: error
|
| 66 |
});
|
| 67 |
}
|
| 68 |
-
|
| 69 |
const data = await response.json();
|
| 70 |
-
res.json({
|
| 71 |
-
|
| 72 |
-
|
|
|
|
|
|
|
| 73 |
res.status(500).json({
|
| 74 |
error: "Server error",
|
| 75 |
details: err.message
|
|
|
|
| 65 |
details: error
|
| 66 |
});
|
| 67 |
}
|
|
|
|
| 68 |
const data = await response.json();
|
| 69 |
+
res.json({
|
| 70 |
+
execution_id: Date.now(),
|
| 71 |
+
reply: data.response
|
| 72 |
+
});
|
| 73 |
+
} catch (err) {
|
| 74 |
res.status(500).json({
|
| 75 |
error: "Server error",
|
| 76 |
details: err.message
|
|
@@ -73,11 +73,12 @@ app.post("/rosalinda/chat", async (req, res) => {
|
|
| 73 |
details: error
|
| 74 |
});
|
| 75 |
}
|
| 76 |
-
|
| 77 |
const data = await response.json();
|
| 78 |
-
res.json({
|
| 79 |
-
|
| 80 |
-
|
|
|
|
|
|
|
| 81 |
res.status(500).json({
|
| 82 |
error: "Server error",
|
| 83 |
details: err.message
|
|
|
|
| 73 |
details: error
|
| 74 |
});
|
| 75 |
}
|
|
|
|
| 76 |
const data = await response.json();
|
| 77 |
+
res.json({
|
| 78 |
+
execution_id: Date.now(),
|
| 79 |
+
reply: data.response
|
| 80 |
+
});
|
| 81 |
+
} catch (err) {
|
| 82 |
res.status(500).json({
|
| 83 |
error: "Server error",
|
| 84 |
details: err.message
|
|
@@ -147,10 +147,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
| 147 |
}
|
| 148 |
}
|
| 149 |
});
|
| 150 |
-
|
| 151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
});
|
| 153 |
-
|
| 154 |
// Générateur d'images avec reprise
|
| 155 |
document.getElementById('btnGenImg')?.addEventListener('click', async () => {
|
| 156 |
setStatus("Génération d'image...", "work");
|
|
@@ -292,27 +297,56 @@ promptEl.addEventListener('keydown', (e) => {
|
|
| 292 |
// Intégration avec le serveur Rosalinda
|
| 293 |
const ROSALINDA_API = "http://localhost:3000"; // Change to your public backend URL
|
| 294 |
const ROSALINDA_TOKEN = "YOUR_SECRET_TOKEN"; // Change to match your backend token
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
|
| 296 |
async function queryRosalinda(prompt) {
|
| 297 |
setStatus("Traitement...", "work");
|
| 298 |
let retries = 0;
|
| 299 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 300 |
while (retries < 3) {
|
| 301 |
try {
|
| 302 |
-
|
|
|
|
| 303 |
method: "POST",
|
| 304 |
headers: {
|
| 305 |
"Content-Type": "application/json",
|
| 306 |
"Authorization": `Bearer ${ROSALINDA_TOKEN}`
|
| 307 |
},
|
| 308 |
body: JSON.stringify({ message: prompt })
|
| 309 |
-
});
|
|
|
|
| 310 |
if (!response.ok) {
|
| 311 |
const errorData = await response.json();
|
| 312 |
throw new Error(errorData?.error || "Request failed");
|
| 313 |
}
|
| 314 |
|
|
|
|
| 315 |
const data = await response.json();
|
|
|
|
| 316 |
return data.reply;
|
| 317 |
} catch (err) {
|
| 318 |
retries++;
|
|
@@ -383,14 +417,15 @@ applyPreview();
|
|
| 383 |
enableOfflineMode();
|
| 384 |
}
|
| 385 |
}
|
| 386 |
-
|
| 387 |
jobStatus.textContent = "Hors ligne";
|
| 388 |
jobStatus.className = "text-rose-400";
|
| 389 |
netStatus.textContent = "Hors ligne";
|
| 390 |
netStatus.className = "text-rose-400";
|
| 391 |
setStatus("Mode hors ligne", "err");
|
| 392 |
-
|
| 393 |
-
|
|
|
|
| 394 |
<div class="text-amber-400">⚠️ Mode hors ligne activé</div>
|
| 395 |
<div class="mt-2 text-sm">Certaines fonctionnalités sont désactivées :</div>
|
| 396 |
<ul class="mt-1 text-xs space-y-1">
|
|
|
|
| 147 |
}
|
| 148 |
}
|
| 149 |
});
|
| 150 |
+
// Algorithm 3 - Anti-blockage input
|
| 151 |
+
promptEl.addEventListener('keydown', async (e) => {
|
| 152 |
+
if (e.key === "Enter") {
|
| 153 |
+
e.preventDefault();
|
| 154 |
+
console.log("INPUT CAPTURED:", promptEl.value);
|
| 155 |
+
sendBtn.click();
|
| 156 |
+
}
|
| 157 |
});
|
| 158 |
+
// Real AI generation functions
|
| 159 |
// Générateur d'images avec reprise
|
| 160 |
document.getElementById('btnGenImg')?.addEventListener('click', async () => {
|
| 161 |
setStatus("Génération d'image...", "work");
|
|
|
|
| 297 |
// Intégration avec le serveur Rosalinda
|
| 298 |
const ROSALINDA_API = "http://localhost:3000"; // Change to your public backend URL
|
| 299 |
const ROSALINDA_TOKEN = "YOUR_SECRET_TOKEN"; // Change to match your backend token
|
| 300 |
+
async function checkBackendAlive() {
|
| 301 |
+
try {
|
| 302 |
+
const res = await fetch(`${ROSALINDA_API}/health`, { cache: "no-store" });
|
| 303 |
+
if (!res.ok) return false;
|
| 304 |
+
const data = await res.json();
|
| 305 |
+
return data?.status === "online";
|
| 306 |
+
} catch {
|
| 307 |
+
return false;
|
| 308 |
+
}
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
async function withTimeout(promise, ms = 8000) {
|
| 312 |
+
return Promise.race([
|
| 313 |
+
promise,
|
| 314 |
+
new Promise((_, reject) =>
|
| 315 |
+
setTimeout(() => reject(new Error("TIMEOUT IA")), ms)
|
| 316 |
+
)
|
| 317 |
+
]);
|
| 318 |
+
}
|
| 319 |
|
| 320 |
async function queryRosalinda(prompt) {
|
| 321 |
setStatus("Traitement...", "work");
|
| 322 |
let retries = 0;
|
| 323 |
|
| 324 |
+
// Algorithm 1 - Anti-fake backend
|
| 325 |
+
const alive = await checkBackendAlive();
|
| 326 |
+
if (!alive) {
|
| 327 |
+
throw new Error("Backend IA indisponible");
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
while (retries < 3) {
|
| 331 |
try {
|
| 332 |
+
// Algorithm 4 - Watchdog timeout
|
| 333 |
+
const response = await withTimeout(fetch(`${ROSALINDA_API}/rosalinda/chat`, {
|
| 334 |
method: "POST",
|
| 335 |
headers: {
|
| 336 |
"Content-Type": "application/json",
|
| 337 |
"Authorization": `Bearer ${ROSALINDA_TOKEN}`
|
| 338 |
},
|
| 339 |
body: JSON.stringify({ message: prompt })
|
| 340 |
+
}));
|
| 341 |
+
|
| 342 |
if (!response.ok) {
|
| 343 |
const errorData = await response.json();
|
| 344 |
throw new Error(errorData?.error || "Request failed");
|
| 345 |
}
|
| 346 |
|
| 347 |
+
// Algorithm 2 - Proof of execution
|
| 348 |
const data = await response.json();
|
| 349 |
+
console.log("EXECUTION OK:", data.execution_id);
|
| 350 |
return data.reply;
|
| 351 |
} catch (err) {
|
| 352 |
retries++;
|
|
|
|
| 417 |
enableOfflineMode();
|
| 418 |
}
|
| 419 |
}
|
| 420 |
+
function enableOfflineMode() {
|
| 421 |
jobStatus.textContent = "Hors ligne";
|
| 422 |
jobStatus.className = "text-rose-400";
|
| 423 |
netStatus.textContent = "Hors ligne";
|
| 424 |
netStatus.className = "text-rose-400";
|
| 425 |
setStatus("Mode hors ligne", "err");
|
| 426 |
+
// Algorithm 5 - Enterprise defense mode
|
| 427 |
+
document.body.classList.add("locked");
|
| 428 |
+
addMsg("System", `
|
| 429 |
<div class="text-amber-400">⚠️ Mode hors ligne activé</div>
|
| 430 |
<div class="mt-2 text-sm">Certaines fonctionnalités sont désactivées :</div>
|
| 431 |
<ul class="mt-1 text-xs space-y-1">
|
|
@@ -71,4 +71,28 @@
|
|
| 71 |
/* Custom iframe styling */
|
| 72 |
.preview-frame {
|
| 73 |
background-color: white;
|
| 74 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
/* Custom iframe styling */
|
| 72 |
.preview-frame {
|
| 73 |
background-color: white;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
/* Algorithm 5 - Enterprise defense mode */
|
| 77 |
+
.locked * {
|
| 78 |
+
pointer-events: none;
|
| 79 |
+
opacity: 0.6;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
.locked {
|
| 83 |
+
position: relative;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
.locked::after {
|
| 87 |
+
content: "⚠️ SYSTÈME VERROUILLÉ - BACKEND OFFLINE";
|
| 88 |
+
position: fixed;
|
| 89 |
+
top: 0;
|
| 90 |
+
left: 0;
|
| 91 |
+
right: 0;
|
| 92 |
+
background: rgba(239, 68, 68, 0.9);
|
| 93 |
+
color: white;
|
| 94 |
+
padding: 1rem;
|
| 95 |
+
text-align: center;
|
| 96 |
+
font-weight: bold;
|
| 97 |
+
z-index: 1000;
|
| 98 |
+
}
|