Feature: Estúdio de Poesias profissional com dual-stage engine, analise de metricas literarias, guia fonetico, audio TTS narrado, player com equalizer e exportacao PDF/TXT

This commit is contained in:
2026-08-31 11:21:33 +00:00
parent 88d7163b9f
commit 3931af93db
4 changed files with 1086 additions and 255 deletions
+525 -127
View File
@@ -6168,6 +6168,8 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
// ============================================================
// ESTÚDIO DE POESIA
// ============================================================
// ESTÚDIO DE POESIAS (ESTÚDIO PROFISSIONAL)
// ============================================================
const poesiaModal = document.getElementById('poesiaModal');
const btnClosePoesiaModal = document.getElementById('btnClosePoesiaModal');
const barBtnPoesia = document.getElementById('barBtnPoesia');
@@ -6175,47 +6177,499 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
const poesiaHistoryModal = document.getElementById('poesiaHistoryModal');
const btnClosePoesiaHistory = document.getElementById('btnClosePoesiaHistory');
const poesiaTemplateSelect = document.getElementById('poesiaTemplateSelect');
const poesiaTemaInput = document.getElementById('poesiaTemaInput');
const poesiaTurmaSelect = document.getElementById('poesiaTurmaSelect');
const poesiaFaixaEtaria = document.getElementById('poesiaFaixaEtaria');
const poesiaEstruturaSelect = document.getElementById('poesiaEstruturaSelect');
const poesiaEstiloSelect = document.getElementById('poesiaEstiloSelect');
const poesiaVozSelect = document.getElementById('poesiaVozSelect');
const btnGeneratePoesia = document.getElementById('btnGeneratePoesia');
const poesiaGenerateLoader = document.getElementById('poesiaGenerateLoader');
const poesiaResultArea = document.getElementById('poesiaResultArea');
const poesiaTextOutput = document.getElementById('poesiaTextOutput');
const btnCopyPoesia = document.getElementById('btnCopyPoesia');
const btnDownloadPoesiaPdf = document.getElementById('btnDownloadPoesiaPdf');
const poesiaTemaInput = document.getElementById('poesiaTemaInput');
const poesiaFaixaEtaria = document.getElementById('poesiaFaixaEtaria');
let currentPoesia = null;
let selectedEstrofes = 3;
// Elementos do Painel Direito
const poesiaBnccBadge = document.getElementById('poesiaBnccBadge');
const poesiaMetricsBox = document.getElementById('poesiaMetricsBox');
const poesiaEsquemaBadge = document.getElementById('poesiaEsquemaBadge');
const poesiaMetricRimaVal = document.getElementById('poesiaMetricRimaVal');
const poesiaMetricRimaBar = document.getElementById('poesiaMetricRimaBar');
const poesiaMetricRitmoVal = document.getElementById('poesiaMetricRitmoVal');
const poesiaMetricRitmoBar = document.getElementById('poesiaMetricRitmoBar');
const poesiaMetricAliteracaoVal = document.getElementById('poesiaMetricAliteracaoVal');
const poesiaMetricAliteracaoBar = document.getElementById('poesiaMetricAliteracaoBar');
const poesiaMetricMusicalidadeVal = document.getElementById('poesiaMetricMusicalidadeVal');
const poesiaMetricMusicalidadeBar = document.getElementById('poesiaMetricMusicalidadeBar');
const poesiaMetricaDesc = document.getElementById('poesiaMetricaDesc');
// Seleção de estrofes
const poesiaAudioPlayerBox = document.getElementById('poesiaAudioPlayerBox');
const poesiaAudioPlayer = document.getElementById('poesiaAudioPlayer');
const poesiaPlayerTitle = document.getElementById('poesiaPlayerTitle');
const btnDownloadPoesiaAudio = document.getElementById('btnDownloadPoesiaAudio');
const poesiaContentTabs = document.getElementById('poesiaContentTabs');
const btnTabPoesiaOriginal = document.getElementById('btnTabPoesiaOriginal');
const btnTabPoesiaFonetica = document.getElementById('btnTabPoesiaFonetica');
const btnTabPoesiaPedagogica = document.getElementById('btnTabPoesiaPedagogica');
const poesiaPlaceholderText = document.getElementById('poesiaPlaceholderText');
const poesiaActiveBox = document.getElementById('poesiaActiveBox');
const poesiaActiveTitle = document.getElementById('poesiaActiveTitle');
const poesiaActiveSubtitle = document.getElementById('poesiaActiveSubtitle');
const poesiaActiveContent = document.getElementById('poesiaActiveContent');
const poesiaPedagogicalTipBox = document.getElementById('poesiaPedagogicalTipBox');
const poesiaPedagogicalTipText = document.getElementById('poesiaPedagogicalTipText');
const btnCopyActivePoesia = document.getElementById('btnCopyActivePoesia');
const btnDownloadActivePoesiaTxt = document.getElementById('btnDownloadActivePoesiaTxt');
const btnSendPoesiaToMusic = document.getElementById('btnSendPoesiaToMusic');
const btnExportActivePoesiaPdf = document.getElementById('btnExportActivePoesiaPdf');
let selectedPoesiaEstrofes = 3;
let activePoesiaTab = 'original';
// TEMPLATES TEMÁTICOS DO ESTÚDIO DE POESIAS
const POESIA_TEMPLATES = {
horta: {
tema: "Plantar sementinhas na horta da escola, regar a terra com carinho, ver os brotinhos crescerem e colher vegetais coloridos e saudáveis.",
faixa: "Crianças pequenas (4 anos a 5 anos e 11 meses)",
estrutura: "Quadras (Rimas A-B-A-B)",
estilo: "Lúdico-cantado e sonoro",
voz: "mulher",
estrofes: 3
},
animais: {
tema: "Os bichinhos da fazenda, o canto do galo pela manhã, a vaquinha mimosa, o cachorrinho amigo e as onomatopeias dos sons dos animais.",
faixa: "Crianças bem pequenas (1 ano e 7 meses a 3 anos e 11 meses)",
estrutura: "Quadras (Rimas A-B-A-B)",
estilo: "Lúdico-cantado e sonoro",
voz: "mulher",
estrofes: 3
},
familia: {
tema: "O abraço quentinho da família, o carinho ao chegar em casa, os beijinhos de boa noite e o afeto entre pais, avós e irmãos.",
faixa: "Crianças bem pequenas (1 ano e 7 meses a 3 anos e 11 meses)",
estrutura: "Redondilhas (7 sílabas poéticas)",
estilo: "Sensorial, suave e afetivo",
voz: "mulher",
estrofes: 3
},
higiene: {
tema: "Bolhas de sabão lavando as mãozinhas, a escova de dentes dançando na boca e o cheirinho gostoso de banho tomado.",
faixa: "Crianças pequenas (4 anos a 5 anos e 11 meses)",
estrutura: "Quadras (Rimas A-B-A-B)",
estilo: "Lúdico-cantado e sonoro",
voz: "crianca",
estrofes: 3
},
chuva: {
tema: "As gotinhas de chuva batendo ploc-ploc no telhado, o cheiro de terra molhada e a dança com guarda-chuva colorido.",
faixa: "Crianças pequenas (4 anos a 5 anos e 11 meses)",
estrutura: "Redondilhas (7 sílabas poéticas)",
estilo: "Sensorial, suave e afetivo",
voz: "mulher",
estrofes: 3
},
alfabeto: {
tema: "As letrinhas encantadas brincando no papel, as rimas das vogais e a mágica de escrever o primeiro nome.",
faixa: "Crianças pequenas (4 anos a 5 anos e 11 meses)",
estrutura: "Quadras (Rimas A-B-A-B)",
estilo: "Narrativo-infantil com história",
voz: "mulher",
estrofes: 4
},
cores: {
tema: "O azul do céu infinito, o amarelo do sol brilhante, o verde das folhinhas e a aquarela das cores na pintura com os dedinhos.",
faixa: "Crianças pequenas (4 anos a 5 anos e 11 meses)",
estrutura: "Haiku Infantil (5-7-5 sílabas)",
estilo: "Sensorial, suave e afetivo",
voz: "mulher",
estrofes: 3
}
};
// Estado da poesia ativa
let activePoesiaData = {
titulo: '',
poesia: '',
versaoFonetica: '',
esquemaRima: '',
analiseLiteraria: { rima: 80, ritmo: 80, aliteracao: 60, musicalidade: 85, explicacaoMetrica: '' },
bnccCampos: '',
dicas: '',
audioUrl: '',
tema: '',
estrutura: '',
estilo: '',
faixaEtaria: ''
};
// Botões de contagem de estrofes
document.querySelectorAll('.btn-poesia-estrofes').forEach(btn => {
btn.addEventListener('click', (e) => {
document.querySelectorAll('.btn-poesia-estrofes').forEach(b => b.classList.remove('active'));
e.target.classList.add('active');
selectedEstrofes = parseInt(e.target.dataset.estrofes);
selectedPoesiaEstrofes = parseInt(e.target.dataset.estrofes);
});
});
// Abrir/Fechar Modal Principal
// Carregar turmas no seletor do estúdio de poesia
const loadTurmasForPoesia = async () => {
if (!poesiaTurmaSelect) return;
try {
const res = await fetch('/api/turmas');
if (res.ok) {
const turmas = await res.json();
poesiaTurmaSelect.innerHTML = '<option value="">-- Selecionar Turma --</option>';
turmas.forEach(t => {
const opt = document.createElement('option');
opt.value = t.id;
opt.textContent = `${t.nome} (${t.ano || '2026'})`;
poesiaTurmaSelect.appendChild(opt);
});
}
} catch (err) {
console.warn('Erro ao carregar turmas para poesia:', err);
}
};
// Abrir Modal
if (barBtnPoesia) {
barBtnPoesia.addEventListener('click', () => {
poesiaModal.style.display = 'flex';
poesiaTemaInput.value = '';
poesiaResultArea.style.display = 'none';
poesiaGenerateLoader.style.display = 'none';
btnGeneratePoesia.disabled = false;
currentPoesia = null;
loadTurmasForPoesia();
if (!poesiaTemaInput.value) {
applyPoesiaTemplate('horta');
}
});
}
if (btnClosePoesiaModal) {
btnClosePoesiaModal.addEventListener('click', () => {
poesiaModal.style.display = 'none';
if (poesiaAudioPlayer) poesiaAudioPlayer.pause();
});
}
// Abrir/Fechar Modal de Histórico
poesiaModal.addEventListener('click', (e) => {
if (e.target === poesiaModal) {
poesiaModal.style.display = 'none';
if (poesiaAudioPlayer) poesiaAudioPlayer.pause();
}
});
// Aplicar Template
const applyPoesiaTemplate = (key) => {
const tmpl = POESIA_TEMPLATES[key];
if (!tmpl) return;
if (poesiaTemaInput) poesiaTemaInput.value = tmpl.tema;
if (poesiaFaixaEtaria) poesiaFaixaEtaria.value = tmpl.faixa;
if (poesiaEstruturaSelect) poesiaEstruturaSelect.value = tmpl.estrutura;
if (poesiaEstiloSelect) poesiaEstiloSelect.value = tmpl.estilo;
if (poesiaVozSelect) poesiaVozSelect.value = tmpl.voz;
// Atualizar botões de estrofes
document.querySelectorAll('.btn-poesia-estrofes').forEach(b => {
const isMatch = parseInt(b.dataset.estrofes) === tmpl.estrofes;
b.classList.toggle('active', isMatch);
if (isMatch) selectedPoesiaEstrofes = tmpl.estrofes;
});
};
if (poesiaTemplateSelect) {
poesiaTemplateSelect.addEventListener('change', (e) => {
if (e.target.value) {
applyPoesiaTemplate(e.target.value);
}
});
}
// Alternar Abas no Painel Direito
const switchPoesiaTab = (tab) => {
activePoesiaTab = tab;
[btnTabPoesiaOriginal, btnTabPoesiaFonetica, btnTabPoesiaPedagogica].forEach(b => {
if (b) {
b.classList.remove('active');
b.style.background = 'transparent';
b.style.color = 'var(--text-secondary)';
}
});
let currentContent = '';
let subtitleText = `${activePoesiaData.estrutura || 'Quadras'}${activePoesiaData.esquemaRima || 'A-B-A-B'}`;
if (tab === 'original') {
if (btnTabPoesiaOriginal) {
btnTabPoesiaOriginal.classList.add('active');
btnTabPoesiaOriginal.style.background = 'rgba(234,179,8,0.15)';
btnTabPoesiaOriginal.style.color = '#fbbf24';
}
currentContent = activePoesiaData.poesia;
} else if (tab === 'fonetica') {
if (btnTabPoesiaFonetica) {
btnTabPoesiaFonetica.classList.add('active');
btnTabPoesiaFonetica.style.background = 'rgba(234,179,8,0.15)';
btnTabPoesiaFonetica.style.color = '#fbbf24';
}
currentContent = activePoesiaData.versaoFonetica || activePoesiaData.poesia;
subtitleText = '🗣️ Guia Fonético com Sílabas Tônicas e Pausas Rítmicas';
} else if (tab === 'pedagogica') {
if (btnTabPoesiaPedagogica) {
btnTabPoesiaPedagogica.classList.add('active');
btnTabPoesiaPedagogica.style.background = 'rgba(234,179,8,0.15)';
btnTabPoesiaPedagogica.style.color = '#fbbf24';
}
currentContent = `📚 Campo de Experiência BNCC:\n${activePoesiaData.bnccCampos}\n\n💡 Vivência em Sala de Aula:\n${activePoesiaData.dicas || 'Recite o poema em roda incentivando as crianças a acompanharem o ritmo com palmas.'}`;
subtitleText = '💡 Vivência Pedagógica & Alinhamento BNCC';
}
if (poesiaActiveSubtitle) poesiaActiveSubtitle.textContent = subtitleText;
if (poesiaActiveContent) {
if (tab === 'fonetica') {
// Converte **palavra** em negrito no HTML
const formatted = currentContent.replace(/\*\*(.*?)\*\*/g, '<strong style="color: #fbbf24; text-decoration: underline;">$1</strong>');
poesiaActiveContent.innerHTML = formatted;
} else {
poesiaActiveContent.textContent = currentContent;
}
}
};
if (btnTabPoesiaOriginal) btnTabPoesiaOriginal.addEventListener('click', () => switchPoesiaTab('original'));
if (btnTabPoesiaFonetica) btnTabPoesiaFonetica.addEventListener('click', () => switchPoesiaTab('fonetica'));
if (btnTabPoesiaPedagogica) btnTabPoesiaPedagogica.addEventListener('click', () => switchPoesiaTab('pedagogica'));
// Equalizer visualizer quando o áudio recitado toca
if (poesiaAudioPlayer) {
poesiaAudioPlayer.addEventListener('play', () => {
const bars = document.querySelectorAll('#poesiaWaveformVisualizer .wave-bar');
bars.forEach(b => b.classList.add('wave-active'));
});
poesiaAudioPlayer.addEventListener('pause', () => {
const bars = document.querySelectorAll('#poesiaWaveformVisualizer .wave-bar');
bars.forEach(b => b.classList.remove('wave-active'));
});
}
// --- GERAR POESIA (ANÁLISE LITERÁRIA + ÁUDIO RECITADO) ---
if (btnGeneratePoesia) {
btnGeneratePoesia.addEventListener('click', async () => {
const tema = (poesiaTemaInput?.value || '').trim();
if (!tema) {
await showCustomAlert('Aviso', 'Por favor, informe a ideia ou tema da poesia.');
return;
}
btnGeneratePoesia.disabled = true;
if (poesiaGenerateLoader) poesiaGenerateLoader.style.display = 'flex';
try {
const res = await fetch('/api/poesias/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
tema,
faixaEtaria: poesiaFaixaEtaria?.value,
estrofes: selectedPoesiaEstrofes,
estrutura: poesiaEstruturaSelect?.value || 'Quadras (Rimas A-B-A-B)',
estilo: poesiaEstiloSelect?.value || 'Lúdico-cantado e sonoro',
voz: poesiaVozSelect?.value || 'mulher',
turmaId: poesiaTurmaSelect?.value || null,
gerarAudio: true
})
});
const data = await res.json();
if (res.ok && data.success) {
activePoesiaData = {
titulo: data.titulo || `Poema: ${tema}`,
poesia: data.poesia,
versaoFonetica: data.versaoFonetica,
esquemaRima: data.esquemaRima || 'A-B-A-B',
analiseLiteraria: data.analiseLiteraria || { rima: 85, ritmo: 80, aliteracao: 65, musicalidade: 90 },
bnccCampos: data.bnccCampos || 'EI02EF01 / EI03EF02 • Escuta, Fala, Pensamento e Imaginação',
dicas: data.dicasPedagogicas || '',
audioUrl: data.audioUrl,
tema: tema,
estrutura: data.estrutura || poesiaEstruturaSelect?.value,
estilo: data.estilo || poesiaEstiloSelect?.value,
faixaEtaria: data.faixaEtaria || poesiaFaixaEtaria?.value
};
// Atualizar Interface
if (poesiaPlaceholderText) poesiaPlaceholderText.style.display = 'none';
if (poesiaMetricsBox) poesiaMetricsBox.style.display = 'flex';
if (poesiaContentTabs) poesiaContentTabs.style.display = 'flex';
if (poesiaActiveBox) poesiaActiveBox.style.display = 'flex';
if (poesiaActiveTitle) poesiaActiveTitle.textContent = activePoesiaData.titulo;
if (poesiaBnccBadge) {
poesiaBnccBadge.textContent = `BNCC: ${activePoesiaData.bnccCampos.split('•')[0].trim()}`;
poesiaBnccBadge.style.display = 'inline-block';
}
if (poesiaEsquemaBadge) {
poesiaEsquemaBadge.textContent = `Esquema: ${activePoesiaData.esquemaRima}`;
}
// Atualizar Barras de Métricas Literárias
const metrics = activePoesiaData.analiseLiteraria;
if (poesiaMetricRimaVal) poesiaMetricRimaVal.textContent = `${metrics.rima || 85}%`;
if (poesiaMetricRimaBar) poesiaMetricRimaBar.style.width = `${metrics.rima || 85}%`;
if (poesiaMetricRitmoVal) poesiaMetricRitmoVal.textContent = `${metrics.ritmo || 80}%`;
if (poesiaMetricRitmoBar) poesiaMetricRitmoBar.style.width = `${metrics.ritmo || 80}%`;
if (poesiaMetricAliteracaoVal) poesiaMetricAliteracaoVal.textContent = `${metrics.aliteracao || 65}%`;
if (poesiaMetricAliteracaoBar) poesiaMetricAliteracaoBar.style.width = `${metrics.aliteracao || 65}%`;
if (poesiaMetricMusicalidadeVal) poesiaMetricMusicalidadeVal.textContent = `${metrics.musicalidade || 90}%`;
if (poesiaMetricMusicalidadeBar) poesiaMetricMusicalidadeBar.style.width = `${metrics.musicalidade || 90}%`;
if (poesiaMetricaDesc && metrics.explicacaoMetrica) {
poesiaMetricaDesc.textContent = metrics.explicacaoMetrica;
}
if (poesiaPedagogicalTipText && activePoesiaData.dicas) {
poesiaPedagogicalTipText.textContent = activePoesiaData.dicas;
poesiaPedagogicalTipBox.style.display = 'block';
}
// Áudio Recitado
if (data.audioUrl) {
poesiaAudioPlayer.src = data.audioUrl;
if (poesiaPlayerTitle) poesiaPlayerTitle.textContent = activePoesiaData.titulo;
if (btnDownloadPoesiaAudio) btnDownloadPoesiaAudio.href = data.audioUrl;
if (poesiaAudioPlayerBox) poesiaAudioPlayerBox.style.display = 'flex';
} else {
if (poesiaAudioPlayerBox) poesiaAudioPlayerBox.style.display = 'none';
}
switchPoesiaTab('original');
showToast('Poesia pedagógica e métricas geradas com sucesso!', 'success');
} else {
await showCustomAlert('Erro', data.error || 'Erro ao gerar poesia.');
}
} catch (err) {
console.error('Erro ao compor poesia:', err);
await showCustomAlert('Erro', 'Não foi possível conectar ao servidor: ' + err.message);
} finally {
btnGeneratePoesia.disabled = false;
if (poesiaGenerateLoader) poesiaGenerateLoader.style.display = 'none';
}
});
}
// Copiar Poema Ativo
if (btnCopyActivePoesia) {
btnCopyActivePoesia.addEventListener('click', () => {
const text = activePoesiaData.poesia || '';
if (text) {
navigator.clipboard.writeText(`${activePoesiaData.titulo}\n\n${text}`);
showToast('Poema copiado para a área de transferência!', 'success');
}
});
}
// Baixar Poema TXT
if (btnDownloadActivePoesiaTxt) {
btnDownloadActivePoesiaTxt.addEventListener('click', () => {
const text = activePoesiaData.poesia || '';
if (!text) return;
const content = `POESIA PEDAGÓGICA - PEDAGOGIA\n========================================\nTítulo: ${activePoesiaData.titulo}\nFaixa Etária: ${activePoesiaData.faixaEtaria}\nEstrutura: ${activePoesiaData.estrutura}\nEsquema de Rima: ${activePoesiaData.esquemaRima}\nBNCC: ${activePoesiaData.bnccCampos}\n========================================\n\n${text}\n\n----------------------------------------\nGuia de Leitura / Fonética:\n${activePoesiaData.versaoFonetica}\n\n----------------------------------------\nVivência Pedagógica:\n${activePoesiaData.dicas}\n`;
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = `poema_${(activePoesiaData.titulo || 'poesia').replace(/[^a-zA-Z0-9_-]/g, '_').toLowerCase()}.txt`;
document.body.appendChild(link);
link.click();
link.remove();
});
}
// Enviar Poema ao Musicando Ideias
if (btnSendPoesiaToMusic) {
btnSendPoesiaToMusic.addEventListener('click', () => {
poesiaModal.style.display = 'none';
const barBtnMusica = document.getElementById('barBtnMusica');
const musicaModal = document.getElementById('musicaModal');
const musicaTemaInput = document.getElementById('musicaTemaInput');
if (musicaModal && musicaTemaInput) {
musicaModal.style.display = 'flex';
musicaTemaInput.value = `Musicar a poesia "${activePoesiaData.titulo}": ${activePoesiaData.poesia.substring(0, 200)}...`;
showToast('Poema transferido para o Estúdio de Música!', 'success');
}
});
}
// Exportar PDF Ilustrado Formatado
if (btnExportActivePoesiaPdf) {
btnExportActivePoesiaPdf.addEventListener('click', () => {
const text = activePoesiaData.poesia || '';
if (!text) return;
const printWindow = window.open('', '_blank');
printWindow.document.write(`
<html>
<head>
<title>${activePoesiaData.titulo} - PedaGog</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@400;600;700&family=Outfit:wght@400;600;700&display=swap" rel="stylesheet">
<style>
body { font-family: 'Fredoka', 'Outfit', sans-serif; padding: 40px; color: #1e293b; background: #fffdf8; line-height: 1.8; }
.header-box { border-bottom: 3px dashed #eab308; padding-bottom: 16px; margin-bottom: 24px; }
h1 { color: #ca8a04; margin: 0 0 8px 0; font-size: 2rem; }
.meta-tags { display: flex; gap: 12px; font-size: 0.9rem; color: #64748b; font-weight: 600; margin-bottom: 8px; flex-wrap: wrap; }
.meta-tag { background: #fef9c3; color: #a16207; padding: 4px 10px; border-radius: 6px; }
.poetry-box { font-size: 1.25rem; background: #ffffff; padding: 28px; border-radius: 12px; border: 1px solid #fef08a; white-space: pre-wrap; margin-bottom: 24px; box-shadow: 0 4px 6px rgba(0,0,0,0.02); }
.metrics-box { background: #f8fafc; border: 1px solid #e2e8f0; padding: 14px 18px; border-radius: 8px; font-size: 0.85rem; color: #475569; margin-bottom: 20px; }
.tip-box { background: #fefce8; border: 1px solid #fde047; color: #854d0e; padding: 14px 18px; border-radius: 8px; font-size: 0.92rem; }
@media print { body { padding: 20px; } button { display: none; } }
</style>
</head>
<body>
<div style="max-width: 750px; margin: 0 auto;">
<div class="header-box">
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
<div>
<h1>📜 ${activePoesiaData.titulo}</h1>
<div class="meta-tags">
<span class="meta-tag">👶 ${activePoesiaData.faixaEtaria}</span>
<span class="meta-tag">📐 ${activePoesiaData.estrutura}</span>
<span class="meta-tag">📚 ${activePoesiaData.bnccCampos.split('•')[0]}</span>
</div>
</div>
<button onclick="window.print()" style="background: #eab308; color: #1e293b; border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-weight: bold; font-family: sans-serif;">🖨 Imprimir / Salvar PDF</button>
</div>
</div>
<div class="poetry-box">${text}</div>
<div class="metrics-box">
<strong>📊 Análise Métrica:</strong> Rima: ${activePoesiaData.analiseLiteraria.rima}% | Ritmo: ${activePoesiaData.analiseLiteraria.ritmo}% | Musicalidade: ${activePoesiaData.analiseLiteraria.musicalidade}% (Esquema: ${activePoesiaData.esquemaRima})
</div>
${activePoesiaData.dicas ? `
<div class="tip-box">
💡 <strong>Vivência Pedagógica / Roda de Leitura:</strong><br>
${activePoesiaData.dicas}
</div>` : ''}
<div style="margin-top: 30px; text-align: center; font-size: 0.8rem; color: #94a3b8; border-top: 1px solid #e2e8f0; padding-top: 10px;">
Estúdio de Poesias PedagogIA Assistente Pedagógica da Professora Camila
</div>
</div>
</body>
</html>
`);
printWindow.document.close();
});
}
// --- HISTÓRICO DE POESIAS ---
if (btnOpenPoesiaHistory) {
btnOpenPoesiaHistory.addEventListener('click', () => {
poesiaHistoryModal.style.display = 'flex';
@@ -6229,163 +6683,107 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
});
}
window.addEventListener('click', (e) => {
if (e.target === poesiaModal) poesiaModal.style.display = 'none';
if (e.target === poesiaHistoryModal) poesiaHistoryModal.style.display = 'none';
poesiaHistoryModal.addEventListener('click', (e) => {
if (e.target === poesiaHistoryModal) {
poesiaHistoryModal.style.display = 'none';
}
});
// Gerar Poesia
if (btnGeneratePoesia) {
btnGeneratePoesia.addEventListener('click', async () => {
const tema = poesiaTemaInput.value.trim();
const faixaEtaria = poesiaFaixaEtaria.value;
if (!tema) {
showToast('Por favor, digite o tema da poesia.', 'error');
return;
}
btnGeneratePoesia.disabled = true;
poesiaGenerateLoader.style.display = 'flex';
poesiaResultArea.style.display = 'none';
try {
const response = await fetch('/api/poesias/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ faixaEtaria, estrofes: selectedEstrofes, tema })
});
const data = await response.json();
if (response.ok && data.success) {
currentPoesia = data.poesia;
poesiaTextOutput.innerHTML = window.marked ? marked.parse(currentPoesia) : currentPoesia;
poesiaResultArea.style.display = 'flex';
showToast('Poesia criada com sucesso!', 'success');
} else {
showToast(data.error || 'Falha ao gerar poesia.', 'error');
}
} catch (err) {
console.error('Erro na geração da poesia:', err);
showToast('Erro de conexão ao gerar poesia.', 'error');
} finally {
btnGeneratePoesia.disabled = false;
poesiaGenerateLoader.style.display = 'none';
}
});
}
// Copiar e Baixar
if (btnCopyPoesia) {
btnCopyPoesia.addEventListener('click', () => {
if (currentPoesia) {
navigator.clipboard.writeText(currentPoesia);
showToast('Poesia copiada para a área de transferência!', 'success');
}
});
}
if (btnDownloadPoesiaPdf) {
btnDownloadPoesiaPdf.addEventListener('click', () => {
if (!currentPoesia) return;
const printWindow = window.open('', '_blank');
printWindow.document.write(`
<html>
<head>
<title>Poesia - Assistente 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; }
}
</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; border: none; padding: 0;">📜 Poesia 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 / Salvar PDF</button>
</div>
<div>
${window.marked ? marked.parse(currentPoesia) : currentPoesia}
</div>
</div>
</body>
</html>
`);
printWindow.document.close();
});
}
// Carregar Histórico
async function loadPoesiaHistory() {
const listContainer = document.getElementById('poesiaHistoryList');
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órico...</p>';
try {
const response = await fetch('/api/poesias/list');
const data = await response.json();
if (data && data.length > 0) {
listContainer.innerHTML = '';
data.forEach(item => {
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.03); padding: 14px; border-radius: 10px; border: 1px solid var(--border-light); display: flex; flex-direction: column; gap: 8px; cursor: pointer; position: relative; transition: all 0.2s;';
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.estrofes} Estrofes)</strong>
<span style="font-size: 0.75rem; color: var(--text-secondary);">${date}</span>
<strong style="color: #fbbf24; font-size: 0.95rem;">${item.faixa_etaria} (${item.estrofes} Estrofes)</strong>
<span style="font-size: 0.72rem; color: var(--text-secondary);">${date}</span>
</div>
<p style="margin: 0; font-size: 0.85rem; color: var(--text-primary); opacity: 0.9;">Tema: ${item.tema}</p>
<p style="margin: 0; font-size: 0.85rem; color: var(--text-primary); opacity: 0.9;"><strong>Tema:</strong> ${item.tema}</p>
${item.audio_url ? `
<div style="display: flex; align-items: center; gap: 8px; margin-top: 4px;">
<span style="font-size: 0.75rem; color: #10b981; font-weight: 600;">🎙 Áudio Recitado Disponível</span>
</div>
` : ''}
<button class="btn-delete-poesia" 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 Poesia">🗑</button>
`;
div.addEventListener('click', async (e) => {
if (e.target.closest('.btn-delete-poesia')) {
e.stopPropagation();
if (confirm('Tem certeza que deseja excluir esta poesia?')) {
if (confirm('Tem certeza que deseja excluir esta poesia do histórico?')) {
try {
const delRes = await fetch(`/api/poesias/${item.id}`, { method: 'DELETE' });
if (delRes.ok) {
showToast('Poesia excluída.', 'success');
showToast('Poesia excluída do histórico.', 'success');
loadPoesiaHistory();
} else {
showToast('Erro ao excluir.', 'error');
}
} catch (err) {
showToast('Erro de conexão.', 'error');
showToast('Erro ao excluir poesia.', 'error');
}
}
return;
}
// Carregar poesia clicada
try {
const res = await fetch(`/api/poesias/${item.id}`);
const detail = await res.json();
if (res.ok) {
currentPoesia = detail.poesia;
poesiaTextOutput.innerHTML = window.marked ? marked.parse(currentPoesia) : currentPoesia;
poesiaResultArea.style.display = 'flex';
activePoesiaData = {
titulo: `Poema: ${detail.tema}`,
poesia: detail.poesia,
versaoFonetica: detail.versao_fonetica || detail.poesia,
esquemaRima: 'A-B-A-B',
analiseLiteraria: typeof detail.analise_metrica === 'string' ? JSON.parse(detail.analise_metrica) : (detail.analise_metrica || { rima: 85, ritmo: 80, aliteracao: 65, musicalidade: 90 }),
bnccCampos: detail.bncc || 'EI02EF01 / EI03EF02 • Escuta, Fala, Pensamento e Imaginação',
dicas: detail.dicas || '',
audioUrl: detail.audio_url,
tema: detail.tema,
estrutura: detail.estrutura || 'Quadras',
estilo: detail.estilo || 'Lúdico-cantado',
faixaEtaria: detail.faixa_etaria
};
if (poesiaPlaceholderText) poesiaPlaceholderText.style.display = 'none';
if (poesiaMetricsBox) poesiaMetricsBox.style.display = 'flex';
if (poesiaContentTabs) poesiaContentTabs.style.display = 'flex';
if (poesiaActiveBox) poesiaActiveBox.style.display = 'flex';
if (poesiaActiveTitle) poesiaActiveTitle.textContent = activePoesiaData.titulo;
if (detail.audio_url) {
poesiaAudioPlayer.src = detail.audio_url;
if (btnDownloadPoesiaAudio) btnDownloadPoesiaAudio.href = detail.audio_url;
if (poesiaAudioPlayerBox) poesiaAudioPlayerBox.style.display = 'flex';
} else {
if (poesiaAudioPlayerBox) poesiaAudioPlayerBox.style.display = 'none';
}
switchPoesiaTab('original');
poesiaHistoryModal.style.display = 'none';
}
} catch (err) {
showToast('Erro ao carregar poesia.', 'error');
showToast('Erro ao carregar detalhes da poesia.', 'error');
}
});
listContainer.appendChild(div);
});
} else {
listContainer.innerHTML = '<p style="text-align:center; color:var(--text-secondary);">Nenhuma poesia salva ainda.</p>';
listContainer.innerHTML = '<p style="text-align:center; color:var(--text-secondary); padding: 20px;">Nenhuma poesia gerada até o momento.</p>';
}
} catch (err) {
listContainer.innerHTML = '<p style="text-align:center; color:#ef4444;">Erro ao carregar histórico.</p>';
listContainer.innerHTML = '<p style="text-align:center; color:#ef4444;">Erro ao carregar histórico de poesias.</p>';
}
}