feat: fase 3 - integração de observações com chat da IA
- Nova API GET /api/observacoes/buscar (filtros: crianca, mes, tags) - Nova API GET /api/observacoes/resumo (compila relatório pedagógico via GPT) - Resumo pedagógico estruturado: perfil, aspectos sociais/cognitivos/motores, pontos de atenção, pontos fortes, sugestões para planejamento - System prompt atualizado: IA reconhece comandos como 'observações da Maria', 'resumo pedagógico do João' e 调用a API para buscar/compilar registros
This commit is contained in:
@@ -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
|
||||
═══════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user