# Phase 2.3: EHR/FHIR Integration ## Overview **Phase 2.3** integrates the application with Electronic Health Record (EHR) systems through: - **FHIR APIs** (Fast Healthcare Interoperability Resources) - **HL7 v2 messaging** (legacy EHR systems) - **Real patient data** from hospital systems - **Bi-directional data sync** **Prerequisites:** - Phase 2.1 (PostgreSQL Database) - Phase 2.2 (Analytics) - optional --- ## Features ### 1. **FHIR API Integration** #### Patient Data Retrieval ```python from ehr_integration import FHIRAPIClient client = FHIRAPIClient("https://fhir.hospital.com") # Get patient demographics patient = client.get_patient("12345") # Get patient's conditions conditions = client.get_patient_conditions("12345") # Get vital signs and labs observations = client.get_patient_observations("12345") # Get active care plans care_plans = client.get_patient_care_plans("12345") # Get patient goals goals = client.get_patient_goals("12345") ``` #### Data Submission ```python # Create new observation (e.g., blood pressure reading) obs_id = client.create_observation("12345", { "code": {"coding": [{"code": "85354-9"}]}, # BP "valueQuantity": {"value": 120, "unit": "mmHg"} }) # Update care plan client.update_care_plan("cp-123", updated_data) ``` ### 2. **HL7 v2 Messaging** For integration with legacy EHR systems: ```python from ehr_integration import HL7Parser parser = HL7Parser() # Parse incoming HL7 message message = """MSH|^~\\&|APP|FAC|APP|FAC|20251129... PID|||12345||Doe^John||19800101|M OBX|1|NM|85354-9||120||80-120|N""" parsed = parser.parse_hl7_message(message) # Returns: { # "patient": {"id": "12345", "name": "Doe^John", ...}, # "observations": [{"type": "85354-9", "value": "120", ...}] # } ``` ### 3. **FHIR Resource Building** Helper functions to create standardized FHIR resources: ```python from ehr_integration import FHIRResourceBuilder builder = FHIRResourceBuilder() # Create condition condition = builder.build_condition( patient_id="12345", code="80891009", # SNOMED code for type 2 diabetes display="Type 2 Diabetes Mellitus", onset_date="2020-01-15" ) # Create observation (lab result) observation = builder.build_observation( patient_id="12345", code="2345-7", # Glucose value=125, unit="mg/dL", reference_range=(70, 100) ) # Create goal goal = builder.build_goal( patient_id="12345", description="Achieve HbA1c < 7%", status="in-progress", target_date="2026-01-15" ) ``` ### 4. **EHR Integration Manager** Comprehensive manager for all EHR operations: ```python from ehr_integration import EHRIntegrationManager manager = EHRIntegrationManager( fhir_url="https://fhir.hospital.com", api_key="your-api-key" ) # Sync all patient data patient_record = manager.sync_patient_data("12345") # Returns complete record with: # - Patient demographics # - Conditions # - Observations # - Care plans # - Goals # Send observation to EHR obs_id = manager.send_observation_to_ehr("12345", observation) # Process incoming HL7 parsed = manager.process_hl7_message(hl7_message) ``` --- ## Setup Instructions ### 1. Prerequisites ```bash # Install FHIR libraries pip install fhir-parser requests # Or add to requirements.txt fhir-parser==1.2.0 requests==2.28.0 ``` ### 2. Configure FHIR Server Connection ```bash # Update .env.production EHR_FHIR_URL=https://fhir.hospital.com EHR_API_KEY=your_api_key EHR_TIMEOUT=10 EHR_VERIFY_SSL=true EHR_SYNC_INTERVAL=3600 # seconds ``` ### 3. Register with FHIR Server Most FHIR servers require: 1. **OAuth 2.0 credentials** or **API key** 2. **Client registration** (get client_id, client_secret) 3. **Scope permissions** (read, write, admin) Example (Azure Health Data Services): ```bash # Register application az ad app create \ --display-name "Nursing Validator" \ --reply-urls "http://localhost:8501" # Get credentials AZURE_AD_TENANT_ID=your-tenant-id AZURE_AD_CLIENT_ID=your-client-id AZURE_AD_CLIENT_SECRET=your-secret ``` ### 4. Initialize EHR Integration ```python from ehr_integration import EHRIntegrationManager import os manager = EHRIntegrationManager( fhir_url=os.getenv("EHR_FHIR_URL"), api_key=os.getenv("EHR_API_KEY") ) # Verify connection patient = manager.fhir_client.get_patient("test-patient-id") if patient: print("✅ Connected to FHIR server") else: print("❌ Failed to connect") ``` --- ## FHIR Resources Supported ### Patient - Demographics - Contact information - Insurance information ### Condition - Diagnoses - Problems - Chronic conditions ### Observation - Vital signs (BP, temp, O2) - Lab results - Assessment findings ### Goal - Clinical goals - Patient goals - Progress tracking ### CarePlan - Nursing care plans - Treatment protocols - Intervention activities ### Medication - Current medications - Dosage information - Allergies ### Procedure - Surgical procedures - Clinical procedures - Completed interventions ### Appointment - Scheduled visits - Follow-ups - Clinic appointments --- ## Data Synchronization ### Real-time Sync ```python # Background task to sync patient data import asyncio import time async def sync_patient_data_loop(patient_id, interval=3600): """Continuously sync patient data.""" while True: patient_data = manager.sync_patient_data(patient_id) # Save to database from database import save_patient_record save_patient_record(patient_id, patient_data) await asyncio.sleep(interval) # Run in background asyncio.create_task(sync_patient_data_loop("12345")) ``` ### Event-Driven Sync ```python # Listen for EHR events (webhook) @st.streamlit_route("/ehr-webhook", methods=["POST"]) def receive_ehr_update(request): data = request.json patient_id = data["patient_id"] # Sync on update patient_data = manager.sync_patient_data(patient_id) return {"status": "updated"} ``` --- ## HL7 v2 Message Types ### ADT (Admission/Discharge/Transfer) ``` MSH|^~\&|SENDAPP|SENDFAC|RECAPP|RECFAC|20251129120000||ADT^A01 PID|1||12345||Doe^John ``` ### ORM (Order Message) ``` MSH|^~\&|SENDAPP|SENDFAC|RECAPP|RECFAC|20251129120000||ORM^O01 ORC|NW|123456 OBX|1|NM|85354-9||120||80-120|N ``` ### ORU (Observation/Result - Lab) ``` MSH|^~\&|LAB|HOSPITAL|APP|FACILITY|20251129120000||ORU^R01 OBX|1|NM|2345-7||125||70-100|N ``` --- ## Security Considerations ### HIPAA Compliance - ✅ Encryption in transit (HTTPS/TLS) - ✅ Encryption at rest (database encryption) - ✅ API key management - ✅ Audit logging - ✅ Access controls - ✅ Data anonymization - ✅ Consent management ### OAuth 2.0 Implementation ```python from oauthlib.oauth2 import WebApplicationClient client_id = os.getenv("AZURE_AD_CLIENT_ID") client_secret = os.getenv("AZURE_AD_CLIENT_SECRET") client = WebApplicationClient(client_id) # Get authorization URL authorization_url, state = client.prepare_request_uri( "https://login.microsoftonline.com/common/oauth2/v2.0/authorize" ) # Exchange code for token token = client.prepare_refresh_token_request_body( refresh_token, client_id, client_secret ) ``` ### Certificate Pinning ```python import requests from requests.adapters import HTTPAdapter from requests.packages.urllib3.util.ssl_ import create_urllib3_context class SSLAdapter(HTTPAdapter): def init_poolmanager(self, *args, **kwargs): ctx = create_urllib3_context() ctx.load_verify_locations('hospital_ca.pem') kwargs['ssl_context'] = ctx return super().init_poolmanager(*args, **kwargs) session = requests.Session() session.mount('https://', SSLAdapter()) ``` --- ## Troubleshooting ### Connection Errors ```python # Test connection try: patient = client.get_patient("test-id") if patient: print("✅ Connection successful") else: print("❌ Invalid patient ID") except Exception as e: print(f"❌ Connection failed: {e}") ``` ### Authentication Issues ```bash # Verify API key is valid curl -H "Authorization: Bearer YOUR_API_KEY" \ https://fhir.hospital.com/Patient/test-id # Check token expiry # Refresh token if needed ``` ### FHIR Server Compatibility Some common FHIR servers: - **Azure Health Data Services**: FHIR R4 - **Cerner**: FHIR R4 (with extensions) - **Epic**: FHIR R4 (limited) - **InterSystems**: FHIR R3/R4 - **HAPI FHIR**: Full FHIR support Verify server's FHIR version: ```bash curl https://fhir.hospital.com/metadata ``` --- ## Integration with Main App ### Add Patient Context to Chat ```python # In app_phase2.py if st.session_state.get("patient_id"): manager = EHRIntegrationManager(ehr_fhir_url, api_key) patient_data = manager.sync_patient_data(patient_id) # Use in chat context context = f""" Patient: {patient_data['patient']['name']} Conditions: {', '.join([c['code']['text'] for c in patient_data['conditions']])} """ # Include in LLM prompt qa = RetrievalQA.from_chain_type( llm=AzureOpenAI(), chain_type="stuff", retriever=vector_db.as_retriever(), return_source_documents=True, ) response = qa.run(f"{context}\n\nQuestion: {user_input}") ``` ### Save Assessments Back to EHR ```python # After nursing assessment assessment_observation = builder.build_observation( patient_id=st.session_state.patient_id, code="84811-6", # Nursing assessment value="Assessment complete", unit="text" ) obs_id = manager.send_observation_to_ehr( st.session_state.patient_id, assessment_observation ) st.success(f"Assessment saved to EHR: {obs_id}") ``` --- ## Performance Optimization ### Caching ```python import streamlit as st from functools import lru_cache @st.cache_data(ttl=3600) def get_patient_data(patient_id): return manager.sync_patient_data(patient_id) ``` ### Batch Operations ```python # Sync multiple patients patient_ids = ["123", "456", "789"] for patient_id in patient_ids: patient_data = manager.sync_patient_data(patient_id) # Process... ``` ### Pagination ```python # Most FHIR servers support _count and _offset url = f"{self.base_url}/Observation?subject=Patient/{patient_id}&_count=100&_offset=0" ``` --- ## Next Steps 1. **Get FHIR server credentials** from your EHR vendor 2. **Test connection** to FHIR server 3. **Configure patient sync** frequency 4. **Implement UI** for patient selection 5. **Add audit logging** for all data access 6. **Deploy to staging** and test with real data 7. **Proceed to Phase 2.4** - Mobile App --- ## Files Created/Modified **New Files:** - `ehr_integration.py` (400+ lines) **Integration Points:** - Update `app_phase2.py` for patient selection - Add `save_patient_record()` to database.py - Update requirements.txt with fhir-parser **Documentation:** - `PHASE2_FHIR.md` (this file) --- ## References - [FHIR Specification](http://hl7.org/fhir/R4/) - [HL7 v2 Reference](http://www.hl7.org/implement/standards/product_brief.cfm?product_id=20) - [SMART on FHIR](http://docs.smarthealthit.org/) - [Azure Health Data Services](https://learn.microsoft.com/en-us/azure/healthcare-apis/) --- *Phase 2.3 Implementation - November 29, 2025*