109 lines
3.7 KiB
JavaScript
109 lines
3.7 KiB
JavaScript
const express = require('express');
|
|
const multer = require('multer');
|
|
const cors = require('cors');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const OpenAI = require('openai');
|
|
require('dotenv').config();
|
|
|
|
const app = express();
|
|
const port = 3001;
|
|
|
|
// Configurações de Segurança e JSON
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
|
|
// Configuração da OpenAI
|
|
const openai = new OpenAI({
|
|
apiKey: process.env.OPENAI_API_KEY,
|
|
});
|
|
|
|
// Configuração do Multer (Upload de arquivos temporários)
|
|
const upload = multer({ dest: 'uploads/' });
|
|
|
|
// Rota Principal: Recebe áudio e devolve JSON
|
|
app.post('/api/transcrever-relatorio', upload.single('audio'), async (req, res) => {
|
|
|
|
if (!req.file) {
|
|
return res.status(400).json({ error: 'Nenhum arquivo de áudio enviado.' });
|
|
}
|
|
|
|
// --- CORREÇÃO DO FORMATO DE ARQUIVO ---
|
|
const originalExt = path.extname(req.file.originalname);
|
|
const audioPath = req.file.path + originalExt;
|
|
|
|
// Renomeia o arquivo físico na pasta uploads
|
|
fs.renameSync(req.file.path, audioPath);
|
|
// ---------------------------------------
|
|
|
|
try {
|
|
console.log(`1. Processando arquivo: ${audioPath}`);
|
|
|
|
// PASSO 1: Whisper (Áudio -> Texto)
|
|
const transcription = await openai.audio.transcriptions.create({
|
|
file: fs.createReadStream(audioPath),
|
|
model: "whisper-1",
|
|
language: "pt",
|
|
});
|
|
|
|
const textoTranscrevido = transcription.text;
|
|
console.log("Texto Transcrito:", textoTranscrevido);
|
|
|
|
console.log("2. Enviando para GPT-4 extrair dados...");
|
|
|
|
// PASSO 2: GPT-4o (Texto -> JSON Estruturado)
|
|
const completion = await openai.chat.completions.create({
|
|
model: "gpt-4o",
|
|
response_format: { type: "json_object" },
|
|
messages: [
|
|
{
|
|
role: "system",
|
|
content: `
|
|
Você é um assistente médico especialista em estruturar laudos.
|
|
Sua tarefa é ler a transcrição de um ditado médico e extrair as informações para um JSON.
|
|
|
|
Os campos obrigatórios do JSON são:
|
|
- "paciente": O Nome completo do paciente mencionado. Se não houver, retorne string vazia "".
|
|
- "exam": Nome do exame realizado.
|
|
- "diagnostico": O texto completo referente aos achados/diagnóstico. (Não repita o nome do paciente aqui, foque na doença).
|
|
- "conclusao": O texto da conclusão ou impressão diagnóstica.
|
|
|
|
Se o médico não mencionar algum campo, deixe como string vazia "".
|
|
Não invente informações.
|
|
`
|
|
},
|
|
{
|
|
role: "user",
|
|
content: `Aqui está a transcrição do áudio: \n\n ${textoTranscrevido}`
|
|
}
|
|
]
|
|
});
|
|
|
|
// Parse do resultado da IA para Objeto JS
|
|
const dadosEstruturados = JSON.parse(completion.choices[0].message.content);
|
|
|
|
console.log("Dados Prontos:", dadosEstruturados);
|
|
|
|
// Devolve para o React
|
|
res.json(dadosEstruturados);
|
|
|
|
} catch (error) {
|
|
console.error("Erro no processamento:", error);
|
|
|
|
if (error.code === 'insufficient_quota') {
|
|
return res.status(429).json({ error: 'Erro: Saldo insuficiente na API da OpenAI. Verifique o Billing.' });
|
|
}
|
|
|
|
res.status(500).json({ error: 'Erro ao processar o áudio na IA.' });
|
|
|
|
} finally {
|
|
// PASSO 3: Limpeza
|
|
if (fs.existsSync(audioPath)) {
|
|
fs.unlinkSync(audioPath);
|
|
}
|
|
}
|
|
});
|
|
|
|
app.listen(port, () => {
|
|
console.log(`🚀 Backend rodando em http://localhost:${port}`);
|
|
}); |