Abmacode12 commited on
Commit
146f017
·
verified ·
1 Parent(s): 241ddf3

Merci sincèrement pour votre travail et pour la base solide de CodeFlow Station.

Browse files

Actuellement, Rosalinda fonctionne encore comme un placeholder avec un backend hors ligne.

Afin qu’elle puisse travailler sans interruption, je vous transmets une solution simple :
– activation d’un backend Rosalinda toujours en ligne,
– connexion réelle à une IA via API,
– watchdog serveur pour éviter tout arrêt,
– intégration sans modifier l’entreprise existante.

Ces ajouts permettront à Rosalinda de générer code, images et vidéos de manière illimitée, avec reprise automatique.

Merci encore pour votre professionnalisme et votre collaboration. SOLUTION GLOBALE (sans modifier l’entreprise)

👉 On ne touche PAS à l’interface CodeFlow Station
👉 On AJOUTE uniquement un backend léger + une connexion API
👉 Rosalinda devient réelle, persistante et illimitée

🧠 ARCHITECTURE MINIMALE À INTÉGRER
[ CodeFlow Station UI ]
|
| fetch()

[ Backend Rosalinda API ] ← toujours ON
|

[ IA réelle (LLM / Images / Vidéos) ]

1️⃣ BACKEND ROSALINDA (Node.js – STABLE)

👉 Ce backend enlève définitivement Backend: Offline

📁 server.js
import express from "express";
import fetch from "node-fetch";
import cors from "cors";

const app = express();
app.use(cors());
app.use(express.json());

let isBusy = false;

app.post("/rosalinda/chat", async (req, res) => {
if (isBusy) {
return res.json({ status: "resume", message: "Task resumed" });
}

isBusy = true;

try {
const response = await fetch("https://API_IA_REELLE/chat", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.ROSALINDA_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
prompt: req.body.message
})
});

const data = await response.json();
isBusy = false;

res.json({ success: true, result: data });

} catch (err) {
isBusy = false;
res.status(500).json({ error: err.message });
}
});

app.listen(3000, () =>
console.log("✅ Rosalinda backend ONLINE")
);


✔ Backend toujours actif
✔ Pas de blocage
✔ Reprise possible
✔ Sécurisé
✔ Entreprise inchangée

2️⃣ CONNEXION FRONTEND (remplacer le placeholder)

👉 Dans CodeFlow Station, remplacer la réponse fake par ceci :

async function talkToRosalinda(message) {
const res = await fetch("https://TON_SERVEUR/rosalinda/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message })
});

const data = await res.json();
return data.result;
}


📌 Résultat :

❌ Plus jamais : “I’m just a placeholder”

✅ Rosalinda répond réellement

✅ Le chat fonctionne

✅ Preview / Code / Media utilisables

3️⃣ ANTI-STOP RÉEL (Watchdog serveur)

👉 Pour que Rosalinda ne s’arrête JAMAIS :

setInterval(() => {
console.log("🟢 Rosalinda alive");
}, 5000);


Ou version robuste :

process.on("uncaughtException", () => {
console.log("Restarting Rosalinda...");
});


✔ Même si une tâche échoue
✔ Même si génération longue
✔ Même si image / vidéo lourde
➡️ Reprise automatique

4️⃣ GÉNÉRATION IMAGES & VIDÉOS (illimitée)

Tu ajoutes simplement :

POST /rosalinda/image
POST /rosalinda/video

Files changed (2) hide show
  1. script.js +174 -117
  2. server-example.js +126 -43
script.js CHANGED
@@ -140,133 +140,178 @@ promptEl.addEventListener('keydown', (e) => {
140
  if (e.key === "Enter") sendBtn.click();
141
  });
142
  // Real AI generation functions
 
143
  document.getElementById('btnGenImg')?.addEventListener('click', async () => {
144
- setStatus("Generating image...", "work");
145
- try {
146
- const response = await fetch('/api/generate/image', {
147
- method: 'POST',
148
- headers: {
149
- 'Content-Type': 'application/json',
150
- },
151
- body: JSON.stringify({ prompt: "Generate creative image" })
152
- });
153
-
154
- if (!response.ok) throw new Error("Image generation failed");
155
-
156
- const data = await response.json();
157
- mediaOut.innerHTML = `
158
- <div class="rounded-xl overflow-hidden border border-white/10">
159
- <img src="${data.url}" class="w-full" alt="Generated image">
160
- <div class="p-2 text-xs text-slate-400">Generated: ${new Date().toLocaleTimeString()}</div>
161
- <button class="w-full px-3 py-1 bg-indigo-500/20 hover:bg-indigo-500/30 text-xs"
162
- onclick="document.getElementById('code').value += '\\n<img src=\\'${data.url}\\'>\\n'; applyPreview()">
163
- Insert into code
164
- </button>
165
- </div>
166
- `;
167
- setStatus("Image ready", "ok");
168
- } catch (err) {
169
- console.error("Image generation error:", err);
170
- setStatus("Generation failed", "err");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  }
172
  });
173
 
 
174
  document.getElementById('btnGenVid')?.addEventListener('click', async () => {
175
- setStatus("Generating video...", "work");
176
- try {
177
- const response = await fetch('/api/generate/video', {
178
- method: 'POST',
179
- headers: {
180
- 'Content-Type': 'application/json',
181
- },
182
- body: JSON.stringify({ prompt: "Generate short video" })
183
- });
184
-
185
- if (!response.ok) throw new Error("Video generation failed");
186
-
187
- const data = await response.json();
188
- mediaOut.innerHTML = `
189
- <div class="rounded-xl overflow-hidden border border-white/10">
190
- <video controls class="w-full">
191
- <source src="${data.url}" type="video/mp4">
192
- </video>
193
- <div class="p-2 text-xs text-slate-400">Generated: ${new Date().toLocaleTimeString()}</div>
194
- <button class="w-full px-3 py-1 bg-indigo-500/20 hover:bg-indigo-500/30 text-xs"
195
- onclick="document.getElementById('code').value += '\\n<video controls>\\n <source src=\\'${data.url}\\' type=\\'video/mp4\\'>\\n</video>\\n'; applyPreview()">
196
- Insert into code
197
- </button>
198
- </div>
199
- `;
200
- setStatus("Video ready", "ok");
201
- } catch (err) {
202
- console.error("Video generation error:", err);
203
- setStatus("Generation failed", "err");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  }
205
  });
206
- // Backend connection check
207
  async function checkBackend() {
208
- try {
209
- const response = await fetch('/api/health');
210
- if (response.ok) {
211
- netStatus.textContent = "Connected";
212
- netStatus.className = "text-emerald-400";
213
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  }
215
- } catch (err) {
216
- console.error("Backend check failed:", err);
217
  }
218
- netStatus.textContent = "Offline";
219
- netStatus.className = "text-rose-400";
220
- return false;
221
  }
222
-
223
- // Real AI integration
224
  async function queryRosalinda(prompt) {
225
  setStatus("Processing...", "work");
226
- try {
227
- const response = await fetch('/api/rosalinda', {
228
- method: 'POST',
229
- headers: {
230
- 'Content-Type': 'application/json',
231
- },
232
- body: JSON.stringify({ prompt })
233
- });
234
-
235
- if (!response.ok) throw new Error("API error");
236
-
237
- const data = await response.json();
238
- return data.result || "No response from AI";
239
- } catch (err) {
240
- console.error("AI query failed:", err);
241
- setStatus("Error - retrying", "err");
242
-
243
- // Anti-Stop retry mechanism
244
- let retries = 0;
245
- while (retries < 3) {
 
 
 
 
 
 
 
 
 
246
  retries++;
 
247
  retryPill.textContent = `${retries} / 3`;
248
- await new Promise(resolve => setTimeout(resolve, 2000));
249
- try {
250
- const retryResponse = await fetch('/api/rosalinda', {
251
- method: 'POST',
252
- headers: {
253
- 'Content-Type': 'application/json',
254
- },
255
- body: JSON.stringify({ prompt })
256
- });
257
- if (retryResponse.ok) {
258
- const data = await retryResponse.json();
259
- return data.result || "No response from AI";
260
- }
261
- } catch (e) {
262
- console.error(`Retry ${retries} failed:`, e);
263
  }
 
 
264
  }
265
- throw new Error("Max retries exceeded");
266
  }
267
  }
268
-
269
- // Initialize with default code
270
  codeEl.value = `<!DOCTYPE html>
271
  <html>
272
  <head>
@@ -285,18 +330,30 @@ promptEl.addEventListener('keydown', (e) => {
285
  </div>
286
  </body>
287
  </html>`;
288
- // Initial setup
289
- checkBackend().then(online => {
290
- if (online) {
291
- addMsg("System", "✅ Backend connected. Rosalinda AI is ready.");
292
- jobStatus.textContent = "Ready";
 
 
 
 
 
 
 
 
293
  } else {
294
- addMsg("System", "⚠️ Backend offline. Some features may not work.");
295
- jobStatus.textContent = "Offline";
296
  }
297
- });
 
 
 
298
 
299
- applyPreview();
 
300
  switchTab('preview');
301
  });
302
 
 
140
  if (e.key === "Enter") sendBtn.click();
141
  });
142
  // Real AI generation functions
143
+ // Générateur d'images avec reprise
144
  document.getElementById('btnGenImg')?.addEventListener('click', async () => {
145
+ setStatus("Génération d'image...", "work");
146
+ let retries = 0;
147
+
148
+ while (retries < 3) {
149
+ try {
150
+ const response = await fetch('/api/generate/image', {
151
+ method: 'POST',
152
+ headers: { 'Content-Type': 'application/json' },
153
+ body: JSON.stringify({ prompt: "Image créative haute qualité" })
154
+ });
155
+
156
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
157
+
158
+ const data = await response.json();
159
+
160
+ mediaOut.innerHTML = `
161
+ <div class="rounded-xl overflow-hidden border border-white/10">
162
+ <img src="${data.url}" class="w-full" alt="Image générée">
163
+ <div class="p-2 text-xs text-slate-400">Généré: ${new Date().toLocaleTimeString()}</div>
164
+ <button class="w-full px-3 py-1 bg-indigo-500/20 hover:bg-indigo-500/30 text-xs"
165
+ onclick="document.getElementById('code').value += '\\n<img src=\\'${data.url}\\' alt=\\'Image générée\\'>\\n'; applyPreview()">
166
+ Insérer dans le code
167
+ </button>
168
+ </div>
169
+ `;
170
+
171
+ setStatus("Image prête", "ok");
172
+ return;
173
+
174
+ } catch (err) {
175
+ retries++;
176
+ console.error(`Tentative ${retries} échouée:`, err);
177
+
178
+ if (retries >= 3) {
179
+ setStatus("Échec de génération", "err");
180
+ addMsg("System", `❌ Échec après 3 tentatives: ${err.message}`);
181
+ return;
182
+ }
183
+
184
+ await new Promise(resolve => setTimeout(resolve, 3000 * retries));
185
+ }
186
  }
187
  });
188
 
189
+ // Générateur de vidéos avec reprise
190
  document.getElementById('btnGenVid')?.addEventListener('click', async () => {
191
+ setStatus("Génération de vidéo...", "work");
192
+ let retries = 0;
193
+
194
+ while (retries < 3) {
195
+ try {
196
+ const response = await fetch('/api/generate/video', {
197
+ method: 'POST',
198
+ headers: { 'Content-Type': 'application/json' },
199
+ body: JSON.stringify({ prompt: "Vidéo courte créative" })
200
+ });
201
+
202
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
203
+
204
+ const data = await response.json();
205
+
206
+ mediaOut.innerHTML = `
207
+ <div class="rounded-xl overflow-hidden border border-white/10">
208
+ <video controls class="w-full">
209
+ <source src="${data.url}" type="video/mp4">
210
+ </video>
211
+ <div class="p-2 text-xs text-slate-400">Généré: ${new Date().toLocaleTimeString()}</div>
212
+ <button class="w-full px-3 py-1 bg-indigo-500/20 hover:bg-indigo-500/30 text-xs"
213
+ onclick="document.getElementById('code').value += '\\n<video controls>\\n <source src=\\'${data.url}\\' type=\\'video/mp4\\'>\\n</video>\\n'; applyPreview()">
214
+ Insérer dans le code
215
+ </button>
216
+ </div>
217
+ `;
218
+
219
+ setStatus("Vidéo prête", "ok");
220
+ return;
221
+
222
+ } catch (err) {
223
+ retries++;
224
+ console.error(`Tentative ${retries} échouée:`, err);
225
+
226
+ if (retries >= 3) {
227
+ setStatus("Échec de génération", "err");
228
+ addMsg("System", `❌ Échec après 3 tentatives: ${err.message}`);
229
+ return;
230
+ }
231
+
232
+ await new Promise(resolve => setTimeout(resolve, 3000 * retries));
233
+ }
234
  }
235
  });
236
+ // Vérification améliorée du backend
237
  async function checkBackend() {
238
+ let retries = 0;
239
+
240
+ while (retries < 3) {
241
+ try {
242
+ const response = await fetch('/api/health');
243
+ if (response.ok) {
244
+ const data = await response.json();
245
+ netStatus.textContent = data.status === 'online' ? "En ligne" : "Maintenance";
246
+ netStatus.className = data.status === 'online' ? "text-emerald-400" : "text-amber-400";
247
+
248
+ if (data.status === 'online') {
249
+ addMsg("Rosalinda", "✅ Backend connecté et prêt");
250
+ return true;
251
+ } else {
252
+ addMsg("System", "⚠️ Backend en maintenance - certaines fonctionnalités peuvent être limitées");
253
+ return false;
254
+ }
255
+ }
256
+ throw new Error(`HTTP ${response.status}`);
257
+
258
+ } catch (err) {
259
+ retries++;
260
+ if (retries >= 3) {
261
+ netStatus.textContent = "Hors ligne";
262
+ netStatus.className = "text-rose-400";
263
+ addMsg("System", "❌ Impossible de se connecter au backend Rosalinda");
264
+ return false;
265
+ }
266
+ await new Promise(resolve => setTimeout(resolve, 2000));
267
  }
 
 
268
  }
 
 
 
269
  }
270
+ // Intégration réelle avec Rosalinda
 
271
  async function queryRosalinda(prompt) {
272
  setStatus("Processing...", "work");
273
+ let retries = 0;
274
+
275
+ while (retries < 3) {
276
+ try {
277
+ const response = await fetch('/api/rosalinda', {
278
+ method: 'POST',
279
+ headers: {
280
+ 'Content-Type': 'application/json',
281
+ },
282
+ body: JSON.stringify({
283
+ prompt,
284
+ options: {
285
+ auto_resume: true,
286
+ max_length: 2000
287
+ }
288
+ })
289
+ });
290
+
291
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
292
+
293
+ const data = await response.json();
294
+
295
+ if (data.status === 'resume') {
296
+ await new Promise(resolve => setTimeout(resolve, 2000));
297
+ continue;
298
+ }
299
+
300
+ return data.result || data.message || "Réponse de Rosalinda";
301
+ } catch (err) {
302
  retries++;
303
+ console.error(`Attempt ${retries} failed:`, err);
304
  retryPill.textContent = `${retries} / 3`;
305
+
306
+ if (retries >= 3) {
307
+ throw new Error("Échec après 3 tentatives");
 
 
 
 
 
 
 
 
 
 
 
 
308
  }
309
+
310
+ await new Promise(resolve => setTimeout(resolve, 2000 * retries));
311
  }
 
312
  }
313
  }
314
+ // Initialize with default code
 
315
  codeEl.value = `<!DOCTYPE html>
316
  <html>
317
  <head>
 
330
  </div>
331
  </body>
332
  </html>`;
333
+ // Initialisation améliorée
334
+ async function initialize() {
335
+ const isBackendOnline = await checkBackend();
336
+
337
+ if (isBackendOnline) {
338
+ jobStatus.textContent = "Prêt";
339
+ addMsg("Rosalinda", "Bonjour ! Je suis Rosalinda, votre assistante IA. Comment puis-je vous aider aujourd'hui ?");
340
+
341
+ // Vérification périodique du backend
342
+ setInterval(async () => {
343
+ await checkBackend();
344
+ }, 30000);
345
+
346
  } else {
347
+ jobStatus.textContent = "Hors ligne";
348
+ addMsg("System", "Mode hors ligne activé - certaines fonctionnalités seront limitées");
349
  }
350
+
351
+ applyPreview();
352
+ switchTab('preview');
353
+ }
354
 
355
+ initialize();
356
+ applyPreview();
357
  switchTab('preview');
358
  });
359
 
server-example.js CHANGED
@@ -1,30 +1,57 @@
 
1
  const express = require('express');
2
- const { createProxyMiddleware } = require('http-proxy-middleware');
3
- const fs = require('fs');
4
  const path = require('path');
5
 
6
  const app = express();
 
7
  app.use(express.json());
8
 
9
  // Configuration
10
  const CONFIG = {
11
- AI_API_KEY: process.env.AI_API_KEY || 'your-ai-api-key',
12
- AI_BASE_URL: process.env.AI_BASE_URL || 'https://api.openai.com/v1',
13
  PORT: process.env.PORT || 3000,
14
- MAX_RETRIES: 3
 
15
  };
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  // Health check endpoint
18
  app.get('/api/health', (req, res) => {
19
- res.json({ status: 'ok', timestamp: new Date().toISOString() });
 
 
 
 
 
20
  });
21
 
22
- // AI Proxy endpoint
 
23
  app.post('/api/rosalinda', async (req, res) => {
24
- try {
25
- const retryFetch = async (attempt = 1) => {
 
 
 
 
 
 
26
  try {
27
- const response = await fetch(`${CONFIG.AI_BASE_URL}/chat/completions`, {
28
  method: 'POST',
29
  headers: {
30
  'Content-Type': 'application/json',
@@ -33,57 +60,113 @@ app.post('/api/rosalinda', async (req, res) => {
33
  body: JSON.stringify({
34
  model: "gpt-4",
35
  messages: [{ role: "user", content: req.body.prompt }],
36
- temperature: 0.7
 
37
  })
38
  });
39
 
40
  if (!response.ok) throw new Error(`AI API error: ${response.status}`);
41
- return response;
 
 
 
 
 
 
42
  } catch (err) {
43
- if (attempt >= CONFIG.MAX_RETRIES) throw err;
44
- await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
45
- return retryFetch(attempt + 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
- };
 
 
 
48
 
49
- const response = await retryFetch();
50
- const data = await response.json();
51
- res.json({ result: data.choices[0]?.message?.content || "No response" });
52
  } catch (err) {
53
- console.error("Rosalinda error:", err);
54
  res.status(500).json({ error: err.message });
55
  }
56
  });
57
 
58
- // Media generation endpoints
59
- app.post('/api/generate/image', async (req, res) => {
60
  try {
61
- const response = await fetch(`${CONFIG.AI_BASE_URL}/images/generations`, {
62
- method: 'POST',
63
- headers: {
64
- 'Content-Type': 'application/json',
65
- 'Authorization': `Bearer ${CONFIG.AI_API_KEY}`
66
- },
67
- body: JSON.stringify({
68
- prompt: req.body.prompt || "creative image",
69
- n: 1,
70
- size: "1024x1024"
71
- })
72
- });
73
-
74
- if (!response.ok) throw new Error(`Image generation failed: ${response.status}`);
75
- const data = await response.json();
76
- res.json({ url: data.data[0].url });
77
  } catch (err) {
78
- console.error("Image generation error:", err);
79
  res.status(500).json({ error: err.message });
80
  }
81
  });
82
-
83
  // Static files for preview
84
  app.use('/preview', express.static(path.join(__dirname, 'previews')));
85
 
86
  app.listen(CONFIG.PORT, () => {
87
- console.log(`Server running on port ${CONFIG.PORT}`);
88
- console.log(`AI connected to: ${CONFIG.AI_BASE_URL}`);
89
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
  const express = require('express');
3
+ const fetch = require('node-fetch');
4
+ const cors = require('cors');
5
  const path = require('path');
6
 
7
  const app = express();
8
+ app.use(cors());
9
  app.use(express.json());
10
 
11
  // Configuration
12
  const CONFIG = {
13
+ AI_API_KEY: process.env.ROSALINDA_API_KEY || 'your-ai-api-key',
 
14
  PORT: process.env.PORT || 3000,
15
+ MAX_RETRIES: 5,
16
+ WATCHDOG_INTERVAL: 5000
17
  };
18
 
19
+ // Watchdog pour éviter tout arrêt
20
+ setInterval(() => {
21
+ console.log("🟢 Rosalinda alive -", new Date().toISOString());
22
+ }, CONFIG.WATCHDOG_INTERVAL);
23
+
24
+ process.on('uncaughtException', (err) => {
25
+ console.error('⚠️ Uncaught Exception - Restarting process:', err);
26
+ });
27
+
28
+ process.on('unhandledRejection', (err) => {
29
+ console.error('⚠️ Unhandled Rejection:', err);
30
+ });
31
+
32
  // Health check endpoint
33
  app.get('/api/health', (req, res) => {
34
+ res.json({
35
+ status: 'online',
36
+ timestamp: new Date().toISOString(),
37
+ version: '1.0.0',
38
+ features: ['chat', 'images', 'videos']
39
+ });
40
  });
41
 
42
+ // AI Proxy endpoint avec reprise automatique
43
+ let isProcessing = false;
44
  app.post('/api/rosalinda', async (req, res) => {
45
+ if (isProcessing) {
46
+ return res.json({ status: 'resume', message: 'Reprise en cours...' });
47
+ }
48
+
49
+ isProcessing = true;
50
+ let retries = 0;
51
+
52
+ while (retries < CONFIG.MAX_RETRIES) {
53
  try {
54
+ const response = await fetch('https://api.openai.com/v1/chat/completions', {
55
  method: 'POST',
56
  headers: {
57
  'Content-Type': 'application/json',
 
60
  body: JSON.stringify({
61
  model: "gpt-4",
62
  messages: [{ role: "user", content: req.body.prompt }],
63
+ temperature: 0.7,
64
+ max_tokens: 2000
65
  })
66
  });
67
 
68
  if (!response.ok) throw new Error(`AI API error: ${response.status}`);
69
+
70
+ const data = await response.json();
71
+ isProcessing = false;
72
+ return res.json({
73
+ result: data.choices[0]?.message?.content || "No response",
74
+ usage: data.usage
75
+ });
76
  } catch (err) {
77
+ retries++;
78
+ console.error(`Attempt ${retries} failed:`, err);
79
+ if (retries >= CONFIG.MAX_RETRIES) {
80
+ isProcessing = false;
81
+ throw err;
82
+ }
83
+ await new Promise(resolve => setTimeout(resolve, 2000 * retries));
84
+ }
85
+ }
86
+ isProcessing = false;
87
+ res.status(500).json({ error: err.message });
88
+ });
89
+
90
+ // Endpoints de génération améliorés avec reprise
91
+ const mediaGenerators = {
92
+ image: {
93
+ endpoint: 'https://api.openai.com/v1/images/generations',
94
+ defaults: { n: 1, size: "1024x1024" }
95
+ },
96
+ video: {
97
+ endpoint: 'https://api.deepai.org/api/video-generator',
98
+ defaults: { length: 5, fps: 24 }
99
+ }
100
+ };
101
+
102
+ const processMedia = async (type, req, res) => {
103
+ let retries = 0;
104
+ const config = mediaGenerators[type];
105
+
106
+ while (retries < CONFIG.MAX_RETRIES) {
107
+ try {
108
+ const response = await fetch(config.endpoint, {
109
+ method: 'POST',
110
+ headers: {
111
+ 'Content-Type': 'application/json',
112
+ 'Authorization': `Bearer ${CONFIG.AI_API_KEY}`
113
+ },
114
+ body: JSON.stringify({
115
+ prompt: req.body.prompt || `creative ${type}`,
116
+ ...config.defaults
117
+ })
118
+ });
119
+
120
+ if (!response.ok) throw new Error(`${type} generation failed: ${response.status}`);
121
+
122
+ const data = await response.json();
123
+ return res.json({
124
+ url: data.url || data.output_url,
125
+ details: data
126
+ });
127
+ } catch (err) {
128
+ retries++;
129
+ console.error(`${type} generation attempt ${retries} failed:`, err);
130
+ if (retries >= CONFIG.MAX_RETRIES) {
131
+ throw err;
132
  }
133
+ await new Promise(resolve => setTimeout(resolve, 3000 * retries));
134
+ }
135
+ }
136
+ };
137
 
138
+ app.post('/api/generate/image', async (req, res) => {
139
+ try {
140
+ await processMedia('image', req, res);
141
  } catch (err) {
 
142
  res.status(500).json({ error: err.message });
143
  }
144
  });
145
 
146
+ app.post('/api/generate/video', async (req, res) => {
 
147
  try {
148
+ await processMedia('video', req, res);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  } catch (err) {
 
150
  res.status(500).json({ error: err.message });
151
  }
152
  });
 
153
  // Static files for preview
154
  app.use('/preview', express.static(path.join(__dirname, 'previews')));
155
 
156
  app.listen(CONFIG.PORT, () => {
157
+ console.log(`
158
+ ██████╗ ██████╗ ███████╗ █████╗ ██╗ ███╗ ██╗██████╗ █████╗
159
+ ██╔══██╗██╔═══██╗██╔════╝██╔══██╗██║ ████╗ ██║██╔══██╗██╔══██╗
160
+ ██████╔╝██║ ██║███████╗███████║██║ ██╔██╗ ██║██║ ██║███████║
161
+ ██╔══██╗██║ ██║╚════██║██╔══██║██║ ██║╚██╗██║██║ ██║██╔══██║
162
+ ██║ ██║╚██████╔╝███████║██║ ██║███████╗██║ ╚████║██████╔╝██║ ██║
163
+ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝
164
+ `);
165
+ console.log(`✅ Rosalinda backend ONLINE - Port ${CONFIG.PORT}`);
166
+ console.log(`🔗 Endpoints disponibles:`);
167
+ console.log(`- POST /api/rosalinda - Chat AI`);
168
+ console.log(`- POST /api/generate/image - Génération d'images`);
169
+ console.log(`- POST /api/generate/video - Génération de vidéos`);
170
+ console.log(`- GET /api/health - Vérification du statut`);
171
+ console.log(`\n🛡️ Watchdog actif - Intervalle: ${CONFIG.WATCHDOG_INTERVAL}ms`);
172
+ });