diff --git a/.env b/.env index 771b733..003d7c7 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -OPENAI_API_KEY=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 +OPENAI_API_KEY=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 PORT=5000 \ No newline at end of file diff --git a/backend-relatorio (mova essa pasta para fora antes de usar )/.env b/backend-relatorio (mova essa pasta para fora antes de usar )/.env index c567ebc..b479ab2 100644 --- a/backend-relatorio (mova essa pasta para fora antes de usar )/.env +++ b/backend-relatorio (mova essa pasta para fora antes de usar )/.env @@ -1 +1 @@ -OPENAI_API_KEY=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 \ No newline at end of file +OPENAI_API_KEY=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 \ No newline at end of file diff --git a/backend-relatorio (mova essa pasta para fora antes de usar )/server.js b/backend-relatorio (mova essa pasta para fora antes de usar )/server.js index 98432f1..3e5ccac 100644 --- a/backend-relatorio (mova essa pasta para fora antes de usar )/server.js +++ b/backend-relatorio (mova essa pasta para fora antes de usar )/server.js @@ -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}`); }); \ No newline at end of file diff --git a/src/PagesMedico/NovoRelatorioAudio.jsx b/src/PagesMedico/NovoRelatorioAudio.jsx index 2959239..72d6a78 100644 --- a/src/PagesMedico/NovoRelatorioAudio.jsx +++ b/src/PagesMedico/NovoRelatorioAudio.jsx @@ -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 diff --git a/src/perfis/Perfil_paciente/Perfilpaciente.jsx b/src/perfis/Perfil_paciente/Perfilpaciente.jsx index 86ef589..cab8259 100644 --- a/src/perfis/Perfil_paciente/Perfilpaciente.jsx +++ b/src/perfis/Perfil_paciente/Perfilpaciente.jsx @@ -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({}) Página não encontrada} /> + ); }