Feature: Inventando Histórias profissional com 3-stage pipeline narrativa, vinculacao a turmas/alunos, ilustracoes por cena, leitor interativo, TTS narrado e exportacao PDF/TXT
This commit is contained in:
+530
-68
@@ -7694,8 +7694,67 @@ window.toggleCustomAudio = (btn) => {
|
||||
|
||||
|
||||
// ============================================================
|
||||
// INVENTANDO HISTORIAS
|
||||
// INVENTANDO HISTÓRIAS (ESTÚDIO PROFISSIONAL)
|
||||
// ============================================================
|
||||
const HISTORIA_TEMPLATES = {
|
||||
arca: {
|
||||
titulo: 'A Arca da Imaginação',
|
||||
objeto: 'Arca Mágica de Madeira',
|
||||
tema: 'As crianças encontram uma arca misteriosa no parquinho que se abre apenas quando todos dão as mãos e compartilham uma ideia criativa.',
|
||||
estilo: 'Lúdico, Afetivo e Dialogado',
|
||||
faixa: 'Crianças pequenas (4 anos a 5 anos e 11 meses)',
|
||||
visual: 'Cartoon colorido e acolhedor'
|
||||
},
|
||||
horta: {
|
||||
titulo: 'O Mistério da Horta Encantada',
|
||||
objeto: 'Semente Brilhante de Girassol',
|
||||
tema: 'A turma planta uma sementinha brilhante na horta da escola e descobre que ela cresce quando ouve canções de carinho e risadas.',
|
||||
estilo: 'Contação Clássica com Suspense Leve',
|
||||
faixa: 'Crianças pequenas (4 anos a 5 anos e 11 meses)',
|
||||
visual: 'Aquarela suave infantil'
|
||||
},
|
||||
dinossauro: {
|
||||
titulo: 'O Pequeno Dinossauro Amigo',
|
||||
objeto: 'Pegada Colorida de Brinquedo',
|
||||
tema: 'Um pequeno dinossauro verde e tímido aparece na hora do lanche procurando amigos para brincar de roda e desenhar.',
|
||||
estilo: 'Lúdico, Afetivo e Dialogado',
|
||||
faixa: 'Crianças bem pequenas (1 ano e 7 meses a 3 anos e 11 meses)',
|
||||
visual: 'Cartoon colorido e acolhedor'
|
||||
},
|
||||
chuva: {
|
||||
titulo: 'O Dia em que a Chuva Dançou',
|
||||
objeto: 'Galochas Amarelas Saltitantes',
|
||||
tema: 'Em um dia chuvoso, as gotas batem na janela fazendo música e convidam as crianças para uma dança aconchegante dentro da sala.',
|
||||
estilo: 'Roda de Conversa Interativa',
|
||||
faixa: 'Crianças pequenas (4 anos a 5 anos e 11 meses)',
|
||||
visual: 'Aquarela suave infantil'
|
||||
},
|
||||
bolhas: {
|
||||
titulo: 'O Reino Mágico das Bolhas de Sabão',
|
||||
objeto: 'Varinha de Fazer Bolhas Gigantes',
|
||||
tema: 'Cada bolha de sabão que as crianças assopram no pátio leva um desejo de abraço e alegria até as nuvens coloridas.',
|
||||
estilo: 'Lúdico, Afetivo e Dialogado',
|
||||
faixa: 'Bebês (0 a 1 ano e 6 meses)',
|
||||
visual: 'Giz de cera e textura lúdica'
|
||||
},
|
||||
brinquedos: {
|
||||
titulo: 'A Reunião Secreta dos Brinquedos',
|
||||
objeto: 'Ursinho de Pano Guardião',
|
||||
tema: 'Na hora do descanso, os brinquedos se organizam com muito capricho para esperar o acordar dos alunos com uma surpresa de blocos montados.',
|
||||
estilo: 'Aventura e Descoberta na Escola',
|
||||
faixa: 'Crianças pequenas (4 anos a 5 anos e 11 meses)',
|
||||
visual: 'Livro infantil clássico e detalhado'
|
||||
},
|
||||
emocoes: {
|
||||
titulo: 'O Monstrinho das Cores e dos Sentimentos',
|
||||
objeto: 'Pote Brilhante das Emoções',
|
||||
tema: 'Um monstrinho amigo muda de cor quando sente alegria (amarelo), calma (azul) ou saudade (rosa), ensinando a turma a expressar o que sente.',
|
||||
estilo: 'Roda de Conversa Interativa',
|
||||
faixa: 'Crianças pequenas (4 anos a 5 anos e 11 meses)',
|
||||
visual: 'Cartoon colorido e acolhedor'
|
||||
}
|
||||
};
|
||||
|
||||
const barBtnHistoria = document.getElementById('barBtnHistoria');
|
||||
const historiaModal = document.getElementById('historiaModal');
|
||||
const btnCloseHistoriaModal = document.getElementById('btnCloseHistoriaModal');
|
||||
@@ -7703,35 +7762,118 @@ window.toggleCustomAudio = (btn) => {
|
||||
const historiaHistoryModal = document.getElementById('historiaHistoryModal');
|
||||
const btnCloseHistoriaHistory = document.getElementById('btnCloseHistoriaHistory');
|
||||
|
||||
const historiaTemplateSelect = document.getElementById('historiaTemplateSelect');
|
||||
const historiaTurmaSelect = document.getElementById('historiaTurmaSelect');
|
||||
const historiaPersonagemInput = document.getElementById('historiaPersonagemInput');
|
||||
const historiaObjetoMagicoInput = document.getElementById('historiaObjetoMagicoInput');
|
||||
const historiaFaixaEtaria = document.getElementById('historiaFaixaEtaria');
|
||||
const historiaParagrafos = document.getElementById('historiaParagrafos');
|
||||
const historiaPersonagens = document.getElementById('historiaPersonagens');
|
||||
const historiaEstilo = document.getElementById('historiaEstilo');
|
||||
const historiaEstiloVisual = document.getElementById('historiaEstiloVisual');
|
||||
const historiaTemaInput = document.getElementById('historiaTemaInput');
|
||||
const btnGenerateHistoria = document.getElementById('btnGenerateHistoria');
|
||||
|
||||
const historiaGenerateLoader = document.getElementById('historiaGenerateLoader');
|
||||
const historiaResultArea = document.getElementById('historiaResultArea');
|
||||
const historiaTextOutput = document.getElementById('historiaTextOutput');
|
||||
const btnCopyHistoria = document.getElementById('btnCopyHistoria');
|
||||
const btnDownloadHistoriaPdf = document.getElementById('btnDownloadHistoriaPdf');
|
||||
|
||||
let currentHistoria = '';
|
||||
// Elementos do Leitor e Visualizador
|
||||
const historiaPlaceholderText = document.getElementById('historiaPlaceholderText');
|
||||
const historiaActiveBox = document.getElementById('historiaActiveBox');
|
||||
const historiaActiveTitle = document.getElementById('historiaActiveTitle');
|
||||
const historiaActiveSubtitle = document.getElementById('historiaActiveSubtitle');
|
||||
const historiaBnccBadge = document.getElementById('historiaBnccBadge');
|
||||
|
||||
if (barBtnHistoria) {
|
||||
barBtnHistoria.addEventListener('click', () => {
|
||||
historiaModal.style.display = 'flex';
|
||||
historiaTemaInput.value = '';
|
||||
historiaResultArea.style.display = 'none';
|
||||
historiaGenerateLoader.style.display = 'none';
|
||||
btnGenerateHistoria.disabled = false;
|
||||
currentHistoria = '';
|
||||
// Player de Áudio
|
||||
const historiaAudioPlayerBox = document.getElementById('historiaAudioPlayerBox');
|
||||
const historiaAudioPlayer = document.getElementById('historiaAudioPlayer');
|
||||
const btnDownloadHistoriaAudio = document.getElementById('btnDownloadHistoriaAudio');
|
||||
const historiaWaveBars = document.querySelectorAll('.wave-bar-historia');
|
||||
|
||||
// Abas
|
||||
const historiaContentTabs = document.getElementById('historiaContentTabs');
|
||||
const btnTabHistoriaCenas = document.getElementById('btnTabHistoriaCenas');
|
||||
const btnTabHistoriaTexto = document.getElementById('btnTabHistoriaTexto');
|
||||
const btnTabHistoriaAtividades = document.getElementById('btnTabHistoriaAtividades');
|
||||
const historiaCenasView = document.getElementById('historiaCenasView');
|
||||
const historiaTextoView = document.getElementById('historiaTextoView');
|
||||
const historiaAtividadesView = document.getElementById('historiaAtividadesView');
|
||||
|
||||
// Cenas Interativas
|
||||
const btnPrevCena = document.getElementById('btnPrevCena');
|
||||
const btnNextCena = document.getElementById('btnNextCena');
|
||||
const historiaCenaIndicator = document.getElementById('historiaCenaIndicator');
|
||||
const historiaCenaTitle = document.getElementById('historiaCenaTitle');
|
||||
const historiaCenaText = document.getElementById('historiaCenaText');
|
||||
const historiaCenaImageContainer = document.getElementById('historiaCenaImageContainer');
|
||||
const historiaCenaImg = document.getElementById('historiaCenaImg');
|
||||
const btnGenerateSceneImage = document.getElementById('btnGenerateSceneImage');
|
||||
|
||||
// BNCC e Perguntas
|
||||
const historiaBnccDesc = document.getElementById('historiaBnccDesc');
|
||||
const historiaPerguntasList = document.getElementById('historiaPerguntasList');
|
||||
|
||||
// Ações
|
||||
const btnCopyActiveHistoria = document.getElementById('btnCopyActiveHistoria');
|
||||
const btnDownloadActiveHistoriaTxt = document.getElementById('btnDownloadActiveHistoriaTxt');
|
||||
const btnSendHistoriaToMusic = document.getElementById('btnSendHistoriaToMusic');
|
||||
const btnExportActiveHistoriaPdf = document.getElementById('btnExportActiveHistoriaPdf');
|
||||
|
||||
let currentHistoriaData = null;
|
||||
let currentSceneIndex = 0;
|
||||
|
||||
// Carregar turmas no select de histórias
|
||||
async function loadTurmasForHistoria() {
|
||||
if (!historiaTurmaSelect) return;
|
||||
try {
|
||||
const res = await fetch('/api/turmas');
|
||||
if (res.ok) {
|
||||
const turmas = await res.json();
|
||||
historiaTurmaSelect.innerHTML = '<option value="">-- Selecionar Turma --</option>';
|
||||
turmas.forEach(t => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = t.id;
|
||||
opt.textContent = `${t.nome} (${t.ano_letivo || '2026'})`;
|
||||
historiaTurmaSelect.appendChild(opt);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Erro ao carregar turmas para histórias:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Mudança de template
|
||||
if (historiaTemplateSelect) {
|
||||
historiaTemplateSelect.addEventListener('change', () => {
|
||||
const key = historiaTemplateSelect.value;
|
||||
if (key && HISTORIA_TEMPLATES[key]) {
|
||||
const tpl = HISTORIA_TEMPLATES[key];
|
||||
historiaTemaInput.value = tpl.tema;
|
||||
if (historiaObjetoMagicoInput) historiaObjetoMagicoInput.value = tpl.objeto;
|
||||
if (historiaEstilo) historiaEstilo.value = tpl.estilo;
|
||||
if (historiaFaixaEtaria) historiaFaixaEtaria.value = tpl.faixa;
|
||||
if (historiaEstiloVisual) historiaEstiloVisual.value = tpl.visual;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (btnCloseHistoriaModal) historiaModal.addEventListener('click', (e) => { if(e.target === historiaModal) historiaModal.style.display = 'none'; });
|
||||
if (btnCloseHistoriaModal) btnCloseHistoriaModal.addEventListener('click', () => historiaModal.style.display = 'none');
|
||||
|
||||
// Abertura do Modal
|
||||
if (barBtnHistoria) {
|
||||
barBtnHistoria.addEventListener('click', () => {
|
||||
historiaModal.style.display = 'flex';
|
||||
loadTurmasForHistoria();
|
||||
if (!currentHistoriaData) {
|
||||
if (historiaPlaceholderText) historiaPlaceholderText.style.display = 'block';
|
||||
if (historiaActiveBox) historiaActiveBox.style.display = 'none';
|
||||
if (historiaAudioPlayerBox) historiaAudioPlayerBox.style.display = 'none';
|
||||
if (historiaContentTabs) historiaContentTabs.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (btnCloseHistoriaModal) {
|
||||
historiaModal.addEventListener('click', (e) => { if (e.target === historiaModal) historiaModal.style.display = 'none'; });
|
||||
btnCloseHistoriaModal.addEventListener('click', () => historiaModal.style.display = 'none');
|
||||
}
|
||||
|
||||
// Histórico
|
||||
if (btnOpenHistoriaHistory) {
|
||||
btnOpenHistoriaHistory.addEventListener('click', () => {
|
||||
historiaHistoryModal.style.display = 'flex';
|
||||
@@ -7739,93 +7881,358 @@ window.toggleCustomAudio = (btn) => {
|
||||
});
|
||||
}
|
||||
if (btnCloseHistoriaHistory) btnCloseHistoriaHistory.addEventListener('click', () => historiaHistoryModal.style.display = 'none');
|
||||
historiaHistoryModal.addEventListener('click', (e) => { if(e.target === historiaHistoryModal) historiaHistoryModal.style.display = 'none'; });
|
||||
historiaHistoryModal.addEventListener('click', (e) => { if (e.target === historiaHistoryModal) historiaHistoryModal.style.display = 'none'; });
|
||||
|
||||
// Alternância de Abas
|
||||
function switchHistoriaTab(tab) {
|
||||
[btnTabHistoriaCenas, btnTabHistoriaTexto, btnTabHistoriaAtividades].forEach(b => {
|
||||
if (b) {
|
||||
b.classList.remove('active');
|
||||
b.style.background = 'transparent';
|
||||
b.style.color = 'var(--text-secondary)';
|
||||
}
|
||||
});
|
||||
if (historiaCenasView) historiaCenasView.style.display = 'none';
|
||||
if (historiaTextoView) historiaTextoView.style.display = 'none';
|
||||
if (historiaAtividadesView) historiaAtividadesView.style.display = 'none';
|
||||
|
||||
if (tab === 'cenas') {
|
||||
if (btnTabHistoriaCenas) {
|
||||
btnTabHistoriaCenas.classList.add('active');
|
||||
btnTabHistoriaCenas.style.background = 'rgba(16,185,129,0.15)';
|
||||
btnTabHistoriaCenas.style.color = '#34d399';
|
||||
}
|
||||
if (historiaCenasView) historiaCenasView.style.display = 'flex';
|
||||
} else if (tab === 'texto') {
|
||||
if (btnTabHistoriaTexto) {
|
||||
btnTabHistoriaTexto.classList.add('active');
|
||||
btnTabHistoriaTexto.style.background = 'rgba(16,185,129,0.15)';
|
||||
btnTabHistoriaTexto.style.color = '#34d399';
|
||||
}
|
||||
if (historiaTextoView) historiaTextoView.style.display = 'block';
|
||||
} else if (tab === 'atividades') {
|
||||
if (btnTabHistoriaAtividades) {
|
||||
btnTabHistoriaAtividades.classList.add('active');
|
||||
btnTabHistoriaAtividades.style.background = 'rgba(16,185,129,0.15)';
|
||||
btnTabHistoriaAtividades.style.color = '#34d399';
|
||||
}
|
||||
if (historiaAtividadesView) historiaAtividadesView.style.display = 'flex';
|
||||
}
|
||||
}
|
||||
|
||||
if (btnTabHistoriaCenas) btnTabHistoriaCenas.addEventListener('click', () => switchHistoriaTab('cenas'));
|
||||
if (btnTabHistoriaTexto) btnTabHistoriaTexto.addEventListener('click', () => switchHistoriaTab('texto'));
|
||||
if (btnTabHistoriaAtividades) btnTabHistoriaAtividades.addEventListener('click', () => switchHistoriaTab('atividades'));
|
||||
|
||||
// Renderizar Cena Atual
|
||||
function renderCurrentScene() {
|
||||
if (!currentHistoriaData || !currentHistoriaData.cenas || currentHistoriaData.cenas.length === 0) return;
|
||||
const total = currentHistoriaData.cenas.length;
|
||||
if (currentSceneIndex < 0) currentSceneIndex = 0;
|
||||
if (currentSceneIndex >= total) currentSceneIndex = total - 1;
|
||||
|
||||
const cena = currentHistoriaData.cenas[currentSceneIndex];
|
||||
if (historiaCenaIndicator) historiaCenaIndicator.textContent = `Cena ${currentSceneIndex + 1} de ${total}`;
|
||||
if (historiaCenaTitle) historiaCenaTitle.textContent = cena.titulo || `Ato ${currentSceneIndex + 1}`;
|
||||
if (historiaCenaText) historiaCenaText.textContent = cena.texto || '';
|
||||
|
||||
// Imagem da cena
|
||||
if (cena.imageUrl) {
|
||||
if (historiaCenaImg) historiaCenaImg.src = cena.imageUrl;
|
||||
if (historiaCenaImageContainer) historiaCenaImageContainer.style.display = 'block';
|
||||
if (btnGenerateSceneImage) btnGenerateSceneImage.innerHTML = '🔄 Regenerar Ilustração';
|
||||
} else {
|
||||
if (historiaCenaImageContainer) historiaCenaImageContainer.style.display = 'none';
|
||||
if (btnGenerateSceneImage) btnGenerateSceneImage.innerHTML = '🎨 Gerar Ilustração';
|
||||
}
|
||||
|
||||
if (btnPrevCena) btnPrevCena.disabled = currentSceneIndex === 0;
|
||||
if (btnNextCena) btnNextCena.disabled = currentSceneIndex === total - 1;
|
||||
}
|
||||
|
||||
if (btnPrevCena) {
|
||||
btnPrevCena.addEventListener('click', () => {
|
||||
if (currentSceneIndex > 0) {
|
||||
currentSceneIndex--;
|
||||
renderCurrentScene();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (btnNextCena) {
|
||||
btnNextCena.addEventListener('click', () => {
|
||||
if (currentHistoriaData && currentHistoriaData.cenas && currentSceneIndex < currentHistoriaData.cenas.length - 1) {
|
||||
currentSceneIndex++;
|
||||
renderCurrentScene();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Gerar Ilustração da Cena Atual
|
||||
if (btnGenerateSceneImage) {
|
||||
btnGenerateSceneImage.addEventListener('click', async () => {
|
||||
if (!currentHistoriaData || !currentHistoriaData.cenas) return;
|
||||
const cena = currentHistoriaData.cenas[currentSceneIndex];
|
||||
if (!cena) return;
|
||||
|
||||
const originalBtnHtml = btnGenerateSceneImage.innerHTML;
|
||||
btnGenerateSceneImage.disabled = true;
|
||||
btnGenerateSceneImage.innerHTML = '⏳ Ilustrando...';
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/historias/scene-image', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
prompt: cena.promptImagem || cena.texto || 'Cute children book illustration',
|
||||
estiloVisual: currentHistoriaData.estiloVisual || 'Cartoon colorido',
|
||||
cenaNumero: currentSceneIndex + 1
|
||||
})
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
if (res.ok && data.imageUrl) {
|
||||
cena.imageUrl = data.imageUrl;
|
||||
renderCurrentScene();
|
||||
showToast('Ilustração da cena criada com sucesso!', 'success');
|
||||
} else {
|
||||
showToast(data.error || 'Erro ao gerar ilustração.', 'error');
|
||||
}
|
||||
} catch (err) {
|
||||
showToast('Erro ao conectar com gerador de ilustração.', 'error');
|
||||
} finally {
|
||||
btnGenerateSceneImage.disabled = false;
|
||||
btnGenerateSceneImage.innerHTML = originalBtnHtml;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Gerar História Completa
|
||||
if (btnGenerateHistoria) {
|
||||
btnGenerateHistoria.addEventListener('click', async () => {
|
||||
const tema = historiaTemaInput.value.trim();
|
||||
if (!tema) {
|
||||
showToast('Por favor, informe o tema da história.', 'error');
|
||||
showToast('Por favor, informe o tema ou enredo da história.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
btnGenerateHistoria.disabled = true;
|
||||
historiaResultArea.style.display = 'none';
|
||||
historiaGenerateLoader.style.display = 'flex';
|
||||
if (historiaGenerateLoader) historiaGenerateLoader.style.display = 'flex';
|
||||
if (historiaPlaceholderText) historiaPlaceholderText.style.display = 'none';
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/historias/generate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
faixaEtaria: historiaFaixaEtaria.value,
|
||||
paragrafos: historiaParagrafos.value,
|
||||
personagens: historiaPersonagens.value,
|
||||
estilo: historiaEstilo.value,
|
||||
tema: tema
|
||||
tema: tema,
|
||||
faixaEtaria: historiaFaixaEtaria ? historiaFaixaEtaria.value : 'Crianças pequenas',
|
||||
paragrafos: historiaParagrafos ? historiaParagrafos.value : '3',
|
||||
estilo: historiaEstilo ? historiaEstilo.value : 'Lúdico',
|
||||
estiloVisual: historiaEstiloVisual ? historiaEstiloVisual.value : 'Cartoon colorido',
|
||||
personagemPrincipal: historiaPersonagemInput ? historiaPersonagemInput.value.trim() : '',
|
||||
objetoMagico: historiaObjetoMagicoInput ? historiaObjetoMagicoInput.value.trim() : '',
|
||||
turmaId: historiaTurmaSelect ? historiaTurmaSelect.value : null
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
currentHistoria = data.historia;
|
||||
historiaTextOutput.innerHTML = window.marked ? marked.parse(currentHistoria) : currentHistoria;
|
||||
historiaResultArea.style.display = 'flex';
|
||||
|
||||
if (response.ok && data.success) {
|
||||
currentHistoriaData = data;
|
||||
currentSceneIndex = 0;
|
||||
|
||||
// Header
|
||||
if (historiaActiveTitle) historiaActiveTitle.textContent = data.titulo || 'História Mágica';
|
||||
if (historiaActiveSubtitle) {
|
||||
historiaActiveSubtitle.textContent = `Personagem: ${data.personagemPrincipal || 'Turma'} • ${data.cenas ? data.cenas.length : 3} Cenas • ${data.duracaoLeitura || '3 min'}`;
|
||||
}
|
||||
if (historiaBnccBadge) {
|
||||
historiaBnccBadge.textContent = `BNCC: ${data.bnccCampos || 'EI02EF04 / EI03EF05'}`;
|
||||
historiaBnccBadge.style.display = 'inline-block';
|
||||
}
|
||||
|
||||
// Player de Áudio
|
||||
if (data.audioUrl) {
|
||||
if (historiaAudioPlayer) historiaAudioPlayer.src = data.audioUrl;
|
||||
if (btnDownloadHistoriaAudio) btnDownloadHistoriaAudio.href = data.audioUrl;
|
||||
if (historiaAudioPlayerBox) historiaAudioPlayerBox.style.display = 'flex';
|
||||
|
||||
if (historiaAudioPlayer) {
|
||||
historiaAudioPlayer.onplay = () => historiaWaveBars.forEach(b => b.classList.add('wave-active'));
|
||||
historiaAudioPlayer.onpause = () => historiaWaveBars.forEach(b => b.classList.remove('wave-active'));
|
||||
historiaAudioPlayer.onended = () => historiaWaveBars.forEach(b => b.classList.remove('wave-active'));
|
||||
}
|
||||
} else {
|
||||
if (historiaAudioPlayerBox) historiaAudioPlayerBox.style.display = 'none';
|
||||
}
|
||||
|
||||
// Abas & Visualização
|
||||
if (historiaContentTabs) historiaContentTabs.style.display = 'flex';
|
||||
if (historiaActiveBox) historiaActiveBox.style.display = 'flex';
|
||||
|
||||
// Texto completo
|
||||
if (historiaTextoView) historiaTextoView.textContent = data.historiaCompleta || '';
|
||||
|
||||
// Atividades e BNCC
|
||||
if (historiaBnccDesc) historiaBnccDesc.textContent = data.bnccCampos || 'EI02EF04 / EI03EF05 • Escuta, Fala, Pensamento e Imaginação';
|
||||
if (historiaPerguntasList) {
|
||||
historiaPerguntasList.innerHTML = '';
|
||||
(data.perguntasCompreensao || []).forEach(p => {
|
||||
const pEl = document.createElement('div');
|
||||
pEl.style.cssText = 'padding: 4px 0; border-bottom: 1px dashed rgba(255,255,255,0.05);';
|
||||
pEl.textContent = p;
|
||||
historiaPerguntasList.appendChild(pEl);
|
||||
});
|
||||
}
|
||||
|
||||
renderCurrentScene();
|
||||
switchHistoriaTab('cenas');
|
||||
showToast('História inventada com sucesso!', 'success');
|
||||
} else {
|
||||
showToast(data.error || 'Erro ao inventar história.', 'error');
|
||||
showToast(data.error || 'Erro ao gerar história.', 'error');
|
||||
}
|
||||
} catch (err) {
|
||||
showToast('Erro de conexão.', 'error');
|
||||
showToast('Erro de conexão ao gerar história.', 'error');
|
||||
} finally {
|
||||
historiaGenerateLoader.style.display = 'none';
|
||||
if (historiaGenerateLoader) historiaGenerateLoader.style.display = 'none';
|
||||
btnGenerateHistoria.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (btnCopyHistoria) {
|
||||
btnCopyHistoria.addEventListener('click', () => {
|
||||
if (currentHistoria) {
|
||||
navigator.clipboard.writeText(currentHistoria);
|
||||
// Copiar História
|
||||
if (btnCopyActiveHistoria) {
|
||||
btnCopyActiveHistoria.addEventListener('click', () => {
|
||||
if (currentHistoriaData && currentHistoriaData.historiaCompleta) {
|
||||
navigator.clipboard.writeText(currentHistoriaData.historiaCompleta);
|
||||
showToast('História copiada para a área de transferência!', 'success');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (btnDownloadHistoriaPdf) {
|
||||
btnDownloadHistoriaPdf.addEventListener('click', () => {
|
||||
if (!currentHistoria) return;
|
||||
const printWindow = window.open('', '_blank');
|
||||
printWindow.document.write(`
|
||||
<html>
|
||||
// Baixar TXT
|
||||
if (btnDownloadActiveHistoriaTxt) {
|
||||
btnDownloadActiveHistoriaTxt.addEventListener('click', () => {
|
||||
if (!currentHistoriaData) return;
|
||||
const content = `=========================================
|
||||
📖 ${currentHistoriaData.titulo || 'HISTÓRIA PEDAGÓGICA'}
|
||||
=========================================
|
||||
Personagem Principal: ${currentHistoriaData.personagemPrincipal || 'Turma'}
|
||||
Objeto Mágico: ${currentHistoriaData.objetoMagico || 'Especial'}
|
||||
BNCC: ${currentHistoriaData.bnccCampos || 'EI02EF04'}
|
||||
Duração Estimada: ${currentHistoriaData.duracaoLeitura || '3 min'}
|
||||
|
||||
--- HISTÓRIA COMPLETA ---
|
||||
${currentHistoriaData.historiaCompleta || ''}
|
||||
|
||||
--- PERGUNTAS PARA RODA DE CONVERSA ---
|
||||
${(currentHistoriaData.perguntasCompreensao || []).join('\n')}
|
||||
|
||||
Gerado por PedagogIA • Assistente da Professora Camila`;
|
||||
|
||||
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${(currentHistoriaData.titulo || 'historia').toLowerCase().replace(/\s+/g, '_')}.txt`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
}
|
||||
|
||||
// Musicar História
|
||||
if (btnSendHistoriaToMusic) {
|
||||
btnSendHistoriaToMusic.addEventListener('click', () => {
|
||||
if (!currentHistoriaData) return;
|
||||
const barBtnMusica = document.getElementById('barBtnMusica');
|
||||
const musicaTemaInput = document.getElementById('musicaTemaInput');
|
||||
historiaModal.style.display = 'none';
|
||||
if (barBtnMusica) barBtnMusica.click();
|
||||
if (musicaTemaInput) {
|
||||
musicaTemaInput.value = `Canção sobre a história "${currentHistoriaData.titulo}": ${currentHistoriaData.objetoMagico || ''}, amizade e imaginação`;
|
||||
}
|
||||
showToast('História transferida para o Musicando Ideias!', 'info');
|
||||
});
|
||||
}
|
||||
|
||||
// Exportar PDF Ilustrado
|
||||
if (btnExportActiveHistoriaPdf) {
|
||||
btnExportActiveHistoriaPdf.addEventListener('click', () => {
|
||||
if (!currentHistoriaData) return;
|
||||
const printWin = window.open('', '_blank');
|
||||
if (!printWin) {
|
||||
showToast('Permita pop-ups para gerar o PDF.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
let cenasHtml = '';
|
||||
(currentHistoriaData.cenas || []).forEach((c, idx) => {
|
||||
cenasHtml += `
|
||||
<div style="margin-bottom: 20px; padding: 15px; border-left: 4px solid #10b981; background: #f8fafc; border-radius: 0 8px 8px 0;">
|
||||
<h3 style="margin-top: 0; color: #059669; font-size: 1.1rem;">${c.titulo || `Ato ${idx + 1}`}</h3>
|
||||
${c.imageUrl ? `<div style="text-align: center; margin: 10px 0;"><img src="${c.imageUrl}" style="max-height: 220px; border-radius: 8px;" /></div>` : ''}
|
||||
<p style="font-size: 1rem; line-height: 1.7; color: #334155; margin: 0;">${c.texto || ''}</p>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
let perguntasHtml = '';
|
||||
(currentHistoriaData.perguntasCompreensao || []).forEach(p => {
|
||||
perguntasHtml += `<li style="margin-bottom: 6px;">${p}</li>`;
|
||||
});
|
||||
|
||||
printWin.document.write(`
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<title>História - Assistente PedaGog</title>
|
||||
<meta charset="UTF-8">
|
||||
<title>${currentHistoriaData.titulo || 'História Pedagógica'} - Pedagog</title>
|
||||
<style>
|
||||
body { font-family: 'Outfit', 'Inter', sans-serif; padding: 40px; color: #333; line-height: 1.6; }
|
||||
h1, h2, h3 { color: #10b981; margin-top: 24px; margin-bottom: 12px; }
|
||||
@media print { body { padding: 0; } button { display: none; } }
|
||||
body { font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 35px; color: #1e293b; line-height: 1.6; max-width: 800px; margin: 0 auto; }
|
||||
h1 { color: #059669; margin: 0 0 6px 0; font-size: 1.8rem; }
|
||||
.header-box { border-bottom: 2px solid #e2e8f0; padding-bottom: 14px; margin-bottom: 24px; }
|
||||
.badge { display: inline-block; background: #d1fae5; color: #065f46; font-size: 0.8rem; padding: 4px 10px; border-radius: 6px; font-weight: bold; margin-right: 6px; }
|
||||
.btn-print { background: #10b981; color: white; border: none; padding: 10px 20px; border-radius: 8px; font-weight: bold; cursor: pointer; float: right; font-size: 0.95rem; }
|
||||
@media print { .btn-print { display: none; } body { padding: 0; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="max-width: 800px; margin: 0 auto;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #e2e8f0; padding-bottom: 10px; margin-bottom: 20px;">
|
||||
<h1 style="margin: 0;">✍️ História Pedagógica</h1>
|
||||
<button onclick="window.print()" style="background: #10b981; color: white; border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-weight: bold;">Imprimir / PDF</button>
|
||||
<button class="btn-print" onclick="window.print()">🖨️ Imprimir / Salvar PDF</button>
|
||||
<div class="header-box">
|
||||
<h1>📖 ${currentHistoriaData.titulo || 'História Pedagógica'}</h1>
|
||||
<div style="margin-top: 8px;">
|
||||
<span class="badge">Personagem: ${currentHistoriaData.personagemPrincipal || 'Turma'}</span>
|
||||
<span class="badge">Objeto: ${currentHistoriaData.objetoMagico || 'Especial'}</span>
|
||||
<span class="badge">BNCC: ${currentHistoriaData.bnccCampos || 'EI02EF04'}</span>
|
||||
</div>
|
||||
<div>${window.marked ? marked.parse(currentHistoria) : currentHistoria}</div>
|
||||
</div>
|
||||
|
||||
<h2 style="color: #0f172a; font-size: 1.2rem; border-bottom: 1px solid #cbd5e1; padding-bottom: 6px;">🎬 Cenas da História</h2>
|
||||
${cenasHtml}
|
||||
|
||||
<div style="margin-top: 30px; padding: 18px; background: #f1f5f9; border-radius: 8px;">
|
||||
<h3 style="margin-top: 0; color: #0f172a; font-size: 1.05rem;">🧩 Roda de Conversa & Atividades</h3>
|
||||
<ul style="margin: 0; padding-left: 20px; color: #475569; font-size: 0.95rem;">
|
||||
${perguntasHtml}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 40px; text-align: center; font-size: 0.8rem; color: #94a3b8; border-top: 1px solid #e2e8f0; padding-top: 12px;">
|
||||
Pedagog • Estúdio de Literatura Infantil da Professora Camila Martella Gasparini Reifonas
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
printWindow.document.close();
|
||||
printWin.document.close();
|
||||
});
|
||||
}
|
||||
|
||||
// Carregar Histórico
|
||||
async function loadHistoriaHistory() {
|
||||
const listContainer = document.getElementById('historiaHistoryList');
|
||||
if (!listContainer) return;
|
||||
listContainer.innerHTML = '<p style="text-align:center; color:var(--text-secondary);">Carregando...</p>';
|
||||
listContainer.innerHTML = '<p style="text-align:center; color:var(--text-secondary);">Carregando histórias...</p>';
|
||||
try {
|
||||
const response = await fetch('/api/historias/list');
|
||||
const data = await response.json();
|
||||
@@ -7835,19 +8242,24 @@ window.toggleCustomAudio = (btn) => {
|
||||
const date = new Date(item.created_at).toLocaleString('pt-BR');
|
||||
const div = document.createElement('div');
|
||||
div.className = 'history-item-card';
|
||||
div.style.cssText = 'background: rgba(255,255,255,0.02); padding: 14px; border-radius: 8px; border: 1px solid var(--border-light); display: flex; flex-direction: column; gap: 8px; cursor: pointer; position: relative;';
|
||||
div.style.cssText = 'background: rgba(255,255,255,0.02); padding: 14px; border-radius: 8px; border: 1px solid var(--border-light); display: flex; flex-direction: column; gap: 6px; cursor: pointer; position: relative;';
|
||||
div.innerHTML = `
|
||||
<div style="display: flex; justify-content: space-between; align-items: flex-start; padding-right: 30px;">
|
||||
<strong style="color: var(--brand-green); font-size: 0.95rem;">${item.faixa_etaria} (${item.estilo})</strong>
|
||||
<span style="font-size: 0.75rem; color: var(--text-secondary);">${date}</span>
|
||||
<strong style="color: #34d399; font-size: 0.95rem;">${item.titulo || item.tema || 'História'}</strong>
|
||||
<span style="font-size: 0.72rem; color: var(--text-secondary);">${date}</span>
|
||||
</div>
|
||||
<p style="margin: 0; font-size: 0.82rem; color: var(--text-primary); opacity: 0.9;">Tema: ${item.tema}</p>
|
||||
<div style="display: flex; gap: 8px; font-size: 0.72rem; color: var(--text-secondary);">
|
||||
<span>👶 ${item.faixa_etaria}</span>
|
||||
${item.personagem_principal ? `<span>• 👤 ${item.personagem_principal}</span>` : ''}
|
||||
${item.audio_url ? `<span>• 🎙️ Áudio MP3</span>` : ''}
|
||||
</div>
|
||||
<p style="margin: 0; font-size: 0.85rem; color: var(--text-primary); opacity: 0.9;">Tema: ${item.tema}</p>
|
||||
<button class="btn-delete-historia" data-id="${item.id}" style="position: absolute; top: 12px; right: 12px; background: transparent; border: none; color: #ef4444; cursor: pointer; font-size: 1.1rem; padding: 4px; border-radius: 4px;" title="Excluir">🗑️</button>
|
||||
`;
|
||||
div.addEventListener('click', async (e) => {
|
||||
if (e.target.closest('.btn-delete-historia')) {
|
||||
e.stopPropagation();
|
||||
if (confirm('Tem certeza que deseja excluir?')) {
|
||||
if (confirm('Tem certeza que deseja excluir esta história?')) {
|
||||
try {
|
||||
const delRes = await fetch(`/api/historias/${item.id}`, { method: 'DELETE' });
|
||||
if (delRes.ok) { showToast('História excluída.', 'success'); loadHistoriaHistory(); }
|
||||
@@ -7859,19 +8271,69 @@ window.toggleCustomAudio = (btn) => {
|
||||
const res = await fetch(`/api/historias/${item.id}`);
|
||||
const detail = await res.json();
|
||||
if (res.ok) {
|
||||
currentHistoria = detail.historia;
|
||||
historiaTextOutput.innerHTML = window.marked ? marked.parse(currentHistoria) : currentHistoria;
|
||||
historiaResultArea.style.display = 'flex';
|
||||
currentHistoriaData = {
|
||||
id: detail.id,
|
||||
titulo: detail.titulo || `História: ${detail.tema}`,
|
||||
personagemPrincipal: detail.personagem_principal || '',
|
||||
objetoMagico: detail.objeto_magico || '',
|
||||
historiaCompleta: detail.historia || '',
|
||||
cenas: typeof detail.cenas === 'string' ? JSON.parse(detail.cenas) : (detail.cenas || []),
|
||||
perguntasCompreensao: typeof detail.perguntas_compreensao === 'string' ? JSON.parse(detail.perguntas_compreensao) : (detail.perguntas_compreensao || []),
|
||||
bnccCampos: detail.bncc || 'EI02EF04 / EI03EF05',
|
||||
duracaoLeitura: detail.duracao_leitura || '3 min',
|
||||
complexidade: detail.complexidade || 'Lúdica',
|
||||
audioUrl: detail.audio_url || null,
|
||||
estiloVisual: detail.estilo_visual || 'Cartoon colorido'
|
||||
};
|
||||
currentSceneIndex = 0;
|
||||
|
||||
if (historiaActiveTitle) historiaActiveTitle.textContent = currentHistoriaData.titulo;
|
||||
if (historiaActiveSubtitle) {
|
||||
historiaActiveSubtitle.textContent = `Personagem: ${currentHistoriaData.personagemPrincipal || 'Turma'} • ${currentHistoriaData.cenas ? currentHistoriaData.cenas.length : 3} Cenas`;
|
||||
}
|
||||
if (historiaBnccBadge) {
|
||||
historiaBnccBadge.textContent = `BNCC: ${currentHistoriaData.bnccCampos}`;
|
||||
historiaBnccBadge.style.display = 'inline-block';
|
||||
}
|
||||
|
||||
if (currentHistoriaData.audioUrl) {
|
||||
if (historiaAudioPlayer) historiaAudioPlayer.src = currentHistoriaData.audioUrl;
|
||||
if (btnDownloadHistoriaAudio) btnDownloadHistoriaAudio.href = currentHistoriaData.audioUrl;
|
||||
if (historiaAudioPlayerBox) historiaAudioPlayerBox.style.display = 'flex';
|
||||
} else {
|
||||
if (historiaAudioPlayerBox) historiaAudioPlayerBox.style.display = 'none';
|
||||
}
|
||||
|
||||
if (historiaContentTabs) historiaContentTabs.style.display = 'flex';
|
||||
if (historiaActiveBox) historiaActiveBox.style.display = 'flex';
|
||||
if (historiaPlaceholderText) historiaPlaceholderText.style.display = 'none';
|
||||
|
||||
if (historiaTextoView) historiaTextoView.textContent = currentHistoriaData.historiaCompleta;
|
||||
if (historiaBnccDesc) historiaBnccDesc.textContent = currentHistoriaData.bnccCampos;
|
||||
if (historiaPerguntasList) {
|
||||
historiaPerguntasList.innerHTML = '';
|
||||
(currentHistoriaData.perguntasCompreensao || []).forEach(p => {
|
||||
const pEl = document.createElement('div');
|
||||
pEl.style.cssText = 'padding: 4px 0; border-bottom: 1px dashed rgba(255,255,255,0.05);';
|
||||
pEl.textContent = p;
|
||||
historiaPerguntasList.appendChild(pEl);
|
||||
});
|
||||
}
|
||||
|
||||
renderCurrentScene();
|
||||
switchHistoriaTab('cenas');
|
||||
historiaHistoryModal.style.display = 'none';
|
||||
}
|
||||
} catch (err) { showToast('Erro ao carregar.', 'error'); }
|
||||
} catch (err) { showToast('Erro ao carregar história.', 'error'); }
|
||||
});
|
||||
listContainer.appendChild(div);
|
||||
});
|
||||
} else {
|
||||
listContainer.innerHTML = '<p style="text-align:center; color:var(--text-secondary);">Nenhum histórico.</p>';
|
||||
listContainer.innerHTML = '<p style="text-align:center; color:var(--text-secondary);">Nenhuma história salva ainda.</p>';
|
||||
}
|
||||
} catch (err) { listContainer.innerHTML = '<p style="text-align:center; color:#ef4444;">Erro ao carregar.</p>'; }
|
||||
} catch (err) {
|
||||
listContainer.innerHTML = '<p style="text-align:center; color:#ef4444;">Erro ao carregar histórico de histórias.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
|
||||
Reference in New Issue
Block a user