Comic Developer
Initial clean commit - Comic generator with SDXL
4595df6
// Elementos do DOM
const comicForm = document.getElementById('comic-form');
const loadingSection = document.getElementById('loading');
const resultSection = document.getElementById('result');
const comicViewer = document.getElementById('comic-viewer');
const newStoryBtn = document.getElementById('new-story-btn');
const generateBtn = document.getElementById('generate-btn');
// Função para mostrar/ocultar seções
function toggleSections(showLoading = false, showResult = false) {
document.querySelector('.generator-form').style.display =
(!showLoading && !showResult) ? 'block' : 'none';
loadingSection.style.display = showLoading ? 'block' : 'none';
resultSection.style.display = showResult ? 'block' : 'none';
}
// Função para gerar uma história em quadrinhos
async function generateComicStory(formData) {
try {
console.log('Gerando história com os seguintes dados:', formData);
// Fazer uma chamada AJAX para o endpoint de geração de histórias
const response = await fetch('/api/generate-comic', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
theme: formData.theme,
title: formData.title
})
});
const result = await response.json();
if (!result.success) {
throw new Error(result.error || 'Erro ao gerar a história em quadrinhos');
}
// Carregar os metadados da história gerada
const metadataResponse = await fetch(`/${result.directory}/story_metadata.json`);
const metadata = await metadataResponse.json();
return {
title: metadata.title,
theme: metadata.theme,
mainCharacter: {
characteristics: {
appearance: metadata.character.split(',')[0] || '',
clothing: metadata.character.split(',')[1] || '',
personality: '',
background: '',
abilities: ''
}
},
panels: metadata.panels,
directory: result.directory,
createdAt: metadata.created_at
};
} catch (error) {
console.error('Erro ao gerar história:', error);
throw error;
}
}
// Função para obter pontos de enredo com base no tema
function getPlotPoint(theme, type) {
const plotPoints = {
adventure: {
action: "O herói embarca em uma jornada épica em busca de um tesouro perdido",
climax: "O herói enfrenta o guardião do tesouro em uma batalha épica",
resolution: "O herói obtém o tesouro e retorna como um herói"
},
mystery: {
action: "O detetive começa a investigar um caso misterioso",
climax: "O detetive revela o culpado em uma cena dramática",
resolution: "A justiça é feita e a ordem é restaurada"
},
romance: {
action: "Os dois protagonistas se encontram pela primeira vez",
climax: "Os protagonistas enfrentam um obstáculo que ameaça seu amor",
resolution: "Os protagonistas superam os desafios e ficam juntos"
}
};
return plotPoints[theme][type] || plotPoints.adventure[type];
}
// Função para renderizar o visualizador de quadrinhos
function renderComicViewer(comicData) {
const themeNames = {
adventure: 'Aventura',
mystery: 'Mistério',
romance: 'Romance'
};
const viewerHTML = `
<div class="comic-header">
<h1>${comicData.title}</h1>
<p>Uma história em quadrinhos gerada dinamicamente</p>
</div>
<div class="comic-character">
<h2>Personagem Principal</h2>
<div class="character-grid">
<div class="character-item">
<strong>Aparência:</strong> ${comicData.mainCharacter.characteristics.appearance}
</div>
<div class="character-item">
<strong>Roupas:</strong> ${comicData.mainCharacter.characteristics.clothing}
</div>
<div class="character-item">
<strong>Personalidade:</strong> ${comicData.mainCharacter.characteristics.personality}
</div>
<div class="character-item">
<strong>Histórico:</strong> ${comicData.mainCharacter.characteristics.background}
</div>
<div class="character-item">
<strong>Habilidades:</strong> ${comicData.mainCharacter.characteristics.abilities}
</div>
</div>
</div>
<h2 style="text-align: center;">Painéis do Quadrinho</h2>
<div class="comic-panels">
${comicData.panels.map(panel => `
<div class="panel">
<h3>Painel ${panel.id}</h3>
<div class="panel-image">
<img src="/${panel.image}" alt="Painel ${panel.id}" onerror="this.style.display='none'; this.parentElement.innerHTML='<span>Imagem não disponível</span>'">
</div>
<p class="panel-description">${panel.description}</p>
</div>
`).join('')}
</div>
<div style="text-align: center; margin-top: 2rem; color: #7f8c8d; font-size: 0.9rem;">
<p>História gerada em: ${new Date(comicData.createdAt).toLocaleString('pt-BR')}</p>
<p>Tema: ${themeNames[comicData.theme] || comicData.theme}</p>
</div>
`;
comicViewer.innerHTML = viewerHTML;
}
// Evento de envio do formulário
comicForm.addEventListener('submit', async (e) => {
e.preventDefault();
// Coletar dados do formulário
const formData = {
theme: document.getElementById('theme').value,
title: document.getElementById('title').value,
appearance: document.getElementById('appearance').value,
clothing: document.getElementById('clothing').value,
personality: document.getElementById('personality').value,
background: document.getElementById('background').value,
abilities: document.getElementById('abilities').value
};
// Validar dados
if (!formData.title || !formData.appearance || !formData.clothing ||
!formData.personality || !formData.background || !formData.abilities) {
alert('Por favor, preencha todos os campos do personagem.');
return;
}
// Desabilitar botão e mostrar loading
generateBtn.disabled = true;
toggleSections(true, false);
try {
// Gerar história
const comicData = await generateComicStory(formData);
// Renderizar visualizador
renderComicViewer(comicData);
// Mostrar resultado
toggleSections(false, true);
} catch (error) {
console.error('Erro ao gerar história:', error);
alert('Ocorreu um erro ao gerar a história. Por favor, tente novamente.');
toggleSections(false, false);
} finally {
// Reabilitar botão
generateBtn.disabled = false;
}
});
// Evento para criar nova história
newStoryBtn.addEventListener('click', () => {
toggleSections(false, false);
});
// Preencher título automaticamente com base no tema
document.getElementById('theme').addEventListener('change', (e) => {
const titleInput = document.getElementById('title');
if (!titleInput.value) {
const themeTitles = {
adventure: 'A Jornada do Herói',
mystery: 'O Mistério da Cidade',
romance: 'Amor Além das Estrelas'
};
titleInput.value = themeTitles[e.target.value] || '';
}
});
// Preencher personagem automaticamente com base no tema
document.getElementById('theme').addEventListener('change', (e) => {
const theme = e.target.value;
// Preencher campos de personagem com exemplos
if (!document.getElementById('appearance').value) {
const appearances = {
adventure: 'elfo com cabelos prateados e olhos esmeralda',
mystery: 'detetive com sobretudo e chapéu',
romance: 'explorador espacial com uniforme futurista'
};
document.getElementById('appearance').value = appearances[theme] || '';
}
if (!document.getElementById('clothing').value) {
const clothings = {
adventure: 'armadura élfica brilhante',
mystery: 'sobretudo marrom e gravata',
romance: 'uniforme espacial branco e azul'
};
document.getElementById('clothing').value = clothings[theme] || '';
}
if (!document.getElementById('personality').value) {
const personalities = {
adventure: 'corajoso e determinado',
mystery: 'perspicaz e metódico',
romance: 'aventureiro e sensível'
};
document.getElementById('personality').value = personalities[theme] || '';
}
if (!document.getElementById('background').value) {
const backgrounds = {
adventure: 'guerreiro de um reino antigo',
mystery: 'ex-policial reformado',
romance: 'explorador de novos planetas'
};
document.getElementById('background').value = backgrounds[theme] || '';
}
if (!document.getElementById('abilities').value) {
const abilities = {
adventure: 'mestre em combate com espada e magia elemental',
mystery: 'habilidade de dedução e rastreamento',
romance: 'piloto habilidoso e conhecimento de tecnologia avançada'
};
document.getElementById('abilities').value = abilities[theme] || '';
}
});