diff --git a/public/app.js b/public/app.js
index 31a7e8e..8029035 100644
--- a/public/app.js
+++ b/public/app.js
@@ -6219,7 +6219,7 @@ document.addEventListener('DOMContentLoaded', () => {
}
if (btnGenerateMindLab) {
- btnGenerateMindLab.addEventListener('click', () => {
+ btnGenerateMindLab.addEventListener('click', async () => {
const activeFaixa = document.querySelector('.btn-mindlab-faixa.active');
const activeJogoBtn = document.querySelector('.btn-mindlab-jogo.active');
const activeMetodo = document.querySelector('.btn-mindlab-metodo.active');
@@ -6236,25 +6236,153 @@ document.addEventListener('DOMContentLoaded', () => {
const duracaoStr = document.getElementById('mindLabDuracaoSelect').value;
const temaLivre = document.getElementById('mindLabTemaLivreInput').value.trim();
- const promptText = `Atue como um especialista na metodologia educacional Mente Inovadora (Mind Lab). Crie um planejamento de aula super detalhado e engajador com os seguintes parâmetros:
-- *Faixa Etária:* ${faixaStr}
-- *Jogo de Raciocínio:* ${jogoStr}
-- *Método Metacognitivo Foco:* ${metodoStr}
-- *Foco de Transferência (Socioemocional):* ${focoStr}
-- *Duração:* ${duracaoStr}${temaLivre ? '\n- *Tema Contextual:* ' + temaLivre : ''}
+ const btnG = document.getElementById('btnGenerateMindLab');
+ const loader = document.getElementById('mindLabGenerateLoader');
+ const resultArea = document.getElementById('mindLabResultArea');
+ const output = document.getElementById('mindLabOutput');
+
+ btnG.style.display = 'none';
+ loader.style.display = 'flex';
+ resultArea.style.display = 'none';
-Por favor, estruture a aula com:
-1. *Abertura (Contextualização):* Como introduzir o método e o tema.
-2. *Jogo (Aplicação):* Orientações para a mediação durante a partida.
-3. *Reflexão (Mediação Transcendental):* Perguntas provocativas para fazer as crianças refletirem.
-4. *Transferência:* Como conectar o que aprenderam no jogo e o método escolhido (ex: Semáforo) com situações reais da vida deles.`;
-
- mindLabModal.style.display = 'none';
- if (typeof handleSendMessage === 'function') {
- handleSendMessage(promptText);
- } else {
- console.error("handleSendMessage not found");
+ try {
+ const res = await fetch('/api/mindlab/generate', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` },
+ body: JSON.stringify({ faixa_etaria: faixaStr, jogo: jogoStr, metodo: metodoStr, foco: focoStr, duracao: duracaoStr, tema: temaLivre })
+ });
+ const data = await res.json();
+ if (!res.ok) throw new Error(data.error || 'Erro na requisição');
+
+ output.innerHTML = typeof marked !== 'undefined' ? marked.parse(data.planejamento) : data.planejamento;
+ output.dataset.raw = data.planejamento;
+ resultArea.style.display = 'block';
+ btnG.style.display = 'flex';
+ btnG.innerHTML = '🧠 Criar Novo Planejamento';
+ } catch (err) {
+ alert('Erro ao gerar: ' + err.message);
+ btnG.style.display = 'flex';
+ } finally {
+ loader.style.display = 'none';
}
});
}
+
+ const btnCopyMindLab = document.getElementById('btnCopyMindLab');
+ if (btnCopyMindLab) {
+ btnCopyMindLab.addEventListener('click', () => {
+ const output = document.getElementById('mindLabOutput');
+ if (output && output.dataset.raw) {
+ navigator.clipboard.writeText(output.dataset.raw);
+ btnCopyMindLab.innerHTML = 'check Copiado!';
+ setTimeout(() => {
+ btnCopyMindLab.innerHTML = 'content_copy Copiar';
+ }, 2000);
+ }
+ });
+ }
+
+ const btnPdfMindLab = document.getElementById('btnPdfMindLab');
+ if (btnPdfMindLab) {
+ btnPdfMindLab.addEventListener('click', () => {
+ const output = document.getElementById('mindLabOutput');
+ if (output && output.dataset.raw && window.jspdf) {
+ const { jsPDF } = window.jspdf;
+ const doc = new jsPDF();
+ doc.setFontSize(12);
+ doc.setFont("helvetica", "normal");
+ const lines = doc.splitTextToSize(output.dataset.raw.replace(/[#*]/g, ''), 180);
+ doc.text(lines, 15, 20);
+ doc.save('Planejamento_Mind_Lab.pdf');
+ } else {
+ alert('Carregando biblioteca PDF ou nenhum conteúdo para salvar.');
+ }
+ });
+ }
+
+ const btnOpenMindLabHistory = document.getElementById('btnOpenMindLabHistory');
+ const mindLabHistoryModal = document.getElementById('mindLabHistoryModal');
+ const btnCloseMindLabHistory = document.getElementById('btnCloseMindLabHistory');
+ const mindLabHistoryList = document.getElementById('mindLabHistoryList');
+
+ if (btnOpenMindLabHistory) {
+ btnOpenMindLabHistory.addEventListener('click', async () => {
+ mindLabHistoryModal.style.display = 'flex';
+ mindLabHistoryList.innerHTML = '
Carregando histórico...
';
+ try {
+ const res = await fetch('/api/mindlab/list', {
+ headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }
+ });
+ const data = await res.json();
+ mindLabHistoryList.innerHTML = '';
+ if (data.length === 0) {
+ mindLabHistoryList.innerHTML = 'Nenhum planejamento salvo ainda.
';
+ return;
+ }
+ data.forEach(item => {
+ const div = document.createElement('div');
+ div.style.background = 'var(--bg-tertiary)';
+ div.style.padding = '12px 15px';
+ div.style.borderRadius = '8px';
+ div.style.display = 'flex';
+ div.style.justifyContent = 'space-between';
+ div.style.alignItems = 'center';
+ div.innerHTML = `
+
+
🎲 ${item.jogo} - ${item.faixa_etaria}
+
🎯 ${item.foco}
+
${new Date(item.created_at).toLocaleString()}
+
+
+
+
+
+ `;
+ mindLabHistoryList.appendChild(div);
+ });
+
+ document.querySelectorAll('.btn-ver-mindlab').forEach(btn => {
+ btn.addEventListener('click', async (e) => {
+ const id = e.target.dataset.id;
+ try {
+ const res = await fetch(`/api/mindlab/${id}`, {
+ headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }
+ });
+ const itemData = await res.json();
+
+ document.getElementById('mindLabOutput').innerHTML = typeof marked !== 'undefined' ? marked.parse(itemData.planejamento) : itemData.planejamento;
+ document.getElementById('mindLabOutput').dataset.raw = itemData.planejamento;
+ document.getElementById('mindLabResultArea').style.display = 'block';
+
+ mindLabHistoryModal.style.display = 'none';
+ document.getElementById('btnGenerateMindLab').style.display = 'flex';
+ } catch (err) { alert('Erro ao carregar planejamento.'); }
+ });
+ });
+
+ document.querySelectorAll('.btn-del-mindlab').forEach(btn => {
+ btn.addEventListener('click', async (e) => {
+ if(!confirm('Tem certeza que deseja apagar este planejamento?')) return;
+ const id = e.target.dataset.id;
+ try {
+ await fetch(`/api/mindlab/${id}`, {
+ method: 'DELETE',
+ headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }
+ });
+ e.target.closest('div[style*="var(--bg-tertiary)"]').remove();
+ } catch (err) { alert('Erro ao deletar.'); }
+ });
+ });
+
+ } catch (err) {
+ mindLabHistoryList.innerHTML = 'Erro ao carregar histórico.
';
+ }
+ });
+ }
+
+ if (btnCloseMindLabHistory) {
+ btnCloseMindLabHistory.addEventListener('click', () => {
+ mindLabHistoryModal.style.display = 'none';
+ });
+ }
});
diff --git a/public/index.html b/public/index.html
index f74f025..ad119cd 100644
--- a/public/index.html
+++ b/public/index.html
@@ -910,7 +910,12 @@
@@ -982,6 +987,32 @@
Elaborando metodologia e transferência...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/sw.js b/public/sw.js
index 734b1dc..deb80e2 100644
--- a/public/sw.js
+++ b/public/sw.js
@@ -1,4 +1,4 @@
-const CACHE_NAME = 'camila-ai-v4';
+const CACHE_NAME = 'camila-ai-v5';
const urlsToCache = [
'/',
'/index.html',
diff --git a/server.js b/server.js
index c937b2f..41749fe 100644
--- a/server.js
+++ b/server.js
@@ -1453,6 +1453,86 @@ app.delete('/api/historias/:id', requireAuth, async (req, res) => {
} catch (err) { res.status(500).json({ error: 'Erro ao deletar.' }); }
});
+// ============================================================
+// ROTAS DO MIND LAB
+// ============================================================
+app.post('/api/mindlab/generate', requireAuth, async (req, res) => {
+ const { faixa_etaria, jogo, metodo, foco, duracao, tema } = req.body;
+ const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
+
+ if (!faixa_etaria || !jogo || !metodo || !foco) {
+ return res.status(400).json({ error: 'Os campos obrigatórios do planejamento não foram preenchidos.' });
+ }
+
+ try {
+ const systemInstruction = `Você é um especialista na metodologia educacional Mente Inovadora (Mind Lab).
+Crie um planejamento de aula detalhado em Markdown com os seguintes parâmetros:
+- Faixa Etária: ${faixa_etaria}
+- Jogo de Raciocínio: ${jogo}
+- Método Metacognitivo Foco: ${metodo}
+- Foco de Transferência (Socioemocional): ${foco}
+- Duração: ${duracao}
+- Tema Contextual: ${tema || 'Nenhum especifico'}
+
+Por favor, estruture a aula obrigatoriamente com:
+1. **Abertura (Contextualização):** Como introduzir o método e o tema.
+2. **O Jogo (Aplicação):** Orientações para a mediação durante a partida.
+3. **Reflexão (Mediação Transcendental):** Perguntas provocativas para fazer as crianças refletirem.
+4. **Transferência:** Como conectar o que aprenderam no jogo e o método escolhido com situações reais da vida deles.`;
+
+ let planejamentoText = '';
+ if (process.env.GOOGLE_AI_API_KEY) {
+ const geminiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${process.env.GOOGLE_AI_MODEL || 'gemini-2.5-flash'}:generateContent?key=${process.env.GOOGLE_AI_API_KEY}`;
+ const response = await fetch(geminiUrl, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ contents: [{ parts: [{ text: systemInstruction }] }] })
+ });
+ if (!response.ok) throw new Error('Erro na API Gemini');
+ const data = await response.json();
+ planejamentoText = data.candidates?.[0]?.content?.parts?.[0]?.text || '';
+ }
+
+ planejamentoText = planejamentoText.replace(/[\s\S]*?<\/think>/gi, '').trim();
+
+ if (!planejamentoText) throw new Error('Falha ao gerar o planejamento.');
+
+ const dbRes = await dbPool.query(
+ `INSERT INTO escola.mindlab (usuario_id, faixa_etaria, jogo, metodo, foco, tema, planejamento) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id`,
+ [usuarioId, faixa_etaria, jogo, metodo, foco, tema, planejamentoText]
+ );
+
+ res.json({ id: dbRes.rows[0].id, planejamento: planejamentoText });
+ } catch (err) {
+ console.error('Erro Mind Lab:', err);
+ res.status(500).json({ error: 'Erro ao gerar planejamento Mind Lab: ' + err.message });
+ }
+});
+
+app.get('/api/mindlab/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, jogo, metodo, foco, created_at FROM escola.mindlab WHERE usuario_id = $1 ORDER BY created_at DESC`, [usuarioId]);
+ res.json(dbRes.rows);
+ } catch (err) { res.status(500).json({ error: 'Erro ao listar histórico do Mind Lab.' }); }
+});
+
+app.get('/api/mindlab/:id', requireAuth, async (req, res) => {
+ const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
+ try {
+ const dbRes = await dbPool.query(`SELECT * FROM escola.mindlab WHERE id = $1 AND usuario_id = $2`, [req.params.id, usuarioId]);
+ if (dbRes.rows.length === 0) return res.status(404).json({ error: 'Não encontrada.' });
+ res.json(dbRes.rows[0]);
+ } catch (err) { res.status(500).json({ error: 'Erro ao buscar.' }); }
+});
+
+app.delete('/api/mindlab/:id', requireAuth, async (req, res) => {
+ const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
+ try {
+ const dbRes = await dbPool.query(`DELETE FROM escola.mindlab WHERE id = $1 AND usuario_id = $2`, [req.params.id, usuarioId]);
+ res.json({ success: true });
+ } catch (err) { res.status(500).json({ error: 'Erro ao deletar.' }); }
+});
// Rota GET para obter configurações do agente
app.get('/api/agent-config', requireAuth, (req, res) => {
@@ -1677,6 +1757,19 @@ async function initDatabase() {
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
+ -- Planejamento Mind Lab
+ CREATE TABLE IF NOT EXISTS escola.mindlab (
+ 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,
+ jogo VARCHAR(100) NOT NULL,
+ metodo VARCHAR(100) NOT NULL,
+ foco VARCHAR(100) NOT NULL,
+ tema TEXT,
+ planejamento TEXT NOT NULL,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+ );
+
-- Histórias (Inventando Histórias)
CREATE TABLE IF NOT EXISTS escola.historias (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),