Which conditions cause rise in serum igE and also tell me when to consider biologics? what are the indications and absolute contraindications for biologics for treatment of high serum igE . Aslo tell me Which drugs lowers the circulating serum igE levels. If my patients serum ig E is 700 and having recurrent pharyngitis sore throat runny nose what to consider? Also tell me most common cause of High serum ig E among young adult Indian population?
most common cause high serum IgE young adults India allergic disease parasitic
elevated serum IgE India prevalence allergy parasitic infection
| Drug | Mechanism | Effect on IgE |
|---|---|---|
| Omalizumab | Binds free IgE | Drastically lowers free IgE; total IgE remains elevated (trapped in IgE-omalizumab complexes) for up to 1 year |
| Corticosteroids (systemic) | Broad immunosuppression, reduces Th2 cytokines | Modest reduction in total IgE; primarily reduce inflammatory response |
| Dupilumab | Blocks IL-4/IL-13 signaling (which drives IgE class switching) | Reduces IgE synthesis over time |
| Cyclosporine | Suppresses T-cell function, reduces IL-4/IL-13 | Reduces IgE in atopic dermatitis |
| Allergen immunotherapy (AIT) | Induces immune tolerance, shifts Th2 to Th1/Treg | Gradually reduces specific and total IgE over years |
| Anti-helminthic treatment | Eradicating parasitic infection removes chronic IgE stimulus | Normalizes IgE if parasites were the cause |
| Condition | Why consider | Clue |
|---|---|---|
| Allergic rhinitis (primary) | Most likely | Seasonal or perennial triggers |
| Helminthic infection | IgE 700 in India | Eosinophilia, GI symptoms, exposure history |
| ABPA | IgE this high + respiratory symptoms | Check chest X-ray, Aspergillus IgE |
| Hyper-IgE Syndrome | If recurrent bacterial skin/lung infections | Eczema, pneumatoceles, retained teeth |
| Chronic sinusitis with nasal polyps | Concomitant | Smell loss, facial pressure |
Key clinical pearl for India: Always check a CBC with differential when IgE is elevated. If eosinophilia (> 500/uL) is present alongside elevated IgE, parasitic infection must be actively ruled out before attributing the picture purely to allergy. Both conditions can coexist, and treating the parasite alone may normalize IgE substantially.
Create a clinical decision flowchart for managing elevated IgE by etiology
Clinical decision flowchart for managing elevated serum IgE by etiology. Professional medical flowchart with clean white background, blue and teal color scheme, clear boxes and arrows. Start at top: "ELEVATED SERUM IgE (>100 IU/mL)" in large bold header box. First branch: "INITIAL WORKUP" box containing: CBC with differential, Eosinophil count, Detailed allergy history, Stool exam/parasitic serology, Specific IgE (RAST/ImmunoCAP), Chest X-ray if respiratory symptoms. Then split into THREE main branches based on etiology: BRANCH 1 (LEFT) - "ALLERGIC/ATOPIC CAUSE" (blue): - Triggers: aeroallergens, food, drugs - Eosinophilia mild-moderate - Specific IgE positive - Sub-boxes: * Allergic Rhinitis → Intranasal steroids + Antihistamines → If severe/refractory → Omalizumab (IgE 30-700) or Allergen Immunotherapy * Allergic Asthma → ICS + LABA → Step up: Add Omalizumab or Dupilumab or Benralizumab/Mepolizumab (if eosinophilic) * Atopic Dermatitis → Topical steroids/calcineurin inhibitors → Dupilumab if moderate-severe * Chronic Urticaria → Antihistamines → Omalizumab 300mg/month if refractory * ABPA → Itraconazole + Prednisolone → Omalizumab adjunct BRANCH 2 (MIDDLE) - "PARASITIC/INFECTIOUS" (green): - Marked eosinophilia (>1000/uL) - Rural/tropical exposure - Stool exam positive / serology positive - Sub-boxes: * Helminthic (Ascaris, Hookworm, Strongyloides) → Albendazole/Mebendazole/Ivermectin → Recheck IgE at 3 months * Tropical Pulmonary Eosinophilia (TPE/Filaria) → Diethylcarbamazine (DEC) → Monitor IgE decline * Toxocara → Albendazole + steroids if visceral involvement * NOTE: Avoid omalizumab until parasites cleared BRANCH 3 (RIGHT) - "IMMUNODEFICIENCY/RARE CAUSES" (orange/red): - Recurrent bacterial/fungal/viral infections - Hyper-IgE Syndrome (HIES/Job's) → STAT3 mutation testing → Prophylactic antibiotics/antifungals, HSCT if AR-HIES - IgG4-Related Disease → Elevated IgG4, steroids first-line, Rituximab if refractory - Malignancy (Hodgkin lymphoma, IgE myeloma) → Oncology referral, chemotherapy - Omenn Syndrome/SCID → HSCT urgently Bottom section: "BIOLOGIC SELECTION GUIDE" summary table: - Omalizumab: IgE 30-700 IU/mL, allergic asthma/CSU/rhinitis - Dupilumab: Atopic dermatitis, asthma, CRSwNP - Mepolizumab/Benralizumab: Eosinophilic asthma, EGPA - Tezepelumab: Severe asthma any phenotype CONTRAINDICATIONS box (red border): Active parasitic infection, IgE outside dosing range (omalizumab), known hypersensitivity, active serious infection, live vaccines within 30 days Footer: "IgE monitoring: Recheck total IgE at 3-6 months. On omalizumab: measure FREE IgE not total IgE"

Generate a quick reference PDF of IgE-based treatment algorithms
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace empty or missing"
~/ige-protocol/generate_ige_pdf.py
#!/usr/bin/env python3
"""
IgE-Based Treatment Algorithm - Quick Reference PDF
Generated using ReportLab
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import PageBreak
from reportlab.lib.colors import HexColor
OUTPUT = "/home/daytona/workspace/ige-protocol/IgE_Treatment_Algorithm.pdf"
# ── Color palette ──────────────────────────────────────────────────────────────
NAVY = HexColor("#1a3a5c")
TEAL = HexColor("#0d7a8a")
LIGHT_BLUE= HexColor("#d6eaf8")
GREEN = HexColor("#1a6b3c")
LIGHT_GREEN=HexColor("#d5f5e3")
ORANGE = HexColor("#c0392b")
LIGHT_RED = HexColor("#fde8e8")
AMBER = HexColor("#d68910")
LIGHT_AMB = HexColor("#fef9e7")
GREY_HDR = HexColor("#2c3e50")
GREY_LIGHT= HexColor("#f2f3f4")
WHITE = colors.white
BLACK = colors.black
# ── Document setup ─────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=15*mm, rightMargin=15*mm,
topMargin=12*mm, bottomMargin=12*mm,
title="IgE-Based Treatment Algorithm Quick Reference",
author="Orris Medical AI",
)
styles = getSampleStyleSheet()
def style(name, parent="Normal", **kwargs):
return ParagraphStyle(name, parent=styles[parent], **kwargs)
# ── Custom paragraph styles ────────────────────────────────────────────────────
H1 = style("H1", "Heading1", fontSize=17, textColor=WHITE, alignment=TA_CENTER,
spaceAfter=2, spaceBefore=2)
H2 = style("H2", "Heading2", fontSize=11, textColor=WHITE, alignment=TA_LEFT,
spaceAfter=1, spaceBefore=1)
H3 = style("H3", "Heading3", fontSize=9.5, textColor=NAVY, spaceBefore=3, spaceAfter=2)
BODY = style("BODY", fontSize=8.2, leading=12, spaceAfter=2)
BODY_SM = style("BODY_SM", fontSize=7.5, leading=11, spaceAfter=1)
BOLD = style("BOLD", fontSize=8.2, leading=12, fontName="Helvetica-Bold")
CAPTION = style("CAPTION", fontSize=7.2, textColor=HexColor("#555555"), leading=10)
RED_BOLD = style("RED_BOLD", fontSize=8.2, textColor=ORANGE, fontName="Helvetica-Bold")
GREEN_BOLD = style("GREEN_BOLD", fontSize=8.2, textColor=GREEN, fontName="Helvetica-Bold")
W = A4[0] - 30*mm # usable width
story = []
# ══════════════════════════════════════════════════════════════════════════════
# HEADER BANNER
# ══════════════════════════════════════════════════════════════════════════════
header_data = [[
Paragraph("<b>IgE-Based Treatment Algorithm</b><br/>"
"<font size=9>Quick Reference Card for Clinical Practice</font>", H1)
]]
header_tbl = Table(header_data, colWidths=[W])
header_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("ROWPADDING", (0,0), (-1,-1), 8),
("BOX", (0,0), (-1,-1), 0.5, TEAL),
]))
story.append(header_tbl)
story.append(Spacer(1, 4*mm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 1 — NORMAL VALUES & CLASSIFICATION
# ══════════════════════════════════════════════════════════════════════════════
def section_header(title, bg=TEAL):
tbl = Table([[Paragraph(f"<b>{title}</b>", H2)]], colWidths=[W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("ROWPADDING", (0,0), (-1,-1), 5),
("BOX", (0,0), (-1,-1), 0.3, WHITE),
]))
return tbl
story.append(section_header("1. Normal IgE Values & Interpretation"))
story.append(Spacer(1, 2*mm))
ige_class_data = [
[Paragraph("<b>Serum IgE (IU/mL)</b>", BOLD),
Paragraph("<b>Interpretation</b>", BOLD),
Paragraph("<b>Common Context</b>", BOLD)],
["< 10", "Very low", "Possible IgE deficiency; recurrent infections"],
["10 – 100", "Normal", "Healthy adults"],
["100 – 500", "Mildly elevated", "Mild atopy, early sensitisation, low helminth load"],
["500 – 2000","Moderately elevated","Active allergy, moderate helminthic infection, ABPA"],
["> 2000", "Markedly elevated", "Hyper-IgE syndrome, heavy helminthiasis, ABPA flare"],
["> 10 000", "Very high", "Severe HIES (Job's), ABPA, heavy parasitic burden"],
]
t = Table(ige_class_data, colWidths=[W*0.20, W*0.28, W*0.52])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), GREY_HDR),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LIGHT]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("ROWPADDING", (0,0), (-1,-1), 4),
("ALIGN", (0,0), (0,-1), "CENTER"),
]))
story.append(t)
story.append(Spacer(1, 4*mm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 2 — INITIAL WORKUP ALGORITHM
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("2. Initial Workup When IgE > 100 IU/mL"))
story.append(Spacer(1, 2*mm))
workup_steps = [
["Step", "Investigation", "Purpose / Key Finding"],
["1", "CBC with differential + absolute eosinophil count",
"Eosinophils >500/µL → allergy or parasite; >1500/µL → helminthic or HIES"],
["2", "Detailed allergy history (triggers, seasonality, family history)",
"Guides specific IgE panel selection"],
["3", "Specific IgE (ImmunoCAP/RAST) or skin-prick test",
"Identifies sensitising allergen (HDM, cockroach, mold, food, drug)"],
["4", "Stool microscopy × 3 + Strongyloides / Toxocara serology",
"Mandatory in India/tropical settings; rules out helminthic cause"],
["5", "Chest X-ray / CT chest (if respiratory symptoms)",
"Central bronchiectasis/mucus plugging → ABPA; pneumatoceles → HIES"],
["6", "Aspergillus-specific IgE + Aspergillus precipitins",
"If IgE >1000 + asthma → rule out ABPA"],
["7", "IgG4 level (if multi-organ involvement, eosinophilia)",
"IgG4-related disease: elevated IgG4 + IgE + eosinophilia"],
["8", "STAT3 / DOCK8 genetic testing (if recurrent bacterial/viral infections)",
"Hyper-IgE Syndrome (AD-HIES/AR-HIES)"],
]
tw = [W*0.06, W*0.38, W*0.56]
wt = Table(workup_steps, colWidths=tw)
wt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), GREY_HDR),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.8),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LIGHT]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("ROWPADDING", (0,0), (-1,-1), 4),
("ALIGN", (0,0), (0,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(wt)
story.append(Spacer(1, 4*mm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 3 — TREATMENT BY ETIOLOGY (3-column layout)
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("3. Treatment Algorithm by Etiology"))
story.append(Spacer(1, 2*mm))
col_w = (W - 4*mm) / 3
def etiology_box(title, bg, items):
"""Create a coloured etiology column."""
hdr = Table([[Paragraph(f"<b>{title}</b>",
style("eh", fontSize=9, textColor=WHITE, alignment=TA_CENTER))]],
colWidths=[col_w])
hdr.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("ROWPADDING", (0,0), (-1,-1), 5),
]))
rows = [[hdr]]
for bullet, text in items:
rows.append([Paragraph(f"<b>{bullet}</b> {text}",
style("eb", fontSize=7.6, leading=11, leftIndent=4))])
inner = Table(rows, colWidths=[col_w])
inner.setStyle(TableStyle([
("BOX", (0,0), (-1,-1), 0.5, bg),
("ROWPADDING", (0,1), (-1,-1), 3),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return inner
allergic_items = [
("Allergic Rhinitis:", "1st line: Intranasal corticosteroids + 2nd-gen antihistamine + saline irrigation"),
("→ Refractory:", "Allergen immunotherapy (AIT) — lowers IgE long-term"),
("→ Severe:", "Omalizumab (IgE 30–700 IU/mL) — every 2–4 weeks SC"),
("Allergic Asthma:", "Step 1–3: SABA + ICS ± LABA"),
("→ Step 4–5:", "Add Omalizumab (allergic) or Mepolizumab/Benralizumab (eosinophilic) or Dupilumab or Tezepelumab"),
("Atopic Dermatitis:", "Mild: topical steroids / calcineurin inhibitors"),
("→ Moderate–Severe:", "Dupilumab 300 mg SC q2w"),
("Chronic Urticaria:", "Antihistamine (up to 4×) → Omalizumab 300 mg/month"),
("ABPA:", "Prednisolone + Itraconazole; Omalizumab adjunct if refractory"),
("Eosinophilic Esophagitis:", "PPI + topical steroids → Dupilumab"),
]
parasitic_items = [
("⚠ Key clue:", "Eosinophils >1000/µL + tropical exposure + rural/India"),
("Ascaris/Hookworm:", "Albendazole 400 mg single dose; repeat in 2 weeks"),
("Strongyloides:", "Ivermectin 200 µg/kg × 2 days (preferred over albendazole)"),
("Toxocara (VLM):", "Albendazole 400 mg BD × 5 days + steroids if severe"),
("TPE (Filaria):", "Diethylcarbamazine (DEC) 6 mg/kg/day × 3 weeks"),
("Schistosoma:", "Praziquantel 40 mg/kg single dose"),
("Echinococcus:", "Albendazole + surgery/PAIR procedure"),
("Monitor:", "Recheck total IgE at 3 months post-treatment"),
("Biologic use:", "Avoid omalizumab until parasites are cleared — may impair anti-parasite immunity"),
]
rare_items = [
("AD-HIES (Job's):", "STAT3 mutation; recurrent bacterial/fungal infections, pneumatoceles, retained teeth"),
("Treatment:", "Prophylactic TMP-SMX + antifungal (voriconazole/itraconazole); avoid live vaccines"),
("AR-HIES (DOCK8):", "Severe viral infections; indication for HSCT"),
("IgG4-RD:", "Oral prednisolone 0.5–1 mg/kg; Rituximab if refractory"),
("EGPA:", "High-dose steroids + cyclophosphamide; Mepolizumab for eosinophilic phase"),
("Hodgkin Lymphoma:", "Oncology referral; chemotherapy (ABVD/BEV-ABVD)"),
("IgE Myeloma:", "Haematology referral; standard myeloma protocols"),
("Omenn SCID:", "Urgent HSCT — IgE extremely high (>10,000)"),
]
etiology_table = Table(
[[etiology_box("ALLERGIC / ATOPIC", TEAL, allergic_items),
Spacer(2*mm, 1),
etiology_box("PARASITIC / INFECTIOUS", GREEN, parasitic_items),
Spacer(2*mm, 1),
etiology_box("IMMUNODEFICIENCY / RARE", ORANGE, rare_items)]],
colWidths=[col_w, 2*mm, col_w, 2*mm, col_w]
)
etiology_table.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(etiology_table)
story.append(Spacer(1, 4*mm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 4 — BIOLOGIC SELECTION GUIDE
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("4. Biologic Selection Guide"))
story.append(Spacer(1, 2*mm))
bio_data = [
["Biologic", "Target", "IgE Requirement", "Approved Indications", "Dose & Route", "Key Adverse Effects"],
["Omalizumab\n(Xolair)", "Free IgE\n(anti-IgE)", "30–700 IU/mL\nfor asthma indication;\nCSU: any IgE",
"Allergic asthma (≥12yr)\nChronic spontaneous urticaria\nAllergic rhinitis (trials)",
"Weight + IgE-based\nSC every 2–4 weeks\n(CSU: 300 mg/month)",
"Anaphylaxis (monitor 30–60 min)\nLocal site reaction\nArteriothrombotic events"],
["Dupilumab\n(Dupixent)", "IL-4Rα\n(blocks IL-4 + IL-13)", "No IgE threshold\nrequired",
"Moderate–severe atopic dermatitis\nModerate–severe asthma\nCRSwNP\nEosinophilic esophagitis",
"300 mg SC q2w\n(loading 600 mg)",
"Conjunctivitis\nInjection site reaction\nEosinophilia (transient)"],
["Mepolizumab\n(Nucala)", "IL-5\n(anti-IL-5)", "Not IgE-based;\neosinophils ≥150/µL",
"Severe eosinophilic asthma\nEGPA (Churg-Strauss)\nHypereosinophilic syndrome",
"100 mg SC q4w",
"Anaphylaxis\nAngioedema\nHeadache"],
["Benralizumab\n(Fasenra)", "IL-5Rα\n(anti-IL-5 receptor)", "Not IgE-based;\neosinophils ≥300/µL preferred",
"Severe eosinophilic asthma",
"30 mg SC q4w × 3\nthen q8w",
"Hypersensitivity\nNasopharyngitis"],
["Reslizumab\n(Cinqair)", "IL-5\n(anti-IL-5)", "Not IgE-based;\neosinophils ≥400/µL",
"Severe eosinophilic asthma",
"3 mg/kg IV q4w",
"Anaphylaxis (IV infusion)\nMuscle pain"],
["Tezepelumab\n(Tezspire)", "TSLP\n(anti-TSLP)", "No IgE/eosinophil\nthreshold required",
"Severe asthma (any phenotype)\n— broadest biologic",
"210 mg SC q4w",
"Pharyngitis\nBack pain\nInjection site reaction"],
]
bio_cw = [W*0.11, W*0.10, W*0.14, W*0.26, W*0.19, W*0.20]
bt = Table(bio_data, colWidths=bio_cw)
bt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), GREY_HDR),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.2),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LIGHT]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("ROWPADDING", (0,0), (-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "TOP"),
# Highlight omalizumab row
("BACKGROUND", (0,1), (-1,1), LIGHT_BLUE),
# Highlight tezepelumab row (broadest)
("BACKGROUND", (0,6), (-1,6), LIGHT_AMB),
]))
story.append(bt)
story.append(Spacer(1, 4*mm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 5 — ABSOLUTE CONTRAINDICATIONS
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("5. Absolute / Important Contraindications to Biologics", bg=ORANGE))
story.append(Spacer(1, 2*mm))
contra_data = [
["Contraindication", "Applies To", "Rationale"],
["Known hypersensitivity / anaphylaxis to the biologic",
"All biologics", "Class effect; alternate agent required"],
["Active helminthic/parasitic infection",
"All (especially omalizumab)", "May impair protective IgE-mediated anti-parasite immunity; treat parasites first"],
["Serum IgE < 30 or > 700 IU/mL (asthma indication)",
"Omalizumab (asthma)", "Outside validated dosing range; dose cannot be accurately calculated"],
["Non-allergic (intrinsic) asthma with normal IgE",
"Omalizumab", "Mechanism of action requires allergen-IgE pathway"],
["Active serious bacterial/viral/fungal infection",
"All biologics", "Immunomodulation may worsen active infection"],
["Live vaccines within 30 days prior to initiation",
"All biologics (esp. dupilumab)", "Risk of disseminated vaccine-strain infection"],
["Active malignancy (relative — case-by-case)",
"All biologics", "Insufficient safety data; Th2 shift may promote some tumour progression"],
["Pregnancy (relative — insufficient data for most)",
"All biologics", "Risk-benefit discussion required; omalizumab has most data (category B-like)"],
]
cc = [W*0.35, W*0.23, W*0.42]
ct = Table(contra_data, colWidths=cc)
ct.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), HexColor("#7b241c")),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_RED]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("ROWPADDING", (0,0), (-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(ct)
story.append(Spacer(1, 4*mm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 6 — DRUGS THAT LOWER IgE + MONITORING
# ══════════════════════════════════════════════════════════════════════════════
left_w = W * 0.53
right_w = W * 0.45
# Left: Drugs lowering IgE
lower_data = [
[Paragraph("<b>Drugs / Interventions That Lower Serum IgE</b>",
style("lh", fontSize=9, textColor=WHITE, alignment=TA_CENTER))],
]
lower_tbl = Table(lower_data, colWidths=[left_w])
lower_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), TEAL),
("ROWPADDING", (0,0), (-1,-1), 5),
]))
lower_rows = [
["Drug / Intervention", "Effect on IgE", "Notes"],
["Omalizumab", "↓ Free IgE dramatically\n(total IgE rises paradoxically)", "Total IgE stays elevated up to 1 yr after stopping — measure FREE IgE on treatment"],
["Allergen Immunotherapy (AIT)", "Gradual ↓ specific + total IgE over 3–5 yrs", "Only intervention with long-term remission"],
["Dupilumab", "Slow ↓ IgE synthesis (blocks IL-4/IL-13 class switch)", "IgE falls over months; not primarily an IgE-lowering drug"],
["Systemic corticosteroids", "Modest ↓ via Th2 suppression", "Short-term effect; not suitable long-term"],
["Cyclosporine", "↓ IgE in atopic dermatitis via T-cell suppression", "Second-line for atopic dermatitis"],
["Anti-helminthic treatment", "Normalises IgE if parasites were driving it", "Recheck IgE at 3 months post-treatment"],
]
lt = Table(lower_rows, colWidths=[left_w*0.28, left_w*0.34, left_w*0.38])
lt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), GREY_HDR),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.2),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LIGHT]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("ROWPADDING", (0,0), (-1,-1), 3.5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
# Right: Monitoring
monitor_data = [
[Paragraph("<b>Monitoring Protocol</b>",
style("mh", fontSize=9, textColor=WHITE, alignment=TA_CENTER))],
]
monitor_tbl = Table(monitor_data, colWidths=[right_w])
monitor_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("ROWPADDING", (0,0), (-1,-1), 5),
]))
monitor_items = [
("Baseline:", "Total IgE + specific IgE + CBC with eosinophils"),
("On biologic therapy:", "Absolute eosinophil count every 3 months"),
("Omalizumab:", "Measure FREE IgE (not total) to assess response\nTotal IgE unreliable for up to 1 year"),
("IgE re-check:", "Every 3–6 months during treatment\nAnnually once stable"),
("Response criteria:", "≥25% fall in total IgE (ABPA protocol)\nClinical symptom improvement"),
("Skin testing:", "Wait ≥8 weeks after stopping omalizumab before skin-prick testing — drug affects wheal/flare"),
("India-specific:", "Always re-check stool exam if IgE fails to fall\nCo-infection with helminth is common"),
]
mon_rows = [[Paragraph(f"<b>{k}</b>", style("mk", fontSize=7.5, leading=10)),
Paragraph(v, style("mv", fontSize=7.5, leading=10))]
for k, v in monitor_items]
mt = Table([[monitor_tbl]] + [[Table(mon_rows, colWidths=[right_w*0.28, right_w*0.72],
style=TableStyle([
("FONTSIZE", (0,0), (-1,-1), 7.5),
("ROWBACKGROUNDS", (0,0), (-1,-1), [WHITE, GREY_LIGHT]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("ROWPADDING", (0,0), (-1,-1), 3.5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))]],
colWidths=[right_w]
)
mt.setStyle(TableStyle([
("BOX", (0,0), (-1,-1), 0.5, NAVY),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
combined = Table(
[[Table([[lower_tbl], [lt]], colWidths=[left_w],
style=TableStyle([("VALIGN",(0,0),(-1,-1),"TOP"),("BOX",(0,0),(-1,-1),0.5,TEAL)])),
Spacer(2*mm, 1),
mt]],
colWidths=[left_w, 2*mm, right_w]
)
combined.setStyle(TableStyle([("VALIGN",(0,0),(-1,-1),"TOP")]))
story.append(section_header("6. Drugs That Lower IgE & Monitoring Protocol"))
story.append(Spacer(1, 2*mm))
story.append(combined)
story.append(Spacer(1, 4*mm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 7 — CLINICAL SCENARIO ALGORITHM (IgE 700 + pharyngitis + rhinitis)
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("7. Clinical Algorithm: IgE = 700 IU/mL + Recurrent Pharyngitis + Rhinitis"))
story.append(Spacer(1, 2*mm))
scenario_data = [
["Step", "Action", "Expected Finding / Next Step"],
["1. Clinical assessment",
"Characterise symptoms: seasonal vs perennial?\nTriggered by dust, pollen, cockroach?\nGI symptoms? Travel/rural exposure?\nSkin changes (eczema)?",
"Seasonal → pollen allergy\nPerennial → HDM, cockroach (most common in India)\nGI symptoms → consider helminth co-infection"],
["2. CBC + differential",
"Eosinophil count",
"Eos <500/µL → allergic rhinitis likely\nEos >1000/µL → rule out helminthic infection FIRST"],
["3. Specific IgE / Skin test",
"Test for: HDM (D. pteronyssinus/D. farinae), cockroach\n(Periplaneta americana), Alternaria, Aspergillus, food panel",
"Positive specific IgE confirms allergen(s)\nCockroach IgE most commonly positive in urban India"],
["4. Stool exam × 3 + serology",
"Strongyloides IgG ELISA, Toxocara IgG, Ascaris IgG",
"If positive → treat parasite first; recheck IgE in 3 months before biologic decision"],
["5. Diagnose + treat primary cause",
"Allergic rhinitis + post-nasal drip:\n→ Intranasal fluticasone/mometasone daily\n→ Cetirizine/loratadine 10 mg OD\n→ Saline nasal irrigation BD",
"Post-nasal drip is the cause of recurrent 'pharyngitis'\nNo antibiotics needed for this — treat rhinitis"],
["6. Escalation if uncontrolled",
"Allergen immunotherapy (AIT) for long-term remission\nIf severe asthma develops → Omalizumab\n(IgE 700 is at upper limit of dosing range — eligible)",
"Omalizumab dose at IgE 700: weight-based (use online calculator)\nAlso treats allergic rhinitis (clinical trial evidence)"],
["7. Biologic eligibility check",
"Omalizumab: IgE must be 30–700 IU/mL ✓\nAge ≥12 years ✓\nSensitisation to perennial allergen confirmed ✓\nNo active parasitic infection ✓",
"Patient is ELIGIBLE for omalizumab IF:\n• Moderate–severe persistent allergic asthma present\n• ICS + LABA insufficient control\n• No active helminthic infection"],
]
sc_cw = [W*0.18, W*0.40, W*0.42]
sct = Table(scenario_data, colWidths=sc_cw)
sct.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), GREY_HDR),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LIGHT]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("ROWPADDING", (0,0), (-1,-1), 4.5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("BACKGROUND", (0,6), (-1,6), LIGHT_BLUE), # highlight biologic row
]))
story.append(sct)
story.append(Spacer(1, 4*mm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 8 — INDIA-SPECIFIC KEY POINTS
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("8. India-Specific Considerations (Young Adult Population)", bg=AMBER))
story.append(Spacer(1, 2*mm))
india_points = [
("#1 Cause – Urban India:", "Allergic rhinitis (sensitised to house dust mite + cockroach). Cockroach (Periplaneta americana) is the single most common sensitising aeroallergen in Indian urban adults."),
("#1 Cause – Rural/Semi-urban India:", "Helminthic parasitic infection (Ascaris, hookworm, Strongyloides) — warm humid climate + agrarian soil contact = high transmission. Always rule out before biologic therapy."),
("Dual Cause:", "Both allergy AND parasite can coexist. Treat helminth first; IgE may fall significantly — may alter biologic eligibility."),
("Tropical Pulmonary Eosinophilia (TPE):", "Filarial infection (Wuchereria bancrofti/Brugia malayi) — classical triad: nocturnal cough + wheeze + eosinophilia >3000/µL + IgE very high. Treat with Diethylcarbamazine (DEC)."),
("Hygiene Hypothesis:", "Rapidly urbanising India shows rising atopic prevalence as helminth burden falls. Young adults in metros have allergy rates approaching Western countries (20–30%)."),
("Biologic Access:", "Omalizumab and dupilumab available in India but expensive. RAST/ImmunoCAP testing available at tertiary centres. AIT is cost-effective long-term alternative."),
("Important Pitfall:", "Recurrent 'pharyngitis' in young Indians with high IgE is most often allergic post-nasal drip — NOT recurrent streptococcal infection. Avoid repeated antibiotic courses; treat rhinitis."),
]
india_rows = [[Paragraph(f"<b>{k}</b>", style("ik", fontSize=7.8, textColor=NAVY, leading=11)),
Paragraph(v, style("iv", fontSize=7.8, leading=11))]
for k, v in india_points]
it = Table(india_rows, colWidths=[W*0.28, W*0.72])
it.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [LIGHT_AMB, WHITE]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("ROWPADDING", (0,0), (-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(it)
story.append(Spacer(1, 4*mm))
# ══════════════════════════════════════════════════════════════════════════════
# FOOTER
# ══════════════════════════════════════════════════════════════════════════════
story.append(HRFlowable(width=W, thickness=0.5, color=TEAL))
story.append(Spacer(1, 2*mm))
footer_txt = (
"<b>Sources:</b> Harrison's Principles of Internal Medicine 22E (2025, McGraw Hill) · "
"Goldman-Cecil Medicine International Edition · K.J. Lee's Essential Otolaryngology · "
"Katzung's Basic & Clinical Pharmacology 16th Ed. · Fishman's Pulmonary Diseases · "
"Murray & Nadel's Textbook of Respiratory Medicine · Fitzpatrick's Dermatology 9th Ed. | "
"<b>Generated by Orris Medical AI · May 2026</b> | "
"<i>For clinical guidance only. Verify doses against current product labelling and institutional protocols.</i>"
)
story.append(Paragraph(footer_txt, style("FT", fontSize=6.5, textColor=HexColor("#666666"), leading=9)))
# ══════════════════════════════════════════════════════════════════════════════
# BUILD
# ══════════════════════════════════════════════════════════════════════════════
doc.build(story)
print(f"PDF generated: {OUTPUT}")
cd /home/daytona/workspace/ige-protocol && python3 generate_ige_pdf.py 2>&1
~/ige-protocol/generate_ige_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ige-protocol/generate_ige_pdf.py'
cd /home/daytona/workspace/ige-protocol && python3 generate_ige_pdf.py 2>&1
~/ige-protocol/generate_ige_pdf.py
#!/usr/bin/env python3
"""
IgE-Based Treatment Algorithm - Quick Reference PDF
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.lib.colors import HexColor
OUTPUT = "/home/daytona/workspace/ige-protocol/IgE_Treatment_Algorithm.pdf"
# Colors
NAVY = HexColor("#1a3a5c")
TEAL = HexColor("#0d7a8a")
LIGHT_BLUE = HexColor("#d6eaf8")
GREEN = HexColor("#1a6b3c")
LIGHT_GREEN= HexColor("#d5f5e3")
ORANGE = HexColor("#c0392b")
LIGHT_RED = HexColor("#fde8e8")
AMBER = HexColor("#d68910")
LIGHT_AMB = HexColor("#fef9e7")
GREY_HDR = HexColor("#2c3e50")
GREY_LIGHT = HexColor("#f2f3f4")
WHITE = colors.white
W = A4[0] - 30*mm # usable page width
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=15*mm, rightMargin=15*mm,
topMargin=12*mm, bottomMargin=12*mm,
title="IgE-Based Treatment Algorithm Quick Reference",
author="Orris Medical AI",
)
styles = getSampleStyleSheet()
def ps(name, **kw):
return ParagraphStyle(name, parent=styles["Normal"], **kw)
HDR_STYLE = ps("HDR", fontSize=16, textColor=WHITE, alignment=TA_CENTER, leading=22)
SEC_STYLE = ps("SEC", fontSize=9.5, textColor=WHITE, alignment=TA_LEFT, leading=13)
BODY = ps("BODY", fontSize=8, leading=11)
BODY_B = ps("BODYB",fontSize=8, leading=11, fontName="Helvetica-Bold")
SMALL = ps("SMALL",fontSize=7.2, leading=10)
SMALL_B = ps("SMALLB",fontSize=7.2,leading=10, fontName="Helvetica-Bold")
CAP = ps("CAP", fontSize=6.5, textColor=HexColor("#666666"), leading=9)
story = []
# ── helpers ───────────────────────────────────────────────────────────────────
def banner(text, sub="", bg=NAVY):
content = f"<b>{text}</b>"
if sub:
content += f"<br/><font size=9>{sub}</font>"
t = Table([[Paragraph(content, HDR_STYLE)]], colWidths=[W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING",(0,0),(-1,-1),8),
("BOX", (0,0), (-1,-1), 0.5, TEAL),
]))
return t
def sec_hdr(text, bg=TEAL):
t = Table([[Paragraph(f"<b>{text}</b>", SEC_STYLE)]], colWidths=[W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1),5),
]))
return t
def simple_table(rows, col_widths, header_bg=GREY_HDR, row_bgs=None):
if row_bgs is None:
row_bgs = [WHITE, GREY_LIGHT]
t = Table(rows, colWidths=col_widths)
style_cmds = [
("BACKGROUND", (0,0), (-1,0), header_bg),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), row_bgs),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING",(0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]
t.setStyle(TableStyle(style_cmds))
return t
def p(text, sty=None, **kw):
if sty is None:
sty = SMALL
return Paragraph(text, sty)
def pb(text, **kw):
return Paragraph(f"<b>{text}</b>", SMALL_B)
# ═══════════════════════════════════════════════════════════════════════════════
# PAGE 1
# ═══════════════════════════════════════════════════════════════════════════════
story.append(banner(
"IgE-Based Treatment Algorithm",
"Quick Reference Card for Clinical Practice · Orris Medical AI · May 2026"
))
story.append(Spacer(1, 3*mm))
# ── Section 1: Normal values ──────────────────────────────────────────────────
story.append(sec_hdr("1. Normal IgE Values & Interpretation"))
story.append(Spacer(1, 1.5*mm))
rows = [
[pb("Serum IgE (IU/mL)"), pb("Interpretation"), pb("Common Context")],
[p("< 10"), p("Very low"), p("Possible IgE deficiency; recurrent sinopulmonary infections")],
[p("10 – 100"), p("Normal"), p("Healthy adult")],
[p("100 – 500"), p("Mildly elevated"), p("Mild atopy, early sensitisation, low helminth load")],
[p("500 – 2000"),p("Moderately elevated"),p("Active allergy, moderate helminthic infection, ABPA watch")],
[p("> 2000"), p("Markedly elevated"), p("Hyper-IgE syndrome, heavy helminthiasis, ABPA flare")],
[p("> 10 000"), p("Very high"), p("Severe HIES (Job's Syndrome), ABPA, heavy parasitic burden")],
]
story.append(simple_table(rows, [W*0.18, W*0.22, W*0.60]))
story.append(Spacer(1, 3*mm))
# ── Section 2: Initial Workup ─────────────────────────────────────────────────
story.append(sec_hdr("2. Initial Workup When IgE > 100 IU/mL"))
story.append(Spacer(1, 1.5*mm))
rows = [
[pb("Step"), pb("Investigation"), pb("Key Finding / Purpose")],
[p("1"), p("CBC with differential + absolute eosinophil count"),
p("Eos >500/µL → allergy or parasite; >1500/µL → helminthic or HIES strongly suspected")],
[p("2"), p("Detailed allergy history (triggers, seasonality, family history)"),
p("Seasonal → pollen; perennial → HDM/cockroach (India: cockroach most common)")],
[p("3"), p("Specific IgE panel (ImmunoCAP/RAST) or skin-prick test"),
p("Identifies sensitising allergen. Panel: HDM, cockroach, mold, food, drug")],
[p("4"), p("Stool microscopy ×3 + Strongyloides IgG / Toxocara IgG / Ascaris IgG"),
p("Mandatory in India/tropical settings. Rule out before starting biologics")],
[p("5"), p("Chest X-ray / HRCT chest (if respiratory symptoms)"),
p("Central bronchiectasis/mucus plugging → ABPA; pneumatoceles → HIES")],
[p("6"), p("Aspergillus-specific IgE + Aspergillus precipitins (if IgE >1000)"),
p("ABPA diagnosis requires Aspergillus IgE >0.35 kUA/L + compatible radiology")],
[p("7"), p("IgG4 level (multi-organ involvement, eosinophilia)"),
p("IgG4-related disease: elevated IgG4 + IgE + eosinophilia + hypocomplementemia")],
[p("8"), p("STAT3 / DOCK8 genetic testing (recurrent bacterial/viral/fungal infections)"),
p("Hyper-IgE Syndrome (AD-HIES = STAT3; AR-HIES = DOCK8)")],
]
story.append(simple_table(rows, [W*0.05, W*0.43, W*0.52]))
story.append(Spacer(1, 3*mm))
# ── Section 3: Treatment by Etiology ─────────────────────────────────────────
story.append(sec_hdr("3. Treatment Algorithm by Etiology"))
story.append(Spacer(1, 1.5*mm))
# 3a — Allergic/Atopic
t3a_hdr = Table([[p("<b>ALLERGIC / ATOPIC CAUSES</b>", ps("t3ah", fontSize=8.5, textColor=WHITE, alignment=TA_CENTER))]], colWidths=[W])
t3a_hdr.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),TEAL),("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4)]))
story.append(t3a_hdr)
rows = [
[pb("Condition"), pb("1st Line"), pb("Escalation"), pb("Biologic Option")],
[p("Allergic Rhinitis"),
p("Intranasal corticosteroids (fluticasone/mometasone) + 2nd-gen antihistamine + saline irrigation"),
p("Allergen immunotherapy (AIT) — lowers IgE long-term; montelukast adjunct"),
p("Omalizumab (IgE 30–700)\nif severe + asthma coexists")],
[p("Allergic Asthma\n(Step 1–3)"),
p("SABA PRN → Low-dose ICS → ICS + LABA"),
p("Step 4: Medium-high ICS + LABA\nStep 5: Add oral corticosteroid or biologic"),
p("Omalizumab (allergic, IgE 30–700)\nDupilumab (any IgE)\nTezepelumab (any phenotype)")],
[p("Eosinophilic Asthma\n(blood Eos ≥150/µL)"),
p("ICS + LABA"),
p("Maximise ICS; consider oral prednisone burst"),
p("Mepolizumab 100 mg SC q4w\nBenralizumab 30 mg SC q4/8w\nReslizumab 3 mg/kg IV q4w")],
[p("Atopic Dermatitis"),
p("Emollients + topical steroids / calcineurin inhibitors"),
p("Cyclosporine / methotrexate (short-term)"),
p("Dupilumab 300 mg SC q2w\n(mod–severe uncontrolled)")],
[p("Chronic Spontaneous\nUrticaria (CSU)"),
p("2nd-gen antihistamine (up to 4× standard dose)"),
p("Add montelukast; short-course steroids for flare"),
p("Omalizumab 300 mg SC/month\n(no IgE threshold for CSU)")],
[p("ABPA"),
p("Prednisolone 0.5 mg/kg/day × 2 wks then taper\n+ Itraconazole 200 mg BD × 4 months"),
p("Monitor IgE: ≥25% fall = good response\nLong-term itraconazole for recurrent ABPA"),
p("Omalizumab adjunct for\nrefractory/recurrent ABPA")],
[p("Eosinophilic\nEsophagitis"),
p("PPI + swallowed topical fluticasone/budesonide"),
p("Dietary elimination therapy (6-food elimination)"),
p("Dupilumab 300 mg SC q2w")],
]
story.append(simple_table(rows, [W*0.14, W*0.30, W*0.28, W*0.28]))
story.append(Spacer(1, 2*mm))
# 3b — Parasitic
t3b_hdr = Table([[p("<b>PARASITIC / INFECTIOUS CAUSES — ⚠ Treat Parasite BEFORE Starting Biologics</b>",
ps("t3bh", fontSize=8.5, textColor=WHITE, alignment=TA_CENTER))]],
colWidths=[W])
t3b_hdr.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),GREEN),("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4)]))
story.append(t3b_hdr)
rows = [
[pb("Organism"), pb("Clinical Clue"), pb("Treatment"), pb("IgE Follow-up")],
[p("Ascaris lumbricoides\n(Roundworm)"),
p("Loeffler syndrome (transient pulmonary eosinophilia), abdominal pain, worms in stool"),
p("Albendazole 400 mg single dose OR\nMebendazole 500 mg single dose"),
p("Recheck at 3 months")],
[p("Hookworm\n(Ancylostoma/Necator)"),
p("Iron-deficiency anaemia, hypoproteinaemia, pruritus plantaris, soil exposure"),
p("Albendazole 400 mg × 3 days\n(single dose less effective for hookworm)"),
p("IgE may take 6 months to normalise")],
[p("Strongyloides"),
p("Larva currens rash, eosinophilia, can disseminate if immunosuppressed — check BEFORE steroids/biologics"),
p("Ivermectin 200 µg/kg/day × 2 days\n(drug of choice; repeat in 2 weeks)"),
p("Critical: treat before any immunosuppression")],
[p("Toxocara (VLM/OLM)"),
p("Children/dog exposure, hepatomegaly, eosinophilia, positive Toxocara IgG ELISA"),
p("Albendazole 400 mg BD × 5 days\n+ prednisolone if severe organ involvement"),
p("Recheck at 3 months")],
[p("Tropical Pulmonary\nEosinophilia (TPE)\n[Filaria]"),
p("Nocturnal cough/wheeze + Eos >3000/µL + IgE very high. Endemic: India, SE Asia"),
p("Diethylcarbamazine (DEC)\n6 mg/kg/day in 3 divided doses × 3 weeks"),
p("IgE should fall significantly\nafter treatment")],
[p("Schistosoma"),
p("Fresh water exposure, Katayama fever, haematuria, hepatosplenomegaly"),
p("Praziquantel 40 mg/kg as single dose\n(or 20 mg/kg × 2 doses same day)"),
p("Recheck at 3 months")],
]
story.append(simple_table(rows, [W*0.17, W*0.30, W*0.30, W*0.23]))
story.append(Spacer(1, 2*mm))
# 3c — Rare/Immunodeficiency
t3c_hdr = Table([[p("<b>IMMUNODEFICIENCY / RARE CAUSES</b>",
ps("t3ch", fontSize=8.5, textColor=WHITE, alignment=TA_CENTER))]],
colWidths=[W])
t3c_hdr.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),ORANGE),("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4)]))
story.append(t3c_hdr)
rows = [
[pb("Condition"), pb("Key Features"), pb("IgE Level"), pb("Treatment")],
[p("AD-HIES (Job's Syndrome)\nSTAT3 mutation (dominant)"),
p("Recurrent staph skin abscesses + pneumonia + pneumatoceles\nFacial dysmorphia, retained primary teeth, scoliosis, hyperextensibility"),
p(">2000\n(often >10,000)"),
p("Prophylactic TMP-SMX + antifungal (voriconazole)\nAvoid live vaccines; IVIG if antibody defect")],
[p("AR-HIES\nDOCK8 mutation (recessive)"),
p("Severe viral infections (molluscum, HPV, HSV) + recurrent bacterial infections\nLow T and B lymphocyte counts"),
p("Very high"),
p("HSCT — definitive cure\nProphylactic antimicrobials until transplant")],
[p("IgG4-Related Disease"),
p("Multi-organ fibroinflammatory disease; elevated IgG4 + IgE + eosinophilia\nPancreatitis, cholangitis, sialadenitis, aortitis"),
p("Mildly–\nmoderately elevated"),
p("Prednisolone 0.5–1 mg/kg/day → taper\nRituximab for refractory/relapsing disease")],
[p("EGPA\n(Churg-Strauss)"),
p("Asthma + eosinophilia + granulomatous vasculitis\nNeuropathy, cardiac involvement, p-ANCA positive"),
p("Elevated"),
p("High-dose prednisolone ± cyclophosphamide\nMepolizumab for eosinophilic remission maintenance")],
[p("Hodgkin Lymphoma"),
p("B symptoms, painless lymphadenopathy, mediastinal mass, Reed-Sternberg cells"),
p("Mildly elevated"),
p("Oncology referral; ABVD/BEV-ABVD chemotherapy")],
[p("Omenn Syndrome\n(SCID variant)"),
p("Neonatal erythroderma, diarrhoea, failure to thrive, absent B cells, eosinophilia"),
p("Extremely high\n(>10,000)"),
p("Urgent HSCT — life-saving\nSupportive: IVIG, antimicrobial prophylaxis")],
]
story.append(simple_table(rows, [W*0.20, W*0.38, W*0.12, W*0.30]))
story.append(Spacer(1, 3*mm))
# ── Section 4: Biologic selection ────────────────────────────────────────────
story.append(sec_hdr("4. Biologic Selection Guide"))
story.append(Spacer(1, 1.5*mm))
rows = [
[pb("Biologic"), pb("Target"), pb("IgE Threshold"), pb("Approved Indications"), pb("Dose & Route"), pb("Key Adverse Effects")],
[p("Omalizumab\n(Xolair)"),
p("Free IgE"),
p("30–700 IU/mL\n(asthma)\nAny IgE (CSU)"),
p("Allergic asthma ≥12 yr\nChronic spontaneous urticaria\nAllergic rhinitis (trials)"),
p("Weight + IgE-based\nSC q2–4w\nCSU: 300 mg/month"),
p("Anaphylaxis (monitor 30–60 min post-injection)\nLocal site reaction\nArteriothrombotic events")],
[p("Dupilumab\n(Dupixent)"),
p("IL-4Rα\n(IL-4 + IL-13)"),
p("No IgE threshold"),
p("Mod–severe atopic dermatitis\nMod–severe asthma\nCRSwNP\nEosinophilic esophagitis"),
p("300 mg SC q2w\n(loading 600 mg)"),
p("Conjunctivitis (common)\nInjection site reaction\nTransient eosinophilia")],
[p("Mepolizumab\n(Nucala)"),
p("IL-5"),
p("Not IgE-based\nEos ≥150/µL"),
p("Severe eosinophilic asthma\nEGPA (Churg-Strauss)\nHypereosinophilic syndrome"),
p("100 mg SC q4w"),
p("Anaphylaxis / angioedema\nHeadache, fatigue\nBack pain")],
[p("Benralizumab\n(Fasenra)"),
p("IL-5Rα"),
p("Not IgE-based\nEos ≥300/µL preferred"),
p("Severe eosinophilic asthma"),
p("30 mg SC q4w ×3\nthen q8w"),
p("Hypersensitivity reactions\nNasopharyngitis")],
[p("Reslizumab\n(Cinqair)"),
p("IL-5"),
p("Not IgE-based\nEos ≥400/µL"),
p("Severe eosinophilic asthma\n(inadequate ICS control)"),
p("3 mg/kg IV q4w"),
p("Anaphylaxis (IV — higher risk)\nMuscle pain / myalgia")],
[p("Tezepelumab\n(Tezspire)"),
p("TSLP\n(epithelial)"),
p("NO threshold\n(any phenotype)"),
p("Severe asthma — broadest biologic;\nworks regardless of eosinophil level"),
p("210 mg SC q4w"),
p("Pharyngitis\nBack pain\nInjection site reaction")],
]
t = simple_table(rows, [W*0.11, W*0.09, W*0.12, W*0.25, W*0.19, W*0.24])
# Highlight omalizumab (row 1) and tezepelumab (row 6)
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), GREY_HDR),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.2),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LIGHT]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING",(0,0),(-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "TOP"),
("BACKGROUND", (0,1), (-1,1), LIGHT_BLUE), # omalizumab highlighted
("BACKGROUND", (0,6), (-1,6), LIGHT_AMB), # tezepelumab highlighted
]))
story.append(t)
story.append(Spacer(1, 3*mm))
# ── Section 5: Contraindications ──────────────────────────────────────────────
story.append(sec_hdr("5. Absolute / Important Contraindications to Biologics", bg=ORANGE))
story.append(Spacer(1, 1.5*mm))
rows = [
[pb("Contraindication"), pb("Applies To"), pb("Rationale")],
[p("Known hypersensitivity / anaphylaxis to the biologic"),
p("All biologics"),
p("Class effect — switch to alternate agent or class")],
[p("Active helminthic / parasitic infection"),
p("All (especially omalizumab)"),
p("Omalizumab reduces free IgE which is protective against helminths. Treat parasite first; recheck IgE at 3 months")],
[p("Serum IgE <30 or >700 IU/mL (asthma indication only)"),
p("Omalizumab — asthma indication"),
p("Outside validated dosing range; dose cannot be accurately calculated from nomogram")],
[p("Non-allergic (intrinsic) asthma with normal IgE"),
p("Omalizumab"),
p("Mechanism requires allergen–IgE pathway activation; no benefit without it")],
[p("Active serious infection (bacterial / fungal / viral)"),
p("All biologics"),
p("Immunomodulation may worsen active infection; treat and clear infection first")],
[p("Live vaccines within 30 days before or after starting"),
p("All biologics (esp. dupilumab)"),
p("Risk of disseminated vaccine-strain infection; give all live vaccines before initiating biologic")],
[p("Active malignancy (relative)"),
p("All biologics"),
p("Insufficient safety data; Th2 skewing may promote some tumours — case-by-case oncology review")],
[p("Pregnancy (relative — insufficient data for most)"),
p("All biologics"),
p("Omalizumab has most pregnancy data (used for severe asthma). Shared decision-making required")],
]
t = Table(rows, colWidths=[W*0.35, W*0.22, W*0.43])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), HexColor("#7b241c")),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_RED]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING",(0,0),(-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(t)
story.append(Spacer(1, 3*mm))
# ── Section 6: Drugs lowering IgE ────────────────────────────────────────────
story.append(sec_hdr("6. Drugs / Interventions That Lower Serum IgE"))
story.append(Spacer(1, 1.5*mm))
rows = [
[pb("Drug / Intervention"), pb("Effect on IgE"), pb("Mechanism"), pb("Notes")],
[p("Omalizumab"),
p("Dramatically lowers FREE IgE\n(total IgE paradoxically rises)"),
p("Binds circulating free IgE; IgE–drug complexes measured as total IgE"),
p("Measure FREE IgE on treatment. Total IgE remains elevated up to 1 year after stopping")],
[p("Allergen Immunotherapy (AIT)"),
p("Gradual ↓ specific + total IgE over 3–5 years"),
p("Induces immune tolerance; shifts Th2 → Th1/Treg; increases IgG4 blocking antibodies"),
p("Only intervention offering long-term remission. Can reduce IgE by 30–50%")],
[p("Dupilumab"),
p("Slow ↓ in IgE synthesis over months"),
p("Blocks IL-4/IL-13 receptor → prevents IgE class-switch recombination in B cells"),
p("IgE falls gradually; not primarily an IgE-lowering drug but useful in atopic disease")],
[p("Systemic corticosteroids"),
p("Modest, transient reduction"),
p("Broad Th2 suppression; reduces IL-4/IL-13 driving IgE synthesis"),
p("Not suitable for long-term IgE reduction due to side effects")],
[p("Cyclosporine"),
p("Reduces IgE in atopic dermatitis"),
p("Suppresses T-cell IL-4 production, reducing IgE class switching"),
p("Second-line for severe atopic dermatitis; renal monitoring required")],
[p("Anti-helminthic treatment\n(albendazole / ivermectin / DEC)"),
p("Normalises IgE if parasite was the cause"),
p("Eliminates chronic parasitic antigen drive of polyclonal IgE synthesis"),
p("Recheck total IgE at 3 months. If IgE falls to near-normal, allergy less likely the sole cause")],
]
story.append(simple_table(rows, [W*0.20, W*0.22, W*0.28, W*0.30]))
story.append(Spacer(1, 3*mm))
# ── Section 7: Monitoring ─────────────────────────────────────────────────────
story.append(sec_hdr("7. Monitoring Protocol", bg=NAVY))
story.append(Spacer(1, 1.5*mm))
rows = [
[pb("Timepoint / Scenario"), pb("What to Measure"), pb("Interpretation / Action")],
[p("Baseline (before any biologic)"),
p("Total IgE, specific IgE panel, CBC + eosinophils, stool exam, chest X-ray"),
p("Establishes baseline for comparison; rules out parasites and ABPA")],
[p("On omalizumab therapy"),
p("FREE IgE (not total IgE)"),
p("Total IgE unreliable — drug-IgE complexes elevate total IgE for up to 1 year. Free IgE should be near-undetectable if dose correct")],
[p("Every 3 months on biologic"),
p("Absolute eosinophil count, symptom score, exacerbation frequency"),
p("Assess clinical response; eosinophil normalisation expected with anti-IL-5 agents")],
[p("ABPA monitoring"),
p("Total IgE every 6–8 weeks during treatment"),
p("≥25% fall from baseline = satisfactory response to prednisolone + itraconazole")],
[p("Post-anti-helminthic treatment"),
p("Total IgE at 3 months"),
p("Significant fall (>50%) confirms parasitic origin. If IgE remains elevated, consider allergic/atopic aetiology")],
[p("Before skin-prick testing"),
p("Last omalizumab dose"),
p("Wait ≥8 weeks after stopping omalizumab before skin testing — drug suppresses wheal/flare response")],
[p("Annual stable patient"),
p("Total IgE, eosinophil count, spirometry (if asthma)"),
p("Detect disease progression or new sensitisation")],
]
story.append(simple_table(rows, [W*0.24, W*0.30, W*0.46]))
story.append(Spacer(1, 3*mm))
# ── Section 8: Clinical Scenario ─────────────────────────────────────────────
story.append(sec_hdr("8. Clinical Algorithm: Patient with IgE 700 IU/mL + Recurrent Pharyngitis + Runny Nose"))
story.append(Spacer(1, 1.5*mm))
rows = [
[pb("Step"), pb("Action"), pb("Expected Finding / Decision")],
[p("1. Clinical assessment"),
p("Characterise: seasonal vs perennial? Dust/pollen/cockroach triggers?\nGI symptoms? Rural exposure? Eczema? Asthma?"),
p("Perennial triggers → HDM/cockroach (most likely in India)\nSeasonal → pollen\nGI symptoms → helminth workup")],
[p("2. CBC + differential"),
p("Absolute eosinophil count"),
p("Eos <500/µL → allergic rhinitis likely\nEos >1000/µL → rule out helminthic infection FIRST before any biologic")],
[p("3. Specific IgE / SPT"),
p("ImmunoCAP: HDM (D. pteronyssinus, D. farinae), cockroach\n(Periplaneta americana), Alternaria, Aspergillus, food panel"),
p("Positive cockroach or HDM IgE → confirms allergic rhinitis\nAspergillus IgE positive → investigate ABPA")],
[p("4. Stool exam + serology"),
p("Stool microscopy ×3\nStrongyloides IgG, Toxocara IgG, Ascaris IgG ELISA"),
p("If positive → treat parasite first\nRecheck IgE at 3 months before biologic decision")],
[p("5. Diagnose & treat\nprimary cause"),
p("Dx: Allergic rhinitis with post-nasal drip\n→ Intranasal fluticasone/mometasone daily\n→ Cetirizine 10 mg OD\n→ Saline nasal irrigation BD"),
p("Post-nasal drip is the cause of recurrent 'pharyngitis'\nAntibiotic courses are NOT needed — treat rhinitis instead\nExpect sore throat to resolve with rhinitis treatment")],
[p("6. Escalation if\nuncontrolled"),
p("Allergen immunotherapy (AIT) — for long-term remission\nIf severe asthma develops → consider omalizumab"),
p("IgE of 700 is at upper limit of omalizumab dosing range — still eligible\nDose calculated from weight + IgE nomogram (use Xolair calculator)")],
[p("7. Biologic eligibility\ncheck (omalizumab)"),
p("IgE 30–700 IU/mL ✓ | Age ≥12 yrs ✓\nAllergic sensitisation confirmed ✓\nNo active parasites ✓\nModerate–severe persistent asthma present?"),
p("ELIGIBLE for omalizumab IF:\n• Moderate–severe allergic asthma confirmed\n• ICS + LABA insufficient\n• No active helminthic infection\nIf asthma absent, AIT is preferred first")],
]
t = Table(rows, colWidths=[W*0.16, W*0.40, W*0.44])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), GREY_HDR),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LIGHT]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING",(0,0),(-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("BACKGROUND", (0,6), (-1,6), LIGHT_BLUE), # biologic eligibility row
]))
story.append(t)
story.append(Spacer(1, 3*mm))
# ── Section 9: India-specific ─────────────────────────────────────────────────
story.append(sec_hdr("9. India-Specific Considerations — Young Adult Population", bg=AMBER))
story.append(Spacer(1, 1.5*mm))
rows = [
[pb("Topic"), pb("Key Points")],
[p("#1 Cause in Urban India"),
p("Allergic rhinitis sensitised to cockroach (Periplaneta americana) — single most common aeroallergen in Indian urban adults — and house dust mite (D. pteronyssinus). IgE prevalence of atopy 20–30% in urban young adults.")],
[p("#1 Cause in Rural/Semi-urban India"),
p("Helminthic parasitic infection (Ascaris lumbricoides, Ancylostoma duodenale, Strongyloides stercoralis). Warm humid climate + agrarian soil contact = high transmission. Always rule out before biologic therapy.")],
[p("Dual Cause"),
p("Both allergy AND parasitic infection can coexist in the same patient. Treat helminth first. Total IgE may fall significantly post-treatment, potentially changing biologic eligibility status.")],
[p("Tropical Pulmonary\nEosinophilia (TPE)"),
p("Classic Indian condition. Filarial species (Wuchereria bancrofti / Brugia malayi). Triad: nocturnal cough + wheeze + eosinophilia >3000/µL. IgE very high. Treatment: DEC 6 mg/kg/day × 3 weeks.")],
[p("Hygiene Hypothesis"),
p("Rapidly urbanising India shows rising atopic disease as helminth burden falls. Young adults in metros approach Western allergy rates. Atopic march (eczema → rhinitis → asthma) increasingly recognised.")],
[p("Biologic Access"),
p("Omalizumab (Xolair) and dupilumab (Dupixent) are available in India but expensive. ImmunoCAP testing available at tertiary allergy centres. Allergen immunotherapy (AIT) is cost-effective long-term alternative.")],
[p("Most Important Pitfall"),
p("Recurrent 'pharyngitis' in young Indians with high IgE is most often ALLERGIC POST-NASAL DRIP — not recurrent streptococcal tonsillitis. Avoid repeated antibiotic courses. Diagnose and treat allergic rhinitis. Pharyngitis resolves when post-nasal drip is controlled.")],
]
t = Table(rows, colWidths=[W*0.22, W*0.78])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), HexColor("#7d6608")),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.8),
("ROWBACKGROUNDS", (0,1), (-1,-1), [LIGHT_AMB, WHITE]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING",(0,0),(-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(t)
story.append(Spacer(1, 3*mm))
# ── Footer ────────────────────────────────────────────────────────────────────
story.append(HRFlowable(width=W, thickness=0.5, color=TEAL))
story.append(Spacer(1, 1.5*mm))
story.append(Paragraph(
"<b>Sources:</b> Harrison's Principles of Internal Medicine 22E (2025) · Goldman-Cecil Medicine · "
"K.J. Lee's Essential Otolaryngology · Katzung's Basic & Clinical Pharmacology 16th Ed. · "
"Fishman's Pulmonary Diseases · Murray & Nadel's Respiratory Medicine · Fitzpatrick's Dermatology 9th Ed. | "
"<b>Orris Medical AI · May 2026</b> | "
"<i>Clinical guidance only. Verify doses against current product labelling and institutional protocols.</i>",
CAP
))
# ── Build ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF generated successfully: {OUTPUT}")
cat > /home/daytona/workspace/ige-protocol/generate_ige_pdf.py << 'PYEOF' #!/usr/bin/env python3 from reportlab.lib.pagesizes import A4 from reportlab.lib import colors from reportlab.lib.units import mm from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER, TA_LEFT from reportlab.lib.colors import HexColor OUTPUT = "/home/daytona/workspace/ige-protocol/IgE_Treatment_Algorithm.pdf" NAVY = HexColor("#1a3a5c") TEAL = HexColor("#0d7a8a") LIGHT_BLUE = HexColor("#d6eaf8") GREEN = HexColor("#1a6b3c") ORANGE = HexColor("#c0392b") LIGHT_RED = HexColor("#fde8e8") AMBER = HexColor("#d68910") LIGHT_AMB = HexColor("#fef9e7") GREY_HDR = HexColor("#2c3e50") GREY_LIGHT = HexColor("#f2f3f4") WHITE = colors.white W = A4[0] - 30*mm doc = SimpleDocTemplate(OUTPUT, pagesize=A4, leftMargin=15*mm, rightMargin=15*mm, topMargin=12*mm, bottomMargin=12*mm, title="IgE-Based Treatment Algorithm", author="Orris Medical AI") styles = getSampleStyleSheet() def ps(name, **kw): return ParagraphStyle(name, parent=styles["Normal"], **kw) HDR = ps("HDR", fontSize=15, textColor=WHITE, alignment=TA_CENTER, leading=20) SEC = ps("SEC", fontSize=9, textColor=WHITE, alignment=TA_LEFT, leading=13) BODY = ps("BODY", fontSize=7.5, leading=10.5) BOLD = ps("BOLD", fontSize=7.5, leading=10.5, fontName="Helvetica-Bold") CAP = ps("CAP", fontSize=6.2, textColor=HexColor("#666666"), leading=9) def p(t): return Paragraph(t, BODY) def b(t): return Paragraph(f"<b>{t}</b>", BOLD) def banner(text, sub="", bg=NAVY): content = f"<b>{text}</b>" if sub: content += f"<br/><font size=8>{sub}</font>" t = Table([[Paragraph(content, HDR)]], colWidths=[W]) t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),bg),("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8)])) return t def sh(text, bg=TEAL): t = Table([[Paragraph(f"<b>{text}</b>", SEC)]], colWidths=[W]) t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),bg),("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5)])) return t BASE_STYLE = [ ("BACKGROUND",(0,0),(-1,0),GREY_HDR), ("TEXTCOLOR",(0,0),(-1,0),WHITE), ("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"), ("FONTSIZE",(0,0),(-1,-1),7.2), ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,GREY_LIGHT]), ("GRID",(0,0),(-1,-1),0.3,HexColor("#cccccc")), ("TOPPADDING",(0,0),(-1,-1),3.5), ("BOTTOMPADDING",(0,0),(-1,-1),3.5), ("LEFTPADDING",(0,0),(-1,-1),4), ("RIGHTPADDING",(0,0),(-1,-1),4), ("VALIGN",(0,0),(-1,-1),"TOP"), ] def tbl(rows, cw, extra=None): t = Table(rows, colWidths=cw) s = BASE_STYLE[:] if extra: s += extra t.setStyle(TableStyle(s)) return t story = [] story.append(banner("IgE-Based Treatment Algorithm","Quick Reference Card for Clinical Practice · Orris Medical AI · May 2026")) story.append(Spacer(1,3*mm)) # 1. Normal values story.append(sh("1. Normal IgE Values & Interpretation")) story.append(Spacer(1,1.5*mm)) story.append(tbl([ [b("Serum IgE (IU/mL)"),b("Interpretation"),b("Clinical Context")], [p("< 10"),p("Very low"),p("Possible IgE deficiency; recurrent sinopulmonary infections")], [p("10 – 100"),p("Normal"),p("Healthy adult")], [p("100 – 500"),p("Mildly elevated"),p("Mild atopy, early sensitisation, low helminth load")], [p("500 – 2000"),p("Moderately elevated"),p("Active allergy, moderate helminthic infection, ABPA watch")], [p("> 2000"),p("Markedly elevated"),p("Hyper-IgE syndrome, heavy helminthiasis, ABPA flare")], [p("> 10 000"),p("Very high"),p("Severe HIES (Job's), ABPA, heavy parasitic burden")], ],[W*0.18,W*0.20,W*0.62])) story.append(Spacer(1,3*mm)) # 2. Workup story.append(sh("2. Initial Workup When IgE > 100 IU/mL")) story.append(Spacer(1,1.5*mm)) story.append(tbl([ [b("Step"),b("Investigation"),b("Key Finding / Purpose")], [p("1"),p("CBC + differential + absolute eosinophil count"),p("Eos >500/µL → allergy or parasite; >1500/µL → helminthic or HIES")], [p("2"),p("Allergy history (triggers, seasonality, family history)"),p("Seasonal → pollen; perennial → HDM/cockroach (India: cockroach #1)")], [p("3"),p("Specific IgE panel (ImmunoCAP/RAST) or skin-prick test"),p("Identifies sensitising allergen; cockroach + HDM most common in India")], [p("4"),p("Stool microscopy ×3 + Strongyloides / Toxocara / Ascaris serology"),p("Mandatory in tropical/India settings — rule out before biologics")], [p("5"),p("Chest X-ray / HRCT chest (if respiratory symptoms)"),p("Central bronchiectasis → ABPA; pneumatoceles → HIES")], [p("6"),p("Aspergillus-specific IgE + Aspergillus precipitins (IgE >1000)"),p("ABPA: Aspergillus IgE >0.35 kUA/L + compatible radiology")], [p("7"),p("IgG4 level (multi-organ disease, eosinophilia)"),p("IgG4-related disease: elevated IgG4 + IgE + eosinophilia")], [p("8"),p("STAT3 / DOCK8 genetics (recurrent unusual infections)"),p("AD-HIES = STAT3 mutation; AR-HIES = DOCK8 mutation")], ],[W*0.05,W*0.42,W*0.53])) story.append(Spacer(1,3*mm)) # 3. Treatment by etiology — Allergic t3a = Table([[Paragraph("<b>ALLERGIC / ATOPIC CAUSES</b>",ps("A",fontSize=8.5,textColor=WHITE,alignment=TA_CENTER))]],colWidths=[W]) t3a.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),TEAL),("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4)])) story.append(sh("3. Treatment Algorithm by Etiology")) story.append(Spacer(1,1.5*mm)) story.append(t3a) story.append(tbl([ [b("Condition"),b("1st Line"),b("Escalation"),b("Biologic Option")], [p("Allergic Rhinitis"),p("Intranasal corticosteroids + 2nd-gen antihistamine + saline irrigation"),p("Allergen immunotherapy (AIT) — lowers IgE long-term; montelukast adjunct"),p("Omalizumab if severe + asthma coexists (IgE 30–700)")], [p("Allergic Asthma"),p("SABA → ICS → ICS+LABA (Steps 1–3)"),p("Steps 4–5: high ICS+LABA, add biologic when uncontrolled"),p("Omalizumab (allergic)\nDupilumab (any IgE)\nTezepelumab (any phenotype)")], [p("Eosinophilic Asthma\nEos ≥150/µL"),p("ICS + LABA"),p("Maximise ICS; oral prednisone burst; specialist referral"),p("Mepolizumab 100 mg SC q4w\nBenralizumab 30 mg SC q4/8w\nReslizumab 3 mg/kg IV q4w")], [p("Atopic Dermatitis"),p("Emollients + topical steroids / calcineurin inhibitors"),p("Cyclosporine / methotrexate short-term"),p("Dupilumab 300 mg SC q2w\n(mod–severe uncontrolled)")], [p("Chronic Urticaria (CSU)"),p("2nd-gen antihistamine up to 4× dose"),p("Montelukast; short steroids for flare"),p("Omalizumab 300 mg/month\n(any IgE level for CSU)")], [p("ABPA"),p("Prednisolone 0.5 mg/kg/day × 2 wks then taper + Itraconazole 200 mg BD × 4 months"),p("Monitor IgE: ≥25% fall = response. Long-term itraconazole for recurrent ABPA"),p("Omalizumab adjunct\nfor refractory ABPA")], ],[W*0.14,W*0.29,W*0.29,W*0.28])) # Parasitic story.append(Spacer(1,2*mm)) t3b = Table([[Paragraph("<b>PARASITIC / INFECTIOUS CAUSES — ⚠ Treat Parasite BEFORE Any Biologic</b>",ps("B",fontSize=8.5,textColor=WHITE,alignment=TA_CENTER))]],colWidths=[W]) t3b.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),GREEN),("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4)])) story.append(t3b) story.append(tbl([ [b("Organism"),b("Clinical Clue"),b("Treatment"),b("Follow-up")], [p("Ascaris lumbricoides"),p("Loeffler syndrome, abdominal pain, visible worms in stool"),p("Albendazole 400 mg single dose"),p("Recheck IgE 3 months")], [p("Hookworm\n(Ancylostoma/Necator)"),p("Iron-deficiency anaemia, hypoproteinaemia, pruritus plantaris"),p("Albendazole 400 mg × 3 days"),p("IgE may take 6 months")], [p("Strongyloides\n⚠ Critical"),p("Larva currens rash, eosinophilia; can disseminate if immunosuppressed — must screen BEFORE steroids/biologics"),p("Ivermectin 200 µg/kg/day × 2 days (drug of choice; repeat wk 2)"),p("Treat before any immunosuppression")], [p("Toxocara (VLM)"),p("Child/dog exposure, hepatomegaly, eosinophilia, positive Toxocara IgG"),p("Albendazole 400 mg BD × 5 days ± prednisolone if severe"),p("Recheck 3 months")], [p("TPE — Filaria\n(Wuchereria/Brugia)"),p("Nocturnal cough + wheeze + Eos >3000/µL + very high IgE. Endemic: India, SE Asia"),p("Diethylcarbamazine (DEC) 6 mg/kg/day in 3 doses × 3 weeks"),p("IgE falls after Rx")], [p("Schistosoma"),p("Freshwater exposure, Katayama fever, haematuria, hepatosplenomegaly"),p("Praziquantel 40 mg/kg single dose"),p("Recheck 3 months")], ],[W*0.15,W*0.30,W*0.32,W*0.23])) # Rare story.append(Spacer(1,2*mm)) t3c = Table([[Paragraph("<b>IMMUNODEFICIENCY / RARE CAUSES</b>",ps("C",fontSize=8.5,textColor=WHITE,alignment=TA_CENTER))]],colWidths=[W]) t3c.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),ORANGE),("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4)])) story.append(t3c) story.append(tbl([ [b("Condition"),b("Key Features"),b("IgE"),b("Treatment")], [p("AD-HIES (Job's)\nSTAT3 mutation"),p("Recurrent staph abscesses + pneumonia + pneumatoceles; facial dysmorphia; retained primary teeth; scoliosis"),p(">2000\n(often\n>10,000)"),p("Prophylactic TMP-SMX + voriconazole. Avoid live vaccines. IVIG if antibody defect")], [p("AR-HIES\nDOCK8 mutation"),p("Severe viral (molluscum, HPV, HSV) + bacterial infections. Low T + B lymphocyte counts"),p("Very high"),p("HSCT — definitive cure. Prophylactic antimicrobials until transplant")], [p("IgG4-Related Disease"),p("Multi-organ fibroinflammatory; elevated IgG4 + IgE + eosinophilia; pancreatitis, cholangitis, aortitis"),p("Mildly–\nmoderately\nelevated"),p("Prednisolone 0.5–1 mg/kg/day then taper. Rituximab for relapsing disease")], [p("EGPA (Churg-Strauss)"),p("Asthma + eosinophilia + granulomatous vasculitis; neuropathy; p-ANCA positive"),p("Elevated"),p("High-dose prednisolone ± cyclophosphamide. Mepolizumab for remission")], [p("Hodgkin Lymphoma"),p("B symptoms, painless lymphadenopathy, mediastinal mass, Reed-Sternberg cells on biopsy"),p("Mildly\nelevated"),p("Oncology referral; ABVD / BEV-ABVD chemotherapy")], [p("Omenn Syndrome (SCID)"),p("Neonatal erythroderma, diarrhoea, failure to thrive, absent B cells, massive eosinophilia"),p(">10,000"),p("Urgent HSCT — life-saving. IVIG + antimicrobial prophylaxis supportively")], ],[W*0.18,W*0.38,W*0.11,W*0.33])) story.append(Spacer(1,3*mm)) # 4. Biologic guide story.append(sh("4. Biologic Selection Guide")) story.append(Spacer(1,1.5*mm)) bio_rows = [ [b("Biologic"),b("Target"),b("IgE Threshold"),b("Approved Indications"),b("Dose"),b("Key Adverse Effects")], [p("Omalizumab\n(Xolair)"),p("Free IgE"),p("30–700 IU/mL (asthma)\nAny IgE (CSU)"),p("Allergic asthma ≥12 yr; Chronic spontaneous urticaria; Allergic rhinitis (trials)"),p("Weight+IgE based SC q2–4w; CSU: 300 mg/month"),p("Anaphylaxis (monitor 30–60 min); local reaction; arteriothrombotic events")], [p("Dupilumab\n(Dupixent)"),p("IL-4Rα\n(IL-4+IL-13)"),p("No IgE threshold"),p("Mod–severe atopic dermatitis; Mod–severe asthma; CRSwNP; Eosinophilic esophagitis"),p("300 mg SC q2w (loading 600 mg)"),p("Conjunctivitis (common); injection site reaction; transient eosinophilia")], [p("Mepolizumab\n(Nucala)"),p("IL-5"),p("Not IgE-based\nEos ≥150/µL"),p("Severe eosinophilic asthma; EGPA; Hypereosinophilic syndrome"),p("100 mg SC q4w"),p("Anaphylaxis/angioedema; headache; fatigue")], [p("Benralizumab\n(Fasenra)"),p("IL-5Rα"),p("Not IgE-based\nEos ≥300/µL preferred"),p("Severe eosinophilic asthma"),p("30 mg SC q4w×3 then q8w"),p("Hypersensitivity; nasopharyngitis")], [p("Reslizumab\n(Cinqair)"),p("IL-5"),p("Not IgE-based\nEos ≥400/µL"),p("Severe eosinophilic asthma (inadequate ICS control)"),p("3 mg/kg IV q4w"),p("Anaphylaxis (IV — higher risk); myalgia")], [p("Tezepelumab\n(Tezspire)"),p("TSLP"),p("NO threshold\n(any phenotype)"),p("Severe asthma — broadest biologic; effective regardless of eosinophil level"),p("210 mg SC q4w"),p("Pharyngitis; back pain; injection site reaction")], ] t4 = Table(bio_rows, colWidths=[W*0.11,W*0.09,W*0.12,W*0.26,W*0.18,W*0.24]) s4 = BASE_STYLE + [ ("BACKGROUND",(0,1),(-1,1),LIGHT_BLUE), ("BACKGROUND",(0,6),(-1,6),LIGHT_AMB), ] t4.setStyle(TableStyle(s4)) story.append(t4) story.append(Spacer(1,3*mm)) # 5. Contraindications story.append(sh("5. Absolute / Important Contraindications to Biologics", bg=ORANGE)) story.append(Spacer(1,1.5*mm)) ct_rows = [ [b("Contraindication"),b("Applies To"),b("Rationale")], [p("Known hypersensitivity / anaphylaxis to the biologic"),p("All biologics"),p("Class effect — switch to alternate agent/class")], [p("Active helminthic / parasitic infection"),p("All (esp. omalizumab)"),p("Omalizumab reduces protective IgE against helminths. Treat parasites first; recheck IgE at 3 months")], [p("Serum IgE <30 or >700 IU/mL (asthma indication only)"),p("Omalizumab — asthma"),p("Outside validated dosing range; nomogram dose cannot be calculated")], [p("Non-allergic (intrinsic) asthma with normal IgE"),p("Omalizumab"),p("Mechanism requires allergen–IgE pathway; no benefit without it")], [p("Active serious bacterial / fungal / viral infection"),p("All biologics"),p("Immunomodulation may worsen active infection; treat first")], [p("Live vaccines within 30 days before/after initiation"),p("All biologics"),p("Risk of disseminated vaccine-strain infection; administer all live vaccines before starting")], [p("Active malignancy (relative)"),p("All biologics"),p("Insufficient safety data; case-by-case oncology review required")], [p("Pregnancy (relative — insufficient data for most)"),p("All biologics"),p("Omalizumab has most data (category B-like). Shared decision-making required")], ] t5 = Table(ct_rows, colWidths=[W*0.35,W*0.22,W*0.43]) t5.setStyle(TableStyle(BASE_STYLE + [ ("BACKGROUND",(0,0),(-1,0),HexColor("#7b241c")), ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,LIGHT_RED]), ])) story.append(t5) story.append(Spacer(1,3*mm)) # 6. Drugs lowering IgE story.append(sh("6. Drugs / Interventions That Lower Serum IgE")) story.append(Spacer(1,1.5*mm)) story.append(tbl([ [b("Drug / Intervention"),b("Effect on IgE"),b("Notes")], [p("Omalizumab"),p("Dramatically lowers FREE IgE (total IgE paradoxically rises — drug-IgE complexes)"),p("Measure FREE IgE on treatment. Total IgE unreliable for up to 1 year post-stopping")], [p("Allergen Immunotherapy (AIT)"),p("Gradual ↓ specific + total IgE over 3–5 years"),p("Only intervention with long-term remission. Can reduce IgE by 30–50%")], [p("Dupilumab"),p("Slow ↓ in IgE synthesis over months (blocks IL-4/IL-13 class switch)"),p("IgE falls gradually; not a primary IgE-lowering drug but useful in atopic disease")], [p("Systemic corticosteroids"),p("Modest, transient reduction via Th2 suppression"),p("Not suitable long-term for IgE reduction due to side-effect profile")], [p("Cyclosporine"),p("Reduces IgE in atopic dermatitis"),p("Second-line for severe AD; renal monitoring required")], [p("Anti-helminthic treatment\n(albendazole / ivermectin / DEC)"),p("Normalises IgE if parasites were the cause"),p("Recheck total IgE at 3 months. Significant fall (>50%) confirms parasitic origin")], ],[W*0.22,W*0.38,W*0.40])) story.append(Spacer(1,3*mm)) # 7. Monitoring story.append(sh("7. Monitoring Protocol", bg=NAVY)) story.append(Spacer(1,1.5*mm)) story.append(tbl([ [b("Timepoint"),b("What to Measure"),b("Interpretation / Action")], [p("Baseline (before biologic)"),p("Total IgE, specific IgE, CBC + eosinophils, stool exam, CXR"),p("Establishes baseline; rules out parasites and ABPA before starting")], [p("On omalizumab"),p("FREE IgE (not total IgE)"),p("Total IgE unreliable — drug-IgE complexes. Free IgE should be near-undetectable if dose correct")], [p("Every 3 months on biologic"),p("Absolute eosinophil count, symptom scores, exacerbation frequency"),p("Eosinophil normalisation expected with anti-IL-5 agents; assess clinical response")], [p("ABPA monitoring"),p("Total IgE every 6–8 weeks during treatment"),p("≥25% fall = satisfactory response to prednisolone + itraconazole")], [p("Post anti-helminthic"),p("Total IgE at 3 months"),p("Significant fall (>50%) confirms parasitic origin; reassess if IgE remains elevated")], [p("Before skin-prick testing"),p("Date of last omalizumab dose"),p("Wait ≥8 weeks after stopping omalizumab — drug suppresses wheal/flare response")], [p("Annual (stable patient)"),p("Total IgE, eosinophil count, spirometry (if asthma)"),p("Detect disease progression or new sensitisation")], ],[W*0.22,W*0.28,W*0.50])) story.append(Spacer(1,3*mm)) # 8. Clinical scenario story.append(sh("8. Clinical Algorithm: IgE 700 IU/mL + Recurrent Pharyngitis + Runny Nose")) story.append(Spacer(1,1.5*mm)) story.append(tbl([ [b("Step"),b("Action"),b("Finding / Decision")], [p("1. History"),p("Seasonal vs perennial? Dust/cockroach/pollen triggers? GI symptoms? Rural exposure? Eczema?"),p("Perennial → HDM/cockroach (most likely in India). GI symptoms → helminth workup first")], [p("2. CBC + eosinophils"),p("Absolute eosinophil count"),p("Eos <500/µL → allergic rhinitis likely. Eos >1000/µL → rule out helminthic infection FIRST")], [p("3. Specific IgE / SPT"),p("HDM (D. pteronyssinus / farinae), cockroach (Periplaneta americana), Alternaria, Aspergillus, food panel"),p("Positive cockroach or HDM IgE → confirms allergic rhinitis. Aspergillus IgE positive → investigate ABPA")], [p("4. Parasite screen"),p("Stool ×3 + Strongyloides IgG + Toxocara IgG + Ascaris IgG"),p("If positive → treat parasite first; recheck IgE at 3 months before biologic decision")], [p("5. Diagnose & treat"),p("Dx: Allergic rhinitis with post-nasal drip\n→ Intranasal fluticasone daily\n→ Cetirizine 10 mg OD\n→ Saline irrigation BD"),p("Post-nasal drip IS the pharyngitis. No antibiotics needed — treat rhinitis. Sore throat resolves with rhinitis control")], [p("6. Escalation"),p("AIT for long-term remission. If severe asthma develops → consider omalizumab"),p("IgE 700 = upper limit of omalizumab dosing range — still eligible. Use weight+IgE nomogram")], [p("7. Biologic eligibility"),p("IgE 30–700 ✓ | Age ≥12 ✓ | Allergen sensitised ✓ | No parasites ✓ | Mod–severe asthma?"),p("ELIGIBLE if: moderate–severe persistent allergic asthma confirmed + ICS+LABA inadequate + no active parasites")], ],[W*0.14,W*0.42,W*0.44], extra=[("BACKGROUND",(0,6),(-1,6),LIGHT_BLUE)])) story.append(Spacer(1,3*mm)) # 9. India-specific story.append(sh("9. India-Specific Considerations — Young Adult Population", bg=AMBER)) story.append(Spacer(1,1.5*mm)) india_rows = [ [b("Topic"),b("Key Points")], [p("#1 Cause — Urban India"),p("Allergic rhinitis. Cockroach (Periplaneta americana) is the single most common sensitising aeroallergen in Indian urban adults; house dust mite (D. pteronyssinus) second. Atopy prevalence 20–30% in urban young adults.")], [p("#1 Cause — Rural India"),p("Helminthic parasitic infection (Ascaris, hookworm, Strongyloides). Warm humid climate + agrarian soil contact = high transmission. Always rule out before starting any biologic therapy.")], [p("Dual Cause"),p("Allergy AND parasitic infection commonly coexist. Treat helminth first. Total IgE may fall significantly post-treatment, potentially changing biologic eligibility (especially for omalizumab dosing).")], [p("TPE (Tropical\nPulmonary Eosinophilia)"),p("Classic Indian presentation. Wuchereria bancrofti / Brugia malayi. Triad: nocturnal cough + wheeze + Eos >3000/µL + very high IgE. Commonly misdiagnosed as asthma. Treatment: DEC 6 mg/kg/day × 3 weeks.")], [p("Hygiene Hypothesis"),p("Rapidly urbanising India shows rising atopic disease as helminth burden falls. Young urban adults approach Western allergy rates. Atopic march (eczema → rhinitis → asthma) increasingly recognised.")], [p("Critical Pitfall"),p("Recurrent 'pharyngitis' in young Indians with high IgE is most often ALLERGIC POST-NASAL DRIP — NOT recurrent bacterial tonsillitis. Avoid repeated antibiotic courses. Diagnose and treat allergic rhinitis. Pharyngitis resolves when post-nasal drip is controlled.")], ] t9 = Table(india_rows, colWidths=[W*0.21,W*0.79]) t9.setStyle(TableStyle(BASE_STYLE + [ ("BACKGROUND",(0,0),(-1,0),HexColor("#7d6608")), ("ROWBACKGROUNDS",(0,1),(-1,-1),[LIGHT_AMB,WHITE]), ])) story.append(t9) story.append(Spacer(1,3*mm)) story.append(HRFlowable(width=W, thickness=0.5, color=TEAL)) story.append(Spacer(1,1.5*mm)) story.append(Paragraph( "<b>Sources:</b> Harrison's Principles of Internal Medicine 22E (2025, McGraw Hill) · Goldman-Cecil Medicine · " "K.J. Lee's Essential Otolaryngology · Katzung's Basic & Clinical Pharmacology 16th Ed. · " "Fishman's Pulmonary Diseases · Murray & Nadel's Respiratory Medicine · Fitzpatrick's Dermatology 9th Ed. | " "<b>Orris Medical AI · May 2026</b> | " "<i>Clinical guidance only. Verify doses against current product labelling and institutional protocols.</i>", CAP)) doc.build(story) print(f"PDF generated: {OUTPUT}") PYEOF echo "file written"
cd /home/daytona/workspace/ige-protocol && python3 generate_ige_pdf.py 2>&1
ls -lh /home/daytona/workspace/ige-protocol/IgE_Treatment_Algorithm.pdf
IgE Treatment Algorithm
PDF Document · PDF
| Section | Content |
|---|---|
| 1. Normal IgE Values | Interpretation table from <10 to >10,000 IU/mL with clinical context |
| 2. Initial Workup | Step-by-step 8-point investigation protocol including parasite screen |
| 3. Treatment by Etiology | Three colour-coded tables: Allergic/Atopic (teal), Parasitic/Infectious (green), Immunodeficiency/Rare (red) |
| 4. Biologic Selection Guide | All 6 biologics with IgE thresholds, indications, doses, and adverse effects; omalizumab and tezepelumab highlighted |
| 5. Contraindications | 8 absolute/relative contraindications with rationale, highlighted in red |
| 6. Drugs That Lower IgE | Mechanism and monitoring notes for each agent |
| 7. Monitoring Protocol | When to measure free vs total IgE, ABPA follow-up, post-parasite treatment re-check |
| 8. Clinical Scenario | Step-by-step algorithm for the IgE 700 + pharyngitis + rhinitis patient |
| 9. India-Specific Notes | Urban vs rural causes, TPE, cockroach sensitisation, the post-nasal drip pitfall |
Make a summary pdf on omalizumab dosing calculator and monitoring protocol
omalizumab dosing table weight IgE nomogram asthma urticaria 2024
https://www.ohsu.edu/sites/default/files/2025-03/OHSU-HS-MPS…
cat > /home/daytona/workspace/ige-protocol/omalizumab_dosing_pdf.py << 'PYEOF' #!/usr/bin/env python3 """ Omalizumab Dosing Calculator & Monitoring Protocol — Summary PDF """ from reportlab.lib.pagesizes import A4 from reportlab.lib import colors from reportlab.lib.units import mm from reportlab.platypus import ( SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable ) from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT from reportlab.lib.colors import HexColor OUTPUT = "/home/daytona/workspace/ige-protocol/Omalizumab_Dosing_Monitoring.pdf" NAVY = HexColor("#1a3a5c") TEAL = HexColor("#0d7a8a") TEAL_L = HexColor("#d0eef2") GREEN = HexColor("#1a6b3c") GREEN_L = HexColor("#d5f5e3") ORANGE = HexColor("#c0392b") RED_L = HexColor("#fde8e8") AMBER = HexColor("#d68910") AMBER_L = HexColor("#fef9e7") GREY_HDR = HexColor("#2c3e50") GREY_L = HexColor("#f2f3f4") BLUE_L = HexColor("#d6eaf8") PURPLE = HexColor("#6c3483") PURPLE_L = HexColor("#f5eef8") WHITE = colors.white BLACK = colors.black W = A4[0] - 28*mm styles = getSampleStyleSheet() def ps(name, **kw): return ParagraphStyle(name, parent=styles["Normal"], **kw) HDR = ps("HDR", fontSize=16, textColor=WHITE, alignment=TA_CENTER, leading=22) SEC = ps("SEC", fontSize=9, textColor=WHITE, alignment=TA_LEFT, leading=13) BODY = ps("BODY", fontSize=7.8, leading=11) BOLDY = ps("BOLDY",fontSize=7.8, leading=11, fontName="Helvetica-Bold") SMALL = ps("SMALL",fontSize=7.2, leading=10.5) SMALLB= ps("SMALLB",fontSize=7.2,leading=10.5, fontName="Helvetica-Bold") CAP = ps("CAP", fontSize=6.3, textColor=HexColor("#555555"), leading=9) WARN = ps("WARN", fontSize=8, textColor=ORANGE, fontName="Helvetica-Bold", leading=11) NOTE = ps("NOTE", fontSize=7.5, textColor=NAVY, leading=10.5) CENT = ps("CENT", fontSize=7.8, alignment=TA_CENTER, leading=11) CENTB = ps("CENTB",fontSize=7.8, alignment=TA_CENTER, leading=11, fontName="Helvetica-Bold") def p(t, s=None): return Paragraph(t, s or SMALL) def b(t, s=None): return Paragraph(f"<b>{t}</b>", s or SMALLB) def c(t): return Paragraph(t, CENT) def cb(t): return Paragraph(f"<b>{t}</b>", CENTB) def warn(t): return Paragraph(t, WARN) doc = SimpleDocTemplate(OUTPUT, pagesize=A4, leftMargin=14*mm, rightMargin=14*mm, topMargin=10*mm, bottomMargin=10*mm, title="Omalizumab Dosing & Monitoring Protocol", author="Orris Medical AI") BASE = [ ("FONTSIZE",(0,0),(-1,-1),7.5), ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,GREY_L]), ("GRID",(0,0),(-1,-1),0.3,HexColor("#bbbbbb")), ("TOPPADDING",(0,0),(-1,-1),3), ("BOTTOMPADDING",(0,0),(-1,-1),3), ("LEFTPADDING",(0,0),(-1,-1),4), ("RIGHTPADDING",(0,0),(-1,-1),4), ("VALIGN",(0,0),(-1,-1),"MIDDLE"), ] def banner(main, sub=""): content = f"<b>{main}</b>" if sub: content += f"<br/><font size=8.5>{sub}</font>" t = Table([[Paragraph(content, HDR)]], colWidths=[W]) t.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,-1),NAVY), ("TOPPADDING",(0,0),(-1,-1),10),("BOTTOMPADDING",(0,0),(-1,-1),10), ("BOX",(0,0),(-1,-1),1,TEAL), ])) return t def sh(text, bg=TEAL): t = Table([[Paragraph(f"<b>{text}</b>", SEC)]], colWidths=[W]) t.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,-1),bg), ("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5), ("LEFTPADDING",(0,0),(-1,-1),8), ])) return t def hdr_cell(t, bg=GREY_HDR): return Paragraph(f"<b>{t}</b>", ps(f"hc{t[:4]}", fontSize=7.5, textColor=WHITE, alignment=TA_CENTER, fontName="Helvetica-Bold", leading=10)) def colored_cell(t, bg_hex="#f2f3f4"): return Paragraph(t, ps(f"cc{t[:3]}", fontSize=7.5, alignment=TA_CENTER, leading=10)) story = [] # ═══════════════════════════════════════════════════════════════════════════ # HEADER # ═══════════════════════════════════════════════════════════════════════════ story.append(banner( "Omalizumab (Xolair) — Dosing Calculator & Monitoring Protocol", "Quick Reference Summary | Orris Medical AI | May 2026" )) story.append(Spacer(1,3*mm)) # ═══════════════════════════════════════════════════════════════════════════ # SECTION 1 — OVERVIEW # ═══════════════════════════════════════════════════════════════════════════ story.append(sh("1. Drug Overview & Mechanism")) story.append(Spacer(1,1.5*mm)) ov_rows = [ [b("Parameter"),b("Details")], [p("Drug class"),p("Humanised murine monoclonal antibody — IgG1κ subclass")], [p("Target"),p("Binds FREE circulating IgE at the Fc region (same site that binds FcεRI receptor) — prevents IgE from attaching to mast cells and basophils")], [p("Effect on IgE"),p("Dramatically reduces FREE IgE (goal: free IgE <25 IU/mL). TOTAL IgE rises paradoxically due to IgE-drug complexes (longer half-life). Do NOT measure total IgE to assess response on treatment.")], [p("Downstream effect"),p("Downregulates FcεRI receptor expression on mast cells, basophils, and dendritic cells → reduced inflammatory mediator release → decreased eosinophil recruitment → may reverse airway remodelling")], [p("Formulation"),p("Available as 75 mg/0.5 mL, 150 mg/1 mL pre-filled syringe; and 150 mg powder vial for reconstitution. Route: subcutaneous injection only.")], [p("Half-life"),p("~26 days. Steady state reached ~14–28 weeks (3–6 months of dosing)")], ] t = Table(ov_rows, colWidths=[W*0.22, W*0.78]) t.setStyle(TableStyle(BASE + [ ("BACKGROUND",(0,0),(-1,0),GREY_HDR), ("TEXTCOLOR",(0,0),(-1,0),WHITE), ("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"), ])) story.append(t) story.append(Spacer(1,3*mm)) # ═══════════════════════════════════════════════════════════════════════════ # SECTION 2 — INDICATIONS + ELIGIBILITY # ═══════════════════════════════════════════════════════════════════════════ story.append(sh("2. Approved Indications & Eligibility Criteria")) story.append(Spacer(1,1.5*mm)) ind_rows = [ [b("Indication"),b("Age"),b("IgE Criterion"),b("Other Criteria"),b("Dose Range")], [p("Moderate–severe persistent\nALLERGIC ASTHMA"), p("≥6 years\n(≥12 yr: full table\n6–<12 yr: separate table)"), p("30–700 IU/mL\n(asthma indication)"), p("Sensitised to perennial aeroallergen\nInadequate control on ICS\nBody weight ≤150 kg"), p("75–375 mg SC\nq2w or q4w\n(weight+IgE based)")], [p("CHRONIC SPONTANEOUS\nURTICARIA (CSU)"), p("≥12 years"), p("No IgE threshold\n(any level)"), p("Refractory to antihistamines\n(H1 antihistamine at ≥4× dose)"), p("150 mg or 300 mg SC\nevery 4 weeks\n(fixed dose)")], [p("CHRONIC RHINOSINUSITIS\nwith NASAL POLYPS (CRSwNP)"), p("≥18 years"), p("IgE-based dosing\n(per table)"), p("Inadequate response to nasal corticosteroids"), p("75–600 mg SC\nq2w or q4w")], [p("IgE-MEDIATED FOOD ALLERGY\n(peanut, tree nuts, wheat, egg,\nmilk, sesame, shellfish, fin fish)"), p("≥1 year\n(with distinct\ndose table)"), p("IgE-based dosing\n(per table)"), p("Confirmed IgE-mediated food allergy\nBaseline IgE can be >700 for this indication"), p("75–600 mg SC\nq2w or q4w")], [p("ABPA (off-label / adjunct)"), p("All ages"), p("Usually >1000 IU/mL"), p("Refractory to steroids+itraconazole;\nClinical trial evidence"), p("375 mg SC q2w\n(most used dose)")], ] t2 = Table(ind_rows, colWidths=[W*0.21,W*0.12,W*0.16,W*0.30,W*0.21]) t2.setStyle(TableStyle(BASE + [ ("BACKGROUND",(0,0),(-1,0),GREY_HDR), ("TEXTCOLOR",(0,0),(-1,0),WHITE), ("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"), ("BACKGROUND",(0,1),(-1,1),BLUE_L), # asthma ("BACKGROUND",(0,2),(-1,2),GREEN_L), # CSU ("BACKGROUND",(0,3),(-1,3),TEAL_L), # CRSwNP ("BACKGROUND",(0,4),(-1,4),AMBER_L), # food allergy ("BACKGROUND",(0,5),(-1,5),PURPLE_L), # ABPA ])) story.append(t2) story.append(Spacer(1,3*mm)) # ═══════════════════════════════════════════════════════════════════════════ # SECTION 3 — DOSING FORMULA + Q4W TABLE # ═══════════════════════════════════════════════════════════════════════════ story.append(sh("3. Dosing Formula & Official Dose Nomogram (Asthma / CRSwNP — Patients ≥12 years)")) story.append(Spacer(1,1.5*mm)) # Formula box formula_data = [[ Paragraph( "<b>Dosing Formula:</b> Minimum dose = <b>0.016 mg/kg × body weight (kg) × baseline IgE (IU/mL)</b> per 4-week period<br/>" "<font size=7>Doses are rounded to nearest available vial size (75 mg, 150 mg, 225 mg, 300 mg, 375 mg). Maximum single-visit dose = 150 mg per injection site (≤6 injection sites = 600 mg/visit max).</font>", ps("form", fontSize=8.5, textColor=NAVY, leading=13)) ]] ft = Table(formula_data, colWidths=[W]) ft.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,-1),BLUE_L), ("BOX",(0,0),(-1,-1),1.5,TEAL), ("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8), ("LEFTPADDING",(0,0),(-1,-1),10),("RIGHTPADDING",(0,0),(-1,-1),10), ])) story.append(ft) story.append(Spacer(1,2*mm)) # ── Q4W TABLE ────────────────────────────────────────────────────────────── q4_hdr = Table([[Paragraph("<b>EVERY 4 WEEKS (q4w) — Dose in mg | Patients ≥12 years | Asthma & CRSwNP</b>", ps("q4h", fontSize=8, textColor=WHITE, alignment=TA_CENTER))]], colWidths=[W]) q4_hdr.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),TEAL), ("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4)])) story.append(q4_hdr) # Column headers wt_cols = [">30–60 kg",">60–70 kg",">70–90 kg",">90–150 kg"] q4_rows = [ ["Pre-treatment IgE (IU/mL)"] + wt_cols, ["≥30 to 100", "150","150","150","300"], [">100 to 200", "300","300","300","→ q2w table"], [">200 to 300", "300","→ q2w table","→ q2w table","→ q2w table"], [">300 to 400", "→ q2w table","→ q2w table","→ q2w table","→ q2w table"], ] CW4 = [W*0.28, W*0.18, W*0.18, W*0.18, W*0.18] def cell(t, bg=None): style = [("BACKGROUND",(0,0),(-1,-1),bg)] if bg else [] return Paragraph(t, CENT) q4_built = [[cb("Pre-treatment IgE (IU/mL)"),cb(">30–60 kg"),cb(">60–70 kg"),cb(">70–90 kg"),cb(">90–150 kg")]] q4_data_raw = [ ("≥30 to 100", "150","150","150","300"), (">100 to 200", "300","300","300","→ q2w"), (">200 to 300", "300","→ q2w","→ q2w","→ q2w"), (">300 to 400", "→ q2w","→ q2w","→ q2w","→ q2w"), ] for r in q4_data_raw: q4_built.append([c(r[0]),c(r[1]),c(r[2]),c(r[3]),c(r[4])]) t_q4 = Table(q4_built, colWidths=CW4) t_q4.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,0),TEAL), ("TEXTCOLOR",(0,0),(-1,0),WHITE), ("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"), ("FONTSIZE",(0,0),(-1,-1),7.8), ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,GREY_L]), ("GRID",(0,0),(-1,-1),0.4,HexColor("#aaaaaa")), ("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4), ("LEFTPADDING",(0,0),(-1,-1),4),("RIGHTPADDING",(0,0),(-1,-1),4), ("ALIGN",(0,0),(-1,-1),"CENTER"), ("VALIGN",(0,0),(-1,-1),"MIDDLE"), # IgE 30-100 row — lightest dosing ("BACKGROUND",(1,1),(4,1),BLUE_L), # higher IgE rows ("BACKGROUND",(1,4),(4,4),TEAL_L), ])) story.append(t_q4) story.append(Spacer(1,2*mm)) # ── Q2W TABLE ────────────────────────────────────────────────────────────── q2_hdr = Table([[Paragraph("<b>EVERY 2 WEEKS (q2w) — Dose in mg | Patients ≥12 years | Asthma & CRSwNP (use when q4w table shows '→ q2w')</b>", ps("q2h", fontSize=8, textColor=WHITE, alignment=TA_CENTER))]], colWidths=[W]) q2_hdr.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),NAVY), ("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4)])) story.append(q2_hdr) q2_data_raw = [ (">100 to 200", "—","—","—","225"), (">200 to 300", "—","225","225","300"), (">300 to 400", "225","225","300","DO NOT DOSE"), (">400 to 500", "300","300","375","DO NOT DOSE"), (">500 to 600", "300","375","DO NOT DOSE","DO NOT DOSE"), (">600 to 700", "375","DO NOT DOSE","DO NOT DOSE","DO NOT DOSE"), ] q2_built = [[cb("Pre-treatment IgE (IU/mL)"),cb(">30–60 kg"),cb(">60–70 kg"),cb(">70–90 kg"),cb(">90–150 kg")]] for r in q2_data_raw: q2_built.append([c(r[0]),c(r[1]),c(r[2]),c(r[3]),c(r[4])]) t_q2 = Table(q2_built, colWidths=CW4) extra_q2 = [ ("BACKGROUND",(0,0),(-1,0),NAVY), ("TEXTCOLOR",(0,0),(-1,0),WHITE), ("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"), ("FONTSIZE",(0,0),(-1,-1),7.8), ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,GREY_L]), ("GRID",(0,0),(-1,-1),0.4,HexColor("#aaaaaa")), ("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4), ("LEFTPADDING",(0,0),(-1,-1),4),("RIGHTPADDING",(0,0),(-1,-1),4), ("ALIGN",(0,0),(-1,-1),"CENTER"), ("VALIGN",(0,0),(-1,-1),"MIDDLE"), ] # Highlight DO NOT DOSE cells for ri, row in enumerate(q2_data_raw, start=1): for ci, val in enumerate(row[1:], start=1): if "DO NOT" in val: extra_q2.append(("BACKGROUND",(ci,ri),(ci,ri),RED_L)) extra_q2.append(("TEXTCOLOR",(ci,ri),(ci,ri),ORANGE)) extra_q2.append(("FONTNAME",(ci,ri),(ci,ri),"Helvetica-Bold")) t_q2.setStyle(TableStyle(extra_q2)) story.append(t_q2) story.append(Spacer(1,1.5*mm)) # Important note about the table note_box = Table([[Paragraph( "<b>⚠ Important dosing rules:</b><br/>" "• IgE > 700 IU/mL → omalizumab is <b>NOT indicated for asthma</b> by standard dosing (outside validated range). Consider for food allergy or off-label ABPA use.<br/>" "• IgE < 30 IU/mL → NOT indicated for asthma (insufficient IgE to calculate dose).<br/>" "• Body weight > 150 kg → NOT studied; use with extreme caution / case-by-case basis.<br/>" "• Do NOT re-measure IgE once treatment has started — dose is based on PRE-TREATMENT IgE only.<br/>" "• If patient gains/loses significant weight (>15 kg), recalculate dose using original pre-treatment IgE.", ps("nbox", fontSize=7.5, textColor=HexColor("#7b3f00"), leading=11)) ]], colWidths=[W]) note_box.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,-1),AMBER_L), ("BOX",(0,0),(-1,-1),1.2,AMBER), ("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6), ("LEFTPADDING",(0,0),(-1,-1),8),("RIGHTPADDING",(0,0),(-1,-1),8), ])) story.append(note_box) story.append(Spacer(1,3*mm)) # ═══════════════════════════════════════════════════════════════════════════ # SECTION 4 — CSU DOSING (FIXED) # ═══════════════════════════════════════════════════════════════════════════ story.append(sh("4. Fixed Dosing: Chronic Spontaneous Urticaria (CSU)", bg=GREEN)) story.append(Spacer(1,1.5*mm)) csu_rows = [ [b("CSU Dose"),b("Frequency"),b("IgE Requirement"),b("Weight Requirement"),b("Notes")], [p("150 mg SC"),p("Every 4 weeks"),p("No IgE testing required"),p("No weight-based adjustment"),p("May have partial response; consider escalating to 300 mg if insufficient")], [p("300 mg SC\n(preferred)"),p("Every 4 weeks"),p("No IgE testing required"),p("No weight-based adjustment"),p("Recommended dose for most CSU patients; meta-analysis supports 300 mg/month regardless of IgE level")], ] t_csu = Table(csu_rows, colWidths=[W*0.14,W*0.14,W*0.20,W*0.20,W*0.32]) t_csu.setStyle(TableStyle(BASE + [ ("BACKGROUND",(0,0),(-1,0),HexColor("#1a5c3a")), ("TEXTCOLOR",(0,0),(-1,0),WHITE), ("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"), ("BACKGROUND",(0,2),(-1,2),GREEN_L), ])) story.append(t_csu) story.append(Spacer(1,1.5*mm)) # CSU response + stopping csu2 = Table([[Paragraph( "<b>CSU Response Assessment & Stopping Strategy:</b><br/>" "• Assess response at <b>12 weeks</b>. If no improvement in urticaria activity score (UAS7), reconsider diagnosis or escalate dose.<br/>" "• Good response: continue every 4 weeks. Reassess need at <b>1 year</b>.<br/>" "• Stopping: attempt discontinuation after 1 year of good control; if relapse, restart at 300 mg/month.<br/>" "• In CSU with low/absent IgE (<40 IU/mL): response less likely — shared decision-making required.", ps("csub", fontSize=7.5, leading=11)) ]], colWidths=[W]) csu2.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,-1),GREEN_L), ("BOX",(0,0),(-1,-1),1,GREEN), ("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6), ("LEFTPADDING",(0,0),(-1,-1),8),("RIGHTPADDING",(0,0),(-1,-1),8), ])) story.append(csu2) story.append(Spacer(1,3*mm)) # ═══════════════════════════════════════════════════════════════════════════ # SECTION 5 — PEDIATRIC DOSING NOTE # ═══════════════════════════════════════════════════════════════════════════ story.append(sh("5. Paediatric Dosing — Key Points (Asthma, Age 6 to <12 years)", bg=PURPLE)) story.append(Spacer(1,1.5*mm)) ped_rows = [ [b("Weight Range"),b("IgE 30–100"),b("IgE >100–200"),b("IgE >200–300"),b("IgE >300–400"),b("IgE >400–500"),b("IgE >500–700 (q2w)")], [p("20–25 kg"), c("75"), c("150"), c("150"), c("225"), c("225"), c("225–300\n(see full table)")], [p("25–40 kg"), c("75–150"),c("150–300"),c("150–225"),c("225–300"),c("225–300"),c("225–375\n(see full table)")], [p("40–90 kg"), c("150–300"),c("300"),c("225–300"),c("225–300"),c("300–375"),c("see full table")], [p(">90–150 kg"), c("300"), c("300"), c("375"), c("Do Not Dose"),c("Do Not Dose"),c("see full table")], ] t_ped = Table(ped_rows, colWidths=[W*0.15,W*0.13,W*0.14,W*0.14,W*0.14,W*0.14,W*0.16]) t_ped.setStyle(TableStyle(BASE + [ ("BACKGROUND",(0,0),(-1,0),PURPLE), ("TEXTCOLOR",(0,0),(-1,0),WHITE), ("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"), ("FONTSIZE",(0,0),(-1,-1),7), ])) story.append(t_ped) story.append(Spacer(1,1.5*mm)) story.append(Paragraph( "<b>Note:</b> The above is a simplified reference; always use the complete manufacturer dosing table for paediatric patients. " "Paediatric dosing uses the same weight + IgE nomogram principle but has a distinct table for the 6–<12 yr age group. " "The minimum approved age for CSU indication is 12 years.", ps("pednote", fontSize=7.3, textColor=NAVY, leading=10.5))) story.append(Spacer(1,3*mm)) # ═══════════════════════════════════════════════════════════════════════════ # SECTION 6 — DOSE STEP-BY-STEP CALCULATOR # ═══════════════════════════════════════════════════════════════════════════ story.append(sh("6. Step-by-Step Dose Calculation (Asthma / CRSwNP)", bg=NAVY)) story.append(Spacer(1,1.5*mm)) calc_rows = [ [b("Step"),b("Action"),b("Example (70 kg, IgE 450)")], [p("1"),p("Measure baseline TOTAL IgE (IU/mL) BEFORE starting therapy.\nThis value is used for all future dosing — do NOT re-measure."),p("Baseline IgE = 450 IU/mL")], [p("2"),p("Weigh patient in kg at baseline."),p("Weight = 70 kg")], [p("3"),p("Calculate minimum 4-weekly dose:\n0.016 mg/kg × weight × IgE"),p("0.016 × 70 × 450 = 504 mg per 4 weeks")], [p("4"),p("Look up the dosing table (q4w or q2w) using IgE band and weight band.\nThe table dose must meet or exceed the calculated minimum."),p("IgE >400–500, weight >60–70 kg → q2w table → 300 mg every 2 weeks\n= 600 mg per 4 weeks (exceeds 504 mg ✓)")], [p("5"),p("Confirm dose is achievable:\n• Maximum per injection site: 150 mg (i.e., 1 pre-filled syringe per site)\n• Maximum per visit: 600 mg (4 injection sites)\n• Maximum single-frequency dose: 375 mg q2w"),p("300 mg q2w = 2 × 150 mg injections = 2 sites per visit ✓")], [p("6"),p("Administer SC (abdomen, thigh, or upper arm) by healthcare provider.\nMonitor in clinic for 30–60 minutes after each injection."),p("Two 150 mg injections, different sites, every 2 weeks")], [p("7"),p("Do NOT adjust dose if total IgE is measured again during treatment\n(complexed IgE inflates total IgE measurement — meaningless for dosing)."),p("If repeat IgE = 1200 IU/mL on treatment — IGNORE; continue same dose")], ] t_calc = Table(calc_rows, colWidths=[W*0.05,W*0.50,W*0.45]) t_calc.setStyle(TableStyle(BASE + [ ("BACKGROUND",(0,0),(-1,0),GREY_HDR), ("TEXTCOLOR",(0,0),(-1,0),WHITE), ("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"), ("BACKGROUND",(0,4),(-1,4),BLUE_L), ("BACKGROUND",(0,7),(-1,7),AMBER_L), ])) story.append(t_calc) story.append(Spacer(1,3*mm)) # ═══════════════════════════════════════════════════════════════════════════ # SECTION 7 — MONITORING PROTOCOL # ═══════════════════════════════════════════════════════════════════════════ story.append(sh("7. Monitoring Protocol — Before, During & After Omalizumab")) story.append(Spacer(1,1.5*mm)) mon_rows = [ [b("Timepoint"),b("What to Assess / Measure"),b("Action / Target")], [p("PRE-TREATMENT\n(Baseline)"), p("• Total IgE (essential for dosing)\n• Specific IgE panel / skin-prick test (confirm allergen)\n• CBC + absolute eosinophil count\n• Stool exam × 3 + Strongyloides serology (India/tropical)\n• Baseline symptom scores (ACQ, UAS7, SNOT-22)\n• Weight in kg\n• Chest X-ray if respiratory symptoms\n• Rule out active infection, malignancy, pregnancy"), p("• Confirm IgE 30–700 for asthma dosing eligibility\n• Confirm allergic sensitisation\n• Exclude helminthic infection before starting\n• Document baseline for comparison")], [p("DAY OF INJECTION\n(Every visit)"), p("• Clinical symptoms (asthma/urticaria/polyp control)\n• Exacerbation history since last visit\n• Medication use (oral steroid use, rescue inhaler use)\n• Weight (recalculate if >15 kg change)\n• Pre-injection vital signs"), p("• Monitor for anaphylaxis: observe patient 30–60 min post-injection\n• Epinephrine 0.3 mg IM must be available at all injection visits\n• Record injection site reactions")], [p("4 WEEKS\n(1st injection visit)"), p("• Tolerability assessment\n• Injection site reaction\n• Any systemic symptoms"), p("• No dose change at this point — steady state not reached\n• Reassure patient: full effect takes 12–16 weeks")], [p("12–16 WEEKS\n(Response assessment)"), p("• PRIMARY RESPONSE EVALUATION:\n – Asthma: exacerbation frequency, OCS use, ACQ score, FEV1\n – CSU: UAS7 score (target: UAS7 <6 or = 0)\n – CRSwNP: SNOT-22, nasal obstruction score, polyp size\n• FREE IgE (if available) — target <25 IU/mL\n• Eosinophil count\n• Tolerability"), p("• If good response: continue at same dose\n• If partial response: optimise allergen avoidance, adherence; continue ≥6 months before concluding failure\n• If no response at 16 weeks: reassess diagnosis; discontinue if no benefit")], [p("EVERY 3 MONTHS\n(Ongoing)"), p("• Symptom control scores\n• Exacerbation frequency\n• Oral corticosteroid sparing\n• Eosinophil count\n• FREE IgE (if measurable)"), p("• Goal: ≥50% reduction in exacerbations; OCS reduction; improved quality of life\n• If asthma worsening: check inhaler technique, allergen exposure, parasites\n• Do NOT measure total IgE to guide dosing — it is not valid on-treatment")], [p("ANNUALLY"), p("• Full reassessment: spirometry (asthma), nasal endoscopy (CRSwNP)\n• Reassess need for continuation\n• Attempt step-down if well-controlled"), p("• Asthma: attempt ICS dose reduction if controlled ≥12 months\n• CSU: attempt discontinuation after 1 year of complete control\n• CRSwNP: reassess polyp burden; continuation decision with ENT")], [p("ON STOPPING"), p("• Symptoms may recur within 4–8 weeks\n• Total IgE remains elevated for up to 1 year after stopping\n• Skin-prick testing: wait ≥8 weeks post-last dose"), p("• Total IgE is unreliable for up to 1 year — do not use to guide decisions\n• Free IgE normalises within weeks of stopping\n• Restart if symptoms return: use ORIGINAL pre-treatment IgE for dosing")], ] t_mon = Table(mon_rows, colWidths=[W*0.15,W*0.47,W*0.38]) t_mon.setStyle(TableStyle(BASE + [ ("BACKGROUND",(0,0),(-1,0),GREY_HDR), ("TEXTCOLOR",(0,0),(-1,0),WHITE), ("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"), ("FONTSIZE",(0,0),(-1,-1),7.3), ("BACKGROUND",(0,1),(0,1),TEAL_L), # pre-treatment ("BACKGROUND",(0,4),(0,4),BLUE_L), # 12-16 wk ("BACKGROUND",(0,7),(0,7),AMBER_L), # on stopping ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,GREY_L]), ])) story.append(t_mon) story.append(Spacer(1,3*mm)) # ═══════════════════════════════════════════════════════════════════════════ # SECTION 8 — IgE INTERPRETATION ON TREATMENT # ═══════════════════════════════════════════════════════════════════════════ story.append(sh("8. IgE Interpretation On Omalizumab — Critical Points", bg=ORANGE)) story.append(Spacer(1,1.5*mm)) ige_interp = Table([[Paragraph( "<b>The IgE Paradox on Omalizumab:</b><br/><br/>" "• <b>Free IgE</b> → falls dramatically (goal: <25 IU/mL). This reflects successful drug action. MEASURE FREE IgE to assess response.<br/>" "• <b>Total IgE</b> → RISES paradoxically on treatment (typically 2–5× baseline). This is because omalizumab-IgE complexes have a longer half-life than free IgE alone, so they accumulate. This does NOT indicate treatment failure.<br/>" "• <b>Remain elevated up to 1 year after stopping</b>. Do not use total IgE levels measured during or within 1 year of stopping omalizumab to make eligibility decisions for re-starting or switching biologics.<br/>" "• <b>Skin-prick testing</b>: omalizumab suppresses the wheal-and-flare response for up to <b>8 weeks</b> after the last dose. Delay allergy testing accordingly.<br/>" "• <b>ABPA monitoring</b>: use total IgE trends — a 25% or greater fall from pre-treatment baseline signals response to anti-fungal + steroid therapy. On omalizumab adjunct, this rule does not apply.", ps("igebox", fontSize=7.8, leading=12)) ]], colWidths=[W]) ige_interp.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,-1),RED_L), ("BOX",(0,0),(-1,-1),1.5,ORANGE), ("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8), ("LEFTPADDING",(0,0),(-1,-1),10),("RIGHTPADDING",(0,0),(-1,-1),10), ])) story.append(ige_interp) story.append(Spacer(1,3*mm)) # ═══════════════════════════════════════════════════════════════════════════ # SECTION 9 — ADVERSE EFFECTS & MANAGEMENT # ═══════════════════════════════════════════════════════════════════════════ story.append(sh("9. Adverse Effects & Management")) story.append(Spacer(1,1.5*mm)) ae_rows = [ [b("Adverse Effect"),b("Frequency"),b("Onset"),b("Management")], [p("Anaphylaxis / severe hypersensitivity"), p("~0.1–0.2%\n(rare but serious)"), p("Usually within 2 hours of injection; can be delayed up to 24 hrs (rare)"), p("Mandatory 30–60 min observation post-injection at every visit. Epinephrine 0.3 mg IM immediately if anaphylaxis. Discontinue omalizumab permanently.")], [p("Injection site reactions\n(pain, swelling, redness)"), p("~45% (most common\nadverse effect)"), p("Within 1 hour of injection; resolves within days"), p("Warm injection site before injection; slow administration technique; rotate sites. Mild — no dose change needed.")], [p("Arteriothrombotic events\n(MI, stroke, PE, DVT)"), p("Rare; signal from\npost-market data"), p("Any time during treatment"), p("Use with caution in patients at high cardiovascular risk. Weigh benefit vs risk in high-risk patients.")], [p("Malignancy"), p("Not established;\nslightly elevated signal\nin early data"), p("Long-term use"), p("No causal link established in meta-analyses. Annual cancer screening as per standard of care. Monitor.")], [p("Helminth infection risk"), p("Theoretical"), p("On treatment"), p("Avoid starting in patients with active parasitic infection. Screen with stool exam + serology before starting (especially in India/tropics).")], [p("Fever, arthralgia\n(serum-sickness like)"), p("Rare"), p("Days to weeks post-injection"), p("Usually self-limited. If severe, withhold omalizumab and manage symptomatically. Can restart with monitoring.")], [p("Headache, nasopharyngitis,\nfatigue, dizziness"), p("Common (>10%)"), p("Any time"), p("Symptomatic management. Generally mild and do not require dose modification.")], ] t_ae = Table(ae_rows, colWidths=[W*0.22,W*0.14,W*0.20,W*0.44]) t_ae.setStyle(TableStyle(BASE + [ ("BACKGROUND",(0,0),(-1,0),GREY_HDR), ("TEXTCOLOR",(0,0),(-1,0),WHITE), ("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"), ("FONTSIZE",(0,0),(-1,-1),7.2), ("BACKGROUND",(0,1),(-1,1),RED_L), # anaphylaxis ("FONTNAME",(0,1),(0,1),"Helvetica-Bold"), ])) story.append(t_ae) story.append(Spacer(1,3*mm)) # ═══════════════════════════════════════════════════════════════════════════ # SECTION 10 — SPECIAL POPULATIONS # ═══════════════════════════════════════════════════════════════════════════ story.append(sh("10. Special Populations & Practical Notes", bg=PURPLE)) story.append(Spacer(1,1.5*mm)) sp_rows = [ [b("Population / Scenario"),b("Key Consideration")], [p("Pregnancy"),p("Limited data; omalizumab crosses placenta (IgG). Generally avoided in first trimester. If severe uncontrolled asthma: risk of uncontrolled asthma to mother/fetus may outweigh risk. A pregnancy registry (EXPECT) showed no increase in major malformations.")], [p("Breastfeeding"),p("Present in breast milk (IgG). Likely low risk (large molecule, poor oral bioavailability in infant). Risk-benefit discussion with patient.")], [p("Renal impairment"),p("No dose adjustment needed. Omalizumab not renally cleared (cleared as IgG protein).")], [p("Hepatic impairment"),p("No dose adjustment needed. Not hepatically metabolised.")], [p("Elderly (>65 years)"),p("No specific dose adjustment. Monitor cardiovascular risk more carefully (arteriothrombotic signal).")], [p("Obesity / weight >150 kg"),p("Not studied in clinical trials. Use clinical judgement; standard nomogram cannot be reliably applied.")], [p("Switching from omalizumab\nto another biologic"),p("No washout period officially required. However, allow 4–8 weeks for free IgE to partially recover if switching to another IgE-based assessment. Total IgE will remain elevated for up to 1 year — use original pre-treatment IgE value.")], [p("Patients on beta-blockers"),p("Increased risk of severe anaphylaxis and resistance to epinephrine treatment. If possible, discontinue beta-blocker before starting. If essential, have glucagon available at injection visits.")], [p("Live vaccines"),p("Administer all live vaccines ≥30 days before starting omalizumab. Avoid live vaccines while on treatment if possible.")], [p("India-specific: helminth co-infection"),p("Screen ALL patients with stool exam × 3 + Strongyloides IgG BEFORE starting. Treat any parasitic infection first. Recheck IgE at 3 months post-treatment before finalising omalizumab eligibility — IgE may fall significantly.")], ] t_sp = Table(sp_rows, colWidths=[W*0.26,W*0.74]) t_sp.setStyle(TableStyle(BASE + [ ("BACKGROUND",(0,0),(-1,0),PURPLE), ("TEXTCOLOR",(0,0),(-1,0),WHITE), ("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"), ("FONTSIZE",(0,0),(-1,-1),7.3), ("BACKGROUND",(0,10),(-1,10),AMBER_L), # India-specific ("FONTNAME",(0,10),(0,10),"Helvetica-Bold"), ])) story.append(t_sp) story.append(Spacer(1,3*mm)) # ═══════════════════════════════════════════════════════════════════════════ # SECTION 11 — QUICK REFERENCE SUMMARY BOX # ═══════════════════════════════════════════════════════════════════════════ story.append(sh("11. At-a-Glance Quick Reference", bg=GREY_HDR)) story.append(Spacer(1,1.5*mm)) qr = Table([[Paragraph( "<b>BEFORE STARTING:</b> Measure total IgE (IU/mL) + weight (kg). Confirm IgE 30–700 (asthma). Confirm allergen sensitisation. Rule out parasites. Assess CV risk.<br/><br/>" "<b>DOSE LOOKUP (ASTHMA/CRSwNP):</b><br/>" " IgE 30–100: q4w | 150–300 mg depending on weight<br/>" " IgE 101–300: q4w or q2w | 300 mg depending on weight<br/>" " IgE 301–700: q2w | 225–375 mg depending on weight | High weight bands = DO NOT DOSE<br/><br/>" "<b>DOSE (CSU):</b> 300 mg SC every 4 weeks (fixed dose, no IgE/weight calculation)<br/><br/>" "<b>AFTER INJECTION:</b> Observe 30–60 min at every visit. Epinephrine must be available.<br/><br/>" "<b>RESPONSE CHECK:</b> At 12–16 weeks. Measure FREE IgE (goal <25 IU/mL). Do NOT use total IgE on treatment.<br/><br/>" "<b>ON STOPPING:</b> Total IgE elevated up to 1 year. Skin-prick test: wait ≥8 weeks. Use original pre-treatment IgE if restarting.", ps("qrbox", fontSize=7.8, leading=13)) ]], colWidths=[W]) qr.setStyle(TableStyle([ ("BACKGROUND",(0,0),(-1,-1),BLUE_L), ("BOX",(0,0),(-1,-1),2,NAVY), ("TOPPADDING",(0,0),(-1,-1),10),("BOTTOMPADDING",(0,0),(-1,-1),10), ("LEFTPADDING",(0,0),(-1,-1),12),("RIGHTPADDING",(0,0),(-1,-1),12), ])) story.append(qr) story.append(Spacer(1,3*mm)) # ── Footer ─────────────────────────────────────────────────────────────── story.append(HRFlowable(width=W, thickness=0.5, color=TEAL)) story.append(Spacer(1,1.5*mm)) story.append(Paragraph( "<b>Sources:</b> Xolair (omalizumab) US Prescribing Information (Genentech/Novartis, 2024–2025) · " "OHSU Health Services Xolair Protocol (2025) · Goldman-Cecil Medicine (2024) · " "K.J. Lee's Essential Otolaryngology · Katzung's Basic & Clinical Pharmacology 16th Ed. · " "Murray & Nadel's Respiratory Medicine · Fitzpatrick's Dermatology 9th Ed. · " "Chinese Expert Consensus on Omalizumab in CSU (PMC 2022) | " "<b>Orris Medical AI · May 2026</b> | " "<i>Clinical reference only. Always verify against current product labelling and institutional protocols before use.</i>", CAP)) doc.build(story) print(f"PDF generated: {OUTPUT}") PYEOF echo "Script written"
cd /home/daytona/workspace/ige-protocol && python3 omalizumab_dosing_pdf.py 2>&1
ls -lh /home/daytona/workspace/ige-protocol/Omalizumab_Dosing_Monitoring.pdf
Omalizumab Dosing Monitoring
PDF Document · PDF
| Section | Content |
|---|---|
| 1. Mechanism | How omalizumab binds free IgE, downregulates FcεRI, reverses airway remodelling |
| 2. Indications & Eligibility | Colour-coded table: Asthma, CSU, CRSwNP, Food Allergy, ABPA (off-label) with IgE thresholds per indication |
| 3. Dose Nomogram | Full q4w and q2w official dose tables for adults ≥12 yrs; "DO NOT DOSE" cells highlighted in red |
| 4. CSU Fixed Dosing | 150 vs 300 mg/month; response at 12 weeks; stopping strategy |
| 5. Paediatric Dosing | Simplified reference for 6–<12 years with weight bands |
| 6. Step-by-Step Calculator | Worked example (70 kg, IgE 450) showing exactly how to look up dose and confirm it meets the 0.016 formula minimum |
| Section | Content |
|---|---|
| 7. Monitoring Protocol | Pre-treatment → day of injection → 4 weeks → 12–16 weeks → 3-monthly → annual → stopping |
| 8. IgE Interpretation Box | The IgE paradox explained: why total IgE rises on treatment and why FREE IgE is the only valid on-treatment measure |
| 9. Adverse Effects | Anaphylaxis (mandatory 30–60 min observation rule), injection site reactions, arteriothrombotic events, helminth risk |
| 10. Special Populations | Pregnancy, breastfeeding, renal/hepatic impairment, obesity, beta-blocker use, India-specific parasite screening |
| 11. At-a-Glance Summary Box | One-page cheat sheet: before starting → dose lookup → after injection → response → stopping |