Reforca ancora de fidelidade visual de personagens e cenario em 100% dos quadros e adiciona re-sincronizacao de texto editado na regeneracao
This commit is contained in:
+47
-4
@@ -5275,7 +5275,7 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Regenerar um único painel
|
// Regenerar um único painel inteligente (considera textos/legendas alterados e preserva âncora visual de personagens)
|
||||||
const regenerateSinglePanel = async (index, panelCard, imgElement, btnRegen) => {
|
const regenerateSinglePanel = async (index, panelCard, imgElement, btnRegen) => {
|
||||||
const panel = generatedPanelsData[index];
|
const panel = generatedPanelsData[index];
|
||||||
if (!panel) return;
|
if (!panel) return;
|
||||||
@@ -5285,13 +5285,52 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
|
|||||||
btnRegen.textContent = '⏳';
|
btnRegen.textContent = '⏳';
|
||||||
imgElement.style.opacity = '0.4';
|
imgElement.style.opacity = '0.4';
|
||||||
|
|
||||||
const promptToUse = panel.image_prompt || 'cute children illustration';
|
// Captura o diálogo/texto ATUAL que está escrito na textarea do quadrinho (caso o usuário tenha editado)
|
||||||
const fullPrompt = `${promptToUse}, high resolution children book illustration, cute Pixar style, ${selectedComicsRatio === '16:9' ? '16:9 aspect ratio' : '4:3 aspect ratio'}`;
|
const textarea = panelCard.querySelector('.comic-caption-input');
|
||||||
|
const currentDialogue = textarea ? textarea.value.trim() : (panel.dialogue || '');
|
||||||
|
panel.dialogue = currentDialogue;
|
||||||
|
|
||||||
|
// Captura o prompt visual se o mini-editor tiver sido alterado
|
||||||
|
const promptInput = panelCard.querySelector('.comic-prompt-details textarea');
|
||||||
|
let promptToUse = promptInput ? promptInput.value.trim() : (panel.image_prompt || '');
|
||||||
|
|
||||||
|
// Se o diálogo tiver sido preenchido/alterado, re-sincronizamos a cena visual com o novo texto
|
||||||
|
if (currentDialogue) {
|
||||||
|
try {
|
||||||
|
const resyncResp = await fetch('/api/comics/resync-frame-prompt', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
currentDialogue,
|
||||||
|
oldPrompt: promptToUse,
|
||||||
|
character_description: currentComicsCharDescEnglish,
|
||||||
|
cenario: comicsCenarioSelect ? comicsCenarioSelect.value : ''
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (resyncResp.ok) {
|
||||||
|
const resyncData = await resyncResp.json();
|
||||||
|
if (resyncData.image_prompt) {
|
||||||
|
promptToUse = resyncData.image_prompt;
|
||||||
|
panel.image_prompt = promptToUse;
|
||||||
|
if (promptInput) promptInput.value = promptToUse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (resyncErr) {
|
||||||
|
console.warn('Re-sincronização de prompt ao regenerar:', resyncErr.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monta o prompt reforçado com a Âncora Visual Física de Personagens e Estilo 3D Pixar
|
||||||
|
let anchorPart = '';
|
||||||
|
if (currentComicsCharDescEnglish) {
|
||||||
|
anchorPart = `CHARACTER ANCHOR: [${currentComicsCharDescEnglish}]. `;
|
||||||
|
}
|
||||||
|
const fullPrompt = `${anchorPart}${promptToUse}, high resolution children book illustration, cute Pixar style, ${selectedComicsRatio === '16:9' ? '16:9 aspect ratio' : '4:3 aspect ratio'}`;
|
||||||
|
|
||||||
const resp = await fetch('/api/comics/generate-frame', {
|
const resp = await fetch('/api/comics/generate-frame', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ prompt: fullPrompt })
|
body: JSON.stringify({ prompt: fullPrompt, proporcao: selectedComicsRatio })
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
@@ -5303,6 +5342,10 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
|
|||||||
panel.imageUrl = data.imageUrl;
|
panel.imageUrl = data.imageUrl;
|
||||||
imgElement.src = data.imageUrl + '?v=' + Date.now();
|
imgElement.src = data.imageUrl + '?v=' + Date.now();
|
||||||
imgElement.style.opacity = '1';
|
imgElement.style.opacity = '1';
|
||||||
|
|
||||||
|
// Auto-salva o projeto atualizado no banco
|
||||||
|
saveComicsProjectFlow(false).catch(e => console.warn('Auto-save pós regeneração:', e.message));
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Erro ao regenerar painel:', err);
|
console.error('Erro ao regenerar painel:', err);
|
||||||
await showCustomAlert('Erro', 'Não foi possível regenerar o quadrinho: ' + err.message);
|
await showCustomAlert('Erro', 'Não foi possível regenerar o quadrinho: ' + err.message);
|
||||||
|
|||||||
@@ -533,11 +533,11 @@ Cenário/Local principal da nova fase: ${cenario}.
|
|||||||
Gere um JSON perfeitamente válido contendo:
|
Gere um JSON perfeitamente válido contendo:
|
||||||
{
|
{
|
||||||
"title": "${continuationType === 'extend' ? 'Manter o título original ou propor um subtítulo condizente' : 'Novo Título da História'}",
|
"title": "${continuationType === 'extend' ? 'Manter o título original ou propor um subtítulo condizente' : 'Novo Título da História'}",
|
||||||
"character_description": "${character_description || 'Descrição visual constante dos personagens em inglês'}",
|
"character_description": "${character_description || 'Descrição física rigorosamente constante e fixa dos personagens em inglês (roupas fixas, cabelos, cores)'}",
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
"panel_number": ${startPanelNum},
|
"panel_number": ${startPanelNum},
|
||||||
"image_prompt": "Prompt visual detalhado em inglês para o gerador de imagens da MiniMax descrevendo a cena deste quadrinho. IMPORTANTE PARA CONSISTÊNCIA: Substitua TODOS os nomes de personagens por sua descrição física minuciosa em inglês (obtida de character_description) em cada quadrinho que aparecerem (ex: em vez de apenas escrever 'Lucas', escreva a descrição detalhada dele com roupas e cabelos específicos, etc). O estilo deve ser de ilustração de livro infantil de alta qualidade, 3D Pixar, traço limpo.",
|
"image_prompt": "Prompt visual minucioso em inglês para o gerador de imagens. REGRA RÍGIDA DE CONSISTÊNCIA: Substitua nomes de personagens por sua descrição física EXATA e FIXA em inglês (do character_description) em TODOS os quadrinhos onde aparecerem (mesmas roupas, mesma cor de cabelo, mesmas características). Descreva a ação específica do quadrinho mantendo o mesmo estilo visual 3D Pixar.",
|
||||||
"dialogue": "Falas do quadrinho em português (ex: 'Lucas: Veja aquilo!') com NO MÁXIMO 10 palavras, ou narração curta caso não tenha balões."
|
"dialogue": "Falas do quadrinho em português (ex: 'Lucas: Veja aquilo!') com NO MÁXIMO 10 palavras, ou narração curta caso não tenha balões."
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
@@ -556,11 +556,11 @@ Cenário/Local principal: ${cenario}.
|
|||||||
Gere um JSON perfeitamente válido contendo:
|
Gere um JSON perfeitamente válido contendo:
|
||||||
{
|
{
|
||||||
"title": "Título da História",
|
"title": "Título da História",
|
||||||
"character_description": "Descrição visual constante dos personagens em inglês (para usar em geradores de imagens, detalhando roupas específicas, cores, características físicas de forma fixa para manter a consistência).",
|
"character_description": "Descrição física rigorosamente detalhada e fixa dos personagens em inglês (especifique roupas fixas, cores de camiseta/vestido, tipo/cor de cabelo, tom de pele e características físicas fixas para NUNCA mudarem entre os quadrinhos).",
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
"panel_number": 1,
|
"panel_number": 1,
|
||||||
"image_prompt": "Prompt visual detalhado em inglês para o gerador de imagens da MiniMax descrevendo a cena deste quadrinho. IMPORTANTE PARA CONSISTÊNCIA: Substitua TODOS os nomes de personagens por sua descrição física minuciosa em inglês (do character_description) em cada quadrinho que aparecerem (ex: não escreva apenas 'Mariana', escreva a descrição dela detalhando cabelo e roupas de forma fixa e idêntica em todos os quadrinhos). O estilo deve ser de ilustração de livro infantil de alta qualidade, 3D Pixar, traço limpo.",
|
"image_prompt": "Prompt visual minucioso em inglês para o gerador de imagens da MiniMax. REGRA RÍGIDA DE CONSISTÊNCIA: Substitua TODOS os nomes de personagens por sua descrição física EXATA e FIXA em inglês (do character_description) em TODOS os quadrinhos em que aparecerem (mesmas roupas fixas, cabelos e características de forma idêntica em 100% das imagens). Descreva a cena específica mantendo a arte 3D Pixar infantil de traço limpo.",
|
||||||
"dialogue": "Falas do quadrinho em português (ex: 'Lucas: Veja aquilo!') com NO MÁXIMO 10 palavras, ou narração curta caso não tenha balões."
|
"dialogue": "Falas do quadrinho em português (ex: 'Lucas: Veja aquilo!') com NO MÁXIMO 10 palavras, ou narração curta caso não tenha balões."
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
@@ -601,6 +601,42 @@ Responda APENAS o JSON válido, sem qualquer texto explicativo antes ou depois.`
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 1b. Re-sincronizar o prompt visual de um quadrinho quando o texto/fala for alterado na regeneração
|
||||||
|
app.post('/api/comics/resync-frame-prompt', requireAuth, async (req, res) => {
|
||||||
|
const { currentDialogue, oldPrompt, character_description, cenario } = req.body;
|
||||||
|
if (!currentDialogue || !currentDialogue.trim()) {
|
||||||
|
return res.json({ image_prompt: oldPrompt });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const prompt = `Você é um diretor de arte de histórias em quadrinhos infantis 3D estilo Pixar.
|
||||||
|
A professora alterou o diálogo/texto do quadrinho para: "${currentDialogue}".
|
||||||
|
Descrição física fixa dos personagens (em inglês): "${character_description || ''}".
|
||||||
|
Cenário fixo da história: "${cenario || ''}".
|
||||||
|
Prompt antigo da cena: "${oldPrompt || ''}".
|
||||||
|
|
||||||
|
Re-escreva a descrição visual da cena (image_prompt) em inglês para o gerador de imagens.
|
||||||
|
REGRAS RÍGIDAS DE FIDELIDADE VISUAL:
|
||||||
|
1. Mantenha os mesmos personagens com a MESMA descrição física e roupas exatas (do character_description).
|
||||||
|
2. Mantenha o mesmo estilo de iluminação e elementos do cenário (${cenario}).
|
||||||
|
3. Adapte as ações, gestos e expressões faciais para combinarem EXATAMENTE com a nova fala/texto editado: "${currentDialogue}".
|
||||||
|
|
||||||
|
Retorne APENAS a nova descrição visual da cena em inglês, sem explicações.`;
|
||||||
|
|
||||||
|
const r = await callMinimax({
|
||||||
|
messages: [{ role: 'user', content: prompt }],
|
||||||
|
temperature: 0.3,
|
||||||
|
max_tokens: 300
|
||||||
|
});
|
||||||
|
|
||||||
|
const newPrompt = r.text.trim();
|
||||||
|
res.json({ image_prompt: newPrompt || oldPrompt });
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('[Comics Resync] Falha ao re-sincronizar prompt, usando original:', err.message);
|
||||||
|
res.json({ image_prompt: oldPrompt });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 2. Gerar uma imagem individual para um quadrinho usando MiniMax image-01 com Fallback Automático
|
// 2. Gerar uma imagem individual para um quadrinho usando MiniMax image-01 com Fallback Automático
|
||||||
app.post('/api/comics/generate-frame', requireAuth, async (req, res) => {
|
app.post('/api/comics/generate-frame', requireAuth, async (req, res) => {
|
||||||
const { prompt, proporcao } = req.body;
|
const { prompt, proporcao } = req.body;
|
||||||
|
|||||||
Reference in New Issue
Block a user