From 5274c00e5f522d654f97ecf17cdd51716e0ba3c9 Mon Sep 17 00:00:00 2001 From: admtracksteel Date: Mon, 31 Aug 2026 20:18:09 +0000 Subject: [PATCH] Blindagem total da geracao de quadrinhos com retries em segundo plano (Alt+Tab), imagem de fallback SVG e preservacao dos quadros gerados --- public/app.js | 67 ++++++++++++++++++++++++++++++++++----------------- server.js | 17 +++++++++++-- 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/public/app.js b/public/app.js index 34a8c00..6f82a64 100644 --- a/public/app.js +++ b/public/app.js @@ -5069,36 +5069,59 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.` let completedCount = 0; const generateSinglePanel = async (panel) => { - const fullPrompt = `${panel.image_prompt}, high resolution children book illustration, cute Pixar style, ${selectedComicsRatio === '16:9' ? '16:9 aspect ratio' : '4:3 aspect ratio'}`; + let anchorPart = ''; + if (currentComicsCharDescEnglish) { + anchorPart = `CHARACTER ANCHOR: [${currentComicsCharDescEnglish}]. `; + } + const fullPrompt = `${anchorPart}${panel.image_prompt}, high resolution children book illustration, cute Pixar style, ${selectedComicsRatio === '16:9' ? '16:9 aspect ratio' : '4:3 aspect ratio'}`; - let frameResp; - try { - frameResp = await fetch('/api/comics/generate-frame', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ prompt: fullPrompt, proporcao: selectedComicsRatio }) - }); - } catch (netErr) { - throw new Error(`Falha de conexão no quadro ${panel.panel_number}: ${netErr.message}`); + let attempts = 0; + let frameData = null; + + while (attempts < 3 && !frameData) { + attempts++; + try { + const frameResp = await fetch('/api/comics/generate-frame', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ prompt: fullPrompt, proporcao: selectedComicsRatio }) + }); + + if (frameResp.ok) { + frameData = await frameResp.json(); + } else { + console.warn(`[Retry Comics] Tentativa ${attempts} para quadro ${panel.panel_number} respondeu ${frameResp.status}`); + if (attempts < 3) await new Promise(r => setTimeout(r, 1200 * attempts)); + } + } catch (netErr) { + console.warn(`[Retry Comics] Tentativa ${attempts} erro de rede no quadro ${panel.panel_number}:`, netErr.message); + if (attempts < 3) await new Promise(r => setTimeout(r, 1200 * attempts)); + } } - if (!frameResp.ok) { - const errMsg = await safeExtractError(frameResp, 'Erro ao ilustrar quadro'); - throw new Error(`Erro no quadrinho ${panel.panel_number}: ${errMsg}`); - } - - const frameData = await frameResp.json(); completedCount++; const progressPercent = 20 + Math.floor((completedCount / totalPanels) * 75); if (comicsLoaderProgress) comicsLoaderProgress.style.width = `${progressPercent}%`; if (comicsLoaderText) comicsLoaderText.textContent = `🎨 Ilustrando quadrinhos: ${completedCount}/${totalPanels} quadros concluídos...`; - return { - panel_number: panel.panel_number, - imageUrl: frameData.imageUrl, - dialogue: panel.dialogue || '', - image_prompt: panel.image_prompt || '' - }; + if (frameData && frameData.imageUrl) { + return { + panel_number: panel.panel_number, + imageUrl: frameData.imageUrl, + dialogue: panel.dialogue || '', + image_prompt: panel.image_prompt || '', + needsRegeneration: !!frameData.needsRegeneration + }; + } else { + console.warn(`[Comics Resiliencia] Quadro ${panel.panel_number} não pôde ser gerado após 3 tentativas. Preservando a história e liberando botão de regenerar.`); + return { + panel_number: panel.panel_number, + imageUrl: '/assets/img/placeholder_comic.png', + dialogue: panel.dialogue || '', + image_prompt: panel.image_prompt || '', + needsRegeneration: true + }; + } }; // Executa com no máximo 2 quadros em paralelo para estabilidade máxima e resposta fluida diff --git a/server.js b/server.js index 4ea885a..5847968 100644 --- a/server.js +++ b/server.js @@ -743,7 +743,19 @@ app.post('/api/comics/generate-frame', requireAuth, async (req, res) => { } if (!imageBuffer) { - return res.status(500).json({ error: 'Não foi possível gerar a ilustração do quadro no momento. Por favor, tente novamente.' }); + console.warn('[Comics Frame] Todas as IAs de imagem falharam temporariamente para o prompt. Gerando placeholder de fallback resiliente.'); + const is169 = proporcao === '16:9' || (prompt && prompt.includes('16:9')); + const w = is169 ? 1280 : 1024; + const h = is169 ? 720 : 768; + + const svgFallback = ` + + + 🎨 Quadro Pronto para Ilustrar + Clique no botão 🔄 para gerar a imagem deste quadrinho + `; + imageBuffer = Buffer.from(svgFallback, 'utf-8'); + providerUsed = 'fallback-placeholder'; } try { @@ -756,7 +768,8 @@ app.post('/api/comics/generate-frame', requireAuth, async (req, res) => { res.json({ imageUrl: `/generated-media/${fileName}`, - provider: providerUsed + provider: providerUsed, + needsRegeneration: providerUsed === 'fallback-placeholder' }); } catch (saveErr) { console.error('Erro ao salvar imagem localmente:', saveErr);