diff --git a/server.js b/server.js index e93169d..57bd8f3 100644 --- a/server.js +++ b/server.js @@ -383,6 +383,157 @@ app.get('/api/observacoes/:yearMonth/:filename', requireAuth, (req, res) => { res.sendFile(filePath); }); +// Rota: GET /api/observacoes/buscar — busca observações por criança e/ou período +// Query: ?crianca=Nome&mes=YYYY-MM&tags=social,cognitivo&limit=20 +app.get('/api/observacoes/buscar', requireAuth, (req, res) => { + const { crianca, mes, tags, limit = 20 } = req.query; + const idx = readObsIndex(); + let results = idx.observations || []; + + // Filtra por criança + if (crianca) { + const searchName = crianca.toLowerCase(); + results = results.filter(o => + o.criancas && o.criancas.some(c => c.toLowerCase().includes(searchName)) + ); + } + + // Filtra por mês + if (mes) { + results = results.filter(o => o.date && o.date.startsWith(mes)); + } + + // Filtra por tags + if (tags) { + const tagList = tags.split(',').map(t => t.trim()); + results = results.filter(o => + o.tags && tagList.some(t => o.tags.includes(t)) + ); + } + + // Limita resultados + results = results.slice(0, parseInt(limit)); + + // Carrega conteúdo completo de cada resultado + const enriched = results.map(o => { + const filePath = path.join(OBSERVACOES_DIR, o.date?.slice(0, 7), o.filename); + let fullContent = ''; + if (fs.existsSync(filePath)) { + fullContent = fs.readFileSync(filePath, 'utf8'); + } + return { ...o, fullContent }; + }); + + res.json({ observations: enriched, total: idx.observations?.length || 0 }); +}); + +// Rota: GET /api/observacoes/resumo — compila observações em resumo para documentos +// Query: ?crianca=Nome&mes=YYYY-MM +// Retorna resumo estruturado que a IA pode usar em HTPC/planejamentos +app.get('/api/observacoes/resumo', requireAuth, async (req, res) => { + const { crianca, mes } = req.query; + if (!crianca) return res.status(400).json({ error: 'Nome da criança é obrigatório' }); + + // Busca observações + const idx = readObsIndex(); + let results = idx.observations || []; + const searchName = crianca.toLowerCase(); + results = results.filter(o => + o.criancas && o.criancas.some(c => c.toLowerCase().includes(searchName)) + ); + if (mes) results = results.filter(o => o.date?.startsWith(mes)); + + if (results.length === 0) { + return res.json({ resumo: null, total: 0, message: `Nenhuma observação encontrada para "${crianca}"${mes ? ` em ${mes}` : ''}.` }); + } + + // Carrega conteúdo completo + const observations = results.slice(0, 15).map(o => { + const filePath = path.join(OBSERVACOES_DIR, o.date?.slice(0, 7), o.filename); + let fullContent = ''; + if (fs.existsSync(filePath)) { + fullContent = fs.readFileSync(filePath, 'utf8'); + } + return { ...o, fullContent }; + }); + + // Compila textos + const texts = observations.map(o => o.fullContent.replace(/^---[\s\S]*?---\n/, '')).filter(Boolean); + const combined = texts.join('\n\n---\n\n'); + + // Pede para IA compilar resumo pedagógico + const compilePrompt = `Você é a Kemily, assistente pedagógica. Compilar um RESUMO PEDAGÓGICO consolidado a partir de várias observações de uma criança. + +CRIANÇA: ${crianca} +NÚMERO DE OBSERVAÇÕES: ${observations.length} +${mes ? `PERÍODO: ${mes}` : ''} + +COLEÇÃO DE OBSERVAÇÕES: +""" +${combined.slice(0, 4000)} +""" + +GERE UM RESUMO ESTRUTURADO COM: + +## Perfil da Criança +[Padrões de comportamento, habilidades, desenvolvimento observado] + +## Aspectos Sociais e Emocionais +[Interações com outras crianças, gestão emocional, socialização] + +## Aspectos Cognitivos e de Aprendizagem +[Curiosidade, resolução de problemas, atenção, concentração] + +## Aspectos Motores e de Linguagem +[Desenvolvimento motor, linguagem oral, comunicação] + +## Pontos de Atenção +[Dificuldades, necessidades de suporte, áreas a desenvolver] + +## Pontos Fortes +[Conquistas, habilidades desarrolladas, aspectos positivos] + +## Sugestões para Planejamento +[Recomendações para próximos passos, atividades sugeridas, seguimento] + +-use linguagem formal-pedagógica +-Máximo 300 palavras +-Sea objetivo e baseado nas evidências das observações`; + + try { + const compileRes = 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: process.env.OPENROUTER_MODEL || 'openai/gpt-4.1-nano', + messages: [{ role: 'user', content: compilePrompt }], + temperature: 0.4, + max_tokens: 800 + }) + }); + + const compileData = await compileRes.json(); + const resumoText = compileData.choices?.[0]?.message?.content || ''; + + res.json({ + crianca, + mes: mes || 'todos', + total: observations.length, + datas: observations.map(o => o.date).filter(Boolean), + resumo: resumoText, + observations: observations.map(o => ({ + date: o.date, time: o.time, tags: o.tags, turma: o.turma, preview: o.preview + })) + }); + } catch (err) { + console.error('Erro ao compilar resumo:', err); + res.status(500).json({ error: 'Erro ao gerar resumo pedagógico' }); + } +}); + // Rota POST para upload de imagem em base64 app.post('/api/upload-avatar', requireAuth, (req, res) => { const { avatarType, base64Data } = req.body; @@ -688,6 +839,34 @@ ESCRITA DA CRIANÇA: - Hipótese de escrita silábico-alfabética - Hipótese de escrita alfabética +═══════════════════════════════════════════════════ +SISTEMA DE OBSERVAÇÕES POR VOZ — Como acessar registros +═══════════════════════════════════════════════════ + +A Camila possui um sistema de OBSERVAÇÕES POR VOZ onde grava registros sobre crianças durante o dia. Esses registros são salvos e ficam disponíveis para consulta. + +QUANDO A CAMILA PEDIR "observações da [nome da criança]", "resumo da [criança]", "ler observações da [nome]" ou similar: +→ Use a API: GET /api/observacoes/resumo?crianca=[nome]&mes=YYYY-MM +→ O sistema retorna um RESUMO PEDAGÓGICO compilado de todas as observações daquela criança no período +→ Use esse resumo para ajudar a elaborar HTPCs, relatórios, planejamentos + +EXEMPLOS DE COMANDO: +- "mostre as observações da Maria deste mês" +- "resumo pedagógico da Ana" +- "ler observações do João" +- "compilar observações da Sofia em maio" + +AO RECEBER O RESUMO: +- Analise o conteúdo returned +- Use para fundamentar documentos que a Camila pedir +- Se não houver observações, diga: "Não encontrei observações registradas para [criança] neste período. Posso ajudar de outra forma?" +- Integre o resumo de forma natural no documento que estiver criando + +LIMITES: +- Máximo 15 observações por consulta +- Resumos são compactados para caber no contexto +- Se a Camila pedir mais detalhes, pode mostrar a lista de observações individuais + ═══════════════════════════════════════════════════ REGRAS DE ATUAÇÃO ═══════════════════════════════════════════════════