⚡ fix: hoisting do closeRecordModal no frontend e fallback Groq/Gemini no Whisper/Relatório
This commit is contained in:
@@ -230,28 +230,56 @@ app.post('/api/observacao/transcrever', requireAuth, multerUpload.single('audio'
|
||||
// Salva arquivo temporário a partir do buffer
|
||||
fs.writeFileSync(tempPath, req.file.buffer);
|
||||
|
||||
// Transcreve via OpenAI Whisper
|
||||
const whisperFormData = new FormData();
|
||||
whisperFormData.append('file', fs.createReadStream(tempPath));
|
||||
whisperFormData.append('model', 'whisper-1');
|
||||
whisperFormData.append('language', 'pt');
|
||||
whisperFormData.append('response_format', 'text');
|
||||
let transcribedText = '';
|
||||
|
||||
const whisperRes = await fetch('https://api.openai.com/v1/audio/transcriptions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
|
||||
},
|
||||
body: whisperFormData
|
||||
});
|
||||
if (process.env.OPENAI_API_KEY) {
|
||||
console.log('[Smart Transcription] Usando OpenAI Whisper...');
|
||||
const whisperFormData = new FormData();
|
||||
whisperFormData.append('file', fs.createReadStream(tempPath));
|
||||
whisperFormData.append('model', 'whisper-1');
|
||||
whisperFormData.append('language', 'pt');
|
||||
whisperFormData.append('response_format', 'text');
|
||||
|
||||
if (!whisperRes.ok) {
|
||||
const errText = await whisperRes.text();
|
||||
console.error('Whisper error:', errText);
|
||||
throw new Error('Erro na transcrição');
|
||||
const whisperRes = await fetch('https://api.openai.com/v1/audio/transcriptions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
|
||||
},
|
||||
body: whisperFormData
|
||||
});
|
||||
|
||||
if (!whisperRes.ok) {
|
||||
const errText = await whisperRes.text();
|
||||
console.error('OpenAI Whisper error:', errText);
|
||||
throw new Error('Erro na transcrição via OpenAI');
|
||||
}
|
||||
transcribedText = await whisperRes.text();
|
||||
} else if (process.env.GROQ_API_KEY) {
|
||||
console.log('[Smart Transcription] Usando Groq Whisper como fallback...');
|
||||
const whisperFormData = new FormData();
|
||||
whisperFormData.append('file', fs.createReadStream(tempPath));
|
||||
whisperFormData.append('model', 'whisper-large-v3');
|
||||
whisperFormData.append('language', 'pt');
|
||||
whisperFormData.append('response_format', 'text');
|
||||
|
||||
const whisperRes = await fetch('https://api.groq.com/openai/v1/audio/transcriptions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.GROQ_API_KEY}`
|
||||
},
|
||||
body: whisperFormData
|
||||
});
|
||||
|
||||
if (!whisperRes.ok) {
|
||||
const errText = await whisperRes.text();
|
||||
console.error('Groq Whisper error:', errText);
|
||||
throw new Error('Erro na transcrição via Groq');
|
||||
}
|
||||
transcribedText = await whisperRes.text();
|
||||
} else {
|
||||
throw new Error('Nenhuma chave de API configurada para transcrição de áudio (OPENAI_API_KEY ou GROQ_API_KEY).');
|
||||
}
|
||||
|
||||
const transcribedText = await whisperRes.text();
|
||||
fs.unlinkSync(tempPath); // Limpa tmp
|
||||
|
||||
if (!transcribedText || transcribedText.trim().length < 5) {
|
||||
@@ -286,26 +314,96 @@ ${transcribedText}
|
||||
|
||||
Retorne APENAS o JSON válido:`;
|
||||
|
||||
const reportRes = 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: reportPrompt }],
|
||||
temperature: 0.5,
|
||||
max_tokens: 1500
|
||||
})
|
||||
});
|
||||
let rawContent = '';
|
||||
|
||||
if (!reportRes.ok) {
|
||||
throw new Error('Erro ao gerar relatório');
|
||||
// Tentar OpenRouter
|
||||
try {
|
||||
console.log('[Smart Report] Tentando gerar relatório via OpenRouter...');
|
||||
const reportRes = 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: reportPrompt }],
|
||||
temperature: 0.5,
|
||||
max_tokens: 1500
|
||||
})
|
||||
});
|
||||
|
||||
if (reportRes.ok) {
|
||||
const reportData = await reportRes.json();
|
||||
rawContent = reportData.choices?.[0]?.message?.content || '';
|
||||
} else {
|
||||
console.warn('[Smart Report] Falha no OpenRouter:', await reportRes.text());
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Smart Report] Erro de conexão com OpenRouter:', err.message);
|
||||
}
|
||||
|
||||
const reportData = await reportRes.json();
|
||||
const rawContent = reportData.choices?.[0]?.message?.content || '';
|
||||
// Fallback para Groq se OpenRouter falhar
|
||||
if (!rawContent && process.env.GROQ_API_KEY) {
|
||||
try {
|
||||
console.log('[Smart Report] Usando Groq como fallback para gerar relatório...');
|
||||
const reportRes = 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: reportPrompt }],
|
||||
temperature: 0.5,
|
||||
max_tokens: 1500
|
||||
})
|
||||
});
|
||||
|
||||
if (reportRes.ok) {
|
||||
const reportData = await reportRes.json();
|
||||
rawContent = reportData.choices?.[0]?.message?.content || '';
|
||||
} else {
|
||||
console.warn('[Smart Report] Falha no Groq:', await reportRes.text());
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Smart Report] Erro de conexão com Groq:', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback para Google Gemini se OpenRouter e Groq falharem
|
||||
if (!rawContent && process.env.GOOGLE_AI_API_KEY) {
|
||||
try {
|
||||
console.log('[Smart Report] Usando Google Gemini como fallback para gerar relatório...');
|
||||
const reportRes = await fetch('https://generativelanguage.googleapis.com/v1beta/openai/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.GOOGLE_AI_API_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: process.env.GOOGLE_AI_MODEL || 'gemini-2.5-flash',
|
||||
messages: [{ role: 'user', content: reportPrompt }],
|
||||
temperature: 0.5,
|
||||
max_tokens: 1500
|
||||
})
|
||||
});
|
||||
|
||||
if (reportRes.ok) {
|
||||
const reportData = await reportRes.json();
|
||||
rawContent = reportData.choices?.[0]?.message?.content || '';
|
||||
} else {
|
||||
console.warn('[Smart Report] Falha no Google Gemini:', await reportRes.text());
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Smart Report] Erro de conexão com Google Gemini:', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rawContent) {
|
||||
throw new Error('Falha ao processar o relatório pedagógico em todos os provedores de IA (OpenRouter, Groq e Google Gemini).');
|
||||
}
|
||||
|
||||
// Parse JSON da resposta
|
||||
let parsedData = { criancas: null, turma: 'não informada', tags: [], relatorio: rawContent };
|
||||
|
||||
Reference in New Issue
Block a user