Adiciona ferramenta VideoMind para transcrição e análise de vídeos com resumo customizado

This commit is contained in:
2026-06-04 23:37:53 +00:00
parent a53496cd3f
commit 6866d565ec
16 changed files with 1183 additions and 2 deletions
+227
View File
@@ -4489,6 +4489,233 @@ const initApp = () => {
}
});
}
// ============================================================
// VIDEOMIND (TRANSCRIÇÃO E ANÁLISE DE VÍDEO PEDAGÓGICO)
// ============================================================
const videoMindModal = document.getElementById('videoMindModal');
const btnCloseVideoMindModal = document.getElementById('btnCloseVideoMindModal');
const barBtnVideoMind = document.getElementById('barBtnVideoMind');
const btnGenerateVideoMind = document.getElementById('btnGenerateVideoMind');
const videoMindUrlInput = document.getElementById('videoMindUrlInput');
const videoMindLoader = document.getElementById('videoMindLoader');
const videoMindLoaderText = document.getElementById('videoMindLoaderText');
const videoMindResultArea = document.getElementById('videoMindResultArea');
const videoMindThumbnail = document.getElementById('videoMindThumbnail');
const videoMindTitle = document.getElementById('videoMindTitle');
const videoMindAuthor = document.getElementById('videoMindAuthor');
const videoMindReportArea = document.getElementById('videoMindReportArea');
const btnCopyVideoMindReport = document.getElementById('btnCopyVideoMindReport');
const btnDownloadVideoMindReport = document.getElementById('btnDownloadVideoMindReport');
const btnPdfVideoMindReport = document.getElementById('btnPdfVideoMindReport');
let selectedVideoMindLines = 20;
let activeVideoMindReport = null;
// Listener para selecionar o tamanho do resumo
document.querySelectorAll('#videoMindModal .music-option-grid .btn-videomind-lines').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('#videoMindModal .music-option-grid .btn-videomind-lines').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
selectedVideoMindLines = parseInt(btn.dataset.lines) || 20;
});
});
// Abrir modal do VideoMind
if (barBtnVideoMind) {
barBtnVideoMind.addEventListener('click', () => {
videoMindModal.style.display = 'flex';
videoMindUrlInput.value = '';
videoMindResultArea.style.display = 'none';
videoMindReportArea.innerHTML = '';
if (videoMindLoader) videoMindLoader.style.display = 'none';
btnGenerateVideoMind.disabled = false;
activeVideoMindReport = null;
});
}
// Fechar modal
if (btnCloseVideoMindModal) {
btnCloseVideoMindModal.addEventListener('click', () => {
videoMindModal.style.display = 'none';
});
}
window.addEventListener('click', (e) => {
if (e.target === videoMindModal) {
videoMindModal.style.display = 'none';
}
});
// Ação de analisar vídeo
if (btnGenerateVideoMind) {
btnGenerateVideoMind.addEventListener('click', async () => {
const url = videoMindUrlInput.value.trim();
if (!url) {
alert('Por favor, insira o link de um vídeo do YouTube.');
return;
}
btnGenerateVideoMind.disabled = true;
videoMindLoader.style.display = 'flex';
videoMindResultArea.style.display = 'none';
videoMindLoaderText.textContent = 'Buscando metadados do vídeo...';
let statusMsgIdx = 0;
const statusMessages = [
'Buscando legenda automática do vídeo...',
'Carregando a transcrição completa...',
'Enviando transcrição para a IA...',
'Pedagoga IA analisando o conteúdo...',
'Alinhando temas do vídeo com a BNCC...',
'Gerando resumo de ' + selectedVideoMindLines + ' linhas...',
'Criando propostas de atividades pedagógicas...',
'Finalizando o parecer pedagógico...'
];
const statusInterval = setInterval(() => {
if (statusMsgIdx < statusMessages.length) {
videoMindLoaderText.textContent = statusMessages[statusMsgIdx];
statusMsgIdx++;
} else {
videoMindLoaderText.textContent = 'Ajustando formatação da análise...';
}
}, 4000);
try {
const response = await fetch('/api/videomind/analyze', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url,
lines: selectedVideoMindLines
})
});
clearInterval(statusInterval);
if (!response.ok) {
const errData = await response.json();
throw new Error(errData.error || 'Erro desconhecido');
}
const data = await response.json();
activeVideoMindReport = data;
// Preencher informações do vídeo
videoMindTitle.textContent = data.metadata.title;
videoMindAuthor.textContent = 'Canal: ' + data.metadata.author;
videoMindThumbnail.src = data.metadata.thumbnail;
// Renderizar Markdown
if (window.marked) {
videoMindReportArea.innerHTML = marked.parse(data.report);
} else {
videoMindReportArea.textContent = data.report;
}
videoMindLoader.style.display = 'none';
videoMindResultArea.style.display = 'flex';
} catch (err) {
clearInterval(statusInterval);
console.error('Erro no VideoMind:', err);
alert('Erro ao analisar vídeo: ' + err.message);
videoMindLoader.style.display = 'none';
btnGenerateVideoMind.disabled = false;
}
});
}
// Copiar Parecer
if (btnCopyVideoMindReport) {
btnCopyVideoMindReport.addEventListener('click', () => {
if (activeVideoMindReport && activeVideoMindReport.report) {
navigator.clipboard.writeText(activeVideoMindReport.report)
.then(() => {
btnCopyVideoMindReport.textContent = '✅ Copiado!';
setTimeout(() => {
btnCopyVideoMindReport.textContent = '📋 Copiar Parecer';
}, 2000);
})
.catch(err => {
console.error('Falha ao copiar:', err);
});
}
});
}
// Baixar relatório TXT
if (btnDownloadVideoMindReport) {
btnDownloadVideoMindReport.addEventListener('click', () => {
if (activeVideoMindReport && activeVideoMindReport.report) {
const title = activeVideoMindReport.metadata.title || 'analise_video';
const blob = new Blob([activeVideoMindReport.report], { type: 'text/plain;charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `VideoMind_${title.replace(/\s+/g, '_').toLowerCase()}.txt`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
});
}
// Baixar relatório PDF
if (btnPdfVideoMindReport) {
btnPdfVideoMindReport.addEventListener('click', () => {
if (!activeVideoMindReport) return;
const printWindow = window.open('', '_blank');
printWindow.document.write(`
<html>
<head>
<title>VideoMind - Parecer Pedagógico</title>
<style>
body { font-family: 'Outfit', 'Inter', -apple-system, sans-serif; padding: 40px; color: #333; line-height: 1.6; }
h1, h2, h3 { color: #0891b2; margin-top: 24px; margin-bottom: 12px; }
h1 { border-bottom: 2px solid #e2e8f0; padding-bottom: 10px; font-size: 22px; }
h2 { font-size: 18px; border-bottom: 1px solid #f1f5f9; padding-bottom: 6px; }
.meta-box { background: #f8fafc; padding: 16px; border-radius: 8px; margin-bottom: 24px; font-size: 14px; border: 1px solid #e2e8f0; display: flex; gap: 16px; align-items: center; }
.meta-info { display: flex; flex-direction: column; gap: 4px; }
.meta-label { font-weight: bold; color: #475569; }
p { margin-bottom: 14px; text-align: justify; }
ul, ol { margin-bottom: 14px; padding-left: 20px; }
li { margin-bottom: 6px; }
@media print {
body { padding: 0; }
button { display: none; }
}
</style>
</head>
<body>
<h1>🎬 VideoMind - Análise & Parecer Pedagógico</h1>
<div class="meta-box">
<img src="${activeVideoMindReport.metadata.thumbnail}" style="width: 100px; aspect-ratio: 16/9; object-fit: cover; border-radius: 6px;">
<div class="meta-info">
<div><span class="meta-label">Vídeo:</span> <span>${activeVideoMindReport.metadata.title}</span></div>
<div><span class="meta-label">Canal:</span> <span>${activeVideoMindReport.metadata.author}</span></div>
<div><span class="meta-label">Resumo Escolhido:</span> <span>${selectedVideoMindLines} Linhas</span></div>
</div>
</div>
<div>${window.marked ? marked.parse(activeVideoMindReport.report) : activeVideoMindReport.report}</div>
<script>
window.onload = function() {
window.print();
setTimeout(() => { window.close(); }, 500);
};
</script>
</body>
</html>
`);
printWindow.document.close();
});
}
};
// Player de áudio personalizado global para as mídias geradas