From e994ac1c406e4eeb21b5b8b203bbc6ed1cb55edb Mon Sep 17 00:00:00 2001 From: admtracksteel Date: Mon, 31 Aug 2026 14:24:36 +0000 Subject: [PATCH] Corrige ReferenceError safeExtractError e adiciona retries resilientes multi-engine no gerador de imagens --- public/app.js | 20 ++++++++++++++++++++ server.js | 52 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/public/app.js b/public/app.js index a315c26..7b94de4 100644 --- a/public/app.js +++ b/public/app.js @@ -11,6 +11,26 @@ function escapeHtml(text) { .replace(/'/g, "'"); } +// Helper global para extração segura de erros de resposta HTTP no frontend +async function safeExtractError(resp, defaultMsg = 'Erro na operação') { + if (!resp) return defaultMsg; + try { + const text = await resp.text(); + try { + const json = JSON.parse(text); + return json.error || defaultMsg; + } catch (e) { + if (resp.status === 502 || text.includes('Bad Gateway')) { + return 'O servidor está temporariamente ocupado processando a requisição. Por favor, tente novamente em instantes.'; + } + return text.slice(0, 160) || defaultMsg; + } + } catch (e) { + return defaultMsg; + } +} + + // Função global para exibir notificações elegantes estilo Toast function showToast(message, type = 'info') { let container = document.getElementById('toast-container'); diff --git a/server.js b/server.js index 0e8627c..8d73fde 100644 --- a/server.js +++ b/server.js @@ -586,30 +586,44 @@ app.post('/api/comics/generate-frame', requireAuth, async (req, res) => { console.warn('[Comics Image] Falha/Timeout no MiniMax image-01 (' + minimaxErr.message + '), acionando gerador fallback...'); } - // Tentativa 2 (Fallback): Pollinations FLUX de alta resolução estilizado 3D Pixar + // Tentativa 2 (Fallback Resiliente Multi-Engine com Retries): if (!imageBuffer) { - providerUsed = 'pollinations-flux'; - try { - const is169 = proporcao === '16:9' || prompt.includes('16:9'); - const width = is169 ? 1280 : 1024; - const height = is169 ? 720 : 768; - const enhancedPrompt = encodeURIComponent(`${prompt}, 3d pixar disney style, digital children book illustration, vibrant colors, masterpiece, cinematic lighting`); - const fallbackUrl = `https://image.pollinations.ai/prompt/${enhancedPrompt}?width=${width}&height=${height}&nologo=true&seed=${Math.floor(Math.random() * 100000)}`; + const is169 = proporcao === '16:9' || (prompt && prompt.includes('16:9')); + const width = is169 ? 1280 : 1024; + const height = is169 ? 720 : 768; + const cleanPrompt = (prompt || 'cute children book illustration').replace(/[^\w\s,.-]/gi, ''); + const enhancedPrompt = encodeURIComponent(`${cleanPrompt}, 3d pixar disney style, digital children book illustration, vibrant colors, masterpiece, cinematic lighting`); + + const engines = ['flux', 'turbo']; - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 30000); + for (const engine of engines) { + if (imageBuffer) break; + for (let attempt = 1; attempt <= 2; attempt++) { + try { + providerUsed = `pollinations-${engine}`; + const seed = Math.floor(Math.random() * 1000000); + const fallbackUrl = `https://image.pollinations.ai/prompt/${enhancedPrompt}?width=${width}&height=${height}&model=${engine}&nologo=true&seed=${seed}`; - const fbResp = await fetch(fallbackUrl, { signal: controller.signal }); - clearTimeout(timeoutId); + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 25000); - if (fbResp.ok) { - imageBuffer = Buffer.from(await fbResp.arrayBuffer()); - console.log('[Comics Image] Imagem gerada com sucesso via Fallback Inteligente (Pollinations Flux).'); - } else { - throw new Error(`Fallback HTTP ${fbResp.status}`); + const fbResp = await fetch(fallbackUrl, { signal: controller.signal }); + clearTimeout(timeoutId); + + if (fbResp.ok) { + imageBuffer = Buffer.from(await fbResp.arrayBuffer()); + console.log(`[Comics Image] Imagem gerada com sucesso via Fallback (${providerUsed}, tentativa ${attempt}).`); + break; + } else { + console.warn(`[Comics Image] Fallback ${providerUsed} tentativa ${attempt} respondeu ${fbResp.status}`); + if (fbResp.status === 429) { + await new Promise(r => setTimeout(r, 700 * attempt)); + } + } + } catch (fbErr) { + console.warn(`[Comics Image] Erro no fallback ${engine} tentativa ${attempt}:`, fbErr.message); + } } - } catch (fbErr) { - console.error('[Comics Image] Erro também no provedor Fallback:', fbErr.message); } }