Corrige a inclusao de obs gerais e aumenta limites de tokens das IAs para evitar cortes

This commit is contained in:
2026-06-02 15:02:10 +00:00
parent 532bb95e9b
commit c966be7ed4
2 changed files with 192 additions and 3 deletions
+188
View File
@@ -0,0 +1,188 @@
const { Pool } = require('pg');
require('dotenv').config();
const dbPool = new Pool({
connectionString: process.env.DATABASE_URL
});
function readAgentConfig() {
try {
const fs = require('fs');
const path = require('path');
const CONFIG_FILE_PATH = path.join(__dirname, '../agent_config.json');
if (fs.existsSync(CONFIG_FILE_PATH)) {
return JSON.parse(fs.readFileSync(CONFIG_FILE_PATH, 'utf8'));
}
} catch (err) {
console.error('Erro ao ler agent_config.json:', err);
}
return {};
}
async function test() {
try {
const crianca = 'Maria';
const modeloId = 2; // O ID de Avaliação Semestral Individual
// 1. Buscar o modelo/template
const templateRes = await dbPool.query("SELECT * FROM escola.modelos WHERE id = $1;", [modeloId]);
const template = templateRes.rows[0];
console.log('Template:', template.nome);
// 2. Buscar as observações
let sql = `
SELECT date, time, report, criancas, tags
FROM escola.observacoes
WHERE 1=1
`;
const params = [];
let pCount = 1;
sql += ` AND (
(jsonb_typeof(criancas) = 'array' AND EXISTS (
SELECT 1 FROM jsonb_array_elements_text(criancas) AS c
WHERE LOWER(c) LIKE $${pCount}
))
OR jsonb_typeof(criancas) = 'null'
OR criancas IS NULL
)`;
params.push(`%${crianca.toLowerCase()}%`);
pCount++;
sql += ` ORDER BY date ASC`;
const dbRes = await dbPool.query(sql, params);
const observations = dbRes.rows;
console.log('Quantidade de observações:', observations.length);
// 3. Montar prompt
const combinedObsText = observations.map((o, idx) => {
const dateText = o.date ? `Data: ${o.date}` : '';
const tagsText = o.tags ? `Tags: ${Array.isArray(o.tags) ? o.tags.join(', ') : o.tags}` : '';
return `[Observação #${idx + 1} ${dateText} ${tagsText}]\n${o.report}`;
}).join('\n\n---\n\n');
const agentConfig = readAgentConfig();
const agentName = agentConfig.agentName || "Kemily";
const targetStudentInfo = `\nATENÇÃO CRÍTICA: A criança que está sendo avaliada e para quem você deve gerar o relatório individual é especificamente: "${crianca}". Todas as observações, avanços, preferências e conclusões descritas na PARTE 2 (Desenvolvimento Individual) devem referir-se exclusivamente a ${crianca}. Nunca confunda ${crianca} com outros colegas eventualmente citados nas observações (como Joãozinho, Vanderlei, etc.), e não atribua as ações deles a ela.\n`;
const systemPrompt = `Você é a ${agentName}, uma assistente pedagógica e especialista em educação infantil.
Seu objetivo é analisar o histórico de observações de uma criança e redigir um relatório pedagógico consolidado e profissional sobre o desenvolvimento individual desta criança.
${targetStudentInfo}
Você DEVE estruturar o relatório seguindo exatamente as seções e diretrizes fornecidas no modelo de relatório selecionado.
MODELO DE RELATÓRIO: "${template.nome}"
FINALIDADE: "${template.finalidade || 'Não informada'}"
PERIODICIDADE: "${template.periodicidade || 'Não informada'}"
ESTRUTURA/DIRETRIZES DO MODELO:
"""
${template.estrutura}
"""
HISTÓRICO DE OBSERVAÇÕES REGISTRADAS:
"""
${combinedObsText}
"""
Orientações adicionais:
- Redija o relatório em português brasileiro formal e adequado para pedagogia.
- Preencha cada seção da estrutura de forma rica e detalhada, baseando-se estritamente nos fatos reais descritos nas observações.
- Não invente acontecimentos que não estejam descritos nas observações, mas faça as conexões pedagógicas pertinentes de acordo com as evidências apresentadas.
- Retorne apenas o relatório em formato Markdown estruturado.`;
let generatedReport = '';
// Tenta OpenRouter
try {
console.log('Chamando OpenRouter...');
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: process.env.OPENROUTER_MODEL || 'openai/gpt-4.1-nano',
messages: [{ role: 'user', content: systemPrompt }],
temperature: 0.5,
max_tokens: 6000
})
});
if (response.ok) {
const data = await response.json();
generatedReport = data.choices?.[0]?.message?.content || '';
console.log('OpenRouter OK! Comprimento:', generatedReport.length);
} else {
console.warn('Falha no OpenRouter status:', response.status, await response.text());
}
} catch (err) {
console.error('Erro no OpenRouter:', err.message);
}
// Fallback para Google Gemini
if (!generatedReport && process.env.GOOGLE_AI_API_KEY) {
try {
console.log('Fallback para Google Gemini...');
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${process.env.GOOGLE_AI_MODEL || 'gemini-2.5-flash'}:generateContent?key=${process.env.GOOGLE_AI_API_KEY}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
contents: [{ parts: [{ text: systemPrompt }] }],
generationConfig: { temperature: 0.5, maxOutputTokens: 8192 }
})
});
if (response.ok) {
const data = await response.json();
generatedReport = data.candidates?.[0]?.content?.parts?.[0]?.text || '';
console.log('Google Gemini OK! Comprimento:', generatedReport.length);
} else {
console.warn('Falha no Google Gemini status:', response.status, await response.text());
}
} catch (err) {
console.error('Erro no Google Gemini:', err.message);
}
}
// Fallback para Groq
if (!generatedReport && process.env.GROQ_API_KEY) {
try {
console.log('Fallback para Groq...');
const response = await fetch('https://api.groq.com/openai/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.GROQ_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: process.env.GROQ_MODEL || 'llama-3.3-70b-versatile',
messages: [{ role: 'user', content: systemPrompt }],
temperature: 0.5,
max_tokens: 6000
})
});
if (response.ok) {
const data = await response.json();
generatedReport = data.choices?.[0]?.message?.content || '';
console.log('Groq OK! Comprimento:', generatedReport.length);
} else {
console.warn('Falha no Groq status:', response.status, await response.text());
}
} catch (err) {
console.error('Erro no Groq:', err.message);
}
}
console.log('=== REPORT GENERATED ===');
console.log(generatedReport);
console.log('========================');
} catch (err) {
console.error(err);
} finally {
await dbPool.end();
}
}
test();
+4 -3
View File
@@ -913,6 +913,7 @@ app.post('/api/modelos/gerar-relatorio', requireAuth, async (req, res) => {
SELECT 1 FROM jsonb_array_elements_text(criancas) AS c
WHERE LOWER(c) LIKE $${pCount}
))
OR jsonb_typeof(criancas) = 'null'
OR criancas IS NULL
)`;
params.push(`%${crianca.toLowerCase()}%`);
@@ -1017,7 +1018,7 @@ Orientações adicionais:
model: process.env.OPENROUTER_MODEL || 'openai/gpt-4.1-nano',
messages: [{ role: 'user', content: systemPrompt }],
temperature: 0.5,
max_tokens: 2500
max_tokens: 6000
})
});
if (response.ok) {
@@ -1039,7 +1040,7 @@ Orientações adicionais:
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
contents: [{ parts: [{ text: systemPrompt }] }],
generationConfig: { temperature: 0.5, maxOutputTokens: 2500 }
generationConfig: { temperature: 0.5, maxOutputTokens: 8192 }
})
});
if (response.ok) {
@@ -1065,7 +1066,7 @@ Orientações adicionais:
model: process.env.GROQ_MODEL || 'llama-3.3-70b-versatile',
messages: [{ role: 'user', content: systemPrompt }],
temperature: 0.5,
max_tokens: 2500
max_tokens: 6000
})
});
if (response.ok) {