Como usei LLM para extrair dados estruturados de um relato de atendimento médico
Formulário Base
Processando, por favor aguarde...
Fluxo em JS para enviar dados para o backend
/* ====== Evento para o Botão Salvar no Relato ====== */
document.getElementById('saveRelatoBtn').addEventListener('click', function() {
const relatoText = document.querySelector('textarea[name="relato_text"]').value.trim();
if (relatoText === '') {
alert('Por favor, insira o relato do atendimento.');
return;
}
// Exibir o indicador de carregamento
document.getElementById('loadingIndicator').classList.add('active');
// Desabilitar o formulário de dados enquanto aguarda
document.getElementById('dadosForm').classList.add('disabled');
// Enviar o texto via AJAX
fetch(medicoAjax.ajaxurl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: new URLSearchParams({
action: 'processar_relato_medico',
relato_text: relatoText,
nonce: medicoAjax.nonce
})
})
.then(response => response.json())
.then(data => {
// Ocultar o indicador de carregamento
document.getElementById('loadingIndicator').classList.remove('active');
if (data.success) {
// Preencher o formulário com os dados recebidos
preencherFormularioDados(data.data.dados);
// Navegar para a próxima seção
setActiveSection('dados');
} else {
alert('Erro ao processar o relato: ' + data.data.message);
}
})
.catch(error => {
console.error('Erro:', error);
alert('Erro na solicitação. Verifique a conexão ou tente novamente.');
// Ocultar o indicador de carregamento
document.getElementById('loadingIndicator').classList.remove('active');
});
});
Handler AJAX – recebe do frontend e prepara prompt
'Relato vazio.']);
}
// Montar o prompt para a OpenAI
$prompt = "# Extraia as seguintes informações do relato médico fornecido e retorne em formato JSON com os seguintes campos:
{
\"nome_paciente\": \"\",
\"idade_paciente\": \"\",
\"queixa_principal\": \"\",
\"historico_medico\": \"\",
\"sintomas_caracteristicas\": \"\",
\"historico_familiar\": \"\",
\"estilo_vida\": \"\",
\"pressao_arterial\": \"\",
\"frequencia_cardiaca\": \"\",
\"temperatura_corporal\": \"\",
\"saturacao_oxigenio\": \"\",
\"exame_fisico\": \"\",
\"resultados_exames\": \"\",
\"diagnostico_principal\": \"\",
\"diagnosticos_diferenciais\": \"\",
\"problemas_ativos\": \"\",
\"tratamento_prescrito\": \"\",
\"acompanhamento_retorno\": \"\",
\"exames_solicitados\": \"\",
\"encaminhamentos\": \"\",
\"instrucoes_orientacoes\": \"\"
}
# Se alguma informação não estiver disponível no relato, preencha com \"Não informado\".
# Relato: \"$relato_text\"";
// Chamar a API da OpenAI
$messages = [
['role' => 'system', 'content' => 'Você é um assistente que extrai informações de relatos médicos.'],
['role' => 'user', 'content' => $prompt],
];
$response = openai_gpt_35_turbo($messages);
// Verificar se houve erro na resposta
if (strpos($response, 'Erro') === 0) {
wp_send_json_error(['message' => $response]);
}
// Verificar se a resposta está vazia
if (empty($response)) {
wp_send_json_error(['message' => 'Resposta vazia da OpenAI.']);
}
// Remover delimitadores de código, como ```json e ```
$cleaned_response = preg_replace('/^```json|```$/', '', trim($response));
// Tentar decodificar o JSON retornado
$dados = json_decode($cleaned_response, true);
// Tratamento de erros de decodificação JSON
if (json_last_error() !== JSON_ERROR_NONE) {
error_log("Erro ao decodificar JSON da OpenAI: " . json_last_error_msg());
error_log("Resposta da OpenAI: " . $cleaned_response); // Registrar a resposta completa para depuração
wp_send_json_error(['message' => 'Erro ao decodificar a resposta da OpenAI.']);
}
// Verificar se a estrutura esperada está presente
if (!is_array($dados) || empty($dados)) {
wp_send_json_error(['message' => 'Estrutura de resposta inesperada da OpenAI.']);
}
// Retornar os dados decodificados para o frontend
wp_send_json_success(['dados' => $dados]);
}
add_action('wp_ajax_processar_relato_medico', 'processar_relato_medico');
add_action('wp_ajax_nopriv_processar_relato_medico', 'processar_relato_medico');
?>
Chamada de API padrão OpenAi
'gpt-4o-mini', //'gpt-3.5-turbo',
'messages' => $messages,
'temperature' => $temperature,
'max_tokens' => 3500
]);
error_log('OpenAI request data: ' . mb_substr($request_data, 0, 300) . '...');
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $api_key
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_data);
$response = curl_exec($ch);
if ($response === false) {
$error_message = curl_error($ch);
curl_close($ch);
error_log('OpenAI request error: ' . $error_message);
return 'Erro na solicitação da OpenAI: ' . $error_message;
}
error_log('OpenAI response: ' . mb_substr($response, 0, 500) . '...');
curl_close($ch);
$response_data = json_decode($response, true);
if (isset($response_data['choices'][0]['message']['content'])) {
error_log('OpenAI response content retrieved successfully');
return trim($response_data['choices'][0]['message']['content']);
} else {
error_log('Unexpected OpenAI response: ' . print_r($response_data, true));
return 'Erro: Resposta inesperada da OpenAI.';
}
}
?>
Dica extra – Use o Web Speech API direto no front para receber o relato em audio e converter em texto.
Evolution API para Integrações WhatsApp com Backend
https://doc.evolution-api.com/v2/pt/get-started/introduction
https://www.postman.com/agenciadgcode/evolution-api/overview