0 Seguidores · 26 Postagens

Health Level-7 or HL7 refere-se a um conjunto de padrões internacionais para transferência de dados clínicos e administrativos entre aplicações de software usados por vários provedores em saúde.

Saber mais

Artigo Heloisa Paiva · Out. 19, 2025 14m read

Visão Geral

Esta interface web foi projetada para facilitar o gerenciamento de Tabelas de Pesquisa de Dados (Data Lookup Tables) por meio de uma página web amigável. É particularmente útil quando os valores da sua tabela de pesquisa são grandes, dinâmicos e mudam frequentemente. Ao conceder aos usuários finais acesso controlado a esta interface web (permissões de leitura, escrita e exclusão limitadas a esta página), eles podem gerenciar os dados da tabela de pesquisa de forma eficiente, de acordo com suas necessidades.

Os dados gerenciados por meio desta interface podem ser utilizados perfeitamente em regras ou transformações de dados do HealthConnect, eliminando a necessidade de constante monitoramento e gerenciamento manual das tabelas de pesquisa, economizando tempo significativo.

Nota: 

Se a Tabela de Pesquisa de Dados padrão não atender aos seus requisitos de mapeamento, você pode criar uma tabela personalizada e adaptar esta interface web, juntamente com sua classe de suporte, com modificações mínimas. O código de exemplo da classe está disponível mediante solicitação.

0
0 15
Artigo Heloisa Paiva · Out. 17, 2025 3m read

Para gerenciar o acúmulo de dados de produção, o InterSystems IRIS permite aos usuários controlar o tamanho do banco de dados eliminando (expurgando) periodicamente os dados. Esta purga pode ser aplicada a mensagens, registros, processos de negócio e alertas gerenciados.

Consulte a documentação para obter mais detalhes sobre a configuração da tarefa de expurgo:

https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=EGMG_purge#EGMG_purge_settings

0
0 16
Artigo Larissa Prussak · Jul. 3, 2025 2m read

Fazendo Profiling de Documentos CCD com o CCD Data Profiler da LEAD North

Já abriu um CCD e foi recebido por uma parede de XML confuso? Você não está sozinho. Apesar de ser um formato essencial para a troca de dados clínicos, os CCDs são notoriamente densos, verbosos e pouco amigáveis à leitura humana. Para desenvolvedores e analistas que tentam validar sua estrutura ou extrair informações significativas, navegar por esses documentos pode parecer mais arqueologia do que engenharia.

Apresentando o CCD Data Profiler

0
0 22
Artigo Danusa Calixto · jan 4, 2024 8m read

Introdução

Este artigo busca explorar o funcionamento e desenvolvimento do sistema FHIR-PEX, aproveitando os recursos do InterSystems IRIS.

Otimizando a identificação e o processamento de exames médicos nos centros de diagnóstico clínico, nosso sistema visa aumentar a eficiência e precisão dos fluxos de trabalho de saúde. Ao integrar os padrões FHIR ao banco de dados Java-PEX do InterSystems IRIS, o sistema ajuda os profissionais de saúde com recursos de validação e roteamento, melhorando, em última análise, a tomada de decisões e o cuidado dos pacientes.

como funciona

  • Interoperabilidade IRIS: Recebe mensagens no padrão FHIR, garantindo a integração e a compatibilidade com os dados da saúde.

  • Processamento de informações com "PEX Java": Processa mensagens no formato FHIR e as direciona a tópicos do Kafka com base nas regras configuradas globalmente no banco de dados, possibilitando um processamento e roteamento de dados eficiente, especialmente para exames direcionados à quarentena.

  • Tratamento de retornos do Kafka via back-end Java externo: Interpreta apenas os exames direcionados à quarentena, permitindo que o sistema trate os retornos do Kafka por um back-end Java externo. Facilita a geração de insights prognósticos para profissionais da saúde através de IA Generativa, contando com consultas de resultados de exames anteriores dos respectivos pacientes.

Desenvolvimento

Através do PEX (Production EXtension) da InterSystems, ferramenta de extensibilidade que permite aprimoramento e personalização do comportamento do sistema, elaboramos uma Operação de Negócios. Este componente tem a tarefa de processar mensagens recebidas no formato FHIR dentro do sistema. Veja este exemplo:

import com.intersystems.enslib.pex.*;
import com.intersystems.jdbc.IRISObject;
import com.intersystems.jdbc.IRIS;
import com.intersystems.jdbc.IRISList;
import com.intersystems.gateway.GatewayContext;

import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.*;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class KafkaOperation extends BusinessOperation {
// Conexão ao InterSystems IRIS
private IRIS iris;

// Conexão ao Kafka
private Producer<Long, String> producer;

// Endereço do servidor do Kafka (se forem vários, separados por vírgula)
public String SERVERS;

// Nome do nosso Produtor
public String CLIENTID;

/// Caminho para o arquivo Config
public String CONFIG;

public void OnInit() throws Exception {
[...]
}

public void OnTearDown() throws Exception {
[...]
}

public Object OnMessage(Object request) throws Exception {
    IRISObject req = (IRISObject) request;
    LOGINFO("Received object: " + req.invokeString("%ClassName", 1));

    // Crie o registro
    String value = req.getString("Text");
    String topic = getTopicPush(req);
    final ProducerRecord<Long, String> record = new ProducerRecord<>(topic, value);

    // Envie o novo registro
    RecordMetadata metadata = producer.send(record).get();

    // Retorne as informações do regitro
    IRISObject response = (IRISObject)(iris.classMethodObject("Ens.StringContainer","%New",topic+"|"+metadata.offset()));
    return response;
}

private Producer<Long, String> createProducer() throws IOException {
[...]
}

private String getTopicPush(IRISObject req) {
[...]
}

[...]
}

`

Dentro da aplicação, o método getTopicPush assume a responsabilidade de identificar o tópico para o qual a mensagem será enviada.

A determinação do tópico a que a mensagem será enviada depende da existência de uma regra na global "quarantineRule", conforme lido no IRIS.

String code = FHIRcoding.path("code").asText();
String system = FHIRcoding.path("system").asText();

IRISList quarantineRule = iris.getIRISList("quarantineRule",code,system);

 String reference = quarantineRule.getString(1);
 String value = quarantineRule.getString(2);

 String observationValue = fhir.path("valueQuantity").path("value").asText()

Quando há a global ^quarantineRule, a validação do objeto FHIR pode ser validada.

private boolean quarantineValueQuantity(String reference, String value, String observationValue) {
    LOGINFO("quarantine rule reference/value: " + reference + "/" + value);
    double numericValue = Double.parseDouble(value);
    double numericObservationValue = Double.parseDouble(observationValue);

    if ("<".equals(reference)) {
        return numericObservationValue < numericValue;
    }
    else if (">".equals(reference)) {
        return numericObservationValue > numericValue;
    }
    else if ("<=".equals(reference)) {
        return numericObservationValue <= numericValue;
    }
    else if (">=".equals(reference)) {
        return numericObservationValue >= numericValue;
    }
    
    return false;
}

Exemplo prático:

Ao definir uma global, como:

Set ^quarantineRule("59462-2","http://loinc.org") = $LB(">","500") 

Isso estabelece uma regra para o código "59462-2" e o sistema ""http://loinc.org"" na global ^quarantineRule, especificando uma condição em que o valor é definido como quarentena quando ultrapassa 500. No aplicativo, o método getTopicPush pode então usar essa regra para determinar o tópico apropriado para enviar a mensagem com base no resultado da validação.

Dada a atribuição, o JSON abaixo seria enviado para quarentena, porque corresponde à condição especificada por ter:

 {
          "system": "http://loinc.org",
          "code": "59462-2",
          "display": "Testosterone"
}

"valueQuantity": { "value": 550, "unit": "ng/dL", "system": "http://unitsofmeasure.org", "code": "ng/dL" }

Observação FHIR:

{
    "resourceType": "Observation",
    "id": "3a8c7d54-1a2b-4c8f-b54a-3d2a7efc98c9",
    "status": "final",
    "category": [
      {
        "coding": [
          {
            "system": "http://terminology.hl7.org/CodeSystem/observation-category",
            "code": "laboratory",
            "display": "laboratory"
          }
        ]
      }
    ],
    "code": {
      "coding": [
        {
          "system": "http://loinc.org",
          "code": "59462-2",
          "display": "Testosterone"
        }
      ],
      "text": "Testosterone"
    },
    "subject": {
      "reference": "urn:uuid:274f5452-2a39-44c4-a7cb-f36de467762e"
    },
    "encounter": {
      "reference": "urn:uuid:100b4a8f-5c14-4192-a78f-7276abdc4bc3"
    },
    "effectiveDateTime": "2022-05-15T08:45:00+00:00",
    "issued": "2022-05-15T08:45:00.123+00:00",
    "valueQuantity": {
      "value": 550,
      "unit": "ng/dL",
      "system": "http://unitsofmeasure.org",
      "code": "ng/dL"
    }
}

O aplicativo Quarkus Java

Após o envio para o tópico desejado, um aplicativo Quarkus Java foi criado para receber exames em quarentena.

@ApplicationScoped
 public class QuarentineObservationEventListener {

@Inject
PatientService patientService;

@Inject
EventBus eventBus;

@Transactional
@Incoming("observation_quarantine")
public CompletionStage<Void> onIncomingMessage(Message<QuarentineObservation> quarentineObservationMessage) {
	var quarentineObservation = quarentineObservationMessage.getPayload();
	var patientId = quarentineObservation.getSubject()
			.getReference();
	var patient = patientService.addObservation(patientId, quarentineObservation);
	publishSockJsEvent(patient.getId(), quarentineObservation.getCode()
			.getText());
	return quarentineObservationMessage.ack();
}

private void publishSockJsEvent(Long patientId, String text) {
	eventBus.publish("monitor", MonitorEventDto.builder()
			.id(patientId)
			.message(" is on quarentine list by observation ." + text)
			.build());
}
 }

Esse segmento do sistema tem a tarefa de persistir as informações recebidas de Kafka, armazená-las nas observações do paciente no banco de dados e notificar a ocorrência ao monitor.

O monitor

Por fim, o monitor do sistema é responsável por fornecer uma visualização simples do front-end. Isso permite que os profissionais de saúde revisem os dados do paciente/exame e realizem as ações necessárias.

Implementação de langchainPT

Através do monitor, o sistema permite que os profissionais de saúde solicitem recomendações da IA ​​Generativa.

@Unremovable
@Slf4j
@ApplicationScoped
public class PatientRepository {
	@Tool("Get anamnesis information for a given patient id")
	public Patient getAnamenisis(Long patientId) {
		log.info("getAnamenisis called with id " + patientId);
		Patient patient = Patient.findById(patientId);
		return patient;
	}

	@Tool("Get the last clinical results for a given patient id")
	public List<Observation> getObservations(Long patientId) {
		log.info("getObservations called with id " + patientId);
		Patient patient = Patient.findById(patientId);
		return patient.getObservationList();
	}

}

segue implementação de langchain4j

@RegisterAiService(chatMemoryProviderSupplier = RegisterAiService.BeanChatMemoryProviderSupplier.class, tools = {PatientRepository.class})
public interface PatientAI {

	@SystemMessage("""
			You are a health care assistant AI. You have to recommend exams for patients based on history information.
			""")
	@UserMessage("""
			 Your task is to recommend clinical exams for the patient id {patientId}.

			 To complete this task, perform the following actions:
			 1 - Retrieve anamnesis information for patient id {patientId}.
			 2 - Retrieve the last clinical results for patient id {patientId}, using the property 'name' as the name of exam and 'value' as the value.
			 3 - Analyse results against well known conditions of health care.

			 Answer with a **single** JSON document containing:
			 - the patient id in the 'patientId' key
			 - the patient weight in the 'weight' key
			 - the exam recommendation list in the 'recommendations' key, with properties exam, reason and condition.
			 - the 'explanation' key containing an explanation of your answer, especially about well known diseases.

			Your response must be just the raw JSON document, without ```json, ``` or anything else.
			 """)
	String recommendExams(Long patientId);
}

Dessa forma, o sistema pode auxiliar os profissionais de saúde a tomar decisões e realizar ações.

Vídeo de demonstração

VÍDEO

Autores

OBSERVAÇÃO:

O aplicativo https://openexchange.intersystems.com/package/fhir-pex está participando atualmente do InterSystems Java Contest 2023. Sinta-se à vontade para explorar a solução e não hesite em entrar em contato se tiver alguma dúvida ou precisar de informações adicionais. Recomendamos executar o aplicativo em seu ambiente local para uma experiência prática. Obrigado pela oportunidade 😀!

0
0 85
Artigo Davi Massaru Teixeira Muta · Nov. 26, 2023 9m read

Introdução

Este artigo tem como objetivo explorar como o sistema FHIR-PEX funciona e foi desenvolvido, aproveitando os recursos do InterSystems IRIS.

Agilizando a identificação e o processamento de exames médicos em centros de diagnóstico clínico, nosso sistema visa aumentar a eficiência e a precisão dos fluxos de trabalho de saúde. Ao integrar os padrões FHIR com o banco de dados Java-PEX da InterSystems IRIS, o sistema ajuda os profissionais de saúde com recursos de validação e roteamento, contribuindo, em última análise, para melhorar a tomada de decisões e o atendimento ao paciente.

como funciona

  • Interoperabilidade IRIS: Recebe mensagens no padrão FHIR, garantindo integração e compatibilidade com dados de saúde.

  • Processamento de informações com 'PEX Java': Processa mensagens no formato FHIR e as direciona para tópicos Kafka com base em regras configuradas globalmente no banco de dados, facilitando o processamento e roteamento eficiente de dados, principalmente para exames direcionados à quarentena.

  • Tratamento de devoluções Kafka via back-end Java externo: Interpreta apenas os exames direcionados à quarentena, permitindo que o sistema trate os retornos do Kafka por meio de um backend Java externo. Facilita a geração de insights prognósticos para profissionais de saúde através de IA Generativa, contando com consultas de resultados de exames anteriores dos respectivos pacientes.

 

Desenvolvimento

Através do PEX (Production EXtension) da InterSystems, ferramenta de extensibilidade que permite aprimoramento e customização do comportamento do sistema, elaboramos uma Operação de Negócio. Este componente tem a tarefa de processar mensagens recebidas no formato FHIR dentro do sistema.

Segue exemplo:

    import com.intersystems.enslib.pex.;     import com.intersystems.jdbc.IRISObject;     import com.intersystems.jdbc.IRIS;     import com.intersystems.jdbc.IRISList;     import com.intersystems.gateway.GatewayContext;          import org.apache.kafka.clients.producer.;     import org.apache.kafka.common.serialization.*;          import com.fasterxml.jackson.databind.JsonNode;     import com.fasterxml.jackson.databind.ObjectMapper;          import java.io.FileInputStream;     import java.io.IOException;     import java.util.Properties;

    public class KafkaOperation extends BusinessOperation {     // Connection to InterSystems IRIS     private IRIS iris;          // Connection to Kafka     private Producer<Long, String> producer;          // Kafka server address (comma separated if several)     public String SERVERS;          // Name of our Producer     public String CLIENTID;          /// Path to Config File     public String CONFIG;          public void OnInit() throws Exception {     [...]     }          public void OnTearDown() throws Exception {     [...]     }          public Object OnMessage(Object request) throws Exception {         IRISObject req = (IRISObject) request;         LOGINFO("Received object: " + req.invokeString("%ClassName", 1));              // Create record         String value = req.getString("Text");         String topic = getTopicPush(req);         final ProducerRecord<Long, String> record = new ProducerRecord<>(topic, value);              // Send new record         RecordMetadata metadata = producer.send(record).get();              // Return record info         IRISObject response = (IRISObject)(iris.classMethodObject("Ens.StringContainer","%New",topic+"|"+metadata.offset()));         return response;     }          private Producer<Long, String> createProducer() throws IOException {     [...]     }          private String getTopicPush(IRISObject req) {     [...]     }          [...]     } `

Dentro da aplicação, o método getTopicPush assume a responsabilidade de identificar o tópico para o qual a mensagem será enviada.

A determinação para qual tópico a mensagem será enviada depende da existência de uma regra na “quarantineRule” global, conforme lida dentro do IRIS.

    String code = FHIRcoding.path("code").asText();     String system = FHIRcoding.path("system").asText();

    IRISList quarantineRule = iris.getIRISList("quarantineRule",code,system);

     String reference = quarantineRule.getString(1);      String value = quarantineRule.getString(2);

     String observationValue = fhir.path("valueQuantity").path("value").asText()

Quando o ^quarantineRule global existe, a validação do objeto FHIR pode ser validada.

    private boolean quarantineValueQuantity(String reference, String value, String observationValue) {         LOGINFO("quarantine rule reference/value: " + reference + "/" + value);         double numericValue = Double.parseDouble(value);         double numericObservationValue = Double.parseDouble(observationValue);

        if ("<".equals(reference)) {             return numericObservationValue < numericValue;         }         else if (">".equals(reference)) {             return numericObservationValue > numericValue;         }         else if ("<=".equals(reference)) {             return numericObservationValue <= numericValue;         }         else if (">=".equals(reference)) {             return numericObservationValue >= numericValue;         }                  return false;     }

Exemplo prático:

Ao definir um global, como:

    Set ^quarantineRule("59462-2","http://loinc.org") = $LB(">","500") 

Isso estabelece uma regra para o código "59462-2" e o sistema ""http://loinc.org"" na ^quarantineRule global, especificando uma condição onde o valor quando maior que 500 é definido como quarentena. No aplicativo, o método getTopicPush pode então usar essa regra para determinar o tópico apropriado para enviar a mensagem com base no resultado da validação.

Dada a atribuição, o JSON abaixo seria enviado para quarentena, pois corresponde à condição especificada por ter:

 {
          "system": "http://loinc.org",
          "code": "59462-2",
          "display": "Testosterone"
}

"valueQuantity": { "value": 550, "unit": "ng/dL", "system": "http://unitsofmeasure.org", "code": "ng/dL" }

FHIR Observation:

{
    "resourceType": "Observation",
    "id": "3a8c7d54-1a2b-4c8f-b54a-3d2a7efc98c9",
    "status": "final",
    "category": [
      {
        "coding": [
          {
            "system": "http://terminology.hl7.org/CodeSystem/observation-category",
            "code": "laboratory",
            "display": "laboratory"
          }
        ]
      }
    ],
    "code": {
      "coding": [
        {
          "system": "http://loinc.org",
          "code": "59462-2",
          "display": "Testosterone"
        }
      ],
      "text": "Testosterone"
    },
    "subject": {
      "reference": "urn:uuid:274f5452-2a39-44c4-a7cb-f36de467762e"
    },
    "encounter": {
      "reference": "urn:uuid:100b4a8f-5c14-4192-a78f-7276abdc4bc3"
    },
    "effectiveDateTime": "2022-05-15T08:45:00+00:00",
    "issued": "2022-05-15T08:45:00.123+00:00",
    "valueQuantity": {
      "value": 550,
      "unit": "ng/dL",
      "system": "http://unitsofmeasure.org",
      "code": "ng/dL"
    }
}

### Quarkus Java application

Após o envio para o tópico desejado, foi construída uma aplicação Quarkus Java para recebimento de exames em quarentena.

    @ApplicationScoped      public class QuarentineObservationEventListener {

    @Inject     PatientService patientService;

    @Inject     EventBus eventBus;

    @Transactional     @Incoming("observation_quarantine")     public CompletionStage<Void> onIncomingMessage(Message<QuarentineObservation> quarentineObservationMessage) {         var quarentineObservation = quarentineObservationMessage.getPayload();         var patientId = quarentineObservation.getSubject()                 .getReference();         var patient = patientService.addObservation(patientId, quarentineObservation);         publishSockJsEvent(patient.getId(), quarentineObservation.getCode()                 .getText());         return quarentineObservationMessage.ack();     }

    private void publishSockJsEvent(Long patientId, String text) {         eventBus.publish("monitor", MonitorEventDto.builder()                 .id(patientId)                 .message(" is on quarentine list by observation ." + text)                 .build());     }      }

Este segmento do sistema tem a tarefa de persistir as informações recebidas de Kafka, armazená-las nas observações do paciente no banco de dados e notificar a ocorrência ao monitor.

O monitor

Por fim, o monitor do sistema é responsável por fornecer uma visualização simples do front-end. Isso permite que os profissionais de saúde revisem os dados do paciente/exame e tomem as ações necessárias.

Implementação of langchain

Através do monitor, o sistema permite que os profissionais de saúde solicitem recomendações da IA ​​Generativa.

    @Unremovable     @Slf4j     @ApplicationScoped     public class PatientRepository {         @Tool("Get anamnesis information for a given patient id")         public Patient getAnamenisis(Long patientId) {             log.info("getAnamenisis called with id " + patientId);             Patient patient = Patient.findById(patientId);             return patient;         }              @Tool("Get the last clinical results for a given patient id")         public List<Observation> getObservations(Long patientId) {             log.info("getObservations called with id " + patientId);             Patient patient = Patient.findById(patientId);             return patient.getObservationList();         }          }

segue implementação de langchain4j

    @RegisterAiService(chatMemoryProviderSupplier = RegisterAiService.BeanChatMemoryProviderSupplier.class, tools = {PatientRepository.class})     public interface PatientAI {              @SystemMessage("""                 You are a health care assistant AI. You have to recommend exams for patients based on history information.                 """)         @UserMessage("""                  Your task is to recommend clinical exams for the patient id {patientId}.                       To complete this task, perform the following actions:                  1 - Retrieve anamnesis information for patient id {patientId}.                  2 - Retrieve the last clinical results for patient id {patientId}, using the property 'name' as the name of exam and 'value' as the value.                  3 - Analyse results against well known conditions of health care.                       Answer with a single JSON document containing:                  - the patient id in the 'patientId' key                  - the patient weight in the 'weight' key                  - the exam recommendation list in the 'recommendations' key, with properties exam, reason and condition.                  - the 'explanation' key containing an explanation of your answer, especially about well known diseases.                      Your response must be just the raw JSON document, without json, or anything else.                  """)         String recommendExams(Long patientId);     }

Dessa forma, o sistema pode auxiliar os profissionais de saúde na tomada de decisões e na execução de ações.

Video demonstração 

VIDEO

Autores

NOTA: 

O aplicativo https://openexchange.intersystems.com/package/fhir-pex está participando atualmente do InterSystems Java Contest 2023. Sinta-se à vontade para explorar a solução e não hesite em entrar em contato se tiver alguma dúvida ou precisar de informações adicionais. Recomendamos executar o aplicativo em seu ambiente local para uma experiência prática. Obrigado pela oportunidade 😀!

Artigo original: https://community.intersystems.com/post/sending-kafka-messages-java-pex-processing-quarantine-exam-prognoses

0
0 147
Artigo Danusa Calixto · Set. 1, 2023 12m read

Uma tarefa "grande" ou "pequena" para o ChatGPT?

Eu testei o modelo de programação do GPT da OpenAI há algumas semanas, para ver se ele consegue, por exemplo, fazer algumas transformações de mensagens entre protocolos de saúde. Ele "consegue", em um nível aparentemente razoável. 

Já faz quase 3 semanas, o que é um tempo bastante longo para o ChatGPT, então me pergunto com que rapidez ele cresce e se poderia fazer alguns jobs de engenharia de integração para nós. Por exemplo, ele consegue criar uma ferramenta DTL de COS da InterSystems para transformar o HL7 em uma mensagem FHIR? 

Imediatamente, obtive algumas respostas rápidas, em menos de um ou dois minutos.

##Teste

Primeiro, quero testar se estou falando com o "cara" certo.


Pergunta 1:  como converter mensagens HL7 V2.4 para FHIR STU3?


ChatGPT:

A conversão de mensagens HL7 V2.4 em FHIR STU3 envolve várias etapas, já que os dois padrões têm modelos e estruturas de dados diferentes. Aqui está uma visão geral de alto nível do processo:

  1. Identifique os elementos de dados relevantes na mensagem HL7 que precisam ser mapeados para os recursos FHIR. Isso dependerá do caso de uso específico e dos dados sendo trocados.
  2. Defina as regras de mapeamento para cada elemento de dados. Isso envolve identificar o recurso FHIR equivalente e o elemento que corresponde ao elemento de dados HL7 e qualquer transformação ou tradução necessária.
  3. Escreva um programa ou um script que consiga extrair os dados da mensagem HL7, aplicar as regras de mapeamento e criar recursos FHIR correspondentes. Isso talvez envolva usar uma combinação de expressões regulares, bibliotecas de análise sintática e bibliotecas de criação de recursos FHIR.
  4. Valide os recursos FHIR em relação à especificação STU3 para garantir que estejam em conformidade com o padrão e tenham todos os elementos necessários.

Aqui está um exemplo de como pode ser o processo de conversão de uma mensagem de observação HL7 V2.4 para um recurso FHIR STU3 Observation:

  1. Identifique os elementos de dados relevantes na mensagem HL7, como o código de observação, o valor e as unidades.
  2. Defina as regras de mapeamento para cada elemento de dados, como o mapeamento do código de observação HL7 para um CodeableConcept FHIR e o valor e as unidades para uma Quantity FHIR.
  3. Escreva um programa ou um script que consiga extrair dados da mensagem HL7, aplicar as regras de mapeamento e criar um recurso FHIR Observation com os elementos apropriados.
  4. Valide o recurso FHIR Observation em relação à especificação STU3 para garantir que tenha todos os elementos necessários e seja válido.

Os detalhes específicos da implementação dependerão da linguagem de programação e das bibliotecas usadas, além da mensagem HL7 específica e do recurso FHIR mapeado. É recomendável consultar as especificações HL7 e FHIR e buscar conselhos de especialistas, se necessário.


Além de estar correto, ele responde de maneira mais detalhada do que a maioria dos humanos. Isso chamou minha atenção, então vamos começar.   
 


Pergunta 2: Você pode criar uma amostra de transformação no Python para converter HL7 em FHIR?  


ChatGPT:

Claro! Aqui está uma amostra de snippet de código do Python que demonstra como converter uma mensagem HL7 em um recurso FHIR STU3 Observation:

fromhl7apyimportcorefromfhir.resources.observationimportObservation
# ParsetheHL7messagehl7_message = 'MSH|^~\&|SENDING_APP|SENDING_FACILITY|RECEIVING_APP|RECEIVING_FACILITY|20220527120512||ORU^R01|MSGID12345|P|2.4\r' \
              'OBX|1|NM|GLU^Glucose||100|mg/dL||N|||F|||20220527120512\r'
hl7_parsed = core.parse_message(hl7_message)

# MapHL7elementstoFHIRelementsobservation = Observation()

observation.code = {
    "coding": [{
        "system": "http://loinc.org",
        "code": hl7_parsed.obx[0].observation_id.value,
        "display": hl7_parsed.obx[0].observation_id.value
    }]
}

observation.valueQuantity = {
    "value": hl7_parsed.obx[0].value.value,
    "unit": hl7_parsed.obx[0].units.value,
    "system": "http://unitsofmeasure.org",
    "code": hl7_parsed.obx[0].units.value
}

# Serialize the FHIR resource as JSON
observation_json = observation.json()

# Print the serialized FHIR resource
print(observation_json)



Esse código usa a biblioteca hl7apy para analisar a mensagem HL7 e extrair os elementos de dados relevantes e a classe fhir.resources.observation do módulo fhir.resources pra criar um recurso FHIR Observation.

Nesse exemplo, o código mapeia o ID de observação HL7 para o elemento de código FHIR, e o valor e as unidades HL7 para o elemento FHIR valueQuantity. O recurso FHIR é depois serializado como JSON usando o método json().

Observe que esse é um exemplo simples e você talvez precise mapear mais elementos de dados dependendo do caso de uso específico. Além disso, você precisará instalar as bibliotecas hl7apy e fhir.resources para executar esse código.


Não é uma resposta nada ruim — fornece um código boilerplate decente. Vamos dar um desafio um pouco específico agora: 


Pergunta 3: Você pode fornecer uma amostra de transformação do HL7 V2 para FHIR Stu3 na DTL do COS da InterSystems?


ChatGPT:


Com certeza! Aqui está um exemplo de como transformar uma mensagem HL7 V2 em um recurso FHIR STU3 Observation na DTL (Linguagem de Transformação de Dados) do COS da InterSystems:

Class DTL.HL7toFHIR Extends%RegisteredObject
{

ClassMethod TransformHL7ToObservation(hl7Message As%String) As%String [ CodeMode = expression, DDLAllowed = 0 ]
{
    set src = ##class(EnsLib.HL7.Message).%New()
    set src.DocType = "2.4"
    set src.Parse(hl7Message)

    set obs = ##class(FHIR.Resource.Observation).%New()
    set obs.subject = { "reference": "Patient/"_src.MSH.GetSendingApplication() }
    set obs.status = "final"
    set loincCode = src.GetSegment("OBX", 1).GetField(3).GetField(1)
    set obs.code = { 
        "coding": [ 
            {
                "system": "http://loinc.org", 
                "code": loincCode, 
                "display": loincCode 
            }
        ]
    }

    set value = src.GetSegment("OBX", 1).GetField(5).GetField(1)
    set units = src.GetSegment("OBX", 1).GetField(6).GetField(1)
    set obs.valueQuantity = { 
        "value": value, 
        "unit": units, 
        "system": "http://unitsofmeasure.org", 
        "code": units 
    }

    quit obs.%ToJSON()
}

}

Esse código define um método de classe chamado TransformHL7ToObservation, que pega uma mensagem HL7 V2 como entrada e retorna um recurso FHIR STU3 Observation como uma string JSON.

O método primeiro cria um novo objeto EnsLib.HL7.Message e o usa para analisar a mensagem HL7 de entrada. Em seguida, ele cria um novo objeto FHIR.Resource.Observation e define os elementos subject e status.

Depois, o código extrai o LOINC, o valor e as unidades da mensagem HL7 e os mapeia para os elementos correspondentes no recurso FHIR.

Por fim, o método serializa o recurso FHIR como JSON e o retorna.

Para usar esse método de classe, você pode chamá-lo de outro método COS ou de um sistema externo usando a API REST da InterSystems. Aqui está um exemplo de como chamar o método de outro método COS:

set hl7Message = "MSH|^~\&|SENDING_APP|SENDING_FACILITY|RECEIVING_APP|RECEIVING_FACILITY|20220527120512||ORU^R01|MSGID12345|P|2.4\rOBX|1|NM|GLU^Glucose||100|mg/dL||N|||F|||20220527120512\r"set fhirObservation = ##class(DTL.HL7toFHIR).TransformHL7ToObservation(hl7Message)
write fhirObservation

Você precisará definir as classes EnsLib.HL7.Message e FHIR.Resource.Observation no seu ambiente da InterSystems e ter as permissões apropriadas para executar o código COS.


Essa é provavelmente a resposta mais eficaz e completa que poderíamos esperar em cerca de 25 segundos. Não é?

(Observação: a amostra COS acima não é perfeitamente precisa. É só uma estrutura boilerplate e precisa de mais ajustes para implementações reais. Como @Tete Zhang gentilmente indicou, a classe de mensagem HL7 do nível Ensemble usa ImportFromSting() em vez de Parse(); DocType deve ser mais específico etc. E, aparentemente, parece criar uma nova hierarquia de classe FHIR por conta própria do zero, em vez de usar a canalização FHIR STU3 integrada do HealthShare existente. Seu "raciocínio" parece seguir a resposta anterior da estrutura do Python. Ele não vai ganhar uma certificação Ensemble ou HealthShare por enquanto e tem muito a aprender com mais interações especializadas. No entanto, como uma desculpa, talvez tenhamos que perdoá-lo pelo seu primeiro teste em menos de 2 minutos até o momento.  )   
  

Agora que estamos aqui, precisamos ser justos com as outras opções amplamente usadas que também tenho gostado. Então, continuei com mais algumas perguntas e um pouco mais de fé:


Pergunta 4: Você pode fornecer uma amostra de transformação do HL7 V2 par FHIR Stu3 no Orion Rhapsody?


ChatGPT:

Com certeza! Aqui está um exemplo de como transformar uma mensagem HL7 V2 para um recurso FHIR STU3 Observation no Orion Rhapsody:

  1. Primeiro, crie um novo canal do Rhapsody e adicione um componente do Conector HL7 para receber a mensagem HL7 V2 de entrada.
  2. Adicione um novo componente de Transformação de Dados ao canal e o configure para usar um script personalizado.
  3. No componente de Transformação de Dados, adicione o seguinte script para transformar a mensagem HL7 V2 em um recurso FHIR STU3 Observation:
functiontransform(msg) {

    var hl7 = Packages.ca.uhn.hl7v2.model.v24.message.ORU_R01(msg.getRawData());

    var observation = new Packages.org.hl7.fhir.dstu3.model.Observation();
    observation.setStatus(Packages.org.hl7.fhir.dstu3.model.Observation.ObservationStatus.FINAL);

    var codeableConcept = new Packages.org.hl7.fhir.dstu3.model.CodeableConcept();
    var coding = new Packages.org.hl7.fhir.dstu3.model.Coding();
    coding.setSystem("http://loinc.org");
    coding.setCode(hl7.getRESPONSE().getORDER_OBSERVATION()[0].getOBR().getUniversalServiceIdentifier().getIdentifier().getValue());
    coding.setDisplay(hl7.getRESPONSE().getORDER_OBSERVATION()[0].getOBR().getUniversalServiceIdentifier().getText().getValue());
    codeableConcept.addCoding(coding);
    observation.setCode(codeableConcept);

    var quantity = new Packages.org.hl7.fhir.dstu3.model.Quantity();
    quantity.setValue(hl7.getRESPONSE().getORDER_OBSERVATION()[0].getOBSERVATION()[0].getOBX().getObservationValue()[0].getValue().getValue());
    quantity.setUnit(hl7.getRESPONSE().getORDER_OBSERVATION()[0].getOBSERVATION()[0].getOBX().getUnits().getText().getValue());
    observation.setValue(quantity);

    var reference = new Packages.org.hl7.fhir.dstu3.model.Reference();
    reference.setReference("Patient/" + hl7.getPATIENT_RESULT().getPATIENT().getPid3_PatientIdentifierList()[0].getID().getValue());
    observation.setSubject(reference);

    returnJSON.stringify(observation);
}
  1. Salve o script e teste a transformação enviando uma mensagem HL7 V2 para o canal. O recurso FHIR STU3 Observation transformado deve ser gerado pelo componente de Transformação de Dados no formato JSON.

Esse script usa as bibliotecas HAPI FHIR e HAPI HL7 v2, que estão incluídas no Orion Rhapsody. Ele começa analisando a mensagem HL7 V2 de entrada usando a biblioteca HAPI HL7.

Em seguida, o script cria um novo recurso FHIR STU3 Observation e define os elementos status, code, value e subject com base nos valores correspondentes na mensagem HL7.

Por fim, o script serializa o recurso FHIR como JSON e o retorna.

Esse é só um exemplo simples e talvez não funcione para todos os tipos de mensagem HL7 V2 ou recursos FHIR. Você pode precisar modificar o script para lidar com os diferentes tipos de mensagens ou mapear campos adicionais para o recurso FHIR.



**Pergunta 5 **Você pode criar uma amostra de transformação convertendo HL7 v2.4 em FHIR R4 no mecanismo de integração Mirth?


ChatGPT

Com certeza! Aqui está um exemplo de como transformar uma mensagem HL7 V2.4 para um recurso FHIR R4 Observation no Mirth:

  1. Primeiro, crie um novo canal do Mirth e adicione um conector de origem Listener HL7v2 para receber a mensagem HL7 V2 de entrada.
  2. Adicione um novo conector de destino do JavaScript Writer ao canal e o configure para usar um script personalizado.
  3. No conector JavaScript Writer, adicione o seguinte script para transformar a mensagem HL7 V2 em um recurso FHIR R4 Observation:
var hl7msg = msg['HL7v2 Message'].toString(); // get the HL7 V2 messagevar hl7data = Packages.ca.uhn.hl7v2.parser.Parser.parse(hl7msg); // parse the message with the HAPI HL7 parser// extract values from the HL7 message and create the FHIR resourcevar obs = new Packages.org.hl7.fhir.r4.model.Observation();
obs.setStatus(Packages.org.hl7.fhir.r4.model.Observation.ObservationStatus.FINAL);

var code = new Packages.org.hl7.fhir.r4.model.CodeableConcept();
code.addCoding()
  .setSystem("http://loinc.org")
  .setCode(hl7data.get("OBR-4-1").getValue())
  .setDisplay(hl7data.get("OBR-4-2").getValue());
obs.setCode(code);

var value = new Packages.org.hl7.fhir.r4.model.Quantity();
value.setValue(hl7data.get("OBX-5-1").getValue());
value.setUnit(hl7data.get("OBX-6").getValue());
obs.setValue(value);

var subject = new Packages.org.hl7.fhir.r4.model.Reference();
subject.setReference("Patient/" + hl7data.get("PID-3-1").getValue());
obs.setSubject(subject);

// output the FHIR resource as JSONvar json = org.hl7.fhir.r4.formats.JsonParser().setPrettyPrint(true).encodeResourceToString(obs);
return json;
  1. Salve o script e teste a transformação enviando uma mensagem HL7 V2 para o canal. O recurso FHIR R4 Observation transformado deve ser gerado pelo conector JavaScript Writer no formato JSON.

Esse script usa as bibliotecas HAPI FHIR e HAPI HL7 v2, que estão incluídas no Mirth. Ele começa extraindo a mensagem HL7 V2 do objeto de mensagem do Mirth e a analisando com o parser HAPI HL7.

Em seguida, o script cria um novo recurso FHIR R4 Observation e define os elementos status, code, value e subject com base nos valores correspondentes na mensagem HL7.

Por fim, o script serializa o recurso FHIR como JSON e o retorna.

Esse é só um exemplo simples e talvez não funcione para todos os tipos de mensagem HL7 V2 ou recursos FHIR. Você pode precisar modificar o script para lidar com os diferentes tipos de mensagens ou mapear campos adicionais para o recurso FHIR.


##Conclusões?

Não tenho mais nenhuma conclusão ou próximas etapas, já que até minha imaginação não consegue acompanhar seus saltos.  Parece que há poucas opções para mim agora: posso gastar tempo buscando os estilos de codificação imperfeitos ou repensar os problemas que eu ainda tiver em mais algumas semanas. Preciso pensar com mais cuidado do que nunca sobre o potencial disso. :)

Brincadeiras à parte, estou gostando de postar neste fórum (graças aos anfitriões), mas outro pensamento que me vem à mente é se isso poderia ser um facilitador importante para algum player de nicho competitivo entrar no mercado de consumo em massa, não é?   Por vários motivos, para se sentir realmente confortável com algumas linguagens de codificação e scripts, isso costumava levar anos, mas o cenário está mudando. O ChatGPT oferece documentação, instruções e amostras bem compostas e, nos próximos meses ou anos, talvez consiga também fabricar automaticamente as ferramentas de engenharia da sua escolha.  Ele parece ser capaz de nivelar o campo nas "linguagens" e, no final, o lado não funcional de recursos, como o desempenho, e as qualidades do serviço pareceriam mais  notáveis.  

0
0 105
Artigo Danusa Calixto · Ago. 11, 2023 12m read

Divertido ou não — quão sério é isso?

Os modelos de linguagem grande estão causando alguns fenômenos nos últimos meses. É claro que eu também estava testando o ChatGPT no final de semana passado, para sondar se ele poderia ser um complemento para alguns chatbots de IA "tradicionais" baseados em BERT que eu estava inventando, ou simplesmente os eliminaria. 

Um pensamento me veio à mente enquanto eu fazia os testes. Sendo um pouco teórico ou filosófico, os padrões de interoperabilidade, como HL7 e FHIR, são uma espécie de "linguagem", certo? O HL7 tem sua própria gramática, regras, vocabulário e até mesmo dialetos — todo sistema fala no seu próprio tom. Por isso, quando uma máquina se comunica com outra, elas precisam de um tradutor (por exemplo, uma transformação de DTL) para alcançar a compreensão mútua. 

Então, olhando em volta, tudo parece ser uma linguagem: codificação, python, javascript e COS são linguagens também. HL7, FHIR e até XML ou JSON são todos linguagens, exceto que são mais estruturados do que linguagens naturais, então devem ser mais fáceis para o GPT aprender? 

Não podemos começar simplesmente reutilizando o modelo de linguagem de programação pré-treinado do GPT para emular uma DTL? Ainda sem nenhum ajuste. Confira abaixo os resultados iniciais:

##Teste 

Modo:   Completo
Modelo:  code-davinci-002
Temperatura: 0
Comprimentomáximo: 1989
Outros:  Padrão
Sequências de interrupção: ###

##1. Transforme o HL7 ADT A01 em A05? 

Entrada:  

##### Translate this function from HL7 V2.8 ADT_A01 to HL7 V2.4 ADT_A05
### HL7 V2.8 ADT_A01 

    MSH|^~\&|ADT1|GOOD HEALTH HOSPITAL|GHH LAB, INC.|GOOD HEALTH HOSPITAL|198808181126|SECURITY|ADT^A01^ADT_A01|MSG00001|P|2.8||
    EVN|A01|200708181123||
    PID|1||PATID1234^5^M11^ADT1^MR^GOOD HEALTH HOSPITAL~123456789^^^USSSA^SS||EVERYMAN^ADAM^A^III||19610615|M||C|2222 HOME STREET^^GREENSBORO^NC^27401-1020|GL|(555) 555-2004|(555)555-2004||S||PATID12345001^2^M10^ADT1^AN^A|444333333|987654^NC|
    NK1|1|NUCLEAR^NELDA^W|SPO^SPOUSE||||NK^NEXT OF KIN
    PV1|1|I|2000^2012^01||||004777^ATTEND^AARON^A|||SUR||||ADM|A0|

### HL7 V2.4 ADT_A05

Saída:

MSH|^~\&|ADT1|GOOD HEALTH HOSPITAL|GHH LAB, INC.|GOOD HEALTH HOSPITAL|198808181126|SECURITY|ADT^A05^ADT_A05|MSG00001|P|2.4||
    EVN|A05|200708181123||
    PID|1||PATID1234^5^M11^ADT1^MR^GOOD HEALTH HOSPITAL~123456789^^^USSSA^SS||EVERYMAN^ADAM^A^III||19610615|M||C|2222 HOME STREET^^GREENSBORO^NC^27401-1020|GL|(555) 555-2004|(555)555-2004||S||PATID12345001^2^M10^ADT1^AN^A|444333333|987654^NC|
    NK1|1|NUCLEAR^NELDA^W|SPO^SPOUSE||||NK^NEXT OF KIN
    PV1|1|I|2000^2012^01||||004777^ATTEND^AARON^A|||SUR||||ADM|A0|

Não está exatamente correto, mas não é nada mal. Ele consegue aprender o vocabulário por natureza, embora não consiga entender o tipo doc ainda.
 

###2. OK, e o pipe e hat HL7 para XML?

##### Translate this function from HL7 to XML
### HL7 
    
    MSH|^~\&|ADT1|GOOD HEALTH HOSPITAL|GHH LAB, INC.|GOOD HEALTH HOSPITAL|198808181126|SECURITY|ADT^A01^ADT_A01|MSG00001|P|2.8||
    EVN|A01|200708181123||
    PID|1||PATID1234^5^M11^ADT1^MR^GOOD HEALTH HOSPITAL~123456789^^^USSSA^SS||EVERYMAN^ADAM^A^III||19610615|M||C|2222 HOME STREET^^GREENSBORO^NC^27401-1020|GL|(555) 555-2004|(555)555-2004||S||PATID12345001^2^M10^ADT1^AN^A|444333333|987654^NC|
    NK1|1|NUCLEAR^NELDA^W|SPO^SPOUSE||||NK^NEXT OF KIN
    PV1|1|I|2000^2012^01||||004777^ATTEND^AARON^A|||SUR||||ADM|A0|
     
### XML

 

Saída

<?xml version="1.0" encoding="UTF-8"?>
    <hl7:ADT_A01 xmlns:hl7="urn:hl7-org:v2xml">
      <hl7:MSH>
        <hl7:MSH.1>|</hl7:MSH.1>
        <hl7:MSH.2>^~\&amp;</hl7:MSH.2>
        <hl7:MSH.3>
          <hl7:HD.1>ADT1</hl7:HD.1>
        </hl7:MSH.3>
        <hl7:MSH.4>
          <hl7:HD.1>GOOD HEALTH HOSPITAL</hl7:HD.1>
        </hl7:MSH.4>
        <hl7:MSH.5>
          <hl7:HD.1>GHH LAB, INC.</hl7:HD.1>
        </hl7:MSH.5>
        <hl7:MSH.6>
          <hl7:HD.1>GOOD HEALTH HOSPITAL</hl7:HD.1>
        </hl7:MSH.6>
        <hl7:MSH.7>
          <hl7:TS.1>198808181126</hl7:TS.1>
        </hl7:MSH.7>
        <hl7:MSH.9>
          <hl7:MSG.1>ADT</hl7:MSG.1>
          <hl7:MSG.2>A01</hl7:MSG.2>
          <hl7:MSG.3>ADT_A01</hl7:MSG.3>
        </hl7:MSH.9>
        <hl7:MSH.10>MSG00001</hl7:MSH.10>
        <hl7:MSH.11>
          <hl7:PT.1>P</hl7:PT.1>
        </hl7:MSH.11>
        <hl7:MSH.12>
          <hl7:VID.1>2.8</hl7:VID.1>
        </hl7:MSH.12>
      </hl7:MSH>
      <hl7:EVN>
        <hl7:EVN.1>
          <hl7:ID.1>A01</hl7:ID.1>
        </hl7:EVN.1>
        <hl7:EVN.2>
          <hl7:TS.1>200708181123</hl7:TS.1>
        </hl7:EVN.2>
      </hl7:EVN>
      <hl7:PID>
        <hl7:PID.1>1</hl7:PID.1>
        <hl7:PID.3>
          <hl7:CX.1>PATID1234</hl7:CX.1>
          <hl7:CX.4>
            <hl7:HD.1>GOOD HEALTH HOSPITAL</hl7:HD.1>
          </hl7:CX.4>
          <hl7:CX.5>
            <hl7:HD.1>ADT1</hl7:HD.1>
          </hl7:CX.5>
          <hl7:CX.6>MR</hl7:CX.6>
        </hl7:PID.3>
        <hl7:PID.5>
          <hl7:XPN.1>EVERYMAN</hl7:XPN.1>
          <hl7:XPN.2>ADAM</hl7:XPN.2>
          <hl7:XPN.3>A</hl7:XPN.3>
          <hl7:XPN.4>III</hl7:XPN.4>
        </hl7:PID.5>
        <hl7:PID.7>
          <hl7:TS.1>19610615</hl7:TS.1>
        </hl7:PID.7>
        <hl7:PID.8>M</hl7:PID.8>
        <hl7:PID.10>
          <hl7:CE.1>C</hl7:CE.1>
        </hl7:PID.10>
        <hl7:PID.11>
          <hl7:XAD.1>2222 HOME STREET</hl7:XAD.1>
          <hl7:XAD.3>GREENSBORO</hl7:XAD.3>
          <hl7:XAD.4>NC</hl7:XAD.4>
          <hl7:XAD.5>27401-1020</hl7:XAD.5>
        </hl7:PID.11>
        <hl7:PID.13>
          <hl7:XTN.1>(555) 555-2004</hl7:XTN.1>
        </hl7:PID.13>
        <hl7:PID.14>
          <hl7:XTN.1>(555)555-2004</hl7:XTN.1>
        </hl7:PID.14>
       ... ...

Agora fica um pouco sério. Aparentemente, já está preparado de alguma forma.   Parece que 1- Não há problema em analisar as mensagens HL7 (o que não era fácil para uma máquina — no passado, precisaria de algumas ferramentas poderosas, como o esquema de doc virtual do ISC bem definido) ; 2- Não há problema em aprender os tipos de dados. 

3. Pipe e hat HL7 para JSON?

Saída:

{
        "MSH": {
            "MSH.1": "|",
            "MSH.2": "^~\\&",
            "MSH.3": {
                "HD.1": "ADT1"
            },
            "MSH.4": {
                "HD.1": "GOOD HEALTH HOSPITAL"
            },
            "MSH.5": {
                "HD.1": "GHH LAB, INC."
            },
            "MSH.6": {
                "HD.1": "GOOD HEALTH HOSPITAL"
            },
            "MSH.7": {
                "TS.1": "198808181126"
            },
            "MSH.9": {
                "MSG.1": "ADT",
                "MSG.2": "A01",
                "MSG.3": "ADT_A01"
            },
            "MSH.10": "MSG00001",
            "MSH.11": {
                "PT.1": "P"
            },
            "MSH.12": {
                "VID.1": "2.8"
            }
        },
        "EVN": {
            "EVN.1": {
                "ID.1": "A01"
            },
            "EVN.2": {
                "TS.1": "200708181123"
            }
        },
        "PID": {
            "PID.1": "1",
            "PID.3": [
                {
                    "CX.1": "PATID1234",
                    "CX.2": "5",
                    "CX.3": "M11",
                    "CX.4": "ADT1",
                    "CX.5": "MR",
                    "CX.6": "GOOD HEALTH HOSPITAL"
                },
                {
                    "CX.1": "123456789"
                },
                {
                    "CX.4": "USSSA",
                    "CX.5": "SS"
                }
            ],
            "PID.5": [
                {
                    "XPN.1": [
                        {
                            "FN.1": "EVERYMAN"
                        },
                        {
                            "ST.1": "ADAM"
                        },
                        {
                            "ST.2": "A"
                        },
                        {
                            "ST.3": "III"
                        }
                    ]
                }
            ],
            "PID.7": {
                "TS.1": "19610615"
            },
            "PID.8": {
                "IS.1": "M"
            },
            "PID.10": {
                "CE.1": "C"
            },
            "PID.11": [
                {
                    "XAD.1": [
                        {
                            "SAD.1": "2222 HOME STREET"
                        },
                        {
                            "SAD.3": "GREENSBORO"
                        },
                        {
                            "SAD.4": "NC"
                        },
                        {
                            "SAD.5": "27401-1020"
                        }
                    ]
                },
                {
                    "CE.1": "GL"
                }
            ],
            "PID.13": [
                {
                    "XTN.1": "(555) 555-2004"
                },
                {
                    "XTN.1": "(555)555-2004"
                }
            ],
            "PID.16": {
                "IS.1": "S"
            },
            "PID.19": [
                {
                    "CX.1": "PATID12345001",
                    "CX.2": "2",
                    "CX.3": "M10",
                    "CX.4": "ADT1",
                    "CX.5": "AN",
                    "CX.6": "A"
                },
                {
                    "CX.1": "444333333"
                },
                {
                    "CX.1": "987654",
                    "CX.5": "NC"
                }
            ]
        },
        "NK1": [
            {
                "NK1.1": "1",
                "NK1.2": [
                    {
                        "XPN.1": [
                            {
                                "FN.1": "NUCLEAR"
                            },
                            {
                                "ST.1": "NELDA"
                            },
                            {
                                "ST.2": "W"
                            }
                        ]
                    },
                    {
                        "CE.1": "SPO",
                        "CE.2": "SPOUSE"
                    }
                ]
            }
        ],
        "PV1": {
            "PV1.1": "1",
            "PV1.2": {
                "IS.1": "I"
            },
            "PV1.3": [
                {
                    "PL.1": "2000"
                },
                {
                    "PL.2": "2012"
                },
                {
                    "PL.3": "01"
                }
            ],
            "PV1.7": [
                {
                    "XCN.1": "004777"
                },
                {
                    "XCN.2": [
                        {
                            "FN.1": "ATTEND"
                        },
                        {
                            "ST.1": "AARON"
                        },
                        {
                            "ST.2": "A"
                        }
                    ]
                }
            ],
            "PV1.10": {
                "IS.1": "SUR"
            },
            "PV1.19": {
                "IS.1": "ADM"
            },
            "PV1.44": {
                "IS.1": "A0"
            }
        }
    }

         Novamente, parece que a análise está boa — tem implicações significativas: se a análise for concluída, posso praticamente transformar todos os tipos de dialetos  HL7 de vários sistemas em JSON analisado e executar qualquer tradutor, como Python, sem um mecanismo entre eles?

#4. HL7 para FHIR
 

Saída: 

```json
{
  "resourceType": "Bundle",
  "type": "message",
  "entry": [
    {
      "resource": {
        "resourceType": "MessageHeader",
        "eventCoding": {
          "system": "http://hl7.org/fhir/message-events",
          "code": "ADT_A01"
        },
        "destination": [
          {
            "endpoint": "http://localhost:8080/fhir/baseDstu3"
          }
        ],
        "source": {
          "name": "ADT1",
          "software": "GOOD HEALTH HOSPITAL",
          "endpoint": "http://localhost:8080/fhir/baseDstu3"
        },
        "timestamp": "2018-08-18T11:26:00+00:00",
        "data": [
          {
            "reference": "#evn"
          },
          {
            "reference": "#pid"
          },
          {
            "reference": "#nk1"
          },
          {
            "reference": "#pv1"
          }
        ]
      },
      "request": {
        "method": "POST",
        "url": "Patient"
      }
    },
    {
      "resource": {
        "resourceType": "Patient",
        "id": "evn",
        "identifier": [
          {
            "system": "http://hl7.org/fhir/sid/us-ssn",
            "value": "123456789"
          }
        ],
        "name": [
          {
            "family": "EVERYMAN",
            "given": [
              "ADAM",
              "A",
              "III"
            ]
          }
        ],
        "gender": "male",
        "birthDate": "1961-06-15",
        "address": [
          {
            "line": [
              "2222 HOME STREET"
            ],
            "city": "GREENSBORO",
            "state": "NC",
            "postalCode": "27401-1020"
          }
        ],
        "maritalStatus": {
          "coding": [
            {
              "system": "http://hl7.org/fhir/v3/MaritalStatus",
              "code": "M"
            }
          ]
        },
        "telecom": [
          {
            "system": "phone",
            "value": "(555) 555-2004"
          },
          {
            "system": "phone",
            "value": "(555)555-2004"
          }
        ],
        "contact": [
          {
            "relationship": [
              {
                "coding": [
                  {
                    "system": "http://hl7.org/fhir/v2/0131",
                    "code": "NK"
                  }
                ]
              }
            ],
            "name": {
              "family": "NUCLEAR",
              "given": [
                "NEL ... ...  ... ...

 

Agora, isso é um pouco impressionante, considerando o esforço que fiz para o FHIR alguns anos atrás.  Mas não estou mais surpreso, não é? 

Alguma ideia... Talvez eu precise fazer uma pausa para repensar esse tipo de "modelo de linguagem", para que eu possa soltar um pouco mais minha imaginação.  :)

#Próximo passo

  1. OK, ele consegue desempenhar as funções de DTLs. Mas ele conseguiria gerar uma DTL no estilo COS do ISC, Python ou qualquer outra linguagem — quero dizer, o código real?  Não consigo ver por que não. 

  2. Certeza: a programação tradicional nos deu certeza e precisão - se alguma transformação funciona, ela continua funcionando com 100% de precisão e certeza para todos os casos testados. As abordagens de ciência de dados às vezes não têm essa certeza. Como podemos injetar a certeza necessária e a qualidade médica nessa "caixa preta"?    

0
0 110
Artigo Cristiano Silva · Ago. 7, 2023 2m read

Transformações DTL e chamadas GetValueAt/SetValueAt em mensagens HL7 truncarão todos os campos com mais de 32 K. Para evitar isso, os métodos GetFieldStreamRaw e StoreFieldStreamRaw devem ser utilizados ao lidar com campos que possam ser maiores que 32K. OBX:5 é um exemplo frequente. Esses métodos têm algumas sutilezas e devem ser usados com cuidado.

0
0 61
Artigo Ana Dascenzio · Jun. 12, 2023 9m read

Escrito por: @Luana Machado e @Ana Dascenzio 
 

Cenário 

No cenário da saúde, seja em um laboratório ou hospital, uma falha de equipamento pode custar muito caro. O custo pode vir pelo tempo de conserto e inutilização da máquina, ou pior, pelo dano a um paciente ou cliente. Portanto, pode ser muito benéfico encontrar sinais antecipados para potenciais problemas, obter essa informação em tempo real e adequar as manutenções em momentos fora do fluxo diário de uso. Para isso, podemos utilizar a tecnologia da InterSystems IRIS em um modelo de manutenção preditiva notificada de equipamentos médicos.

 

12
7 464
Anúncio Angelo Bruno Braga · Set. 13, 2022

Olá Comunidade, 

Nesta demonstração você verá os blocos de construção de uma integração no IRIS for Health e no HealthShare da InterSystems e verá como as mensagens são recebidas, processadas e enviadas —incluíndo mensagens no formato HL7:

⏯ Visão dos Componentes Básicos de Soluções de Integração InterSystems

0
0 85
Artigo Guilherme Koerber · Set. 4, 2021 3m read

Anexei um documento que descreve o produto que desenvolvi chamado NiPaRobotica Pharmacy. Esta é uma interface que desenvolvi que aceita solicitações de dispensa de farmácia e converte os itens de linha no pedido em diálogos de dispensa que são enviados para robôs de farmácia. Implantei a interface em 3 Farmácias Hospitalares, duas das quais tinham 6 robôs que foram dispostos de tal forma que as rampas de dispensação canalizavam os medicamentos para as mesas pelos farmacêuticos sentados em vitrines atendendo 1200 pacientes por dia. Os robôs reduziram o tempo médio de espera de 2 horas para uma

0
0 106
Anúncio Olga Zavrazhnova · Jul. 22, 2021

Olá Comunidade,

Nós estamos querendo seus comentários sobre nossa nova oferta - Serviços de Transformação de Mensagens HealthShare. 
O serviço foi publicado no Marketplace da AWS onde você pode testá-lo de graça!

Nós lançamos um desafio relacionado no Global Masters onde você pode ganhar pontos testando o serviço e um prêmio de "obrigado" a todos que deixarem os comentários a respeito da utilização do serviço nesta postagem.

 

0
0 77
Anúncio Ben Spead · Jul. 7, 2021

Olá Desenvolvedores!

Vocês já tiveram que converter mensagens HL7v2 para FHIR (Fast Healthcare Interoperability Resources) e acharam o processo de transformação complicado e confuso? A InterSystems está criando uma nova oferta de SaaS baseada em nuvem chamada de Serviços de Transformação de Mensagens do HealthShare que faz com que este processo se torne simples. Estamos muito empolgados de anunciar um Programa de Acesso Antecipado para esta nossa nova oferta e adoraríamos que vocês o utilizassem e então nos dessem seu feedback a respeito do mesmo! Para isso basta que vocês possuam uma conta grátis AWS, com um bucket S3 para colocar suas mensagens HL7v2 e outro bucket S3 para colocar a saída em FHIR. 

0
0 128
Artigo Mark Bolinsky · Nov. 23, 2020 9m read

Introdução

Recentemente, a InterSystems concluiu uma comparação de desempenho e escalabilidade da IRIS for Health 2020.1, cujo foco foi a interoperabilidade do HL7 versão 2. Este artigo descreve a taxa de transferência observada para diversas cargas de trabalho e também apresenta diretrizes de configuração geral e dimensionamento para sistemas nos quais a IRIS for Health é usada como um mecanismo de interoperabilidade para as mensagens do HL7v2.

A comparação simula cargas de trabalho parecidas com as de ambientes em produção. Os detalhes da simulação são descritos na seção Descrição e metodologia das cargas de trabalho. As cargas de trabalho testadas consistiram de cargas de Patient Administration (ADT) e Observation Result (ORU) do HL7v2 e incluíram transformações e novo roteamento.

A versão 2020.1 da IRIS for Health demonstrou uma taxa de transferência sustentada de mais de 2,3 bilhões de mensagens (entrada e saída) por dia com um servidor simples com processadores escaláveis Intel® Xeon® de 2ª geração e armazenamento Intel® Optane™ SSD DC P4800X Series. Os resultados mais que dobraram a escalabilidade em relação à comparação de taxa de transferência anterior do Ensemble 2017.1 HL7v2.

Durante os testes, a IRIS for Health foi configurada para preservar a ordem PEPS (primeiro a entrar, primeiro a sair) e para fazer a persistência completa das mensagens e filas para cada mensagem de entrada e saída. Ao fazer a persistência das filas e mensagens, a IRIS for Health proporciona proteção dos dados caso haja travamento do sistema, além de recursos completos de procura e reenvio de mensagens passadas.

Além disso, as diretrizes de configuração são abordadas nas seções abaixo, que ajudarão a escolher uma configuração e implantação adequadas para atender às exigências de desempenho e escalabilidade de suas cargas de trabalho.

Os resultados mostram que a IRIS for Health consegue atender a altíssimas taxas de transferência de mensagens em hardware de prateleira e, na maioria dos casos, permite que um único servidor pequeno forneça interoperabilidade de HL7 para toda a organização.


Visão geral dos resultados

Foram usadas três cargas de trabalho para representar diferentes aspectos da atividade de interoperabilidade do HL7:

  • Carga de trabalho T1: usa passagem simples de mensagens HL7, com uma mensagem de saída para cada mensagem de entrada. As mensagens são passadas diretamente do serviço empresarial do Ensemble (Ensemble Business Service) para a operação de negócios do Ensemble (Ensemble Business Operation), sem um mecanismo de roteamento. Nenhuma regra de roteamento foi usada, e nenhuma transformação foi executada. Foi criada uma instância de mensagens HL7 no banco de dados por mensagem de entrada.
  • Carga de trabalho T2: usa um mecanismo de roteamento para alterar uma média de 4 segmentos da mensagem de entrada e roteá-la para uma única interface de saída (1 para 1 com uma transformação). Para cada mensagem de entrada, foi executada uma transformação de dados, e foram criados dois objetos de mensagem HL7 no banco de dados.
  • Carga de trabalho T4: usa um mecanismo de roteamento para rotear separadamente mensagens modificadas para cada uma das quatro interfaces de saída. Em média, 4 segmentos da mensagem de entrada foram modificadas em cada transformação (1 entrada para 4 saídas com 4 transformações). Para cada mensagem de entrada, foram executadas quatro transformações de dados, foram enviadas quatro mensagens de saída, e foram criados cinco objetos de mensagem HL7 no banco de dados.

As três cargas de trabalha foram executadas em um sistema físico de 48 núcleos com dois processadores escaláveis Intel® Xeon® Gold 6252, com das unidades Intel® Optane™ SSD DC P4800X de 750 GB, com o Red Hat Enterprise Linux 8. Os dados são apresentados como o número de mensagens por segundo (e por hora) de entrada, o número por segundo (e por hora) de saída, bem como o total de mensagens (de entrada e de saída) em 10 horas por dia. Além disso, o uso de CPU é apresentado como medida dos recursos de sistema disponíveis para determinado nível de taxa de transferência. 

Resultados de escalabilidade

Tabela 1: Resumo da  taxa de transferência das quatro cargas de trabalho nesta configuração de hardware testada:

*Carga de trabalho combinada, com 25% de T1, 25% de T2 e 50% de T4


Descrição e metodologia das cargas de trabalho

As cargas de trabalho testadas incluíram mensagens de Patient Administration (ADT) e Observation Result (ORU) do HL7v2, com um tamanho médio de 1,2 KB e uma média de 14 segmentos. Cerca de 4 segmentos foram modificados pelas transformações (para cargas de trabalho T2 e T4). Os testes representam 48 a 128 interfaces de entrada de 48 a 128 interfaces de saída enviando e recebendo mensagens por TCP/IP.

Na carga de trabalho T1, foram usados quatro namespaces separados, cada um com 16 interfaces; na carga de trabalho T2, foram usados três namespaces, cada um com 16 interfaces; na carga de trabalho T4, foram usados quatro namespaces, cada um com 32 interfaces; e, na última "carga de trabalho combinada", foram usados três namespaces, com 16 interfaces para carga de trabalho T1, 16 para carga de trabalho T2 e 32 para carga de trabalho T4.

A escalabilidade foi mensurada aumentando-se gradualmente o tráfego em cada interface para descobrir a taxa de transferência mais alta com critérios de desempenho aceitável. Para que o desempenho seja aceitável, as mensagens devem ser processadas a uma taxa sustentada, sem filas, sem atrasos mensuráveis na entrada das mensagens, e o uso médio de CPU deve ficar abaixo de 80%.

Testes anteriores demonstraram que o tipo de mensagem HL7 usado não é significativo para o desempenho e a escalabilidade do Ensemble. Os fatores significativos são o número de mensagens de entrada, o tamanho das mensagens de entrada e saída, o número de novas mensagens criadas no mecanismo de roteamento e o número de segmentos modificados.

Além disso, testes anteriores demonstraram que o processamento de campos específicos de uma mensagem HL7 em uma transformação de dados não costuma impactar o desempenho de forma significativa. As transformações feitas nesses testes usaram atribuições bem simples para criar novas mensagens. É importante salientar que processamentos complexos (como o uso de consultas SQL extensivas em uma transformação de dados) podem fazer os resultados variarem.

Testes anteriores também indicaram que o processamento de regras não costuma ser significativo. Os conjuntos de regras de roteamento usados nos testes tiveram uma média de 32 regras, e todas eram simples. É importante salientar que conjuntos de regras extremamente grandes ou complexos podem fazer os resultados variarem. 

Hardware 

Configuração do servidor

Os testes utilizaram um servidor com processadores escaláveis Intel® Xeon® Gold 6252 "Cascade Lake" de 2ª geração, com 48 núcleos de 2,1 GHz em um sistema com 2 soquetes, 24 núcleos por soquete com 192 GB de DR4-2933 DRAM e interface de rede Ethernet de 10 Gbits. Foi usado o sistema operacional Red Hat Enterprise Linux Server 8 para esse teste, com a IRIS for Health 2020.1

Configuração do disco

É feita a persistência completa no disco das mensagens que passam pela IRIS for Health. Nesse teste, duas unidades Intel® Optane™ SSD DC P4800X de 750 GB internas do sistema foram usadas, dividindo-se os bancos de dados em una unidade e os registros de log em outro. Além disso, para garantir uma comparação real, foi ativado o commit síncrono nos registros de log para forçar a durabilidade dos dados. Para a carga de trabalho T4 descrita anteriormente neste documento, cada mensagem HL7 de entrada gera aproximadamente 50 KB de dados, que podem ser divididos conforme indicado na tabela 2. Os diários de transações geralmente são mantidos na linha por menos tempo que os logs ou dados das mensagens, e isso deve ser levado em conta ao calcular o espaço em disco total necessário.

Tabela 2: Requisitos de disco por mensagem HL7 de entrada para carga de trabalho T4  

ContribuinteRequisito de dados
Dados do segmento4,5 KB
Objeto da mensagem HL72 KB
Cabeçalho da mensagem1 KB
Log de regra de encaminhamento0,5 KB
Diários de transações42 KB
Total50 KB

Lembre-se de que a carga de trabalho T4 usa um mecanismo de roteamento para rotear separadamente mensagens modificadas para cada uma das quatro interfaces de saída. Em média, 4 segmentos da mensagem de entrada foram modificadas em cada transformação (1 entrada para 4 saídas com 4 transformações). Para cada mensagem de entrada, foram executadas quatro transformações de dados, foram enviadas quatro mensagens de saída e foram criados cinco objetos de mensagem HL7 no banco de dados.

Ao configurar sistemas para uso em produção, os requisitos reais devem ser calculados considerando-se os volumes de entrada diários, bem como o agendamento de limpeza de mensagens HL7 e a política de retenção de arquivos de registros de logs. Além disso, é necessário configurar no sistema um espaço adequado para registros de log, para evitar que os volumes de disco de registros de log fiquem cheios. Os arquivos de registros de log devem ficar em discos separados fisicamente dos arquivos de banco de dados, tanto por questões de desempenho quanto de confiabilidade.

Conclusão

A taxa de transferência de mensagens HL7v2 da InterSystems IRIS for Health demonstrada nesses testes ilustra a enorme capacidade de taxa de transferência com uma configuração básica de servidor de prateleira com 2 soquetes para dar suporte a cargas de trabalho de mensagens bastante exigentes de qualquer organização. Além disso, a InterSystems está comprometida a aprimorar constantemente o desempenho e a escalabilidade a cada versão, além de aproveitar os benefícios das tecnologias mais recentes de servidor e nuvem.

O gráfico abaixo apresenta uma visão geral e um comparativo do aumento da taxa de transferência das comparações anteriores do Ensemble 2015.1 e Ensemble 2017.1 com processadores Intel® E5-2600 v3 (Haswell) e a comparação do Ensemble 2017.1 com processadores escaláveis Intel® Platinum Series (Skylake) de 1ª geração em relação aos resultados mais recentes com os processadores escaláveis Intel® Xeon® Gold Series (Cascade Lake) de 2ª geração executando a IRIS for Health 2020.1.

Gráfico 1: Taxa de transferência de mensagens (em milhões) por 10 horas em um único servidor

A InterSystems IRIS for Health continua aumentar a taxa de transferência de interoperabilidade a cada versão, além de oferecer flexibilidade quanto aos recursos de conectividade. Como o gráfico acima mostra, a taxa de transferência de mensagens aumentou significativamente e, com cargas de trabalho T2, dobrou em relação a 2017 e mais que triplicou em relação a 2015 na mesma janela de 10 horas e sustentou mais de 2,3 bilhões de taxas de mensagens em 24 horas.

Outro indicador importante dos avanços da IRIS for Health é a melhoria da taxa de transferência com cargas mais complexas T2 e T4, que incorporam transformações e regras de roteamento, ao contrário da operação única de passagem da carga de trabalho T1.  

A InterSystems está disponível para conversar sobre soluções de acordo com as necessidades de interoperabilidade de sua organização.

0
0 116
Artigo Guillaume Rongier · Out. 6, 2020 2m read

FHIR-HL7v2-SQL-Demo

Demonstração pronta para uso de um servidor FHIR no IRIS for Health 2020.2:

  • Transformação de mensagens HL7v2 para o servidor FHIR
  • Servidor FHIR que pode ser consultado em SQL

alt text

Instalando

Clone este repositório

git clone https://github.com/grongierisc/FHIR-HL7v2-SQL-Demo.git

Docker

docker-compose up --build -d

Uso

  • Pode-se usar a configuração do postman em misc/fhirhl7v2demo.postman_collection.json

  • Use a IU em http://localhost:4201

  • Login/Senha : SuperUser/password

Como usar a demostração

alt text

3 passos para usá-la:

Importar mensagens HL7v2

Clique na seta para a esquerda entre IRIS e a ambulância.

Esta janela abrirá:

alt text

A partir daqui, você pode importar exemplos deste diretório no repositório Git:

sampleFiles

Selecione um e clique em enviar.

alt text

A partir daqui, você pode clicar em Rastreamento de Mensagem:

alt text

Selecione o primeiro:

alt text

Aqui você pode ver a transformação entre HL7v2 para SDA e depois para FHIR.

Use o Cliente FHIR

Clique na seta entre IRIS e o FHIR :

alt text

O swagger lhe dá a oportunidade de consultar o repositório FHIR populado a partir da mensagem HL7v2 ou do cliente FHIR.

Exemplo:

alt text

Use o cliente SQL

Clique na seta entre IRIS e o cliente SQL:

alt text

A partir daqui você pode ver todos os recursos FHIR de uma forma relacional .

0
0 327