From fd6756c50797e302501d6d7cc01c7896941a93da Mon Sep 17 00:00:00 2001 From: DNXBrasil Date: Tue, 27 Jan 2026 14:26:09 -0300 Subject: [PATCH] Adds agent mock code --- scripts/langgraph_agent.py | 703 +++++++++++++++++++++++++++++++++++++ 1 file changed, 703 insertions(+) create mode 100644 scripts/langgraph_agent.py diff --git a/scripts/langgraph_agent.py b/scripts/langgraph_agent.py new file mode 100644 index 0000000..9d78940 --- /dev/null +++ b/scripts/langgraph_agent.py @@ -0,0 +1,703 @@ +#!/usr/bin/env python3 +""" +Simple LangGraph agent using AWS Bedrock. +This agent demonstrates a basic ReAct-style agent with tool calling capabilities. +""" + +import boto3 +import csv +import json +from pathlib import Path +from typing import Annotated, TypedDict, Literal +from langgraph.graph import StateGraph, END +from langgraph.graph.message import add_messages +from langchain_aws import ChatBedrock +from langchain_core.messages import HumanMessage, AIMessage, ToolMessage, SystemMessage +from langchain_core.tools import tool + +# Global variable to store file content for the check tool +FILE = "" +CODE="" + +# Base paths +SCRIPTS_DIR = Path(__file__).parent +JSON_OUTPUT_DIR = SCRIPTS_DIR / "json_output" +TEXTRACT_OUTPUT_DIR = SCRIPTS_DIR / "textract_output" +RULES={ + "40808130":"""- Mulheres acima de 45 anos ou menopausada +- Homens com mais de 70 anos; +- Osteogênese imperfeita (para esta patologia, poderá haver a liberação de (02) dois +exames ao ano - cada 180 dias); +- RX com osteopenia ou fratura patológica; +- Antecedente pessoal de fratura após os 40 anos: punho, ombros, vértebras, quadril; +- Parente de primeiro grau com osteoporose. +- Mulheres com massa corporal <20kg/m2 ou peso < 57,8kg; +- Menopausa antes dos 45 anos ou hipogonasismo crônico (falência ovariana +precoce); +- Uso de glicocorticóides (>=7,5 prednizona/ dia equivalente por mais três meses, ou +presença de síndrome de cushing; +- Hiperparatireoidismo primário; +- Uso prolongado de anticonvulsivantes (< 10 anos); +- Síndrome de má absorção crônica ou desnutrição doenças inflamatória intestinal +(independente da causa: bariatrica, celiacos, intolerancia a lactose). +- Quimioterapia, se sobrevida esperada for longa (< 5 anos); +- Diminuição documentada de altura; +- Presença de cifose após menopausa. +- Imobilização prolongada""", +"40808122":"""- Mulheres acima de 45 anos ou menopausada +- Homens com mais de 70 anos; +- Osteogênese imperfeita (para esta patologia, poderá haver a liberação de (02) dois +exames ao ano - cada 180 dias); +- RX com osteopenia ou fratura patológica; +- Antecedente pessoal de fratura após os 40 anos: punho, ombros, vértebras, quadril; +- Parente de primeiro grau com osteoporose. +- Mulheres com massa corporal <20kg/m2 ou peso < 57,8kg; +- Menopausa antes dos 45 anos ou hipogonasismo crônico (falência ovariana +precoce); +- Uso de glicocorticóides (>=7,5 prednizona/ dia equivalente por mais três meses, ou +presença de síndrome de cushing; +- Hiperparatireoidismo primário; +- Uso prolongado de anticonvulsivantes (< 10 anos); +- Síndrome de má absorção crônica ou desnutrição doenças inflamatória intestinal +(independente da causa: bariatrica, celiacos, intolerancia a lactose). +- Quimioterapia, se sobrevida esperada for longa (< 5 anos); +- Diminuição documentada de altura; +- Presença de cifose após menopausa. +- Imobilização prolongada""", +"31303293":"""Mirena e Kyleena possuem critérios diferentes para autorização. +Autorizar sem o parecer da Auditoria Médica, somente quando for beneficiária com +idade entre 18 e 45 anos e se o formulário estiver preenchido conforme as quatro +validações abaixo: +· Identificação completa do paciente e médico assistente; +· Campo 1.1: selecionado: Mirena ou Kyleena; +· Campo 1.2: selecionado: +· Mirena: Menorragia idiopática (sangramento) ou Anticoncepção; ou Kyleena: +Anticoncepção; +· Se os itens 2 e 3 estiverem descritos como “NÃO”, “NÃO SE APLICA”, “- “ou EM +BRANCO. +Encaminhar para a auditoria médica (Mirena ou Kyleena) somente quando: +- Solicitações que incluam outros eventos além do implante de DIU; +- Constar pedido de liberação de anestesia; +- No caso de prazo intervalar - Incluir na perícia, a negação gerada e qual a finalidade +da análise do auditor, informar também a data da última liberação do DIU e a +necessidade de avaliação por conta do prazo de repetição. +- Campo 1.1 selecionado: “Outros”; +- Campo 1.2 selecionado: +Mirena: “Outros” ou nenhuma opção selecionada;Kyleena: Menorragia idiopática (Sangramento) ou “Outros”; +- Se qualquer campo dos itens 2 e 3 descreverem alguma contraindicação. +- Beneficiária menor de 18 anos ou acima de 45 anos.""", +"31005470":"""Autorizar sem o parecer da Auditoria Médica se constar no pedido médico ou +laudos, uma das justificativas abaixo: +·Cálculo biliar; +·Colelitíase; +·Litíase; +·Pólipos acima de 01 cm. +Caso a indicação seja outra ou pólipo menor que 01 cm, encaminhar para +auditoria.""", +"41501012":"""Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÃMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Autorizar sem o parecer da Auditoria Médica solicitações de beneficiários acima de +60 anos.Autorizar independentemente da idade solicitações em que a justificativa indique +pelo menos uma das patologias abaixo: +· +4)Catarata senil (CID’S H25-1, H25-2, H25-8, H25-9, H26-1, H26-2, H26-3, H26- +·Outros transtornos do cristalino. +BANDEJA +Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÃMBIO. +Para beneficiário Unimed 0032 (atendimento local): +- Bandeja 143 - AML - OFTALMOLOGIA - obrigatoriamente com a documentação +mínima. +- Bandeja 51 - AML - SEM INFORMAÇÃO MÍNIMA PARA ANÁLISE: Quando for +solicitação eletiva e não houver indicação clínica. +Botão Prioridade: Em caso de beneficiário Intercâmbio, PAC, GLP ou SAC Empresa, é +obrigatório selecionar a bandeja de retorno no botão prioridade, para correta +devolução ao responsável. +ATENDIMENTO INTERCÃMBIO +IMPORTADO (Beneficiários de Outras Unimed's sendo atendidos em Curitiba e +região). +1°Passo: Necessário documentação conforme planilha de racionalização. +2° Passo: Gerar a solicitação em sistema com documentação em anexo. +- Se tiver a documentação, anexar no sistema (ATF não necessita anexar). +- Se não tiver documentação, solicitar que beneficiário providencie para dar entrada.3° Passo: Verificar no monitor de intercâmbio, se o processo está pendente de +perícia. +- Se tiver, abrir sala CHAT e anexar as documentações (ATF não necessita anexar). +- Se não tiver, abrir GPU (ATF não necessita abertura). +4° Passo: Deixar processo pendente na bandeja para monitoramento. +-Se trafegou, bandeja 921. +-Se não trafegou, bandeja 11. +5° Passo: Registrar em anotações administrativas as informações pertinentes ao +processo.""", +"40901254":"""Autorizar no ato do atendimento a 1ª solicitação entre o período (DE 11- 14 SEMANAS +DE GESTAÇÃO). +ou +Se o evento foi gerado decorrente da consulta obstétrica 1.01.01987 - CONSULTA +OBSTÉTRICA - 2ª AVALIAÇÃO (ATÉ 10 SEMANAS DE GESTAÇÃO).""", +"40901262":"""Autorizar no ato do atendimento a 1ª solicitação entre o período de 18 a 24 semanas +de gestação ou se o evento foi gerado decorrente da consulta obstétrica 1.01.01989 +- CONSULTA OBSTÉTRICA - 4ª AVALIAÇÃO (ATÉ 18 SEMANAS DE GESTAÇÃO).A repetição poderá ser autorizada desde que se enquadre em um dos critérios +abaixo: +·Anomalia fetal diagnosticada em exame de rotina. +·Antecedentes de doenças hereditárias. +·Consanguinidade. +·Exposição a drogas. +·Idade materna avançada. +·Infecções pré-natais.""", +"4091262":"""Autorizar no ato do atendimento a 1ª solicitação entre o período de 18 a 24 semanas +de gestação ou se o evento foi gerado decorrente da consulta obstétrica 1.01.01989 +- CONSULTA OBSTÉTRICA - 4ª AVALIAÇÃO (ATÉ 18 SEMANAS DE GESTAÇÃO).A repetição poderá ser autorizada desde que se enquadre em um dos critérios +abaixo: +·Anomalia fetal diagnosticada em exame de rotina. +·Antecedentes de doenças hereditárias. +·Consanguinidade. +·Exposição a drogas. +·Idade materna avançada. +·Infecções pré-natais.""", +"40304906":"""Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÃMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Poderá ser liberada de imediato as solicitações eletivas que contenha a indicação +abaixo, conforme DUT: +• +Avaliação de pacientes adultos com sinais e sintomas de trombose +venosa profunda dos membros inferiores; +URGÊNCIA/EMERGÊNCIA (INTERNAMENTO e AMBULATORIAL) +Poderá ser liberada de imediato as solicitações de Urgência e Emergência em regime +Internamento ou em situação de Observação em Unidades de Urgência que +contenha a indicação: +• +Pacientes adultos com sinais e sintomas de embolia pulmonar. +• +Pneumonia ou síndrome respiratória aguda grave, com quadro suspeito ou +confirmado de infecção pelo SARS-CoV-2 (COVID 19). +PLANOS NÃO REGULAMENTADOS E PLANOS ADAPTADOS +Os planos não regulamentados (UNIPLAN, UNIPLAN 2000 E NOVO UNIPLAN) e +adaptados, asseguram cobertura ilimitada para exames laboratoriais, pois não +seguem o Rol e as diretrizes de utilização. Desta forma podem ser autorizados +segundo regras contratuais.""", + +"20203020":"""utorizar sem o parecer da Auditoria Médica desde +que a justificativa indique pelo menos uma das patologias abaixo ou CID’s +relacionados:·Incontinência urinária (CID R32); +·Disfunção miccional (CID N39); +·Incontinência de tensão (“stress”) (CID N39.3); +·Síndrome da bexiga hiperativa; +·Distúrbios do assoalho pélvico; +·Incontinência fecal (CID R15); +·Outros transtornos funcionais do intestino (CID K59); +·Fortalecimento do Assoalho Pélvico pré e/ou pós-parto.""", +"41001230":"""PROTOCOLO DE LIBERAÇÃO +Para beneficiário de outras Unimed’s (importado) +Ver item ATENDIMENTO INTERCÂMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Todas as solicitações devem ser direcionadas para análise da Auditoria Médica, +com a documentação mínima.""", +"4034906":"""Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÃMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Poderá ser liberada de imediato as solicitações eletivas que contenha a indicação +abaixo, conforme DUT: +• +Avaliação de pacientes adultos com sinais e sintomas de trombose +venosa profunda dos membros inferiores; +URGÊNCIA/EMERGÊNCIA (INTERNAMENTO e AMBULATORIAL) +Poderá ser liberada de imediato as solicitações de Urgência e Emergência em regime +Internamento ou em situação de Observação em Unidades de Urgência que +contenha a indicação: +• +Pacientes adultos com sinais e sintomas de embolia pulmonar. +• +Pneumonia ou síndrome respiratória aguda grave, com quadro suspeito ou +confirmado de infecção pelo SARS-CoV-2 (COVID 19). +PLANOS NÃO REGULAMENTADOS E PLANOS ADAPTADOS +Os planos não regulamentados (UNIPLAN, UNIPLAN 2000 E NOVO UNIPLAN) e +adaptados, asseguram cobertura ilimitada para exames laboratoriais, pois não +seguem o Rol e as diretrizes de utilização. Desta forma podem ser autorizados +segundo regras contratuais.""", +"4101230":"""PROTOCOLO DE LIBERAÇÃO +Para beneficiário de outras Unimed’s (importado) +Ver item ATENDIMENTO INTERCÂMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Todas as solicitações devem ser direcionadas para análise da Auditoria Médica, +com a documentação mínima.""", +"20103190":"""Autorizar sem o parecer da Auditoria Médica desde que a justificativa indique pelo +menos uma das patologias abaixo ou CID’s relacionados: +·Incontinência urinária (CID R32); +·Disfunção miccional (CID N39); +·Incontinência de tensão (“stress”) (CID N39.3);·Síndrome da bexiga hiperativa; +·Distúrbios do assoalho pélvico; +·Incontinência fecal (CID R15); +·Outros transtornos funcionais do intestino (CID K59); +·Fortalecimento do Assoalho Pélvico pré e/ou pós-parto. +BENEFICIARIOS ADULTOS (ACIMA DE 18 ANOS): +Se a solicitação estiver enquadrada nas indicações acima poderá ser autorizado sem +encaminhar para o AML até 10 quantidades ao mês; +Ponto de atenção - pertinente 10 sessões total ao mês: considerar códigos +associados ou individuais (eletroestimulação do assoalho pélvico, disfunção vesico +uretral, biofeedback, reabilitação perineal) +BENEFICIARIOS CRIANÇAS (ATÉ 17 ANOS E 11 MESES): +Se a solicitaçãoEste evento está parametrizado para autorizar automaticamente para beneficiários +carteirinha 0032. +· Para beneficiários PAC, início do cartão 09759032, as solicitações destes exames +devem ser liberadas de imediato, revertendo a guia no motivo: 9 - AUTORIZADO +CONFORME PROTOCOLO DE LIBERAÇÃO· Para beneficiários 0032 no intercâmbio exportado, as solicitações destes exames +devem ser liberadas de imediato, revertendo a guia no motivo: 9 - AUTORIZADO +CONFORME PROTOCOLO DE LIBERAÇÃO +NÃO NEGAR ATENDIMENTO. +ATENÇÃO: Exame contratualizado para realização na Unimed Laboratório, +exclusivamente na Megaunidade. +Telefone de contato para mais informações: (41) 3021-5252. +ATENDIMENTO INTERCÂMBIO +Encaminhar para deliberação da Unimed origem. estiver enquadrada nas indicações acima poderá ser autorizado sem +encaminhar para o AML até 04 quantidades ao mês; +Ponto de atenção - pertinente 04 sessões ao mês: para cada modalidade +(eletroestimulação do assoalho pélvico, disfunção vesico uretral, biofeedback, +reabilitação perineal) +Acima desta quantidade encaminhar para a análise da Auditoria Médica com +justificativa médica.""", +"40202542":"""Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÃMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Esse código não requer análise da Auditoria Médica, analisar baseado na cobertura e +limite contratual do beneficiário. +Caso seja necessário análise da auditoria médica devido alguma mensagem de +negação, consultar o item "Documentação Mínima". +Para beneficiário Unimed 0032 (atendimento em outra singular/Exportado): +A liberação do procedimento não está condicionada a solicitação dos materiais, pois +o mesmo poderá ser realizado sem a utilização da "Alça de Polipectomia" e da +“Agulha de Esclerose ou Injetor”. +Quando houver solicitação dos materiais posteriormente à autorização do evento, +não há a necessidade de análise da AML para os materiais. Deverá ser cadastrado +conforme informações acima e, liberar. (Circular n.º 056/2008 de 01/08/2008).""", +"40202550":"""Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÃMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Esse código não requer análise da Auditoria Médica, analisar baseado na cobertura e +limite contratual do beneficiário. +Caso seja necessário análise da auditoria médica devido alguma mensagem de +negação, consultar o item "Documentação Mínima". +Para beneficiário Unimed 0032 (atendimento em outra singular/Exportado): +A liberação do procedimento não está condicionada a solicitação dos materiais, pois +o mesmo poderá ser realizado sem a utilização da "Alça de Polipectomia" e da +“Agulha de Esclerose ou Injetor”. +Quando houver solicitação dos materiais posteriormente à autorização do evento, +não há a necessidade de análise da AML para os materiais. Deverá ser cadastrado +conforme informações acima e, liberar. (Circular n.º 056/2008 de 01/08/2008).""", +"40323676":"""Este evento está parametrizado para autorizar automaticamente para beneficiários +carteirinha 0032. +· Para beneficiários PAC, início do cartão 09759032, as solicitações destes exames +devem ser liberadas de imediato, revertendo a guia no motivo: 9 - AUTORIZADO +CONFORME PROTOCOLO DE LIBERAÇÃO· Para beneficiários 0032 no intercâmbio exportado, as solicitações destes exames +devem ser liberadas de imediato, revertendo a guia no motivo: 9 - AUTORIZADO +CONFORME PROTOCOLO DE LIBERAÇÃO +NÃO NEGAR ATENDIMENTO. +ATENÇÃO: Exame contratualizado para realização na Unimed Laboratório, +exclusivamente na Megaunidade. +Telefone de contato para mais informações: (41) 3021-5252. +ATENDIMENTO INTERCÂMBIO +Encaminhar para deliberação da Unimed origem.""", + + +} +MIN_DOC={ + "20103190":"""DOCUMENTAÇÃO MÍNIMA +Justificativa Médica e/ou indicação clínica.""", + "20203020":"""DOCUMENTAÇÃO MÍNIMA: +· +Justificativa Médica e/ou indicação clínica.""", +"31303293":"""DOCUMENTAÇÃO MÍNIMA +Beneficiário 0032 (atendidos em Curitiba e em Outras cidades): +·Justificativa médica e/ou indicação clínica; +·Formulário de Solicitação - DIU Hormonal (ver anexo do script). +Beneficiário Intercâmbio/Outras Unimeds: +· +Relatório Médico Detalhado (conforme racionalização).""", +"40202542":"""DOCUMENTAÇÃO MÍNIMA +Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÃMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Justificativa Médica e/ou indicação clínica.""", +"40202550":"""DOCUMENTAÇÃO MÍNIMA +Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÃMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Justificativa Médica e/ou indicação clínica.""", +"40304906":"""DOCUMENTAÇÃO MÍNIMA +Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÃMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Justificativa e/ou indicação clínica.""", +"4034906":"""DOCUMENTAÇÃO MÍNIMA +Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÃMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Justificativa e/ou indicação clínica.""", +"40314626":"""DOCUMENTAÇÃO MÍNIMA +Não há;""", +"40314618":"""DOCUMENTAÇÃO MÍNIMA +Não há;""", +"40323676":"""DOCUMENTAÇÃO MÍNIMA +Não há;""", +"40901254":"""Justificativa Médica e/ou indicação clínica informando a idade gestacional e Laudo +do 1º exame sonográfico gestacional realizado.""", +"40901262":"""DOCUMENTAÇÃO MÍNIMA +Relatório médico informando a idade gestacional + laudo do 1o exame sonográfico +gestacional realizado.""", +"4091262":"""DOCUMENTAÇÃO MÍNIMA +Relatório médico informando a idade gestacional + laudo do 1o exame sonográfico +gestacional realizado.""", +"4101230":"""DOCUMENTAÇÃO MÍNIMA +Para beneficiário de outras Unimed’s (importado) +Ver item ATENDIMENTO INTERCÂMBIO. +Para beneficiário Unimed 0032 (atendimento local): +· +Relatório Médico detalhado com histórico indicando a necessidade de +realização do exame, além de sinais e sintomas, se possui limitação para teste de +esforço físico; +· +Índice de pré-teste segundo os critérios de Diamons e Forrester revisados +e/ ou TIMI risk; +· +Laudos de exames cardiológicos recentes.""", +"4101230":"""DOCUMENTAÇÃO MÍNIMA +Para beneficiário de outras Unimed’s (importado) +Ver item ATENDIMENTO INTERCÂMBIO. +Para beneficiário Unimed 0032 (atendimento local): +· +Relatório Médico detalhado com histórico indicando a necessidade de +realização do exame, além de sinais e sintomas, se possui limitação para teste de +esforço físico; +· +Índice de pré-teste segundo os critérios de Diamons e Forrester revisados +e/ ou TIMI risk; +· +Laudos de exames cardiológicos recentes.""", +"41501144":"""DOCUMENTAÇÃO MÍNIMA +PARA BENEFICIÁRIOS 0032 SENDO ATENDIDO EM CURITIBA, FORA (EXPORTADO), +E PAC: +· +Relatório Médico descrevendo a necessidade de realização do exame.· +Se o pedido for para avaliação de glaucoma, é necessário incluir laudo e +imagem da retinografia. +Atenção: Para as demais situações, NÃO é necessário enviar o laudo da retinografia. +PARA BENEFICIÁRIOS INTERCÂMBIO ESTADUAL, CONFORME DETERMINAÇÃO +DO CERS +·Relatório médico descrevendo a necessidade da realização do exame; +·Laudo e imagem de retinografia. +Atenção: NÃO É OBRIGATÓRIO o envio do laudo e imagem de retinografia para: +> Pacientes com diagnóstico da doença já confirmado e que estejam em tratamento +com aplicação de antiangiogênicos, para as patologias abaixo: +·Doença Macular Relacionada à Idade (DMRI); +·Oclusões Vasculares Retinianas; +·Edema Macular secundário a Diabetes Mellitus. +Caso a informação referente ao tratamento não conste no relatório médico, consultar +eventos recentes para identificar se o beneficiário está em tratamento. +Esclarecemos que o envio de retinografia, poderá eventualmente ser solicitado pela +auditoria para fins de elucidação diagnóstica. +PARA BENEFICIÁRIOS INTERCÂMBIO NACIONAL: +SEGUIR DOCUMENTAÇÃO CONFORME RACIONALIZAÇÃO.""", +"31005101":"""DOCUMENTAÇÃO MÍNIMA: +·Relatório médico detalhado; +·Laudo RX e/ou tomografia e/ou ressonância e/ou ultrassonografia.""", +"31005470":"""DOCUMENTAÇÃO MÍNIMA: +·Relatório médico detalhado; +·Laudo RX e/ou tomografia e/ou ressonância e/ou ultrassonografia.""", +"40808122":"""DOCUMENTAÇÃO MÍNIMA +Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÂMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Justificativa e/ou indicação clínica.""", +"40808130":"""DOCUMENTAÇÃO MÍNIMA +Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÂMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Justificativa e/ou indicação clínica.""", +"41501012":"""Para beneficiário de outras Unimed’s (importado): +Ver item ATENDIMENTO INTERCÃMBIO. +Para beneficiário Unimed 0032 (atendimento local): +Justificativa médica e/ou indicação clínica.""" +} +# System prompt for the agent + +# Define tools the agent can use +@tool +def check(expression: str) -> str: + """Retrieves the values of the files associated with the input for aditional information, if the json is not enough""" + return FILE + +# Define the agent state +class AgentState(TypedDict): + messages: Annotated[list, add_messages] + + +def get_bedrock_client(): + """Initialize and return AWS Bedrock runtime client.""" + return boto3.client("bedrock-runtime", region_name="us-east-2") + + +def create_llm(): + """Create and return the Bedrock LLM.""" + return ChatBedrock( + model_id="arn:aws:bedrock:us-east-2:232048051668:application-inference-profile/uy4xskop19zn", + region_name="us-east-2", + provider="anthropic" + ) + + + +def create_agent(): + """Create and return the LangGraph agent.""" + + # Initialize the LLM with tools + llm = create_llm() + tools = [check] + llm_with_tools = llm.bind_tools(tools) + + # Create tool lookup + tool_map = {tool.name: tool for tool in tools} + + # Define the agent node + def call_model(state: AgentState) -> dict: + """Call the LLM with the current state.""" + messages = state["messages"] + response = llm_with_tools.invoke(messages) + return {"messages": [response]} + + # Define the tool execution node + def call_tools(state: AgentState) -> dict: + """Execute tools based on the last message.""" + last_message = state["messages"][-1] + tool_messages = [] + + for tool_call in last_message.tool_calls: + tool_name = tool_call["name"] + tool_args = tool_call["args"] + + if tool_name in tool_map: + result = tool_map[tool_name].invoke(tool_args) + tool_messages.append( + ToolMessage(content=str(result), tool_call_id=tool_call["id"]) + ) + else: + tool_messages.append( + ToolMessage( + content=f"Tool {tool_name} not found", + tool_call_id=tool_call["id"], + ) + ) + + return {"messages": tool_messages} + + # Define the routing function + def should_continue(state: AgentState) -> Literal["tools", "end"]: + """Determine whether to continue with tools or end.""" + last_message = state["messages"][-1] + if hasattr(last_message, "tool_calls") and last_message.tool_calls: + return "tools" + return "end" + + # Build the graph + workflow = StateGraph(AgentState) + + # Add nodes + workflow.add_node("agent", call_model) + workflow.add_node("tools", call_tools) + + # Set entry point + workflow.set_entry_point("agent") + + # Add conditional edges + workflow.add_conditional_edges( + "agent", + should_continue, + { + "tools": "tools", + "end": END, + }, + ) + + # Add edge from tools back to agent + workflow.add_edge("tools", "agent") + + # Compile the graph + return workflow.compile() + + +def run_agent(query: str,code:str) -> str: + """ + Run the agent with a given query. + + Args: + query: The user's question or request + + Returns: + The agent's final response + """ + agent = create_agent() + SYSTEM_PROMPT = """You are a AI assistant responsible to check if a person is Allowed or Denied acces to medical procedure based on the following rules: + +"""+RULES[code]+"""" +<\rules> +Also this is the required documentation for aproval, try to indetify every document as one of these, or not identified: +"""+MIN_DOC[code]+"""" +Your capabilities: +- You can check the OCR of anexed documents if the json input is not enough to determinate if it should be aproved, using the check tool. + + +Start your answer with either: + Aproved: if any of the rules are met, firts look only at the input, then check the file + Reproved: If there aren't any rules met. + + And list the document classification and the met criteira, in case of aprovation. Be really precise and succint""" + + initial_state = { + "messages": [ + SystemMessage(content=SYSTEM_PROMPT), + HumanMessage(content=query) + ] + } + + print(f"\nUser: {query}") + print("-" * 50) + + # Run the agent + final_state = agent.invoke(initial_state) + + # Get the final response + final_message = final_state["messages"][-1] + response = final_message.content if hasattr(final_message, "content") else str(final_message) + + print(f"Agent: {response}") + return response + + +def get_textract_folder_for_guia(numero_guia: str) -> Path | None: + """Find the textract output folder that starts with the numeroGuia.""" + for folder in TEXTRACT_OUTPUT_DIR.iterdir(): + if folder.is_dir() and folder.name.startswith(numero_guia): + return folder + return None + + +def load_txt_files_from_folder(folder: Path) -> str: + """Load and concatenate all .txt files from a folder.""" + content_parts = [] + for txt_file in sorted(folder.glob("*.txt")): + content_parts.append(f"--- {txt_file.name} ---\n{txt_file.read_text()}") + return "\n\n".join(content_parts) + + +def main(): + """Main function to process JSON files and run the agent.""" + global FILE + + print("=" * 60) + print("LangGraph Agent with AWS Bedrock") + print("=" * 60) + + # Prepare CSV output + output_csv_path = SCRIPTS_DIR / "agent_results.csv" + results = [] + + # Iterate over all JSON files in json_output folder + for json_file in sorted(JSON_OUTPUT_DIR.glob("*.json")): + print(f"\nProcessing: {json_file.name}") + print("-" * 60) + + # Load JSON data + with open(json_file, "r", encoding="utf-8") as f: + data = json.load(f) + + # Get numeroGuia + numero_guia = data.get("numeroGuia") + nome_beneficiario = data.get("nomeBeneficiario", "") + resultado_da_analise = data.get("Resultado_da_analise", "") + por_que_libera = data.get("Por_que_libera?", "") + + # Skip if numeroGuia is NaN or None + if numero_guia is None or (isinstance(numero_guia, float) and str(numero_guia) == "nan"): + skip_reason = "numeroGuia is NaN or missing" + print(f" Skipping: {skip_reason}") + results.append({ + "numeroGuia": str(numero_guia) if numero_guia else "", + "nomeBeneficiario": nome_beneficiario, + "Resultado_da_analise": resultado_da_analise, + "Por_que_libera": por_que_libera, + "agent_output": f"SKIPPED: {skip_reason}" + }) + continue + + numero_guia = str(numero_guia) + print(f" numeroGuia: {numero_guia}") + + # Find corresponding textract folder + textract_folder = get_textract_folder_for_guia(numero_guia) + if textract_folder is None: + skip_reason = f"No textract folder found for {numero_guia}" + print(f" Skipping: {skip_reason}") + results.append({ + "numeroGuia": numero_guia, + "nomeBeneficiario": nome_beneficiario, + "Resultado_da_analise": resultado_da_analise, + "Por_que_libera": por_que_libera, + "agent_output": f"SKIPPED: {skip_reason}" + }) + continue + + print(f" Textract folder: {textract_folder.name}") + + # Load txt files content into FILE global variable + FILE = load_txt_files_from_folder(textract_folder) + + # Get codigoServico and convert to numerical string (remove dots/special chars) + codigo_servico = data.get("codigoServico", "") + code = "".join(c for c in str(codigo_servico) if c.isdigit()) + + # Skip if code not in RULES + if code not in RULES: + skip_reason = f"codigoServico '{codigo_servico}' (code: {code}) not in RULES" + print(f" Skipping: {skip_reason}") + results.append({ + "numeroGuia": numero_guia, + "nomeBeneficiario": nome_beneficiario, + "Resultado_da_analise": resultado_da_analise, + "Por_que_libera": por_que_libera, + "agent_output": f"SKIPPED: {skip_reason}" + }) + continue + + print(f" codigoServico: {codigo_servico} -> code: {code}") + + # Remove fields that should not be sent to the agent + fields_to_drop = ["Resultado_da_analise", "Onde_foi_liberado", "Canal_de_entrada", "Por_que_libera?"] + for field in fields_to_drop: + data.pop(field, None) + + # Run the agent with the JSON data as query + query = json.dumps(data, indent=2, ensure_ascii=False) + agent_output = run_agent(query, code) + + # Add result to list + results.append({ + "numeroGuia": numero_guia, + "nomeBeneficiario": nome_beneficiario, + "Resultado_da_analise": resultado_da_analise, + "Por_que_libera": por_que_libera, + "agent_output": agent_output + }) + + print("\n" + "=" * 60) + + # Write results to CSV + with open(output_csv_path, "w", encoding="utf-8", newline="") as csvfile: + fieldnames = ["numeroGuia", "nomeBeneficiario", "Resultado_da_analise", "Por_que_libera", "agent_output"] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + writer.writeheader() + writer.writerows(results) + + print(f"\nResults saved to: {output_csv_path}") + + +if __name__ == "__main__": + main()