Correção do upload de áudio, integração com OpenAI e ajuste de campos no frontend
This commit is contained in:
parent
bc7a2ed7d8
commit
78f125c279
2
.env
2
.env
@ -1,2 +1,2 @@
|
||||
OPENAI_API_KEY=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
|
||||
OPENAI_API_KEY=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
|
||||
PORT=5000
|
||||
@ -1 +1 @@
|
||||
OPENAI_API_KEY=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
|
||||
OPENAI_API_KEY=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
|
||||
@ -3,11 +3,11 @@ const multer = require('multer');
|
||||
const cors = require('cors');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const OpenAI = require('openai/index.js');
|
||||
const OpenAI = require('openai');
|
||||
require('dotenv').config();
|
||||
|
||||
const app = express();
|
||||
const port = 3001; // O backend rodará na porta 3001
|
||||
const port = 3001;
|
||||
|
||||
// Configurações de Segurança e JSON
|
||||
app.use(cors());
|
||||
@ -28,16 +28,22 @@ app.post('/api/transcrever-relatorio', upload.single('audio'), async (req, res)
|
||||
return res.status(400).json({ error: 'Nenhum arquivo de áudio enviado.' });
|
||||
}
|
||||
|
||||
const audioPath = req.file.path;
|
||||
// --- 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. Recebendo áudio e iniciando transcrição...");
|
||||
console.log(`1. Processando arquivo: ${audioPath}`);
|
||||
|
||||
// PASSO 1: Whisper (Áudio -> Texto)
|
||||
const transcription = await openai.audio.transcriptions.create({
|
||||
file: fs.createReadStream(audioPath),
|
||||
file: fs.createReadStream(audioPath),
|
||||
model: "whisper-1",
|
||||
language: "pt", // Força português para melhorar precisão médica
|
||||
language: "pt",
|
||||
});
|
||||
|
||||
const textoTranscrevido = transcription.text;
|
||||
@ -48,7 +54,7 @@ app.post('/api/transcrever-relatorio', upload.single('audio'), async (req, res)
|
||||
// PASSO 2: GPT-4o (Texto -> JSON Estruturado)
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: "gpt-4o",
|
||||
response_format: { type: "json_object" }, // Garante que volta JSON válido
|
||||
response_format: { type: "json_object" },
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
@ -57,8 +63,9 @@ app.post('/api/transcrever-relatorio', upload.single('audio'), async (req, res)
|
||||
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. Melhore a pontuação e corrija termos médicos se necessário.
|
||||
- "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 "".
|
||||
@ -82,16 +89,21 @@ app.post('/api/transcrever-relatorio', upload.single('audio'), async (req, res)
|
||||
|
||||
} catch (error) {
|
||||
console.error("Erro no processamento:", error);
|
||||
res.status(500).json({ error: 'Erro ao processar o áudio.' });
|
||||
|
||||
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 (Apagar o áudio da pasta uploads para não encher o servidor)
|
||||
// PASSO 3: Limpeza
|
||||
if (fs.existsSync(audioPath)) {
|
||||
fs.unlinkSync(audioPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Iniciar Servidor
|
||||
app.listen(port, () => {
|
||||
console.log(`🚀 Backend rodando em http://localhost:${port}`);
|
||||
});
|
||||
@ -1,11 +1,11 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate, useLocation } from 'react-router-dom'; // <--- 1. ADICIONADO useLocation
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import html2pdf from 'html2pdf.js';
|
||||
import './styleMedico/NovoRelatorioAudio.css';
|
||||
|
||||
const NovoRelatorioAudio = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation(); // <--- 2. Inicializa o hook para ler os dados enviados
|
||||
const location = useLocation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
@ -14,33 +14,26 @@ const NovoRelatorioAudio = () => {
|
||||
exam: '',
|
||||
diagnostico: '',
|
||||
conclusao: '',
|
||||
medico_nome: 'Dr._______________________________' // Ajuste conforme necessário
|
||||
medico_nome: 'Dr._______________________________'
|
||||
});
|
||||
|
||||
// --- 3. NOVO BLOCO: Receber dados da Videochamada ---
|
||||
// --- Receber dados da Videochamada (Se houver) ---
|
||||
useEffect(() => {
|
||||
// Verifica se a navegação trouxe dados no "state"
|
||||
if (location.state && location.state.aiResult) {
|
||||
console.log("Dados recebidos da Videochamada:", location.state);
|
||||
|
||||
const { aiResult, paciente } = location.state;
|
||||
|
||||
// Atualiza o formulário com o que a IA gerou
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
// Se tiver paciente vindo da chamada, usa ele. Se não, mantém vazio.
|
||||
paciente_nome: paciente?.name || prev.paciente_nome,
|
||||
|
||||
// Dados da IA
|
||||
exam: aiResult.exam || 'Consulta Telemedicina',
|
||||
diagnostico: aiResult.diagnostico || '',
|
||||
conclusao: aiResult.conclusao || ''
|
||||
}));
|
||||
}
|
||||
}, [location]); // Executa assim que a página carrega
|
||||
|
||||
// --- FIM DO BLOCO NOVO ---
|
||||
}, [location]);
|
||||
|
||||
// --- LÓGICA DO UPLOAD DE ÁUDIO ---
|
||||
const handleAudioUpload = async (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (!file) return;
|
||||
@ -59,8 +52,10 @@ const NovoRelatorioAudio = () => {
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
// ATUALIZAÇÃO AQUI: Mapeando todos os campos retornados pela IA
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
paciente_nome: result.paciente || prev.paciente_nome, // Pega o nome do paciente
|
||||
exam: result.exam || prev.exam,
|
||||
diagnostico: result.diagnostico || prev.diagnostico,
|
||||
conclusao: result.conclusao || prev.conclusao
|
||||
|
||||
@ -7,6 +7,7 @@ import LaudoManager from "../../pages/LaudoManager";
|
||||
import ConsultaCadastroManager from "../../PagesPaciente/ConsultaCadastroManager";
|
||||
import ConsultasPaciente from "../../PagesPaciente/ConsultasPaciente";
|
||||
import ConsultaEditPage from "../../PagesPaciente/ConsultaEditPage";
|
||||
import BotaoVideoPaciente from "../../components/BotaoVideoPaciente";
|
||||
function PerfilPaciente({ onLogout }) {
|
||||
|
||||
const [dadosConsulta, setConsulta] = useState({})
|
||||
@ -25,6 +26,7 @@ const [dadosConsulta, setConsulta] = useState({})
|
||||
<Route path="*" element={<h2>Página não encontrada</h2>} />
|
||||
</Routes>
|
||||
</div>
|
||||
<BotaoVideoPaciente />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user