Corrigindo output truncado do Garatujas e adicionando rotas de Historias/Musicas

This commit is contained in:
2026-06-05 15:49:57 +00:00
parent d69290b76d
commit 6cb7a7190f
3 changed files with 705 additions and 3 deletions
+165 -1
View File
@@ -906,7 +906,7 @@ Retorne a resposta estruturada em Markdown, usando títulos claros:
],
generationConfig: {
temperature: 0.4,
maxOutputTokens: 2048
maxOutputTokens: 8192
}
})
});
@@ -1277,9 +1277,173 @@ app.delete('/api/poesias/:id', requireAuth, async (req, res) => {
} catch (err) {
console.error('Erro ao deletar poesia:', err);
res.status(500).json({ error: 'Erro ao deletar poesia.' });
});
// ============================================================
// ROTAS DO MUSICANDO IDEIAS
// ============================================================
app.post('/api/musicas/generate', requireAuth, async (req, res) => {
const { faixaEtaria, estrofes, ritmo, tema } = req.body;
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
if (!faixaEtaria || !estrofes || !ritmo || !tema) {
return res.status(400).json({ error: 'Faixa etária, estrofes, ritmo e tema são obrigatórios.' });
}
try {
let idadeInstrucao = '';
if (faixaEtaria.includes('Bebês') || faixaEtaria.includes('bem pequenas')) {
idadeInstrucao = '- NÍVEL FÁCIL: Use palavras EXTREMAMENTE simples e curtas. Foco em onomatopeias e repetições.';
} else {
idadeInstrucao = '- NÍVEL MÉDIO/AVANÇADO: Vocabulário lúdico, com rimas criativas.';
}
const systemInstruction = `Você é um compositor infantil especializado em criar músicas pedagógicas animadas no Brasil.
REGRAS:
- Faixa etária: ${faixaEtaria}
${idadeInstrucao}
- Estrofes: ${estrofes}
- Ritmo musical base: ${ritmo}
- Tema: "${tema}"
- A música deve ter musicalidade e métrica próprias do ritmo escolhido (${ritmo}).
- Responda APENAS a letra da música em Markdown.`;
let musicaText = '';
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 }] }] })
});
const data = await response.json();
musicaText = data.candidates?.[0]?.content?.parts?.[0]?.text || '';
}
// Limpeza
musicaText = musicaText.replace(/<think>[\s\S]*?<\/think>/gi, '').trim();
if (!musicaText) throw new Error('Falha ao gerar música');
const dbRes = await dbPool.query(
`INSERT INTO escola.musicas (usuario_id, faixa_etaria, estrofes, ritmo, tema, musica) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id`,
[usuarioId, faixaEtaria, estrofes, ritmo, tema, musicaText]
);
res.json({ id: dbRes.rows[0].id, musica: musicaText });
} catch (err) {
console.error('Erro Música:', err);
res.status(500).json({ error: 'Erro ao gerar música.' });
}
});
app.get('/api/musicas/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, ritmo, tema, created_at FROM escola.musicas 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.' }); }
});
app.get('/api/musicas/:id', requireAuth, async (req, res) => {
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
try {
const dbRes = await dbPool.query(`SELECT * FROM escola.musicas 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/musicas/:id', requireAuth, async (req, res) => {
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
try {
const dbRes = await dbPool.query(`DELETE FROM escola.musicas 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.' }); }
});
// ============================================================
// ROTAS DO INVENTANDO HISTÓRIAS
// ============================================================
app.post('/api/historias/generate', requireAuth, async (req, res) => {
const { faixaEtaria, paragrafos, personagens, estilo, tema } = req.body;
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
if (!faixaEtaria || !paragrafos || !personagens || !estilo || !tema) {
return res.status(400).json({ error: 'Todos os campos são obrigatórios.' });
}
try {
let idadeInstrucao = '';
if (faixaEtaria.includes('Bebês') || faixaEtaria.includes('bem pequenas')) {
idadeInstrucao = '- NÍVEL FÁCIL: Enredo muito simples, frases curtas, foco em ações diretas.';
} else {
idadeInstrucao = '- NÍVEL MÉDIO/AVANÇADO: Enredo com lição de moral, imaginação fluida e bom vocabulário.';
}
const systemInstruction = `Você é um contador de histórias pedagógico focado na educação infantil brasileira.
REGRAS:
- Faixa etária: ${faixaEtaria}
${idadeInstrucao}
- Tamanho: Exatamente ${paragrafos} parágrafos.
- Quantidade de personagens: ${personagens}
- Estilo narrativo: ${estilo} (se Dialogada, inclua falas claras entre os personagens; se Narração Direta, apenas o narrador conta tudo).
- Tema: "${tema}"
- Responda APENAS a história em Markdown.`;
let historiaText = '';
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 }] }] })
});
const data = await response.json();
historiaText = data.candidates?.[0]?.content?.parts?.[0]?.text || '';
}
historiaText = historiaText.replace(/<think>[\s\S]*?<\/think>/gi, '').trim();
if (!historiaText) throw new Error('Falha ao inventar história');
const dbRes = await dbPool.query(
`INSERT INTO escola.historias (usuario_id, faixa_etaria, paragrafos, personagens, estilo, tema, historia) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id`,
[usuarioId, faixaEtaria, paragrafos, personagens, estilo, tema, historiaText]
);
res.json({ id: dbRes.rows[0].id, historia: historiaText });
} catch (err) {
console.error('Erro História:', err);
res.status(500).json({ error: 'Erro ao inventar história.' });
}
});
app.get('/api/historias/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, estilo, tema, created_at FROM escola.historias 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.' }); }
});
app.get('/api/historias/:id', requireAuth, async (req, res) => {
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
try {
const dbRes = await dbPool.query(`SELECT * FROM escola.historias 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/historias/:id', requireAuth, async (req, res) => {
const usuarioId = req.user?.id || '00000000-0000-0000-0000-000000000000';
try {
const dbRes = await dbPool.query(`DELETE FROM escola.historias 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) => {
const config = readAgentConfig();