Cookbook 356: Offline Clinical Hematology Adult ITP ASH Staging & TPO-RA Titrator Engine

This cookbook details how to deploy a localized, containerized adult hematology, hemostasis, and transfusion medicine decision-support engine for outpatient hematology clinics, infusion suites, and emergency departments to ingest platelet counts, bleeding manifestations, chronicity timelines, prior immunosuppressive responses, and hepatic function telemetry, classify disease according to the American Society of Hematology ($\text{ASH 2019 / 2024}$) and International Consensus Report ($\text{ICR 2019}$) Criteria (Newly Diagnosed, Persistent, Chronic, Refractory ITP), compute WHO / $\text{ITP-BAT}$ Bleeding Severity Scores, automate First-Line Corticosteroid / $\text{IVIG}$ Rescue Gating, precision-titrate Thrombopoietin Receptor Agonists ($\text{TPO-RAs}$: Eltrombopag, Romiplostim, Avatrombopag) within the target platelet window ($50,000 - 150,000/\mu\text{L}$), and enforce Prolonged Corticosteroid Toxicity & Thromboembolism Safety Sentinels according to ASH, ICR, and EHA consensus guidelines without external cloud API reliance.


1. Clinical Background & Adult Hematology Architecture

Immune Thrombocytopenia ($\text{ITP}$) is an acquired autoimmune bleeding disorder mediated by anti-platelet autoantibodies (predominantly targeting platelet surface glycoproteins $\text{GPIIb/IIIa}$ and $\text{GPIb/IX}$) leading to accelerated reticuloendothelial Fc-mediated platelet destruction in the spleen and liver, accompanied by impaired megakaryocytic thrombopoiesis:


2. Pipeline & Workflow Architecture

[Patient Telemetry: Platelets, Bleeding Grade, Chronicity Months, Prior Rx, Ancestry, LFTs]
                                         │
                                         ▼
      [ASH/ICR Phase Classifier: Newly Diagnosed vs Persistent vs Chronic vs Refractory]
                                         │
                                         ▼
      [Bleeding Severity & Emergency Rescue Gating: WHO Grade 0-4 + Platelet Threshold]
                                         │
                                         ▼
      [First-Line Gating: High-Dose Dexamethasone 40mg x 4d vs IVIG 1g/kg vs Observation]
                                         │
                                         ▼
      [Second-Line TPO-RA Precision Titrator: Eltrombopag vs Romiplostim vs Avatrombopag]
                                         │
                                         ▼
      [Safety Sentinels: Steroid Duration <=6w Limit & Thrombosis Thromboembolism Gate]

3. Environment & Prerequisites

Install required scientific Python and hematology modeling packages:

pip install numpy scipy pandas torch torchvision matplotlib

4. Complete Offline Python / PyTorch Implementation

"""
Cookbook 356: Offline Adult Hematology ITP ASH Staging & TPO-RA Titrator Engine
OpenPHR Clinical AI Working Group (https://openphr.org)
"""

import math
import numpy as np
import pandas as pd
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass

@dataclass
class AdultITPTelemetry:
    patient_id: str
    age_years: float = 46.0
    patient_weight_kg: float = 70.0
    disease_duration_months: float = 14.0 # > 12 months = Chronic ITP
    current_platelet_count_per_ul: int = 18000 # < 30,000 /uL
    baseline_platelet_trend: str = "Progressive decline over 3 weeks"
    # Bleeding Telemetry
    who_bleeding_grade: int = 2 # 0: None, 1: Petechiae, 2: Mucosal/Epistaxis, 3: Gross GI/GU, 4: CNS/ICH
    bleeding_manifestations: List[str] = None # ["Bilateral epistaxis", "Extensive oral wet purpura"]
    # Treatment History & Prior Response
    prior_therapies_received: List[str] = None # ["Prednisone (relapsed)", "Dexamethasone (transient response)"]
    has_undergone_splenectomy: bool = False
    current_therapy: str = "Eltrombopag" # "None", "Eltrombopag", "Romiplostim", "Avatrombopag", "Corticosteroids"
    current_daily_dose_mg: float = 50.0 # Current Eltrombopag dose
    weeks_on_current_dose: float = 2.0
    # Demographic & Organ Function Telemetry
    is_east_asian_ancestry: bool = False # If True, starting Eltrombopag dose is 25 mg
    has_hepatic_impairment: bool = False
    serum_alt_u_l: float = 28.0 # Normal ALT < 45
    serum_total_bilirubin_mg_dl: float = 0.8
    serum_hemoglobin_g_dl: float = 13.4

@dataclass
class ITPEvaluationReport:
    patient_id: str
    ash_icr_disease_phase: str # "CHRONIC ITP (> 12 Months)"
    bleeding_risk_category: str # "Grade 2 Mild-Moderate Mucosal Bleeding"
    first_line_recommendations: List[str]
    tpo_ra_titration_guidance: str
    emergency_rescue_protocol: Optional[List[str]]
    safety_sentinels: List[str]
    clinical_ash_icr_directive: str

class AdultITPDecisionEngine:
    """
    Offline clinical engine for ASH 2019/2024 ITP staging, bleeding scoring,
    first-line corticosteroid/IVIG gating, and TPO-RA precision dose titration.
    """

    def classify_ash_phase(self, d: AdultITPTelemetry) -> str:
        if d.has_undergone_splenectomy and d.current_platelet_count_per_ul < 30000:
            return "REFRACTORY ITP (Post-Splenectomy Non-Response / Relapse)"
        elif d.disease_duration_months > 12.0:
            return "CHRONIC ITP (> 12 Months Duration)"
        elif 3.0 <= d.disease_duration_months <= 12.0:
            return "PERSISTENT ITP (3 to 12 Months Duration)"
        else:
            return "NEWLY DIAGNOSED ITP (< 3 Months from Onset)"

    def evaluate_bleeding_and_rescue(self, d: AdultITPTelemetry) -> Tuple[str, Optional[List[str]]]:
        if d.who_bleeding_grade == 4 or (d.current_platelet_count_per_ul < 10000 and d.who_bleeding_grade >= 2):
            risk = "CRITICAL / LIFE-THREATENING HEMORRHAGE (WHO Grade 4 / Critical Low Platelets)"
            rescue = [
                "🚨 STAT ITP EMERGENCY RESCUE PROTOCOL:",
                "1. IV Methylprednisolone 1.0g IV once daily x 3 days.",
                "2. IVIG 1.0 g/kg IV daily x 2 consecutive days (infuse before platelets).",
                "3. Continuous / Multi-Unit Platelet Transfusions (saturates reticuloendothelial Fc receptors).",
                "4. Romiplostim 10 mcg/kg SC STAT (or Eltrombopag 75 mg PO STAT).",
                "5. Tranexamic Acid 1.0g IV q8h (unless active macroscopic hematuria present)."
            ]
        elif d.who_bleeding_grade == 3:
            risk = "SEVERE GROSS BLEEDING (WHO Grade 3 - Transfusion / Packing Required)"
            rescue = [
                "1. High-Dose IVIG 1.0 g/kg IV daily x 1-2 days for rapid platelet rise within 24-48h.",
                "2. High-Dose Dexamethasone 40 mg PO/IV daily x 4 days.",
                "3. Consider platelet transfusion if active uncontrolled gross hemorrhage."
            ]
        elif d.who_bleeding_grade == 2:
            risk = "MILD-MODERATE MUCOSAL BLEEDING (WHO Grade 2 - Epistaxis / Wet Purpura)"
            rescue = None
        elif d.who_bleeding_grade == 1:
            risk = "MINOR CUTANEOUS BLEEDING (WHO Grade 1 - Petechiae / Dry Purpura)"
            rescue = None
        else:
            risk = "NO ACTIVE BLEEDING (WHO Grade 0)"
            rescue = None

        return risk, rescue

    def generate_first_line_orders(self, d: AdultITPTelemetry) -> List[str]:
        plan = []

        if d.current_platelet_count_per_ul >= 30000 and d.who_bleeding_grade <= 1:
            plan.append("1. WATCHFUL OBSERVATION (No Immediate Pharmacotherapy): Platelet count >= 30,000/uL without mucosal bleeding does not mandate drug therapy. Serial CBC monitoring.")
        else:
            plan.append("1. FIRST-LINE CORTICOSTEROID PROTOCOL (Target Platelets > 30,000/uL):")
            plan.append("   • PREFERRED: High-Dose Dexamethasone 40 mg PO daily x 4 days (Cycles may repeat every 14-28 days x 2-3 cycles). Higher sustained response rate than prednisone.")
            plan.append("   • ALTERNATIVE: Oral Prednisone 1.0 mg/kg daily (70 mg/day) x 1-2 weeks, followed by mandatory rapid taper completed by 6 weeks.")
            if d.current_platelet_count_per_ul < 20000 or d.who_bleeding_grade >= 2:
                plan.append("   • ADD-ON IVIG (For Rapid Response): IVIG 1.0 g/kg IV x 1-2 days if urgent platelet elevation is required.")

        return plan

    def titrate_tpo_ra(self, d: AdultITPTelemetry) -> Tuple[str, List[str]]:
        sentinels = []
        plt = d.current_platelet_count_per_ul
        agent = d.current_therapy

        # Target Window: 50,000 to 150,000 /uL
        if agent == "Eltrombopag":
            curr = d.current_daily_dose_mg
            if plt < 50000:
                new_dose = min(75.0, curr + 25.0)
                guidance = f"Eltrombopag Titration: Platelets ({plt:,}/uL) BELOW target window (< 50,000). INCREASE dose from {curr:.0f} mg to {new_dose:.0f} mg PO once daily on empty stomach."
            elif 50000 <= plt <= 150000:
                guidance = f"Eltrombopag Titration: Platelets ({plt:,}/uL) WITHIN optimal target window (50,000 - 150,000). MAINTAIN current dose at {curr:.0f} mg PO daily."
            elif 150000 < plt <= 250000:
                new_dose = max(25.0, curr - 25.0)
                guidance = f"Eltrombopag Titration: Platelets ({plt:,}/uL) elevated (> 150,000). DECREASE dose from {curr:.0f} mg to {new_dose:.0f} mg PO daily to avoid thrombosis."
            else:
                guidance = f"Eltrombopag Titration: Platelets ({plt:,}/uL) SUPRATHERAPEUTIC (> 250,000). TEMPORARILY WITHHOLD Eltrombopag. Resume at {max(25.0, curr - 25.0):.0f} mg daily when platelets < 100,000/uL."
                sentinels.append("🚨 THROMBOSIS SENTINEL: Platelets > 250,000/uL on TPO-RA increases risk of arterial/venous thromboembolism and portal vein thrombosis!")

            # Cation & Dietary Sentinel
            guidance += " (Administer on empty stomach, separated by >= 4 hours from calcium, dairy, antacids, or iron)."

        elif agent == "Romiplostim":
            guidance = f"Romiplostim Titration: Adjust weekly SC dose by 1.0 mcg/kg (Max 10 mcg/kg) to maintain platelets between 50,000 - 150,000/uL."
        elif agent == "Avatrombopag":
            guidance = f"Avatrombopag Titration: Adjust daily dose between 20 mg and 40 mg with food to maintain platelets between 50,000 - 150,000/uL."
        else:
            guidance = "Patient not currently on TPO-RA. If corticosteroids fail or relapse, initiate Second-Line TPO-RA (Eltrombopag 50mg daily [25mg if East Asian] or Romiplostim 1 mcg/kg weekly)."

        return guidance, sentinels

    def evaluate_case(self, data: AdultITPTelemetry) -> ITPEvaluationReport:
        phase = self.classify_ash_phase(data)
        bleed_risk, rescue = self.evaluate_bleeding_and_rescue(data)
        first_line = self.generate_first_line_orders(data)
        tpo_guide, sentinels = self.titrate_tpo_ra(data)

        # Prolonged Steroid Toxicity Sentinel
        sentinels.append("🚨 STEROID STEWARDSHIP: Never prolong corticosteroid therapy beyond 6 to 8 weeks. If unmaintained on taper, transition promptly to Second-Line TPO-RA or Rituximab to prevent steroid-induced osteonecrosis and metabolic toxicity.")

        directives = []
        directives.append(f"STAGE: {phase}.")
        directives.append(f"BLEEDING: {bleed_risk}.")
        directives.append(f"TPO-RA TARGET: 50k-150k/uL.")

        return ITPEvaluationReport(
            patient_id=data.patient_id,
            ash_icr_disease_phase=phase,
            bleeding_risk_category=bleed_risk,
            first_line_recommendations=first_line,
            tpo_ra_titration_guidance=tpo_guide,
            emergency_rescue_protocol=rescue,
            safety_sentinels=sentinels,
            clinical_ash_icr_directive=" ".join(directives)
        )

# Example Execution & Verification
if __name__ == "__main__":
    engine = AdultITPDecisionEngine()

    print("=" * 80)
    print("OpenPHR Clinical Adult Hematology ITP ASH Staging & TPO-RA Titrator")
    print("=" * 80)

    # Test Case 1: 46-year-old female with Chronic ITP (14 months).
    # Current Platelets: 18,000 /uL, WHO Grade 2 Bleeding (Epistaxis & oral wet purpura).
    # Current Rx: Eltrombopag 50 mg PO daily x 2 weeks.
    # Titration: Below 50,000/uL target -> Escalate Eltrombopag to 75 mg PO daily on empty stomach.
    # Sentinel: Strict 4h separation from polyvalent cations (dairy/calcium/iron).
    itp1 = AdultITPTelemetry(
        patient_id="HEME-ITP-6601",
        age_years=46.0,
        patient_weight_kg=70.0,
        disease_duration_months=14.0,
        current_platelet_count_per_ul=18000,
        who_bleeding_grade=2,
        bleeding_manifestations=["Bilateral epistaxis", "Extensive oral wet purpura"],
        prior_therapies_received=["Prednisone (relapsed)", "Dexamethasone (transient response)"],
        has_undergone_splenectomy=False,
        current_therapy="Eltrombopag",
        current_daily_dose_mg=50.0,
        weeks_on_current_dose=2.0,
        is_east_asian_ancestry=False,
        has_hepatic_impairment=False
    )

    rep1 = engine.evaluate_case(itp1)

    print(f"\n[Patient {rep1.patient_id} - ITP Clinical Assessment]")
    print(f"ASH / ICR Phase: {rep1.ash_icr_disease_phase}")
    print(f"Bleeding Severity: {rep1.bleeding_risk_category}")
    print("\nFirst-Line Protocols:")
    for fl in rep1.first_line_recommendations:
        print(f"  {fl}")
    print(f"\nTPO-RA Precision Titration:\n  {rep1.tpo_ra_titration_guidance}")
    if rep1.emergency_rescue_protocol:
        print("\nEmergency Rescue Protocol:")
        for er in rep1.emergency_rescue_protocol:
            print(f"  {er}")
    print("\nSafety Sentinels:")
    for s in rep1.safety_sentinels:
        print(f"  {s}")
    print(f"\nASH / ICR Consensus Directive:\n{rep1.clinical_ash_icr_directive}")

5. Clinical Verification & Guideline Conformance


6. References