🚀 Auto-deploy: Implementação das ferramentas Garatujas e BrincarAtivo
This commit is contained in:
+557
@@ -4713,9 +4713,566 @@ const initApp = () => {
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// GARATUJAS (ANALISADOR DE TRAÇADO INFANTIL)
|
||||
// ============================================================
|
||||
const garatujasModal = document.getElementById('garatujasModal');
|
||||
const btnCloseGaratujasModal = document.getElementById('btnCloseGaratujasModal');
|
||||
const barBtnGaratujas = document.getElementById('barBtnGaratujas');
|
||||
|
||||
const tabGaratujasNova = document.getElementById('tabGaratujasNova');
|
||||
const tabGaratujasHistorico = document.getElementById('tabGaratujasHistorico');
|
||||
const contentGaratujasNova = document.getElementById('contentGaratujasNova');
|
||||
const contentGaratujasHistorico = document.getElementById('contentGaratujasHistorico');
|
||||
|
||||
const garatujasAlunoInput = document.getElementById('garatujasAlunoInput');
|
||||
const garatujaFileInput = document.getElementById('garatujaFileInput');
|
||||
const btnUploadGaratuja = document.getElementById('btnUploadGaratuja');
|
||||
const garatujaFileStatus = document.getElementById('garatujaFileStatus');
|
||||
const garatujaPreviewContainer = document.getElementById('garatujaPreviewContainer');
|
||||
const garatujaImgPreview = document.getElementById('garatujaImgPreview');
|
||||
|
||||
const btnGenerateGaratuja = document.getElementById('btnGenerateGaratuja');
|
||||
const garatujaLoader = document.getElementById('garatujaLoader');
|
||||
const garatujaLoaderText = document.getElementById('garatujaLoaderText');
|
||||
const garatujaResultArea = document.getElementById('garatujaResultArea');
|
||||
const garatujaReportArea = document.getElementById('garatujaReportArea');
|
||||
|
||||
const btnCopyGaratujaReport = document.getElementById('btnCopyGaratujaReport');
|
||||
const btnPdfGaratujaReport = document.getElementById('btnPdfGaratujaReport');
|
||||
const garatujasListContainer = document.getElementById('garatujasListContainer');
|
||||
const garatujasNoData = document.getElementById('garatujasNoData');
|
||||
|
||||
let activeGaratujaReport = null;
|
||||
|
||||
// Abas do Garatujas
|
||||
if (tabGaratujasNova) {
|
||||
tabGaratujasNova.addEventListener('click', () => {
|
||||
tabGaratujasNova.classList.add('active');
|
||||
tabGaratujasHistorico.classList.remove('active');
|
||||
contentGaratujasNova.style.display = 'block';
|
||||
contentGaratujasHistorico.style.display = 'none';
|
||||
});
|
||||
}
|
||||
|
||||
if (tabGaratujasHistorico) {
|
||||
tabGaratujasHistorico.addEventListener('click', () => {
|
||||
tabGaratujasHistorico.classList.add('active');
|
||||
tabGaratujasNova.classList.remove('active');
|
||||
contentGaratujasNova.style.display = 'none';
|
||||
contentGaratujasHistorico.style.display = 'block';
|
||||
loadGaratujasHistory();
|
||||
});
|
||||
}
|
||||
|
||||
// Abrir Modal
|
||||
if (barBtnGaratujas) {
|
||||
barBtnGaratujas.addEventListener('click', () => {
|
||||
garatujasModal.style.display = 'flex';
|
||||
garatujasAlunoInput.value = '';
|
||||
garatujaFileInput.value = '';
|
||||
garatujaFileStatus.textContent = 'Nenhum arquivo selecionado';
|
||||
garatujaPreviewContainer.style.display = 'none';
|
||||
garatujaResultArea.style.display = 'none';
|
||||
garatujaLoader.style.display = 'none';
|
||||
btnGenerateGaratuja.disabled = false;
|
||||
activeGaratujaReport = null;
|
||||
if (tabGaratujasNova) tabGaratujasNova.click();
|
||||
});
|
||||
}
|
||||
|
||||
// Fechar Modal
|
||||
if (btnCloseGaratujasModal) {
|
||||
btnCloseGaratujasModal.addEventListener('click', () => {
|
||||
garatujasModal.style.display = 'none';
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('click', (e) => {
|
||||
if (e.target === garatujasModal) {
|
||||
garatujasModal.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Upload trigger
|
||||
if (btnUploadGaratuja) {
|
||||
btnUploadGaratuja.addEventListener('click', () => {
|
||||
garatujaFileInput.click();
|
||||
});
|
||||
}
|
||||
|
||||
if (garatujaFileInput) {
|
||||
garatujaFileInput.addEventListener('change', () => {
|
||||
const file = garatujaFileInput.files[0];
|
||||
if (file) {
|
||||
garatujaFileStatus.textContent = file.name;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
garatujaImgPreview.src = e.target.result;
|
||||
garatujaPreviewContainer.style.display = 'block';
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
garatujaFileStatus.textContent = 'Nenhum arquivo selecionado';
|
||||
garatujaPreviewContainer.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Gerar Análise
|
||||
if (btnGenerateGaratuja) {
|
||||
btnGenerateGaratuja.addEventListener('click', async () => {
|
||||
const alunoName = garatujasAlunoInput.value.trim();
|
||||
const file = garatujaFileInput.files[0];
|
||||
|
||||
if (!alunoName) {
|
||||
alert('Por favor, informe o nome do aluno.');
|
||||
return;
|
||||
}
|
||||
if (!file) {
|
||||
alert('Por favor, selecione a foto do desenho.');
|
||||
return;
|
||||
}
|
||||
|
||||
btnGenerateGaratuja.disabled = true;
|
||||
garatujaLoader.style.display = 'flex';
|
||||
garatujaResultArea.style.display = 'none';
|
||||
garatujaLoaderText.textContent = 'Enviando imagem pedagógica...';
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('alunoName', alunoName);
|
||||
formData.append('image', file);
|
||||
|
||||
let statusMsgIdx = 0;
|
||||
const statusMessages = [
|
||||
'Carregando desenho infantil...',
|
||||
'IA escaneando os traços e formas...',
|
||||
'Analisando simetria e coordenação motora...',
|
||||
'Definindo estágio evolutivo do desenho...',
|
||||
'Criando sugestões de atividades formativas...',
|
||||
'Finalizando laudo psicopedagógico...'
|
||||
];
|
||||
|
||||
const statusInterval = setInterval(() => {
|
||||
if (statusMsgIdx < statusMessages.length) {
|
||||
garatujaLoaderText.textContent = statusMessages[statusMsgIdx];
|
||||
statusMsgIdx++;
|
||||
} else {
|
||||
garatujaLoaderText.textContent = 'Formatando parecer...';
|
||||
}
|
||||
}, 4500);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/garatujas/analyze', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
clearInterval(statusInterval);
|
||||
|
||||
if (!response.ok) {
|
||||
const errData = await response.json();
|
||||
throw new Error(errData.error || 'Erro desconhecido');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
activeGaratujaReport = data;
|
||||
|
||||
if (window.marked) {
|
||||
garatujaReportArea.innerHTML = marked.parse(data.analise);
|
||||
} else {
|
||||
garatujaReportArea.textContent = data.analise;
|
||||
}
|
||||
|
||||
garatujaLoader.style.display = 'none';
|
||||
garatujaResultArea.style.display = 'flex';
|
||||
btnGenerateGaratuja.disabled = false;
|
||||
|
||||
} catch (err) {
|
||||
clearInterval(statusInterval);
|
||||
console.error(err);
|
||||
alert('Erro na análise: ' + err.message);
|
||||
garatujaLoader.style.display = 'none';
|
||||
btnGenerateGaratuja.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Copiar Parecer Garatujas
|
||||
if (btnCopyGaratujaReport) {
|
||||
btnCopyGaratujaReport.addEventListener('click', () => {
|
||||
if (activeGaratujaReport && activeGaratujaReport.analise) {
|
||||
navigator.clipboard.writeText(activeGaratujaReport.analise)
|
||||
.then(() => {
|
||||
btnCopyGaratujaReport.textContent = '✅ Copiado!';
|
||||
setTimeout(() => { btnCopyGaratujaReport.textContent = '📋 Copiar'; }, 2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Baixar PDF Garatujas
|
||||
if (btnPdfGaratujaReport) {
|
||||
btnPdfGaratujaReport.addEventListener('click', () => {
|
||||
if (!activeGaratujaReport) return;
|
||||
const printWindow = window.open('', '_blank');
|
||||
printWindow.document.write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>Garatujas - Laudo do Desenho</title>
|
||||
<style>
|
||||
body { font-family: 'Outfit', 'Inter', sans-serif; padding: 40px; color: #333; line-height: 1.6; }
|
||||
h1, h2, h3 { color: #ea580c; margin-top: 24px; margin-bottom: 12px; }
|
||||
h1 { border-bottom: 2px solid #e2e8f0; padding-bottom: 10px; font-size: 22px; }
|
||||
.meta-box { background: #f8fafc; padding: 16px; border-radius: 8px; margin-bottom: 24px; border: 1px solid #e2e8f0; display: flex; gap: 16px; align-items: center; }
|
||||
.meta-label { font-weight: bold; color: #475569; }
|
||||
img { border-radius: 6px; border: 1px solid #ddd; max-height: 120px; }
|
||||
@media print {
|
||||
body { padding: 0; }
|
||||
button { display: none; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🎨 Garatujas - Parecer de Traçado Infantil</h1>
|
||||
<div class="meta-box">
|
||||
<img src="${activeGaratujaReport.imageUrl}">
|
||||
<div>
|
||||
<div><span class="meta-label">Aluno(a):</span> <span>${activeGaratujaReport.alunoName}</span></div>
|
||||
<div><span class="meta-label">Data de Análise:</span> <span>${new Date(activeGaratujaReport.createdAt).toLocaleDateString('pt-BR')}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>${window.marked ? marked.parse(activeGaratujaReport.analise) : activeGaratujaReport.analise}</div>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
window.print();
|
||||
setTimeout(() => { window.close(); }, 500);
|
||||
};
|
||||
<\/script>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
printWindow.document.close();
|
||||
});
|
||||
}
|
||||
|
||||
// Carregar Histórico Garatujas
|
||||
async function loadGaratujasHistory() {
|
||||
try {
|
||||
const response = await fetch('/api/garatujas/list');
|
||||
if (!response.ok) throw new Error('Erro ao carregar histórico');
|
||||
const list = await response.json();
|
||||
|
||||
garatujasListContainer.innerHTML = '';
|
||||
if (list.length === 0) {
|
||||
garatujasNoData.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
garatujasNoData.style.display = 'none';
|
||||
|
||||
list.forEach(item => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'quick-note-card';
|
||||
div.style.cursor = 'pointer';
|
||||
div.style.display = 'flex';
|
||||
div.style.flexDirection = 'column';
|
||||
div.style.gap = '8px';
|
||||
div.style.padding = '12px';
|
||||
|
||||
div.innerHTML = `
|
||||
<div style="width: 100%; aspect-ratio: 4/3; overflow: hidden; border-radius: 6px; background: rgba(0,0,0,0.2);">
|
||||
<img src="${item.imageUrl}" style="width: 100%; height: 100%; object-fit: cover;">
|
||||
</div>
|
||||
<div style="font-weight: 600; color: var(--text-primary); font-size: 0.9rem;">${escapeHtml(item.alunoName)}</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted);">${new Date(item.createdAt).toLocaleDateString('pt-BR')}</div>
|
||||
`;
|
||||
|
||||
div.addEventListener('click', async () => {
|
||||
try {
|
||||
const detailResp = await fetch(`/api/garatujas/${item.id}`);
|
||||
if (!detailResp.ok) throw new Error('Erro ao obter detalhes');
|
||||
const detail = await detailResp.json();
|
||||
|
||||
activeGaratujaReport = detail;
|
||||
garatujasAlunoInput.value = detail.alunoName;
|
||||
garatujaImgPreview.src = detail.imageUrl;
|
||||
garatujaPreviewContainer.style.display = 'block';
|
||||
garatujaReportArea.innerHTML = window.marked ? marked.parse(detail.analise) : detail.analise;
|
||||
|
||||
garatujaResultArea.style.display = 'flex';
|
||||
if (tabGaratujasNova) tabGaratujasNova.click();
|
||||
} catch (e) {
|
||||
alert('Falha ao abrir desenho.');
|
||||
}
|
||||
});
|
||||
|
||||
garatujasListContainer.appendChild(div);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// BRINCARATIVO (CIRCUITOS PSICOMOTORES E BRINCADEIRAS)
|
||||
// ============================================================
|
||||
const brincarAtivoModal = document.getElementById('brincarAtivoModal');
|
||||
const btnCloseBrincarAtivoModal = document.getElementById('btnCloseBrincarAtivoModal');
|
||||
const barBtnBrincarAtivo = document.getElementById('barBtnBrincarAtivo');
|
||||
|
||||
const tabBrincarAtivoNova = document.getElementById('tabBrincarAtivoNova');
|
||||
const tabBrincarAtivoHistorico = document.getElementById('tabBrincarAtivoHistorico');
|
||||
const contentBrincarAtivoNova = document.getElementById('contentBrincarAtivoNova');
|
||||
const contentBrincarAtivoHistorico = document.getElementById('contentBrincarAtivoHistorico');
|
||||
|
||||
const brincarAtivoFaixaSelect = document.getElementById('brincarAtivoFaixaSelect');
|
||||
const brincarAtivoRecursosInput = document.getElementById('brincarAtivoRecursosInput');
|
||||
const btnGenerateBrincarAtivo = document.getElementById('btnGenerateBrincarAtivo');
|
||||
const brincarAtivoLoader = document.getElementById('brincarAtivoLoader');
|
||||
const brincarAtivoLoaderText = document.getElementById('brincarAtivoLoaderText');
|
||||
const brincarAtivoResultArea = document.getElementById('brincarAtivoResultArea');
|
||||
const brincarAtivoReportArea = document.getElementById('brincarAtivoReportArea');
|
||||
|
||||
const btnCopyBrincarAtivoReport = document.getElementById('btnCopyBrincarAtivoReport');
|
||||
const btnPdfBrincarAtivoReport = document.getElementById('btnPdfBrincarAtivoReport');
|
||||
const brincarAtivoListContainer = document.getElementById('brincarAtivoListContainer');
|
||||
const brincarAtivoNoData = document.getElementById('brincarAtivoNoData');
|
||||
|
||||
let activeBrincarAtivoReport = null;
|
||||
|
||||
// Abas do BrincarAtivo
|
||||
if (tabBrincarAtivoNova) {
|
||||
tabBrincarAtivoNova.addEventListener('click', () => {
|
||||
tabBrincarAtivoNova.classList.add('active');
|
||||
tabBrincarAtivoHistorico.classList.remove('active');
|
||||
contentBrincarAtivoNova.style.display = 'block';
|
||||
contentBrincarAtivoHistorico.style.display = 'none';
|
||||
});
|
||||
}
|
||||
|
||||
if (tabBrincarAtivoHistorico) {
|
||||
tabBrincarAtivoHistorico.addEventListener('click', () => {
|
||||
tabBrincarAtivoHistorico.classList.add('active');
|
||||
tabBrincarAtivoNova.classList.remove('active');
|
||||
contentBrincarAtivoNova.style.display = 'none';
|
||||
contentBrincarAtivoHistorico.style.display = 'block';
|
||||
loadBrincarAtivoHistory();
|
||||
});
|
||||
}
|
||||
|
||||
// Abrir Modal
|
||||
if (barBtnBrincarAtivo) {
|
||||
barBtnBrincarAtivo.addEventListener('click', () => {
|
||||
brincarAtivoModal.style.display = 'flex';
|
||||
brincarAtivoRecursosInput.value = '';
|
||||
brincarAtivoResultArea.style.display = 'none';
|
||||
brincarAtivoLoader.style.display = 'none';
|
||||
btnGenerateBrincarAtivo.disabled = false;
|
||||
activeBrincarAtivoReport = null;
|
||||
if (tabBrincarAtivoNova) tabBrincarAtivoNova.click();
|
||||
});
|
||||
}
|
||||
|
||||
// Fechar Modal
|
||||
if (btnCloseBrincarAtivoModal) {
|
||||
btnCloseBrincarAtivoModal.addEventListener('click', () => {
|
||||
brincarAtivoModal.style.display = 'none';
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('click', (e) => {
|
||||
if (e.target === brincarAtivoModal) {
|
||||
brincarAtivoModal.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Gerar Atividade
|
||||
if (btnGenerateBrincarAtivo) {
|
||||
btnGenerateBrincarAtivo.addEventListener('click', async () => {
|
||||
const faixaEtaria = brincarAtivoFaixaSelect.value;
|
||||
const recursos = brincarAtivoRecursosInput.value.trim();
|
||||
|
||||
if (!recursos) {
|
||||
alert('Por favor, informe os materiais ou recursos disponíveis.');
|
||||
return;
|
||||
}
|
||||
|
||||
btnGenerateBrincarAtivo.disabled = true;
|
||||
brincarAtivoLoader.style.display = 'flex';
|
||||
brincarAtivoResultArea.style.display = 'none';
|
||||
brincarAtivoLoaderText.textContent = 'Acessando referências BNCC...';
|
||||
|
||||
let statusMsgIdx = 0;
|
||||
const statusMessages = [
|
||||
'Analisando faixa etária psicomotora...',
|
||||
'Estruturando proposta lúdica de circuito...',
|
||||
'Conectando objetivos específicos da BNCC...',
|
||||
'Gerando instruções passo a passo para o professor...',
|
||||
'Finalizando plano de circuito ativo...'
|
||||
];
|
||||
|
||||
const statusInterval = setInterval(() => {
|
||||
if (statusMsgIdx < statusMessages.length) {
|
||||
brincarAtivoLoaderText.textContent = statusMessages[statusMsgIdx];
|
||||
statusMsgIdx++;
|
||||
} else {
|
||||
brincarAtivoLoaderText.textContent = 'Formatando atividade...';
|
||||
}
|
||||
}, 4500);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/brincar-ativo/generate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ faixaEtaria, recursos })
|
||||
});
|
||||
|
||||
clearInterval(statusInterval);
|
||||
|
||||
if (!response.ok) {
|
||||
const errData = await response.json();
|
||||
throw new Error(errData.error || 'Erro desconhecido');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
activeBrincarAtivoReport = data;
|
||||
|
||||
if (window.marked) {
|
||||
brincarAtivoReportArea.innerHTML = marked.parse(data.atividade);
|
||||
} else {
|
||||
brincarAtivoReportArea.textContent = data.atividade;
|
||||
}
|
||||
|
||||
brincarAtivoLoader.style.display = 'none';
|
||||
brincarAtivoResultArea.style.display = 'flex';
|
||||
btnGenerateBrincarAtivo.disabled = false;
|
||||
|
||||
} catch (err) {
|
||||
clearInterval(statusInterval);
|
||||
console.error(err);
|
||||
alert('Erro ao gerar atividade: ' + err.message);
|
||||
brincarAtivoLoader.style.display = 'none';
|
||||
btnGenerateBrincarAtivo.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Copiar Parecer BrincarAtivo
|
||||
if (btnCopyBrincarAtivoReport) {
|
||||
btnCopyBrincarAtivoReport.addEventListener('click', () => {
|
||||
if (activeBrincarAtivoReport && activeBrincarAtivoReport.atividade) {
|
||||
navigator.clipboard.writeText(activeBrincarAtivoReport.atividade)
|
||||
.then(() => {
|
||||
btnCopyBrincarAtivoReport.textContent = '✅ Copiado!';
|
||||
setTimeout(() => { btnCopyBrincarAtivoReport.textContent = '📋 Copiar'; }, 2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Baixar PDF BrincarAtivo
|
||||
if (btnPdfBrincarAtivoReport) {
|
||||
btnPdfBrincarAtivoReport.addEventListener('click', () => {
|
||||
if (!activeBrincarAtivoReport) return;
|
||||
const printWindow = window.open('', '_blank');
|
||||
printWindow.document.write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>BrincarAtivo - Roteiro de Circuito</title>
|
||||
<style>
|
||||
body { font-family: 'Outfit', 'Inter', sans-serif; padding: 40px; color: #333; line-height: 1.6; }
|
||||
h1, h2, h3 { color: #10a37f; margin-top: 24px; margin-bottom: 12px; }
|
||||
h1 { border-bottom: 2px solid #e2e8f0; padding-bottom: 10px; font-size: 22px; }
|
||||
.meta-box { background: #f8fafc; padding: 16px; border-radius: 8px; margin-bottom: 24px; border: 1px solid #e2e8f0; }
|
||||
.meta-label { font-weight: bold; color: #475569; }
|
||||
@media print {
|
||||
body { padding: 0; }
|
||||
button { display: none; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🏃♂️ BrincarAtivo - Planejamento Psicomotor</h1>
|
||||
<div class="meta-box">
|
||||
<div><span class="meta-label">Faixa Etária:</span> <span>${activeBrincarAtivoReport.faixaEtaria}</span></div>
|
||||
<div><span class="meta-label">Recursos:</span> <span>${activeBrincarAtivoReport.recursos}</span></div>
|
||||
<div><span class="meta-label">Data de Criação:</span> <span>${new Date(activeBrincarAtivoReport.createdAt).toLocaleDateString('pt-BR')}</span></div>
|
||||
</div>
|
||||
<div>${window.marked ? marked.parse(activeBrincarAtivoReport.atividade) : activeBrincarAtivoReport.atividade}</div>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
window.print();
|
||||
setTimeout(() => { window.close(); }, 500);
|
||||
};
|
||||
<\/script>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
printWindow.document.close();
|
||||
});
|
||||
}
|
||||
|
||||
// Carregar Histórico BrincarAtivo
|
||||
async function loadBrincarAtivoHistory() {
|
||||
try {
|
||||
const response = await fetch('/api/brincar-ativo/list');
|
||||
if (!response.ok) throw new Error('Erro ao carregar histórico');
|
||||
const list = await response.json();
|
||||
|
||||
brincarAtivoListContainer.innerHTML = '';
|
||||
if (list.length === 0) {
|
||||
brincarAtivoNoData.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
brincarAtivoNoData.style.display = 'none';
|
||||
|
||||
list.forEach(item => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'quick-note-card';
|
||||
div.style.cursor = 'pointer';
|
||||
div.style.display = 'flex';
|
||||
div.style.flexDirection = 'column';
|
||||
div.style.gap = '6px';
|
||||
div.style.padding = '12px';
|
||||
|
||||
const lines = item.recursos || '';
|
||||
const previewText = lines.length > 60 ? lines.substring(0, 60) + '...' : lines;
|
||||
|
||||
div.innerHTML = `
|
||||
<div style="font-weight: 600; color: var(--text-primary); font-size: 0.92rem; display: flex; align-items: center; gap: 6px;">
|
||||
<span>🏃♂️</span> ${escapeHtml(item.faixaEtaria.split(' ')[0])} (${item.faixaEtaria.includes('bem pequenas') ? 'Bem Pequenas' : (item.faixaEtaria.includes('pequenas') ? 'Pequenas' : 'Bebês')})
|
||||
</div>
|
||||
<div style="font-size: 0.8rem; color: var(--text-secondary);">Recursos: ${escapeHtml(previewText)}</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted);">${new Date(item.createdAt).toLocaleDateString('pt-BR')}</div>
|
||||
`;
|
||||
|
||||
div.addEventListener('click', async () => {
|
||||
try {
|
||||
const detailResp = await fetch(`/api/brincar-ativo/${item.id}`);
|
||||
if (!detailResp.ok) throw new Error('Erro ao obter detalhes');
|
||||
const detail = await detailResp.json();
|
||||
|
||||
activeBrincarAtivoReport = detail;
|
||||
brincarAtivoFaixaSelect.value = detail.faixaEtaria;
|
||||
brincarAtivoRecursosInput.value = detail.recursos;
|
||||
brincarAtivoReportArea.innerHTML = window.marked ? marked.parse(detail.atividade) : detail.atividade;
|
||||
|
||||
brincarAtivoResultArea.style.display = 'flex';
|
||||
if (tabBrincarAtivoNova) tabBrincarAtivoNova.click();
|
||||
} catch (e) {
|
||||
alert('Falha ao abrir atividade.');
|
||||
}
|
||||
});
|
||||
|
||||
brincarAtivoListContainer.appendChild(div);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Player de áudio personalizado global para as mídias geradas
|
||||
|
||||
@@ -240,6 +240,12 @@
|
||||
<button type="button" class="btn-prompt-mode mode-video" id="barBtnVideoMind" style="border-color: rgba(6, 182, 212, 0.4); color: #22d3ee; background: rgba(6, 182, 212, 0.05);" title="Análise pedagógica e resumo de vídeos do YouTube">
|
||||
<span class="mode-icon">🎬</span> VideoMind
|
||||
</button>
|
||||
<button type="button" class="btn-prompt-mode mode-image" id="barBtnGaratujas" style="border-color: rgba(249, 115, 22, 0.4); color: #fdba74; background: rgba(249, 115, 22, 0.05);" title="Análise formativa de desenhos e rabiscos infantis">
|
||||
<span class="mode-icon">🎨</span> Garatujas
|
||||
</button>
|
||||
<button type="button" class="btn-prompt-mode mode-text" id="barBtnBrincarAtivo" style="border-color: rgba(16, 163, 127, 0.4); color: #a7f3d0; background: rgba(16, 163, 127, 0.05);" title="Criar circuitos psicomotores e brincadeiras ativas">
|
||||
<span class="mode-icon">🏃♂️</span> BrincarAtivo
|
||||
</button>
|
||||
<button type="button" class="btn-prompt-mode mode-music" data-mode="AUDIO" title="Compor e gerar uma música pedagógica">
|
||||
<span class="mode-icon">🎵</span> Criar Letra de Música
|
||||
</button>
|
||||
@@ -1007,6 +1013,159 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal: Garatujas (Análise de Desenhos) -->
|
||||
<div id="garatujasModal" class="settings-modal" style="display: none;">
|
||||
<div class="settings-modal-content" style="max-width: 750px; width: 95%; max-height: 90vh; display: flex; flex-direction: column;">
|
||||
<div class="settings-modal-header" style="background: var(--bg-secondary); border-bottom: 1px solid var(--border-light);">
|
||||
<h3 style="display: flex; align-items: center; gap: 8px; font-family: 'Outfit', sans-serif;">🎨 Garatujas - Análise de Traçado Infantil</h3>
|
||||
<button id="btnCloseGaratujasModal" class="btn-close-modal" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; font-size: 1.5rem;">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Abas do Modal -->
|
||||
<div class="settings-tabs" style="padding: 12px 20px 0;">
|
||||
<button type="button" class="settings-tab active" id="tabGaratujasNova">Nova Análise</button>
|
||||
<button type="button" class="settings-tab" id="tabGaratujasHistorico">Histórico</button>
|
||||
</div>
|
||||
|
||||
<div class="settings-modal-body" style="padding: 20px; overflow-y: auto; display: flex; flex-direction: column; gap: 18px; flex: 1;">
|
||||
|
||||
<!-- CONTEÚDO: NOVA ANÁLISE -->
|
||||
<div id="contentGaratujasNova" class="tab-content-panel">
|
||||
<div style="display: flex; flex-direction: column; gap: 16px;">
|
||||
<!-- NOME DO ALUNO -->
|
||||
<div class="settings-group">
|
||||
<label style="color: var(--text-secondary); font-size: 0.82rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;">Nome do Aluno</label>
|
||||
<input type="text" id="garatujasAlunoInput" placeholder="Ex: Joãozinho Silva" class="obs-input" style="width: 100%; margin-top: 4px; padding: 10px;">
|
||||
</div>
|
||||
|
||||
<!-- FOTO DO DESENHO -->
|
||||
<div class="settings-group">
|
||||
<label style="color: var(--text-secondary); font-size: 0.82rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;">Foto do Desenho / Rabisco</label>
|
||||
<div style="display: flex; gap: 12px; align-items: center; margin-top: 6px;">
|
||||
<button type="button" id="btnUploadGaratuja" class="btn-change-avatar" style="background: rgba(255,255,255,0.02); display: flex; align-items: center; gap: 8px;">
|
||||
📁 Escolher Imagem
|
||||
</button>
|
||||
<input type="file" id="garatujaFileInput" accept="image/*" style="display: none;">
|
||||
<span id="garatujaFileStatus" style="font-size: 0.85rem; color: var(--text-muted); font-style: italic;">Nenhum arquivo selecionado</span>
|
||||
</div>
|
||||
<div id="garatujaPreviewContainer" style="display: none; margin-top: 10px; border: 1px solid var(--border-light); border-radius: 8px; overflow: hidden; max-width: 250px; aspect-ratio: 4/3; background: rgba(0,0,0,0.1);">
|
||||
<img id="garatujaImgPreview" src="" style="width: 100%; height: 100%; object-fit: contain;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- BOTÃO GERAR -->
|
||||
<div style="display: flex; flex-direction: column; gap: 10px; margin-top: 8px;">
|
||||
<button id="btnGenerateGaratuja" style="background: linear-gradient(135deg, #f97316 0%, #ea580c 100%); color: white; border: none; padding: 12px; border-radius: 8px; font-weight: 600; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 8px; transition: opacity 0.2s; box-shadow: 0 4px 12px rgba(249, 115, 22, 0.25);">
|
||||
<span>🎨 Enviar & Analisar Desenho</span>
|
||||
</button>
|
||||
<div id="garatujaLoader" style="display: none; align-items: center; justify-content: center; gap: 10px; color: var(--text-secondary); font-size: 0.9rem; padding: 10px; background: rgba(255, 255, 255, 0.02); border-radius: 8px;">
|
||||
<div class="record-spinner" style="width: 20px; height: 20px; border-width: 2px; border-top-color: #f97316;"></div>
|
||||
<span id="garatujaLoaderText">Processando imagem...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ÁREA DE RESULTADO (INICIALMENTE OCULTA) -->
|
||||
<div id="garatujaResultArea" style="display: none; border-top: 1px solid var(--border-light); padding-top: 16px; flex-direction: column; gap: 18px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<h4 style="margin: 0; color: var(--text-primary); font-size: 1rem; font-weight: 600;">Laudo de Desenvolvimento</h4>
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<button id="btnCopyGaratujaReport" style="background: none; border: 1px solid var(--border-light); color: var(--text-secondary); padding: 5px 10px; border-radius: 6px; font-size: 0.75rem; cursor: pointer;">📋 Copiar</button>
|
||||
<button id="btnPdfGaratujaReport" style="background: none; border: 1px solid var(--border-light); color: var(--text-secondary); padding: 5px 10px; border-radius: 6px; font-size: 0.75rem; cursor: pointer;">📄 PDF</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="garatujaReportArea" class="report-content-body" style="background: var(--bg-secondary); padding: 16px; border-radius: 10px; max-height: 350px; overflow-y: auto; border: 1px solid var(--border-light); color: var(--text-primary); font-size: 0.95rem; line-height: 1.6;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CONTEÚDO: HISTÓRICO -->
|
||||
<div id="contentGaratujasHistorico" class="tab-content-panel" style="display: none;">
|
||||
<div id="garatujasListContainer" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; width: 100%;">
|
||||
<!-- Itens de lista injetados via JS -->
|
||||
</div>
|
||||
<div id="garatujasNoData" style="text-align: center; color: var(--text-muted); font-style: italic; padding: 40px 0; width: 100%;">
|
||||
Nenhum desenho analisado ainda.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal: BrincarAtivo (Circuitos e Brincadeiras) -->
|
||||
<div id="brincarAtivoModal" class="settings-modal" style="display: none;">
|
||||
<div class="settings-modal-content" style="max-width: 750px; width: 95%; max-height: 90vh; display: flex; flex-direction: column;">
|
||||
<div class="settings-modal-header" style="background: var(--bg-secondary); border-bottom: 1px solid var(--border-light);">
|
||||
<h3 style="display: flex; align-items: center; gap: 8px; font-family: 'Outfit', sans-serif;">🏃♂️ BrincarAtivo - Fábrica de Brincadeiras & Circuitos</h3>
|
||||
<button id="btnCloseBrincarAtivoModal" class="btn-close-modal" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; font-size: 1.5rem;">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Abas do Modal -->
|
||||
<div class="settings-tabs" style="padding: 12px 20px 0;">
|
||||
<button type="button" class="settings-tab active" id="tabBrincarAtivoNova">Nova Atividade</button>
|
||||
<button type="button" class="settings-tab" id="tabBrincarAtivoHistorico">Histórico</button>
|
||||
</div>
|
||||
|
||||
<div class="settings-modal-body" style="padding: 20px; overflow-y: auto; display: flex; flex-direction: column; gap: 18px; flex: 1;">
|
||||
|
||||
<!-- CONTEÚDO: NOVA ATIVIDADE -->
|
||||
<div id="contentBrincarAtivoNova" class="tab-content-panel">
|
||||
<div style="display: flex; flex-direction: column; gap: 16px;">
|
||||
<!-- FAIXA ETÁRIA -->
|
||||
<div class="settings-group">
|
||||
<label style="color: var(--text-secondary); font-size: 0.82rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;">Faixa Etária (BNCC)</label>
|
||||
<select id="brincarAtivoFaixaSelect" class="obs-input" style="width: 100%; margin-top: 4px; padding: 10px; background: var(--bg-secondary); color: var(--text-primary); border: 1px solid var(--border-light); border-radius: 8px;">
|
||||
<option value="Bebês (0 a 1 ano e 6 meses)">👶 Bebês (0 a 1 ano e 6 meses)</option>
|
||||
<option value="Crianças bem pequenas (1 ano e 7 meses a 3 anos)">👧 Crianças bem pequenas (1 ano e 7 meses a 3 anos)</option>
|
||||
<option value="Crianças pequenas (4 anos a 5 anos e 11 meses)">👦 Crianças pequenas (4 anos a 5 anos e 11 meses)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- RECURSOS DISPONÍVEIS -->
|
||||
<div class="settings-group">
|
||||
<label style="color: var(--text-secondary); font-size: 0.82rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;">Recursos / Materiais Disponíveis</label>
|
||||
<textarea id="brincarAtivoRecursosInput" placeholder="Ex: Caixas de papelão, garrafas plásticas vazias, giz para riscar o chão, cones e bambolês." class="obs-input" rows="3" style="width: 100%; margin-top: 4px; padding: 10px; font-family: inherit; resize: vertical;"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- BOTÃO GERAR -->
|
||||
<div style="display: flex; flex-direction: column; gap: 10px; margin-top: 8px;">
|
||||
<button id="btnGenerateBrincarAtivo" style="background: linear-gradient(135deg, #10a37f 0%, #0a5f49 100%); color: white; border: none; padding: 12px; border-radius: 8px; font-weight: 600; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 8px; transition: opacity 0.2s; box-shadow: 0 4px 12px rgba(16, 163, 127, 0.25);">
|
||||
<span>🏃♂️ Criar Circuito / Brincadeira</span>
|
||||
</button>
|
||||
<div id="brincarAtivoLoader" style="display: none; align-items: center; justify-content: center; gap: 10px; color: var(--text-secondary); font-size: 0.9rem; padding: 10px; background: rgba(255, 255, 255, 0.02); border-radius: 8px;">
|
||||
<div class="record-spinner" style="width: 20px; height: 20px; border-width: 2px;"></div>
|
||||
<span id="brincarAtivoLoaderText">Montando planejamento psicomotor...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ÁREA DE RESULTADO (INICIALMENTE OCULTA) -->
|
||||
<div id="brincarAtivoResultArea" style="display: none; border-top: 1px solid var(--border-light); padding-top: 16px; flex-direction: column; gap: 18px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<h4 style="margin: 0; color: var(--text-primary); font-size: 1rem; font-weight: 600;">Planejamento Pedagógico</h4>
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<button id="btnCopyBrincarAtivoReport" style="background: none; border: 1px solid var(--border-light); color: var(--text-secondary); padding: 5px 10px; border-radius: 6px; font-size: 0.75rem; cursor: pointer;">📋 Copiar</button>
|
||||
<button id="btnPdfBrincarAtivoReport" style="background: none; border: 1px solid var(--border-light); color: var(--text-secondary); padding: 5px 10px; border-radius: 6px; font-size: 0.75rem; cursor: pointer;">📄 PDF</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="brincarAtivoReportArea" class="report-content-body" style="background: var(--bg-secondary); padding: 16px; border-radius: 10px; max-height: 350px; overflow-y: auto; border: 1px solid var(--border-light); color: var(--text-primary); font-size: 0.95rem; line-height: 1.6;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CONTEÚDO: HISTÓRICO -->
|
||||
<div id="contentBrincarAtivoHistorico" class="tab-content-panel" style="display: none;">
|
||||
<div id="brincarAtivoListContainer" style="display: flex; flex-direction: column; gap: 12px; width: 100%;">
|
||||
<!-- Itens de lista injetados via JS -->
|
||||
</div>
|
||||
<div id="brincarAtivoNoData" style="text-align: center; color: var(--text-muted); font-style: italic; padding: 40px 0; width: 100%;">
|
||||
Nenhuma atividade gerada ainda.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bibliotecas externas para renderizar markdown e blocos de código -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script>
|
||||
|
||||
@@ -789,6 +789,254 @@ Retorne a resposta estruturada estritamente em Markdown. Separe as seções usan
|
||||
}
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// ROTAS DO GARATUJAS (ANALISADOR DE TRAÇADO INFANTIL)
|
||||
// ============================================================
|
||||
app.post('/api/garatujas/analyze', requireAuth, multerUpload.single('image'), async (req, res) => {
|
||||
const { alunoName } = req.body;
|
||||
const file = req.file;
|
||||
|
||||
if (!alunoName) {
|
||||
return res.status(400).json({ error: 'O nome do aluno é obrigatório.' });
|
||||
}
|
||||
if (!file) {
|
||||
return res.status(400).json({ error: 'A foto do desenho é obrigatória.' });
|
||||
}
|
||||
|
||||
try {
|
||||
const fs = require('fs');
|
||||
const mediaDir = path.join(__dirname, 'public', 'generated-media');
|
||||
if (!fs.existsSync(mediaDir)) {
|
||||
fs.mkdirSync(mediaDir, { recursive: true });
|
||||
}
|
||||
|
||||
const ext = path.extname(file.originalname) || '.png';
|
||||
const fileName = `garatuja_${Date.now()}${ext}`;
|
||||
const filePath = path.join(mediaDir, fileName);
|
||||
fs.writeFileSync(filePath, file.buffer);
|
||||
const imageUrl = `/generated-media/${fileName}`;
|
||||
|
||||
const base64Image = file.buffer.toString('base64');
|
||||
const mimeType = file.mimetype || 'image/png';
|
||||
|
||||
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'google/gemini-2.5-flash',
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `Você é um psicopedagogo e especialista em desenvolvimento infantil no Brasil.
|
||||
Analise a imagem deste desenho/rabisco feito pelo aluno(a) "${alunoName}" (até 6 anos de idade).
|
||||
|
||||
Identifique e descreva com base na literatura científica (como Piaget, Luquet, Lowenfeld):
|
||||
1. O estágio do desenho infantil em que a criança se encontra (ex: Garatuja Desordenada, Garatuja Ordenada, Pré-Esquematismo, etc.) justificando com elementos visuais identificados no desenho.
|
||||
2. A análise do desenvolvimento cognitivo e da coordenação motora fina expressa nos traços.
|
||||
3. Propostas práticas de estimulação pedagógica personalizadas para o professor aplicar com o aluno "${alunoName}" em sala de aula para avançar para o próximo estágio.
|
||||
|
||||
Retorne a resposta estruturada em Markdown, usando títulos claros:
|
||||
# Estágio do Desenho e Análise Psicomotora
|
||||
[Sua análise aqui]
|
||||
|
||||
# Diagnóstico de Desenvolvimento Cognitivo
|
||||
[Seu diagnóstico aqui]
|
||||
|
||||
# Sugestões de Atividades para Estimular ${alunoName}
|
||||
[Suas propostas aqui]`
|
||||
},
|
||||
{
|
||||
type: 'image_url',
|
||||
image_url: {
|
||||
url: `data:${mimeType};base64,${base64Image}`
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errText = await response.text();
|
||||
throw new Error(`Erro na API de visão: ${errText}`);
|
||||
}
|
||||
|
||||
const resData = await response.json();
|
||||
const analise = resData.choices?.[0]?.message?.content || '';
|
||||
|
||||
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
|
||||
const dbRes = await dbPool.query(
|
||||
`INSERT INTO escola.garatujas (usuario_id, aluno_name, image_url, analise)
|
||||
VALUES ($1, $2, $3, $4) RETURNING id, created_at`,
|
||||
[usuarioId, alunoName, imageUrl, analise]
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
id: dbRes.rows[0].id,
|
||||
alunoName,
|
||||
imageUrl,
|
||||
analise,
|
||||
createdAt: dbRes.rows[0].created_at
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error('Erro na análise de garatujas:', err);
|
||||
res.status(500).json({ error: 'Erro ao analisar imagem: ' + err.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/garatujas/list', requireAuth, async (req, res) => {
|
||||
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
|
||||
try {
|
||||
const dbRes = await dbPool.query(
|
||||
`SELECT id, aluno_name as "alunoName", image_url as "imageUrl", created_at as "createdAt"
|
||||
FROM escola.garatujas
|
||||
WHERE usuario_id = $1
|
||||
ORDER BY created_at DESC`,
|
||||
[usuarioId]
|
||||
);
|
||||
res.json(dbRes.rows);
|
||||
} catch (err) {
|
||||
console.error('Erro ao listar garatujas:', err);
|
||||
res.status(500).json({ error: 'Erro ao obter histórico de desenhos.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/garatujas/:id', requireAuth, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
|
||||
try {
|
||||
const dbRes = await dbPool.query(
|
||||
`SELECT id, aluno_name as "alunoName", image_url as "imageUrl", analise, created_at as "createdAt"
|
||||
FROM escola.garatujas
|
||||
WHERE id = $1 AND usuario_id = $2`,
|
||||
[id, usuarioId]
|
||||
);
|
||||
if (dbRes.rows.length === 0) {
|
||||
return res.status(404).json({ error: 'Análise não encontrada.' });
|
||||
}
|
||||
res.json(dbRes.rows[0]);
|
||||
} catch (err) {
|
||||
console.error('Erro ao buscar garatuja:', err);
|
||||
res.status(500).json({ error: 'Erro ao buscar análise.' });
|
||||
}
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// ROTAS DO BRINCARATIVO (CIRCUITOS PSICOMOTORES E BRINCADEIRAS)
|
||||
// ============================================================
|
||||
app.post('/api/brincar-ativo/generate', requireAuth, async (req, res) => {
|
||||
const { faixaEtaria, recursos } = req.body;
|
||||
|
||||
if (!faixaEtaria) {
|
||||
return res.status(400).json({ error: 'A faixa etária é obrigatória.' });
|
||||
}
|
||||
if (!recursos) {
|
||||
return res.status(400).json({ error: 'A descrição dos recursos é obrigatória.' });
|
||||
}
|
||||
|
||||
try {
|
||||
const prompt = `Você é um educador físico e pedagogo especializado na Educação Infantil (crianças de 0 a 6 anos) de acordo com a BNCC no Brasil.
|
||||
Gere uma proposta de circuito psicomotor ou brincadeira ativa adequada para a seguinte faixa etária e com os recursos disponíveis:
|
||||
|
||||
Faixa Etária: ${faixaEtaria}
|
||||
Recursos e Materiais Disponíveis: ${recursos}
|
||||
|
||||
Instruções para o conteúdo:
|
||||
1. Dê um título lúdico e atraente para a atividade.
|
||||
2. Especifique os Objetivos de Aprendizagem e Desenvolvimento da BNCC (incluindo códigos, como EI01CG02, EI02CG05, etc.).
|
||||
3. Descreva o Passo a Passo detalhado de como montar o circuito/brincadeira no espaço e como guiar as crianças.
|
||||
4. Diga o que o professor deve observar durante a atividade para avaliar o desenvolvimento psicomotor dos alunos.
|
||||
|
||||
Retorne a resposta estritamente em Markdown estruturado:
|
||||
# Atividade: [Nome Lúdico]
|
||||
**Faixa Etária:** ${faixaEtaria}
|
||||
**Campos de Experiência (BNCC):** [Campos e Códigos]
|
||||
|
||||
## 📋 Objetivos
|
||||
[Objetivos]
|
||||
|
||||
## 🛠️ Como Montar e Conduzir
|
||||
[Passo a passo]
|
||||
|
||||
## 🔍 O que Observar (Avaliação Formativa)
|
||||
[Dicas de observação]`;
|
||||
|
||||
const aiResponse = await callMinimax({
|
||||
system: "Você é um especialista em educação física e psicomotricidade na educação infantil brasileira.",
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
temperature: 0.5,
|
||||
max_tokens: 3000
|
||||
});
|
||||
|
||||
const atividade = aiResponse.text || '';
|
||||
|
||||
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
|
||||
const dbRes = await dbPool.query(
|
||||
`INSERT INTO escola.brincar_ativo (usuario_id, faixa_etaria, recursos, atividade)
|
||||
VALUES ($1, $2, $3, $4) RETURNING id, created_at`,
|
||||
[usuarioId, faixaEtaria, recursos, atividade]
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
id: dbRes.rows[0].id,
|
||||
faixaEtaria,
|
||||
recursos,
|
||||
atividade,
|
||||
createdAt: dbRes.rows[0].created_at
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Erro no BrincarAtivo:', err);
|
||||
res.status(500).json({ error: 'Erro ao gerar atividade com a IA: ' + err.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/brincar-ativo/list', requireAuth, async (req, res) => {
|
||||
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
|
||||
try {
|
||||
const dbRes = await dbPool.query(
|
||||
`SELECT id, faixa_etaria as "faixaEtaria", recursos, created_at as "createdAt"
|
||||
FROM escola.brincar_ativo
|
||||
WHERE usuario_id = $1
|
||||
ORDER BY created_at DESC`,
|
||||
[usuarioId]
|
||||
);
|
||||
res.json(dbRes.rows);
|
||||
} catch (err) {
|
||||
console.error('Erro ao listar atividades:', err);
|
||||
res.status(500).json({ error: 'Erro ao obter lista de atividades.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/brincar-ativo/:id', requireAuth, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
|
||||
try {
|
||||
const dbRes = await dbPool.query(
|
||||
`SELECT id, faixa_etaria as "faixaEtaria", recursos, atividade, created_at as "createdAt"
|
||||
FROM escola.brincar_ativo
|
||||
WHERE id = $1 AND usuario_id = $2`,
|
||||
[id, usuarioId]
|
||||
);
|
||||
if (dbRes.rows.length === 0) {
|
||||
return res.status(404).json({ error: 'Atividade não encontrada.' });
|
||||
}
|
||||
res.json(dbRes.rows[0]);
|
||||
} catch (err) {
|
||||
console.error('Erro ao buscar atividade:', err);
|
||||
res.status(500).json({ error: 'Erro ao buscar atividade.' });
|
||||
}
|
||||
});
|
||||
|
||||
// Rota GET para obter configurações do agente
|
||||
app.get('/api/agent-config', requireAuth, (req, res) => {
|
||||
const config = readAgentConfig();
|
||||
@@ -968,6 +1216,26 @@ async function initDatabase() {
|
||||
descricao_fisica_en TEXT NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Garatujas (Analisador de Traçado Infantil)
|
||||
CREATE TABLE IF NOT EXISTS escola.garatujas (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
usuario_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
|
||||
aluno_name VARCHAR(255) NOT NULL,
|
||||
image_url TEXT NOT NULL,
|
||||
analise TEXT NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- BrincarAtivo (Circuitos Psicomotores e Brincadeiras)
|
||||
CREATE TABLE IF NOT EXISTS escola.brincar_ativo (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
usuario_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
|
||||
faixa_etaria VARCHAR(100) NOT NULL,
|
||||
recursos TEXT NOT NULL,
|
||||
atividade TEXT NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
`);
|
||||
|
||||
// Garantir que a coluna character_description_english exista na tabela projetos_comics
|
||||
|
||||
Reference in New Issue
Block a user