damccorm commented on code in PR #28873:
URL: https://github.com/apache/beam/pull/28873#discussion_r1368738477


##########
examples/notebooks/healthcare/beam_post_hl7_messages_to_hcapi.ipynb:
##########
@@ -0,0 +1,504 @@
+{
+  "nbformat": 4,
+  "nbformat_minor": 0,
+  "metadata": {
+    "colab": {
+      "provenance": [],
+      "private_outputs": true,
+      "toc_visible": true,
+      "include_colab_link": true
+    },
+    "kernelspec": {
+      "name": "python3",
+      "display_name": "Python 3"
+    },
+    "language_info": {
+      "name": "python"
+    }
+  },
+  "cells": [
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "view-in-github",
+        "colab_type": "text"
+      },
+      "source": [
+        "<a 
href=\"https://colab.research.google.com/github/devanshmodi/beam/blob/devanshmodi-patch-healthcare-hl7-to-hcapi/examples/notebooks/healthcare/beam_post_hl7_messages_to_hcapi.ipynb\";
 target=\"_parent\"><img 
src=\"https://colab.research.google.com/assets/colab-badge.svg\"; alt=\"Open In 
Colab\"/></a>"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "zQ_JXPR3RoFV"
+      },
+      "outputs": [],
+      "source": [
+        "# @title ###### Licensed to the Apache Software Foundation (ASF), 
Version 2.0 (the \"License\")\n",
+        "\n",
+        "# Licensed to the Apache Software Foundation (ASF) under one\n",
+        "# or more contributor license agreements. See the NOTICE file\n",
+        "# distributed with this work for additional information\n",
+        "# regarding copyright ownership. The ASF licenses this file\n",
+        "# to you under the Apache License, Version 2.0 (the\n",
+        "# \"License\"); you may not use this file except in compliance\n",
+        "# with the License. You may obtain a copy of the License at\n",
+        "#\n",
+        "#   http://www.apache.org/licenses/LICENSE-2.0\n";,
+        "#\n",
+        "# Unless required by applicable law or agreed to in writing,\n",
+        "# software distributed under the License is distributed on an\n",
+        "# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+        "# KIND, either express or implied. See the License for the\n",
+        "# specific language governing permissions and limitations\n",
+        "# under the License\n",
+        "\n",
+        "##################################\n",
+        "# Author: Devansh Modi           #\n",
+        "##################################\n"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "**Highlevel Architecture**\n",
+        "\n",
+        "![Screenshot 2023-10-18 at 3.53.31 
PM.png](data:image/png;base64,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)"
+      ],
+      "metadata": {
+        "id": "RL1LDp645ogr"
+      }
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "# **Post Hl7v2 messages to Google Cloud Healthcare API HL7v2 store 
pipeline**\n",
+        "\n",
+        "This example demonstrates how to set up an Apache Beam pipeline that 
reads a HL7 file from [Google Cloud 
Storage](https://https://cloud.google.com/storage), and calls the [Google Cloud 
Healthcare API Hl7v2 store to store Hl7 
messages](https://cloud.google.com/healthcare-api/docs/how-tos/hl7v2-messages) 
to extract information from unstructured data. This application can be used in 
contexts such as reading raw Hl7 messages, if needed parse them or modify them 
as per your defined Hl7v2 store configurations and store data into Hl7v2 
store.\n",
+        "\n",
+        "An Apache Beam pipeline is a pipeline that reads input data, 
transforms that data, and writes output data. It consists of PTransforms and 
PCollections. A PCollection represents a distributed data set that your Beam 
pipeline operates on. A PTransform represents a data processing operation, or a 
step, in your pipeline. It takes one or more PCollections as input, performs a 
processing function that you provide on the elements of that PCollection, and 
produces zero or more output PCollection objects.\n",
+        "\n",
+        "For details about Apache Beam pipelines, including PTransforms and 
PCollections, visit the [Beam Programming 
Guide](https://beam.apache.org/documentation/programming-guide/).\n",
+        "\n",
+        "You'll be able to use this notebook to explore the data in each 
PCollection."
+      ],
+      "metadata": {
+        "id": "wC9KRrlORwKu"
+      }
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "***Sample HL7v2 Message***\n",
+        "\n",
+        "The below reference message shows a sample Hl7v2 messages seperated 
by \\r.\n",
+        "\n",
+        
"**MSH|^~\\&|FROM_APP|FROM_FACILITY|TO_APP|TO_FACILITY|20150503223000||ADT^A01|20150503223000|P|2.5|\\r\n",
+        "EVN|A01|20110613083617|\\r\n",
+        "PID|1||21004053^^^^MRN||SULLY^BRIAN||19611209|M|||123 MAIN 
ST^^MOUNTAIN SPRINGS^CO^80439|\\r\n",
+        "PV1||I|H73 RM1^1^^HIGHWAY 73 CLINIC||||5148^MARY 
QUINN|||||||||Y||||||||||||||||||||||||||||20150503223000|**\n",
+        "\n",
+        "The file contains many such messages and the objective of this code 
will be to split and construct messages and POST it to Google Cloud HealthCare 
API HL7v2 store."
+      ],
+      "metadata": {
+        "id": "AOVYgtyaqSxa"
+      }
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "Lets install necessary packages"
+      ],
+      "metadata": {
+        "id": "81wCK9XnS6Sc"
+      }
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "!pip install apache-beam[gcp]"
+      ],
+      "metadata": {
+        "id": "Yv1phmRZS23c"
+      },
+      "execution_count": null,
+      "outputs": []
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "**GCP Setup**\n",
+        "1. Authenticate your notebook by `gcloud auth application-default 
login` in the Colab terminal.\n",
+        "\n",
+        "2. Run `gcloud config set project <YOUR-PROJECT>`\n",
+        "\n",
+        "Set the variables in the next cell based upon your project and 
preferences.\n",
+        "\n",
+        "Note that below, **us-central1** is hardcoded as the location. This 
is because of the limited number of 
[locations](https://cloud.google.com/healthcare-api/docs/how-tos/hl7v2-messages)
 the API currently supports."
+      ],
+      "metadata": {
+        "id": "tpePe_yOsdSJ"
+      }
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "Before running please set the following variables as arguments as 
mentioned below\n"
+      ],
+      "metadata": {
+        "id": "_1Q3mw1usnoE"
+      }
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "args = {'gcp_project':'xxx', #GCP project ID\n",
+        "        'gcp_region':'xxx', # GCP project region\n",
+        "        'temp_location':'gs://<YOUR Bucket>/tmp', #input location 
where your HL7 messages are stored in GCS bucket\n",
+        "        'input_file':'gs://<YOUR Bucket>/my_message.hl7', #input 
location where your HL7 messages are stored in GCS bucket\n",
+        "        'hcapi_project_id':'xxxxxx', #healthcare API project ID\n",
+        "        'hcapi_dataset':'xxxx', #healthcare dataset\n",
+        "        'hcapi_version':'v1', #healthcare API version by defualt 
v1\n",
+        "        'hcapi_location':'xxxx', #healthcare API configured 
location\n",
+        "        'hcapi_hl7_store':'xxx', #healthcare api hl7 store\n",
+        "        'hcapi_fhir_store':''}"
+      ],
+      "metadata": {
+        "id": "a722GbqdvgOX"
+      },
+      "execution_count": null,
+      "outputs": []
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "**Google Cloud Healthcare (HCAPI) API Utils class**\n",
+        "\n",
+        "Below is the code snippet which describes the class having healthcare 
API connections and configurations. Basic functionality, includes constructing 
the hcapi_url as per the input parameters, clean the HL7 message in terms of 
proper formatting and post hl7v2 message to hl7v2 store. You can add more 
transformations as per your requirements."
+      ],
+      "metadata": {
+        "id": "NHzk8JIqxQoa"
+      }
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "import google.auth\n",
+        "import google.auth.transport.requests\n",
+        "import base64\n",
+        "import json\n",
+        "import hashlib\n",
+        "import requests\n",
+        "import logging\n",
+        "import apache_beam as beam\n",
+        "from apache_beam.options.pipeline_options import PipelineOptions\n",
+        "from apache_beam.options.pipeline_options import SetupOptions\n",
+        "from apache_beam.testing.test_pipeline import TestPipeline\n",
+        "import apache_beam.runners.interactive.interactive_beam as ib\n",
+        "from apache_beam import io\n",
+        "\n",
+        "logging.basicConfig(level=logging.INFO, format='%(asctime)s :: 
%(levelname)s :: %(message)s')\n",
+        "\n",
+        "class hcapi_cls:\n",
+        "\n",
+        "    def __init__(self, args):\n",
+        "        self.hcapi_hl7_store = str(args['hcapi_hl7_store'])\n",
+        "        self.hcapi_project_id = str(args['hcapi_project_id'])\n",
+        "        self.hcapi_version = str(args['hcapi_version'])\n",
+        "        self.hcapi_location = str(args['hcapi_location'])\n",
+        "        self.hcapi_dataset = str(args['hcapi_dataset'])\n",
+        "        self.hcapi_fhir_store = str(args['hcapi_fhir_store'])\n",
+        "        self.token = None\n",
+        "\n",
+        "    def google_api_headers(self):\n",
+        "        \"\"\" Function executes self and gets the token for the 
request \"\"\"\n",
+        "        logging.info(\"fetching token and refreshing 
credentials\")\n",
+        "        creds, project = google.auth.default()\n",
+        "        auth_req = google.auth.transport.requests.Request()\n",
+        "        creds.refresh(auth_req)\n",
+        "        return {\n",
+        "            \"Authorization\": f\"Bearer {creds.token}\",\n",
+        "            \"Prefer\": \"handling=strict\"\n",
+        "        }\n",
+        "\n",
+        "    def hcapi_dataset_url(self, version=None, project=None, 
location=None, dataset=None):\n",
+        "        \"\"\" This function creates base hcapi dataset url and 
returns it \"\"\"\n",
+        "        base = 'https://healthcare.googleapis.com'\n",
+        "        version = self.hcapi_version\n",
+        "        project = self.hcapi_project_id\n",
+        "        location = self.hcapi_location\n",
+        "        dataset = self.hcapi_dataset\n",
+        "        return 
f'{base}/{version}/projects/{project}/locations/{location}/datasets/{dataset}'\n",
+        "\n",
+        "    def hcapi_get(self, url):\n",
+        "        \"\"\" Function to send get request to HCAPI \"\"\"\n",
+        "        response = requests.get(url, 
headers=self.google_api_headers())\n",
+        "        if not response.ok:\n",
+        "            raise Exception(f'Error with HC API 
get:\\n{response.text}')\n",
+        "        return response.json()\n",
+        "\n",
+        "    def hcapi_post(self, url, data):\n",
+        "        \"\"\" Function to send post request to HCAPI \"\"\"\n",
+        "        response = requests.post(url, 
headers=self.google_api_headers(), json=data)\n",
+        "        if not response.ok:\n",
+        "            raise Exception(f'Error with HC API 
post:\\n{response.text}')\n",
+        "        return response.json()\n",
+        "\n",
+        "    def hcapi_delete(self, url):\n",
+        "        \"\"\" Function to send delete request to HCAPI \"\"\"\n",
+        "        response = requests.delete(url, 
headers=self.google_api_headers())\n",
+        "        if not response.ok:\n",
+        "            raise Exception(f'Error with HC API 
get:\\n{response.text}')\n",
+        "        return response.json()\n",
+        "\n",
+        "    def hcapi_hl7_url(self, version=None, project=None, 
location=None, dataset=None, store=None):\n",
+        "        \"\"\" This function creates hcapi hl7V2store url and returns 
the url \"\"\"\n",
+        "        base_url = self.hcapi_dataset_url(version=version, 
project=project,\n",
+        "                                      location=location, 
dataset=dataset)\n",
+        "        hl7_store = self.hcapi_hl7_store\n",
+        "        return f'{base_url}/hl7V2Stores/{hl7_store}'\n",
+        "\n",
+        "    def get_hl7_message(self, message_id):\n",
+        "        \"\"\" Function to get message from HL7v2 store using HCAPI 
URL \"\"\"\n",
+        "        url = f'{self.hcapi_hl7_url()}/messages/{message_id}'\n",
+        "        return self.hcapi_get(url)\n",
+        "\n",
+        "    def post_hl7_message(self, payload):\n",
+        "        \"\"\" Function to post messages to HL7v2 store \"\"\"\n",
+        "        url = f'{self.hcapi_hl7_url()}/messages'\n",
+        "        return self.hcapi_post(url, payload)\n",
+        "\n",
+        "    def message_to_hl7_store(self, message):\n",
+        "        \"\"\" Function to clean up Hl7 messages with \\r seperator 
before posting to HCAPI \"\"\"\n",
+        "        messase =str(message)\n",
+        "        message = message.replace('\\n', '\\r')\n",
+        "        message = message.replace('\\\\r', '\\r')\n",
+        "        message = message.replace('\\r\\r', '\\r')\n",
+        "        encoded = base64.b64encode(str(message).encode())\n",
+        "        payload = {\n",
+        "            \"message\": {\n",
+        "                \"data\": encoded.decode()\n",
+        "            }\n",
+        "        }\n",
+        "        return self.post_hl7_message(payload)\n",
+        "\n",
+        "    def hcapi_fhir_url(self, version=None, project=None, 
location=None, dataset=None, store=None):\n",
+        "        \"\"\" This function creates hcapi fhir store url and returns 
it \"\"\"\n",
+        "        base_url = self.hcapi_dataset_url(version=version, 
project=project,\n",
+        "                                      location=location, 
dataset=dataset)\n",
+        "        if store is None:\n",
+        "            raise Exception('No FHIR store specified')\n",
+        "        return f'{base_url}/fhirStores/{store}/fhir'\n",
+        "\n",
+        "    def hcapi_fhir_request(self, store_key, query, data={}, 
method='GET'):\n",
+        "        \"\"\" Function to send post request to HCAPI FHIR store 
\"\"\"\n",
+        "        store = self.hcapi_fhir_store\n",
+        "        if not store:\n",
+        "            raise Exception(f\"Couldn't FHIR find store named 
{store_key} in config\")\n",
+        "        url = self.hcapi_fhir_url(store=store)\n",
+        "        url = f'{url}/{query}' if query else url\n",
+        "        get = lambda q, d: self.hcapi_get(url)\n",
+        "        post = lambda q, d: self.hcapi_post(url, data)\n",
+        "        delete = lambda q, d: self.hcapi_delete(url)\n",
+        "        return {'GET': get, 'POST': post, 'DELETE' : 
delete}[method](query, data)\n",
+        "\n"
+      ],
+      "metadata": {
+        "id": "H7g4_-rGS9P_"
+      },
+      "execution_count": null,
+      "outputs": []
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "**Pipeline Setup**\n",
+        "\n",
+        "We will use InteractiveRunner in this notebook.\n",
+        "Following are the DoFn classes which carry out its respective 
operations"
+      ],
+      "metadata": {
+        "id": "lXnzAtbHyUd2"
+      }
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "The following class **BuildFileName** takes the file name from the 
element and converts its into string. You can enhance this class to construct 
GCS bucket URL, if your GCS bucket prefix remains constant."
+      ],
+      "metadata": {
+        "id": "TKnL8kxh3Kms"
+      }
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "class BuildFileName(beam.DoFn):\n",
+        "    \"\"\" Class to get file name from variable and returns the 
filename \"\"\"\n",
+        "    def process(self, element):\n",
+        "        logging.info(\"processing the following file: 
{}\".format(element))\n",
+        "        file_path = str(element)\n",
+        "        yield file_path"
+      ],
+      "metadata": {
+        "id": "N01E3dQd3Jr3"
+      },
+      "execution_count": null,
+      "outputs": []
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "The following class **BuildMessages** takes the GCS URL from the 
above class reads it, sepeartes out each message, appends into a list and 
return list for the next class."
+      ],
+      "metadata": {
+        "id": "Jej68R8w3i2Z"
+      }
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "class BuildMessages(beam.DoFn):\n",
+        "    \"\"\" Class to read file, clean and seperate messgaes based on 
MSH\"\"\"\n",
+        "    def process(self, file_name):\n",
+        "        try:\n",
+        "            logging.info(\"starting to read file: 
{}\".format(file_name))\n",
+        "            file = io.gcsio.GcsIO().open(filename=file_name, 
mode='r')\n",
+        "            read_file = file.read()\n",
+        "            new_file = str(read_file, 
encoding='utf-8').replace('\\n', '\\r')\n",
+        "            logging.info(\"starting to seperate HL7 messages into 
list\")\n",
+        "            messages=[]\n",
+        "            for line in new_file.split('\\r'):\n",
+        "                if line[:3] =='MSH':\n",
+        "                    messages.append(line)\n",
+        "                else:\n",
+        "                    messages[-1]+= line\n",
+        "\n",
+        "\n",
+        "            logging.info(\"total number of messages parsed are 
{}\".format(len(messages)))\n",
+        "            return messages\n",
+        "        except Exception as error:\n",
+        "            logging.error(\"got the following error while processing 
: {}\".format('\\n'+str(error)))\n",
+        "            raise Exception\n",
+        "\n",
+        "\n"
+      ],
+      "metadata": {
+        "id": "MC6tr_sGyNKG"
+      },
+      "execution_count": null,
+      "outputs": []
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "The following class **PostToHL7V2Store** takes the messages return in 
the earlier class and POST each messages to Hl7v2 store ."
+      ],
+      "metadata": {
+        "id": "1hpuoUGA33jo"
+      }
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "class PostToHL7V2Store(beam.DoFn):\n",
+        "    \"\"\" Class to read file, clean and seperate messgaes based on 
MSH\"\"\"\n",
+        "    def process(self, element):\n",
+        "        try:\n",
+        "            logging.info(\"starting to prepare and post message\")\n",
+        "            hl7v2_store_response = 
hcapi.message_to_hl7_store(element)\n",
+        "            message_id = 
hl7v2_store_response['name'].split(\"/\")[-1]\n",
+        "            logging.info(\"successfully posted message to Hl7v2 store 
with message id :- {}\".format(message_id))\n",
+        "\n",
+        "            # \"Getting the messagge from HL7V2 store for testing 
purpose\n",
+        "            #message = nb.get_hl7_message(message_id)\n",
+        "            #print(message)\n",
+        "\n",

Review Comment:
   My preference would probably be to get rid of this (or just always print the 
whole thing) since a user could do the same thing if they really want to view 
the full message. If we want to leave it we should at least make the comment 
clearer - maybe something like: `if you'd like to print the full message 
instead of just the id, uncomment the following 2 lines`
   
   Also, no matter what note that message is misspelled in the comment



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to