10yr boy with gradual increase breathlessness and intermediate fever with x ray chest , what is different diagnosis
right upper lobe consolidation child differential diagnosis breathlessness fever
| Investigation | Purpose |
|---|---|
| CBC with differential | Leukocytosis (bacterial), lymphocytosis (viral/TB) |
| CRP / ESR | Inflammatory marker |
| Mantoux / TST + IGRA | TB screen |
| Sputum AFB / gastric lavage | TB confirmation |
| GeneXpert MTB/RIF | Rapid TB diagnosis |
| Mycoplasma IgM serology | Atypical pneumonia |
| Blood culture (aerobic) | Bacteremia |
| CT Chest | Defines extent, cavitation, lymphadenopathy, foreign body |
| Bronchoscopy | If no response to antibiotics |
Source: Community-Acquired Pneumonia in Children - Swanson's Family Medicine Review, p. 584
Search for clinical images of TB and pneumonia consolidation patterns in children
pediatric pulmonary tuberculosis chest xray consolidation clinical images children
lobar pneumonia chest xray children right upper lobe consolidation clinical images
https://pmc.ncbi.nlm.nih.gov/articles/PMC8878790

A (frontal): Dense right upper lobe alveolar consolidation. Fissures are not displaced - no volume loss, consistent with acute bacterial infection. B (lateral): Confirms the posterior upper lobe location.
- Source: Pediatric Chest, Radiology Key

A (initial): Right-sided consolidation with prominent right hilar fullness (lymphadenopathy). B (2 weeks post-treatment): Consolidation has resolved but right hilar lymphadenopathy persists (arrows) - this persistence is characteristic of TB and not bacterial pneumonia.
- Source: Pediatric Chest, Radiology Key

Note the flattened, more linear opacity and subtle fissure displacement - distinguishing features from consolidation. In your patient's X-ray, the trachea was midline, confirming consolidation rather than significant atelectasis.
- Source: Pediatric Chest, Radiology Key

Bilateral innumerable 1-3mm nodules scattered uniformly throughout both lung fields. This pattern is NOT seen in your patient - shown here for comparison only.
- Source: Pediatric Chest, Radiology Key

A (initial CXR): Opacification with effusion. B (after drainage): Underlying consolidation visible. C (CT): Shows fluid loculation - CT is superior for characterizing effusions and guiding drainage.
- Source: Pediatric Chest, Radiology Key

Bilateral patchy infiltrates, peribronchial thickening. Different from the lobar pattern in your patient.
- Source: Pediatric Chest, Radiology Key

A (CXR): Right-sided opacity with arrowheads pointing to a cavity wall. B/C (lateral + zoomed): Air-fluid level within the cavity (arrow) - indicates caseous necrosis and liquefaction. This pattern is rare in 10-year-olds but possible in adolescents or immunocompromised children.
- Source: Pediatric Chest, Radiology Key
| Feature | Primary TB | Bacterial Pneumonia (CAP) |
|---|---|---|
| Onset | Gradual (weeks-months) | Acute (days) |
| Fever pattern | Low-grade, intermittent | High-grade, continuous |
| Consolidation location | RUL/RML most common | Any lobe; RLL common |
| Hilar lymphadenopathy | YES - characteristic | Rare |
| Volume loss | No (usually) | No |
| Cavitation | Rare in <10 yrs | Rare (Staph) |
| Pleural effusion | Uncommon | More common (Staph, Strep) |
| Air bronchogram | Can be present | Often present |
| Response to antibiotics | No improvement | Improves in 48-72h |
| Mantoux/TST | Positive (>10mm) | Negative |
| Constitutional symptoms | Weight loss, night sweats | Cough, pleuritic pain |
Create a diagnostic flowchart (PDF) for pediatric right upper lobe consolidation
ls /home/daytona/workspace/ 2>/dev/null || echo "workspace empty or not found"
mkdir -p /home/daytona/workspace/rul-flowchart && python3 -c "import reportlab; β¦
~/rul-flowchart/create_flowchart.py
"""
Diagnostic Flowchart: Pediatric Right Upper Lobe Consolidation
Uses ReportLab to draw a professional A3-landscape PDF flowchart
"""
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A3, landscape
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
OUTPUT = "/home/daytona/workspace/rul-flowchart/Pediatric_RUL_Consolidation_Flowchart.pdf"
PAGE_W, PAGE_H = landscape(A3)
# ββ colour palette ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
C_TITLE_BG = colors.HexColor("#1a3a5c") # deep navy
C_TITLE_FG = colors.white
C_START = colors.HexColor("#2c7bb6") # blue β entry node
C_DIAMOND = colors.HexColor("#f7c948") # amber β decision
C_DIAMOND_TXT= colors.HexColor("#1a1a1a")
C_TB = colors.HexColor("#d73027") # red β TB box
C_BACT = colors.HexColor("#1a9641") # green β bacterial pneumonia
C_ATYPICAL = colors.HexColor("#756bb1") # purple β atypical / Mycoplasma
C_OTHER = colors.HexColor("#f46d43") # orange β other / rare
C_WORKUP_BG = colors.HexColor("#e8f4fd") # pale blue β workup boxes
C_WORKUP_BR = colors.HexColor("#2c7bb6")
C_TX_BG = colors.HexColor("#f0fff0") # pale green β treatment
C_TX_BR = colors.HexColor("#1a9641")
C_ARROW = colors.HexColor("#333333")
C_FOOTER = colors.HexColor("#666666")
C_SHADOW = colors.HexColor("#cccccc")
def draw_rounded_rect(c, x, y, w, h, r=4*mm, fill_color=colors.white,
stroke_color=colors.black, lw=1, shadow=False):
if shadow:
c.setFillColor(C_SHADOW)
c.setStrokeColor(C_SHADOW)
c.roundRect(x+1.5*mm, y-1.5*mm, w, h, r, stroke=0, fill=1)
c.setFillColor(fill_color)
c.setStrokeColor(stroke_color)
c.setLineWidth(lw)
c.roundRect(x, y, w, h, r, stroke=1, fill=1)
def draw_diamond(c, cx, cy, half_w, half_h,
fill_color=C_DIAMOND, stroke_color=colors.black, lw=1.5):
path = c.beginPath()
path.moveTo(cx, cy + half_h)
path.lineTo(cx + half_w, cy)
path.lineTo(cx, cy - half_h)
path.lineTo(cx - half_w, cy)
path.close()
c.setFillColor(fill_color)
c.setStrokeColor(stroke_color)
c.setLineWidth(lw)
c.drawPath(path, stroke=1, fill=1)
def centred_text(c, x, y, w, h, text, font="Helvetica-Bold", size=8,
color=colors.black, line_height=None):
"""Draw multi-line centred text inside a box (x,y = bottom-left)."""
if line_height is None:
line_height = size * 1.35
lines = text.split("\n")
total_h = len(lines) * line_height
start_y = y + h/2 + total_h/2 - line_height
c.setFont(font, size)
c.setFillColor(color)
for line in lines:
c.drawCentredString(x + w/2, start_y, line)
start_y -= line_height
def arrow(c, x1, y1, x2, y2, label="", label_side="right",
color=C_ARROW, lw=1.5, head=4*mm):
c.setStrokeColor(color)
c.setFillColor(color)
c.setLineWidth(lw)
c.line(x1, y1, x2, y2)
# arrowhead (simple triangle pointing toward x2,y2)
import math
angle = math.atan2(y2 - y1, x2 - x1)
ax1 = x2 - head * math.cos(angle - 0.4)
ay1 = y2 - head * math.sin(angle - 0.4)
ax2 = x2 - head * math.cos(angle + 0.4)
ay2 = y2 - head * math.sin(angle + 0.4)
path = c.beginPath()
path.moveTo(x2, y2)
path.lineTo(ax1, ay1)
path.lineTo(ax2, ay2)
path.close()
c.drawPath(path, stroke=0, fill=1)
if label:
mx, my = (x1+x2)/2, (y1+y2)/2
c.setFont("Helvetica-Bold", 7)
c.setFillColor(color)
off = 4*mm
if label_side == "right":
c.drawString(mx + off, my, label)
elif label_side == "left":
c.drawRightString(mx - off, my, label)
else:
c.drawCentredString(mx, my + off, label)
def build_pdf():
c = canvas.Canvas(OUTPUT, pagesize=landscape(A3))
c.setTitle("Diagnostic Flowchart β Pediatric RUL Consolidation")
W, H = PAGE_W, PAGE_H
# βββββββββββββββββββββββββββββββββββββββββββ
# TITLE BAR
# βββββββββββββββββββββββββββββββββββββββββββ
c.setFillColor(C_TITLE_BG)
c.rect(0, H - 22*mm, W, 22*mm, stroke=0, fill=1)
c.setFont("Helvetica-Bold", 16)
c.setFillColor(C_TITLE_FG)
c.drawCentredString(W/2, H - 14*mm,
"DIAGNOSTIC FLOWCHART: Pediatric Right Upper Lobe Consolidation")
c.setFont("Helvetica", 9)
c.drawCentredString(W/2, H - 19*mm,
"10-Year-Old Child | Gradual Breathlessness + Intermittent Fever")
# βββββββββββββββββββββββββββββββββββββββββββ
# LEGEND (top-right)
# βββββββββββββββββββββββββββββββββββββββββββ
legend_items = [
(C_START, "Entry / Step"),
(C_DIAMOND, "Decision"),
(C_TB, "TB Pathway"),
(C_BACT, "Bacterial Pneumonia"),
(C_ATYPICAL,"Atypical / Mycoplasma"),
(C_OTHER, "Other / Rare"),
]
lx = W - 58*mm
ly = H - 26*mm
c.setFont("Helvetica-Bold", 7.5)
c.setFillColor(C_TITLE_BG)
c.drawString(lx, ly, "LEGEND")
ly -= 4*mm
for col, label in legend_items:
c.setFillColor(col)
c.rect(lx, ly - 2.5*mm, 8*mm, 4*mm, stroke=0, fill=1)
c.setFillColor(colors.black)
c.setFont("Helvetica", 7)
c.drawString(lx + 10*mm, ly, label)
ly -= 5*mm
# βββββββββββββββββββββββββββββββββββββββββββ
# LAYOUT CONSTANTS
# βββββββββββββββββββββββββββββββββββββββββββ
# We'll place nodes on a 5-column layout
# Columns (centre x):
col = [W*0.1, W*0.28, W*0.50, W*0.72, W*0.90]
# Box dimensions
BW, BH = 44*mm, 14*mm # standard box
DW, DH = 28*mm, 12*mm # diamond half-widths
top_y = H - 32*mm # top of first node (top-left corner)
# ββ helper to get box centre ββ
def bc(x, y, w=BW, h=BH):
return x + w/2, y + h/2
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ROW 1 β Entry node (centred)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
r1_y = top_y - BH
r1_x = W/2 - BW/2
draw_rounded_rect(c, r1_x, r1_y, BW, BH,
fill_color=C_START, stroke_color=C_START, lw=1.5, shadow=True)
centred_text(c, r1_x, r1_y, BW, BH,
"CHILD WITH RUL CONSOLIDATION\n(+ Gradual Breathlessness + Intermittent Fever)",
font="Helvetica-Bold", size=8, color=colors.white)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ROW 2 β Initial Workup box
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
r2_y = r1_y - 22*mm
r2_x = W/2 - BW/2 - 10*mm
r2_w = BW + 20*mm
arrow(c, W/2, r1_y, W/2, r2_y + BH + 0.5*mm)
draw_rounded_rect(c, r2_x, r2_y, r2_w, BH,
fill_color=C_WORKUP_BG, stroke_color=C_WORKUP_BR, lw=1.5, shadow=True)
centred_text(c, r2_x, r2_y, r2_w, BH,
"INITIAL ASSESSMENT: History + Exam + CXR Review\n"
"CBC | CRP/ESR | Blood Culture | Oβ Saturation | Mantoux/TST",
font="Helvetica", size=7.5, color=C_TITLE_BG)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ROW 3 β Decision Diamond: Acute or Gradual onset?
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
d1_cx = W/2
d1_cy = r2_y - 22*mm
arrow(c, W/2, r2_y, W/2, d1_cy + DH + 0.5*mm)
draw_diamond(c, d1_cx, d1_cy, DW + 8*mm, DH + 2*mm,
fill_color=C_DIAMOND, stroke_color=colors.HexColor("#c9a800"), lw=2)
centred_text(c, d1_cx - DW - 8*mm, d1_cy - DH - 2*mm,
(DW+8*mm)*2, (DH+2*mm)*2,
"Onset:\nAcute (<3 days)\nor Gradual (>1 wk)?",
font="Helvetica-Bold", size=8, color=C_DIAMOND_TXT)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ROW 4 β Two branches: LEFT = Acute, RIGHT = Gradual
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
r4_y = d1_cy - 32*mm
# -- LEFT: Acute branch --
acute_x = col[1] - BW/2
arrow(c, d1_cx - DW - 8*mm, d1_cy,
acute_x + BW/2, r4_y + BH + 0.5*mm,
label="ACUTE", label_side="left")
draw_rounded_rect(c, acute_x, r4_y, BW, BH,
fill_color=C_BACT, stroke_color=C_BACT, lw=1.5, shadow=True)
centred_text(c, acute_x, r4_y, BW, BH,
"BACTERIAL PNEUMONIA\n(CAP) Most Likely",
font="Helvetica-Bold", size=8, color=colors.white)
# -- RIGHT: Gradual branch --
grad_x = col[3] - BW/2
arrow(c, d1_cx + DW + 8*mm, d1_cy,
grad_x + BW/2, r4_y + BH + 0.5*mm,
label="GRADUAL", label_side="right")
draw_rounded_rect(c, grad_x, r4_y, BW, BH,
fill_color=C_TB, stroke_color=C_TB, lw=1.5, shadow=True)
centred_text(c, grad_x, r4_y, BW, BH,
"SUSPECT TB / ATYPICAL\nPNEUMONIA",
font="Helvetica-Bold", size=8, color=colors.white)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ROW 5 β Sub-decisions under each branch
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
r5_y = r4_y - 28*mm
# LEFT BRANCH: Decision β High fever + toxic?
d2_cx = col[1]
d2_cy = r5_y + DH
arrow(c, acute_x + BW/2, r4_y, d2_cx, d2_cy + DH + 0.5*mm)
draw_diamond(c, d2_cx, d2_cy, DW + 2*mm, DH,
fill_color=C_DIAMOND, stroke_color=colors.HexColor("#c9a800"), lw=1.5)
centred_text(c, d2_cx - DW - 2*mm, d2_cy - DH,
(DW+2*mm)*2, DH*2,
"High fever\n+ Lobar?\nToxic child?",
font="Helvetica-Bold", size=7.5, color=C_DIAMOND_TXT)
# RIGHT BRANCH: Decision β Mantoux +ve / hilar LN?
d3_cx = col[3]
d3_cy = r5_y + DH
arrow(c, grad_x + BW/2, r4_y, d3_cx, d3_cy + DH + 0.5*mm)
draw_diamond(c, d3_cx, d3_cy, DW + 2*mm, DH,
fill_color=C_DIAMOND, stroke_color=colors.HexColor("#c9a800"), lw=1.5)
centred_text(c, d3_cx - DW - 2*mm, d3_cy - DH,
(DW+2*mm)*2, DH*2,
"Mantoux +ve\nOR Hilar LN\non CT?",
font="Helvetica-Bold", size=7.5, color=C_DIAMOND_TXT)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ROW 6 β Four diagnosis boxes
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
r6_y = r5_y - 26*mm
box_w = 40*mm
box_h = 16*mm
# Strep pneumoniae (YES from left diamond)
strep_x = col[0] - box_w/2
arrow(c, d2_cx - DW - 2*mm, d2_cy,
strep_x + box_w/2, r6_y + box_h + 0.5*mm,
label="YES", label_side="left")
draw_rounded_rect(c, strep_x, r6_y, box_w, box_h,
fill_color=C_BACT, stroke_color=C_BACT, lw=1.5, shadow=True)
centred_text(c, strep_x, r6_y, box_w, box_h,
"LOBAR PNEUMONIA\nStrep. pneumoniae\nor H. influenzae",
font="Helvetica-Bold", size=7.5, color=colors.white)
# Mycoplasma (NO from left diamond)
myco_x = col[2] - box_w/2 - 4*mm
arrow(c, d2_cx + DW + 2*mm, d2_cy,
myco_x + box_w/2, r6_y + box_h + 0.5*mm,
label="NO / Low grade", label_side="top")
draw_rounded_rect(c, myco_x, r6_y, box_w, box_h,
fill_color=C_ATYPICAL, stroke_color=C_ATYPICAL, lw=1.5, shadow=True)
centred_text(c, myco_x, r6_y, box_w, box_h,
"ATYPICAL PNEUMONIA\nMycoplasma pneumoniae\n(School-age #1)",
font="Helvetica-Bold", size=7.5, color=colors.white)
# TB confirmed (YES from right diamond)
tb_x = col[3] + 4*mm
arrow(c, d3_cx + DW + 2*mm, d3_cy,
tb_x + box_w/2, r6_y + box_h + 0.5*mm,
label="YES", label_side="right")
draw_rounded_rect(c, tb_x, r6_y, box_w, box_h,
fill_color=C_TB, stroke_color=C_TB, lw=1.5, shadow=True)
centred_text(c, tb_x, r6_y, box_w, box_h,
"PRIMARY TB\nM. tuberculosis\n(GeneXpert / AFB)",
font="Helvetica-Bold", size=7.5, color=colors.white)
# Other (NO from right diamond)
other_x = col[4] - box_w/2
arrow(c, d3_cx, d3_cy - DH,
other_x + box_w/2, r6_y + box_h + 0.5*mm,
label="NO", label_side="right")
draw_rounded_rect(c, other_x, r6_y, box_w, box_h,
fill_color=C_OTHER, stroke_color=C_OTHER, lw=1.5, shadow=True)
centred_text(c, other_x, r6_y, box_w, box_h,
"OTHER: Fungal\nPost-obstructive\nLymphoma / CCAM",
font="Helvetica-Bold", size=7.5, color=colors.white)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ROW 7 β Investigations row
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
r7_y = r6_y - 26*mm
inv_h = 22*mm
# Strep workup
inv1_x = col[0] - box_w/2
arrow(c, strep_x + box_w/2, r6_y, inv1_x + box_w/2, r7_y + inv_h)
draw_rounded_rect(c, inv1_x, r7_y, box_w, inv_h,
fill_color=C_WORKUP_BG, stroke_color=C_WORKUP_BR, lw=1, shadow=False)
centred_text(c, inv1_x, r7_y, box_w, inv_h,
"WORKUP:\nβ’ Blood culture\nβ’ Pneumococcal Ag\nβ’ Procalcitonin",
font="Helvetica", size=7, color=C_TITLE_BG)
# Mycoplasma workup
inv2_x = myco_x
arrow(c, myco_x + box_w/2, r6_y, inv2_x + box_w/2, r7_y + inv_h)
draw_rounded_rect(c, inv2_x, r7_y, box_w, inv_h,
fill_color=C_WORKUP_BG, stroke_color=C_WORKUP_BR, lw=1, shadow=False)
centred_text(c, inv2_x, r7_y, box_w, inv_h,
"WORKUP:\nβ’ Mycoplasma IgM\nβ’ Cold agglutinins\nβ’ NPS PCR",
font="Helvetica", size=7, color=C_TITLE_BG)
# TB workup
inv3_x = tb_x
arrow(c, tb_x + box_w/2, r6_y, inv3_x + box_w/2, r7_y + inv_h)
draw_rounded_rect(c, inv3_x, r7_y, box_w, inv_h,
fill_color=colors.HexColor("#fff0f0"), stroke_color=C_TB, lw=1, shadow=False)
centred_text(c, inv3_x, r7_y, box_w, inv_h,
"WORKUP:\nβ’ GeneXpert MTB/RIF\nβ’ Gastric lavage AFB\nβ’ IGRA / CT Chest",
font="Helvetica", size=7, color=C_TITLE_BG)
# Other workup
inv4_x = other_x
arrow(c, other_x + box_w/2, r6_y, inv4_x + box_w/2, r7_y + inv_h)
draw_rounded_rect(c, inv4_x, r7_y, box_w, inv_h,
fill_color=C_WORKUP_BG, stroke_color=C_OTHER, lw=1, shadow=False)
centred_text(c, inv4_x, r7_y, box_w, inv_h,
"WORKUP:\nβ’ CT Chest\nβ’ Bronchoscopy\nβ’ Fungal serology",
font="Helvetica", size=7, color=C_TITLE_BG)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ROW 8 β Treatment row
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
r8_y = r7_y - 26*mm
tx_h = 22*mm
# Strep treatment
tx1_x = col[0] - box_w/2
arrow(c, inv1_x + box_w/2, r7_y, tx1_x + box_w/2, r8_y + tx_h)
draw_rounded_rect(c, tx1_x, r8_y, box_w, tx_h,
fill_color=C_TX_BG, stroke_color=C_TX_BR, lw=1.5, shadow=False)
centred_text(c, tx1_x, r8_y, box_w, tx_h,
"TREAT:\nAmoxicillin/Ampicillin\nIV β Oral 7-10 days\n(If MRSA: Vancomycin)",
font="Helvetica-Bold", size=7, color=colors.HexColor("#1a4a1a"))
# Mycoplasma treatment
tx2_x = myco_x
arrow(c, inv2_x + box_w/2, r7_y, tx2_x + box_w/2, r8_y + tx_h)
draw_rounded_rect(c, tx2_x, r8_y, box_w, tx_h,
fill_color=C_TX_BG, stroke_color=C_TX_BR, lw=1.5, shadow=False)
centred_text(c, tx2_x, r8_y, box_w, tx_h,
"TREAT:\nAzithromycin 5 days\nor Clarithromycin\n10-14 days",
font="Helvetica-Bold", size=7, color=colors.HexColor("#1a4a1a"))
# TB treatment
tx3_x = tb_x
arrow(c, inv3_x + box_w/2, r7_y, tx3_x + box_w/2, r8_y + tx_h)
draw_rounded_rect(c, tx3_x, r8_y, box_w, tx_h,
fill_color=colors.HexColor("#fff5f5"), stroke_color=C_TB, lw=1.5, shadow=False)
centred_text(c, tx3_x, r8_y, box_w, tx_h,
"TREAT:\n2HRZE + 4HR\nNotify + Contact Trace\nDOTS strategy",
font="Helvetica-Bold", size=7, color=colors.HexColor("#5a0000"))
# Other treatment
tx4_x = other_x
arrow(c, inv4_x + box_w/2, r7_y, tx4_x + box_w/2, r8_y + tx_h)
draw_rounded_rect(c, tx4_x, r8_y, box_w, tx_h,
fill_color=C_TX_BG, stroke_color=C_OTHER, lw=1.5, shadow=False)
centred_text(c, tx4_x, r8_y, box_w, tx_h,
"TREAT:\nDisease-specific\nOncology / Surgery\nor Antifungal",
font="Helvetica-Bold", size=7, color=colors.HexColor("#1a4a1a"))
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ROW 9 β Response Check box (all paths β centre)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
r9_y = r8_y - 26*mm
resp_w = 70*mm
resp_h = 14*mm
resp_x = W/2 - resp_w/2
# Arrows from all 4 treatment boxes converge
# Draw a horizontal connector line first
connect_y = r8_y - 8*mm
c.setStrokeColor(C_ARROW)
c.setLineWidth(1.2)
c.line(tx1_x + box_w/2, r8_y, tx1_x + box_w/2, connect_y)
c.line(tx2_x + box_w/2, r8_y, tx2_x + box_w/2, connect_y)
c.line(tx3_x + box_w/2, r8_y, tx3_x + box_w/2, connect_y)
c.line(tx4_x + box_w/2, r8_y, tx4_x + box_w/2, connect_y)
c.line(tx1_x + box_w/2, connect_y, tx4_x + box_w/2, connect_y)
arrow(c, W/2, connect_y, W/2, r9_y + resp_h + 0.5*mm)
draw_diamond(c, W/2, r9_y + resp_h/2, resp_w/2, resp_h/2,
fill_color=C_DIAMOND, stroke_color=colors.HexColor("#c9a800"), lw=2)
centred_text(c, resp_x, r9_y, resp_w, resp_h,
"Clinical response\nin 48-72 hrs?",
font="Helvetica-Bold", size=8.5, color=C_DIAMOND_TXT)
# YES β Discharge
yes_x = W/2 - resp_w/2 - 50*mm
yes_y = r9_y
yes_w = 40*mm
yes_h = 14*mm
arrow(c, resp_x, r9_y + resp_h/2,
yes_x + yes_w, yes_y + yes_h/2,
label="YES", label_side="top")
draw_rounded_rect(c, yes_x, yes_y, yes_w, yes_h,
fill_color=C_BACT, stroke_color=C_BACT, lw=1.5, shadow=True)
centred_text(c, yes_x, yes_y, yes_w, yes_h,
"CONTINUE Rx\nFollow-up CXR\n@ 4-6 weeks",
font="Helvetica-Bold", size=7.5, color=colors.white)
# NO β Reassess
no_x = W/2 + resp_w/2 + 10*mm
no_y = r9_y
no_w = 48*mm
no_h = 14*mm
arrow(c, resp_x + resp_w, r9_y + resp_h/2,
no_x, no_y + no_h/2,
label="NO", label_side="top")
draw_rounded_rect(c, no_x, no_y, no_w, no_h,
fill_color=C_TB, stroke_color=C_TB, lw=1.5, shadow=True)
centred_text(c, no_x, no_y, no_w, no_h,
"REASSESS: CT Chest\nBronchoscopy / HRCT\nRe-culture & Biopsy",
font="Helvetica-Bold", size=7.5, color=colors.white)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# RED FLAG BOX (bottom-left)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
rf_x = 6*mm
rf_y = 6*mm
rf_w = 80*mm
rf_h = 32*mm
c.setFillColor(colors.HexColor("#fff3cd"))
c.setStrokeColor(colors.HexColor("#e65c00"))
c.setLineWidth(1.5)
c.roundRect(rf_x, rf_y, rf_w, rf_h, 3*mm, stroke=1, fill=1)
c.setFont("Helvetica-Bold", 8)
c.setFillColor(colors.HexColor("#b30000"))
c.drawString(rf_x + 3*mm, rf_y + rf_h - 7*mm, "β RED FLAGS β Urgent Referral")
red_flags = [
"β’ Oβ sat < 92% | Severe respiratory distress",
"β’ Mediastinal shift or tension",
"β’ Bilateral involvement / Miliary pattern",
"β’ Immunocompromised child (HIV, malignancy)",
"β’ No antibiotic response in 48-72 hrs",
]
c.setFont("Helvetica", 7)
c.setFillColor(colors.HexColor("#333333"))
ry = rf_y + rf_h - 13*mm
for flag in red_flags:
c.drawString(rf_x + 3*mm, ry, flag)
ry -= 4.5*mm
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# KEY DIFFERENTIATORS BOX (bottom-right)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
kd_x = W - 96*mm
kd_y = 6*mm
kd_w = 90*mm
kd_h = 32*mm
c.setFillColor(colors.HexColor("#eef6ff"))
c.setStrokeColor(C_WORKUP_BR)
c.setLineWidth(1.5)
c.roundRect(kd_x, kd_y, kd_w, kd_h, 3*mm, stroke=1, fill=1)
c.setFont("Helvetica-Bold", 8)
c.setFillColor(C_TITLE_BG)
c.drawString(kd_x + 3*mm, kd_y + kd_h - 7*mm, "TB vs PNEUMONIA β KEY DIFFERENTIATORS")
rows = [
("Feature", "TB", "Pneumonia"),
("Onset", "Gradual (wks)", "Acute (days)"),
("Fever", "Low / Intermittent", "High / Continuous"),
("Mantoux", "Positive >10mm", "Negative"),
("Hilar LN", "YES (CT)", "Absent"),
("Abx response", "None", "Within 48-72 hrs"),
]
c.setFont("Helvetica-Bold", 6.5)
c.setFillColor(C_TITLE_BG)
col_x = [kd_x + 3*mm, kd_x + 30*mm, kd_x + 62*mm]
ry = kd_y + kd_h - 13*mm
for i, (feat, tb_val, pn_val) in enumerate(rows):
fnt = "Helvetica-Bold" if i == 0 else "Helvetica"
c.setFont(fnt, 6.5)
c.setFillColor(C_TITLE_BG if i == 0 else colors.black)
c.drawString(col_x[0], ry, feat)
c.setFillColor(C_TB if i > 0 else C_TITLE_BG)
c.drawString(col_x[1], ry, tb_val)
c.setFillColor(C_BACT if i > 0 else C_TITLE_BG)
c.drawString(col_x[2], ry, pn_val)
# divider
if i < len(rows) - 1:
c.setStrokeColor(colors.HexColor("#ccddee"))
c.setLineWidth(0.5)
c.line(kd_x + 2*mm, ry - 1*mm, kd_x + kd_w - 2*mm, ry - 1*mm)
ry -= 4.2*mm
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# FOOTER
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
c.setFillColor(C_TITLE_BG)
c.rect(0, 0, W, 5*mm, stroke=0, fill=1)
c.setFont("Helvetica", 6.5)
c.setFillColor(colors.white)
c.drawCentredString(W/2, 1.5*mm,
"For clinical use only. Correlate with local epidemiology, immunisation history, HIV status, and microbiological results. "
"Refer to institutional TB/CAP guidelines. | Generated: July 2026")
c.save()
print(f"PDF saved β {OUTPUT}")
if __name__ == "__main__":
build_pdf()
cd /home/daytona/workspace/rul-flowchart && python3 create_flowchart.py 2>&1
ls -lh /home/daytona/workspace/rul-flowchart/
Pediatric RUL Consolidation Flowchart
PDF Document Β· PDF
Generate a case management protocol Word document for TB vs CAP
ls /home/daytona/skills/docx/scripts/office/ && node --version && npm list -g doβ¦
mkdir -p /home/daytona/workspace/tb-cap-protocol
~/tb-cap-protocol/create_protocol.js
const {
Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
Header, Footer, AlignmentType, HeadingLevel, BorderStyle, WidthType,
ShadingType, VerticalAlign, PageNumber, NumberFormat, TableBorders,
convertInchesToTwip, UnderlineType, PageBreak
} = require('docx');
const fs = require('fs');
// ββ Colour palette ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const NAVY = "1A3A5C";
const RED = "C0392B";
const GREEN = "1A7A41";
const PURPLE = "6C3483";
const ORANGE = "D35400";
const AMBER = "B7950B";
const LGRAY = "F2F3F4";
const MGRAY = "D5D8DC";
const WHITE = "FFFFFF";
const LRED = "FDEDEC";
const LGREEN = "EAFAF1";
const LPURP = "F5EEF8";
const LBLUE = "EBF5FB";
const AMBER_L = "FEF9E7";
// ββ Helper: shaded cell ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
function shadedCell(text, bgHex, fgHex = "000000", bold = false, colspan = 1, width = null) {
const cellOpts = {
shading: { fill: bgHex, type: ShadingType.CLEAR, color: "auto" },
verticalAlign: VerticalAlign.CENTER,
margins: { top: 80, bottom: 80, left: 120, right: 120 },
children: [new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({ text, bold, color: fgHex, size: 18 })]
})]
};
if (width) cellOpts.width = { size: width, type: WidthType.DXA };
if (colspan > 1) cellOpts.columnSpan = colspan;
return new TableCell(cellOpts);
}
function plainCell(text, bgHex = WHITE, fgHex = "000000", bold = false, align = AlignmentType.LEFT) {
return new TableCell({
shading: { fill: bgHex, type: ShadingType.CLEAR, color: "auto" },
verticalAlign: VerticalAlign.CENTER,
margins: { top: 70, bottom: 70, left: 120, right: 120 },
children: [new Paragraph({
alignment: align,
children: [new TextRun({ text, bold, color: fgHex, size: 18 })]
})]
});
}
// ββ Helper: standard bordered table βββββββββββββββββββββββββββββββββββββββββ
const STD_BORDERS = {
top: { style: BorderStyle.SINGLE, size: 6, color: MGRAY },
bottom: { style: BorderStyle.SINGLE, size: 6, color: MGRAY },
left: { style: BorderStyle.SINGLE, size: 6, color: MGRAY },
right: { style: BorderStyle.SINGLE, size: 6, color: MGRAY },
insideHorizontal: { style: BorderStyle.SINGLE, size: 4, color: MGRAY },
insideVertical: { style: BorderStyle.SINGLE, size: 4, color: MGRAY },
};
// ββ Helper: heading paragraph ββββββββββββββββββββββββββββββββββββββββββββββββ
function h1(text) {
return new Paragraph({
heading: HeadingLevel.HEADING_1,
spacing: { before: 300, after: 100 },
children: [new TextRun({ text, bold: true, color: NAVY, size: 28, allCaps: true })]
});
}
function h2(text) {
return new Paragraph({
heading: HeadingLevel.HEADING_2,
spacing: { before: 240, after: 80 },
children: [new TextRun({ text, bold: true, color: NAVY, size: 24 })]
});
}
function h3(text) {
return new Paragraph({
heading: HeadingLevel.HEADING_3,
spacing: { before: 180, after: 60 },
children: [new TextRun({ text, bold: true, color: "444444", size: 22, italics: true })]
});
}
function body(text, options = {}) {
return new Paragraph({
spacing: { before: 60, after: 60 },
children: [new TextRun({ text, size: 20, color: "1A1A1A", ...options })]
});
}
function bullet(text, level = 0) {
return new Paragraph({
bullet: { level },
spacing: { before: 40, after: 40 },
children: [new TextRun({ text, size: 19, color: "1A1A1A" })]
});
}
function gap(n = 1) {
return [...Array(n)].map(() => new Paragraph({ children: [new TextRun({ text: "" })] }));
}
function divider() {
return new Paragraph({
border: { bottom: { style: BorderStyle.SINGLE, size: 6, color: MGRAY } },
children: [new TextRun({ text: "" })],
spacing: { before: 120, after: 120 }
});
}
function noteBox(text, bgHex = AMBER_L, labelColor = AMBER) {
return new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: {
top: { style: BorderStyle.THICK, size: 12, color: labelColor },
bottom: { style: BorderStyle.SINGLE, size: 6, color: labelColor },
left: { style: BorderStyle.THICK, size: 12, color: labelColor },
right: { style: BorderStyle.SINGLE, size: 6, color: labelColor },
insideHorizontal: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
insideVertical: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
},
rows: [
new TableRow({
children: [new TableCell({
shading: { fill: bgHex, type: ShadingType.CLEAR, color: "auto" },
margins: { top: 100, bottom: 100, left: 160, right: 160 },
children: [new Paragraph({
children: [new TextRun({ text, size: 18, color: "1A1A1A" })]
})]
})]
})
]
});
}
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SECTION 1 β Cover / Title
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const coverSection = [
...gap(2),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { before: 0, after: 80 },
children: [new TextRun({ text: "CASE MANAGEMENT PROTOCOL", bold: true, size: 48, color: NAVY, allCaps: true })]
}),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { before: 0, after: 200 },
children: [new TextRun({ text: "Pediatric Right Upper Lobe Consolidation:", bold: true, size: 36, color: NAVY })]
}),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { before: 0, after: 400 },
children: [new TextRun({ text: "Tuberculosis vs. Community-Acquired Pneumonia", bold: true, size: 32, color: RED })]
}),
// meta table
new Table({
alignment: AlignmentType.CENTER,
width: { size: 70, type: WidthType.PERCENTAGE },
borders: STD_BORDERS,
rows: [
new TableRow({ children: [
plainCell("Target Population", NAVY, WHITE, true, AlignmentType.CENTER),
plainCell("Pediatric patients aged 5β15 years", LBLUE, "000000", false)
]}),
new TableRow({ children: [
plainCell("Setting", NAVY, WHITE, true, AlignmentType.CENTER),
plainCell("Inpatient / Emergency / Outpatient Clinic", LBLUE)
]}),
new TableRow({ children: [
plainCell("Document Version", NAVY, WHITE, true, AlignmentType.CENTER),
plainCell("1.0 β July 2026", LBLUE)
]}),
new TableRow({ children: [
plainCell("Classification", NAVY, WHITE, true, AlignmentType.CENTER),
plainCell("Clinical Protocol β For Physician / Paediatric Team Use", LBLUE)
]}),
]
}),
...gap(2),
new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({ text: "Prepared by: Orris Medical AI Assistant | Based on WHO, IAP & IDSA Guidelines", size: 18, color: "777777", italics: true })]
}),
new Paragraph({ children: [new PageBreak()] })
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SECTION 2 β Purpose & Scope
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const purposeSection = [
h1("1. Purpose and Scope"),
body("This protocol provides a structured clinical framework for the differentiation, investigation, and management of right upper lobe (RUL) pulmonary consolidation in a child presenting with gradual-onset breathlessness and intermittent fever. The two most clinically important and epidemiologically significant diagnoses are:"),
...gap(1),
bullet("Primary Pulmonary Tuberculosis (TB) β M. tuberculosis infection"),
bullet("Community-Acquired Pneumonia (CAP) β bacterial, atypical, or viral"),
...gap(1),
body("This protocol is applicable to emergency departments, general paediatric wards, and outpatient settings in any region where TB burden is moderate to high. It does not replace local institutional guidelines or clinical judgement."),
divider(),
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SECTION 3 β Clinical Presentation
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const clinicalSection = [
h1("2. Clinical Presentation & Initial Triage"),
h2("2.1 Presenting Features"),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: STD_BORDERS,
rows: [
new TableRow({ children: [
shadedCell("Feature", NAVY, WHITE, true, 1, 2200),
shadedCell("Primary TB", RED, WHITE, true, 1, 2600),
shadedCell("Bacterial CAP", GREEN, WHITE, true, 1, 2600),
shadedCell("Atypical (Mycoplasma)", PURPLE, WHITE, true, 1, 2600),
]}),
...[
["Onset", "Gradual (weeksβmonths)", "Acute (1β3 days)", "Subacute (1β2 weeks)"],
["Fever pattern", "Low-grade, intermittent", "High-grade, continuous", "Low-grade, persistent"],
["Cough", "Dry or minimal", "Productive, purulent", "Dry, persistent ('walking')"],
["Breathlessness", "Gradual, progressive", "Rapid onset", "Mild to moderate"],
["Chest pain", "Absent / mild", "Pleuritic, sharp", "Absent / mild"],
["Constitutional", "Weight loss, night sweats","Rigors, vomiting", "Fatigue, headache"],
["Auscultation", "Reduced air entry", "Bronchial breath sounds", "Fine crackles"],
["O2 Saturation", "Normalβmildly reduced", "Often <95%", "Usually maintained"],
].map((row, i) =>
new TableRow({ children: [
plainCell(row[0], i%2===0 ? LGRAY : WHITE, "000000", true),
plainCell(row[1], i%2===0 ? LRED : "FFF5F5", RED),
plainCell(row[2], i%2===0 ? LGREEN : "F0FFF4", GREEN),
plainCell(row[3], i%2===0 ? LPURP : "FAF0FE", PURPLE),
]})
)
]
}),
...gap(1),
h2("2.2 Risk Factor Assessment"),
bullet("TB contact history (household or close contact with confirmed TB)"),
bullet("BCG vaccination status (unvaccinated = higher TB risk)"),
bullet("HIV status β immunocompromised children have atypical presentations"),
bullet("Malnutrition / low BMI β independently increases TB risk"),
bullet("Prior TB treatment or incomplete course"),
bullet("Migration from high-burden TB region"),
bullet("School / orphanage exposure"),
divider(),
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SECTION 4 β Radiology
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const radiologySection = [
h1("3. Radiological Assessment"),
h2("3.1 Chest X-Ray Interpretation"),
body("A CXR is mandatory in all children with suspected lower respiratory tract infection with consolidation pattern. Obtain PA view (AP if unable to stand). Request lateral view if upper lobe involvement suspected."),
...gap(1),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: STD_BORDERS,
rows: [
new TableRow({ children: [
shadedCell("CXR Finding", NAVY, WHITE, true, 1, 2200),
shadedCell("Favours TB", RED, WHITE, true, 1, 2600),
shadedCell("Favours Bacterial CAP", GREEN, WHITE, true, 1, 2600),
shadedCell("Significance", AMBER, WHITE, true, 1, 2600),
]}),
...[
["Lobar consolidation", "RUL β classic primary focus", "Any lobe; RLL common", "Location alone insufficient"],
["Hilar lymphadenopathy", "Present (asymmetric, unilateral)", "Absent", "Most specific TB sign in children"],
["Mediastinal shift", "Absent (unless compressive nodes)", "Absent in consolidation", "Shift β collapse not consolidation"],
["Pleural effusion", "Uncommon (<10%)", "Common with Staph, Strep", "Effusion needs drainage evaluation"],
["Cavitation", "Rare <10 yrs; possible in adolescents", "Rare; Staph necrotising", "CT needed if suspected cavity"],
["Miliary nodules", "TB dissemination (severe)", "Absent", "Urgent TB workup mandatory"],
["Air bronchogram", "May be present", "Characteristic finding", "Does not differentiate TB vs CAP"],
["No volume loss", "Present", "Present", "Distinguishes consolidation from atelectasis"],
].map((row, i) =>
new TableRow({ children: [
plainCell(row[0], i%2===0 ? LGRAY : WHITE, "000000", true),
plainCell(row[1], i%2===0 ? LRED : "FFF5F5", RED),
plainCell(row[2], i%2===0 ? LGREEN : "F0FFF4", GREEN),
plainCell(row[3], i%2===0 ? AMBER_L : WHITE, AMBER),
]})
)
]
}),
...gap(1),
h2("3.2 CT Chest Indications"),
body("CT chest is NOT routine. Order CT in the following situations:"),
bullet("CXR shows consolidation but clinical course is atypical or prolonged (>2 weeks)"),
bullet("Suspicion of hilar or mediastinal lymphadenopathy not visible on CXR"),
bullet("No response to empiric antibiotics after 48β72 hours"),
bullet("Suspected complication: cavitation, empyema, lung abscess, pneumothorax"),
bullet("Immunocompromised child with atypical presentation"),
bullet("Suspected foreign body or endobronchial lesion"),
...gap(1),
noteBox("CT Tip: A low-dose CT chest with contrast is preferred in children to minimise radiation. Window the images at both lung and mediastinal settings. Report specifically: lymph node size/distribution, consolidation extent, cavitation, and pleural collections.", LBLUE, NAVY),
divider(),
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SECTION 5 β Investigations
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const investigationsSection = [
h1("4. Investigations"),
h2("4.1 First-Line Investigations (ALL Children)"),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: STD_BORDERS,
rows: [
new TableRow({ children: [
shadedCell("Investigation", NAVY, WHITE, true, 1, 2800),
shadedCell("Purpose", NAVY, WHITE, true, 1, 4200),
shadedCell("Interpretation", NAVY, WHITE, true, 1, 3000),
]}),
...[
["CBC with differential", "Screen for leukocytosis (bacterial), lymphocytosis (TB/viral), anaemia (TB)", "WBC >15,000 with neutrophilia β bacterial; Lymphocytosis β TB/viral"],
["CRP + ESR", "Inflammatory markers; CRP more sensitive for acute bacterial infection", "CRP >100 mg/L β bacterial CAP; mildly elevated β TB or atypical"],
["Blood culture (aerobic)", "Identify bacteraemia in bacterial CAP; positive in ~10β20% lobar pneumonia", "Positive β guides targeted antibiotic therapy"],
["Pulse oximetry / ABG", "Assess oxygenation; guide O2 therapy and admission decision", "SpO2 <92% = indication for admission and oxygen supplementation"],
["Mantoux / TST (5 TU PPD)", "Screen for TB sensitization; β₯10mm = positive in immunocompetent child", "β₯5mm in HIV+ / severely malnourished counts as positive"],
["Chest X-Ray (PA + Lateral)", "Primary imaging; assess consolidation pattern, hilar nodes, effusion", "See Section 3 interpretation guide"],
["Sputum / Nasopharyngeal swab", "Gram stain and culture; PCR for Mycoplasma, Respiratory Viruses", "Positive culture guides targeted therapy"],
].map((row, i) =>
new TableRow({ children: [
plainCell(row[0], i%2===0 ? LGRAY : WHITE, "000000", true),
plainCell(row[1], i%2===0 ? LGRAY : WHITE),
plainCell(row[2], i%2===0 ? LGRAY : WHITE, "333333", false),
]})
)
]
}),
...gap(1),
h2("4.2 TB-Specific Investigations"),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: STD_BORDERS,
rows: [
new TableRow({ children: [
shadedCell("Test", RED, WHITE, true, 1, 2800),
shadedCell("Specimen", RED, WHITE, true, 1, 2000),
shadedCell("When to Order", RED, WHITE, true, 1, 2200),
shadedCell("Key Note", RED, WHITE, true, 1, 3000),
]}),
...[
["GeneXpert MTB/RIF Ultra", "Sputum / Gastric aspirate / BAL", "First-line molecular test; order in all suspected TB", "Detects MTB + RIF resistance in <2 hrs; highest sensitivity in children"],
["Gastric Lavage / Aspirate (x3)", "Gastric juice (early morning, 3 consecutive days)", "Children who cannot produce sputum (<10 yrs)", "Positive AFB smear or culture confirms TB"],
["AFB Smear + Culture (MGIT)", "Sputum or gastric aspirate", "All TB suspect cases; culture is gold standard", "Culture takes 2β6 weeks; sensitivity 40β70% in children"],
["IGRA (QuantiFERON-TB Gold)", "Venous blood", "TST-negative but high clinical suspicion; BCG-vaccinated child", "Not affected by BCG; better specificity than TST"],
["Induced sputum", "Hypertonic saline nebulised sputum", "When spontaneous sputum unobtainable in older child", "Higher yield than gastric aspirate in children >5 yrs"],
["CT Chest with contrast", "Imaging", "When hilar LN suspected but not visible on CXR", "Detects lymphadenopathy, cavitation, complications"],
["HIV serology + CD4 count", "Blood", "All TB-suspected children; mandatory workup", "HIV co-infection alters TB presentation and management"],
].map((row, i) =>
new TableRow({ children: row.map(cell =>
plainCell(cell, i%2===0 ? LRED : "FFF5F5", i===0 ? RED : "000000", i===0)
)})
)
]
}),
...gap(1),
h2("4.3 CAP-Specific Investigations"),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: STD_BORDERS,
rows: [
new TableRow({ children: [
shadedCell("Test", GREEN, WHITE, true, 1, 2800),
shadedCell("Indication", GREEN, WHITE, true, 1, 3000),
shadedCell("Key Note", GREEN, WHITE, true, 1, 4200),
]}),
...[
["Urine Pneumococcal Ag", "Suspected Strep pneumoniae CAP; severe illness", "Rapid; +ve even after antibiotic start; high specificity"],
["Mycoplasma IgM serology", "School-age child, gradual onset, dry cough, Azithro non-response", "Peaks at 2β3 weeks; cold agglutinins +ve in ~50%"],
["Cold Agglutinins", "Suspected Mycoplasma pneumoniae", "Titre β₯1:64 supports diagnosis; cheaper than serology"],
["NPS PCR panel", "Viral CAP (RSV, Influenza, Adeno, hMPV)", "Guides antiviral therapy and infection control"],
["Pleural fluid (if effusion)", "Exudative / Empyema workup: LDH, protein, pH, culture", "pH <7.2 β drainage required; Staph/Strep most common"],
["Procalcitonin (PCT)", "Distinguish bacterial from viral CAP; guide de-escalation", "PCT >0.5 ng/mL supports bacterial aetiology"],
].map((row, i) =>
new TableRow({ children: row.map((cell, j) =>
plainCell(cell, i%2===0 ? LGREEN : "F0FFF4", j===0 ? GREEN : "000000", j===0)
)})
)
]
}),
divider(),
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SECTION 6 β Management TB
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const tbManagementSection = [
h1("5. Management: Tuberculosis"),
h2("5.1 Admission Criteria (TB)"),
bullet("Moderate-to-severe respiratory distress (SpO2 <92%, retractions, tachypnoea)"),
bullet("Miliary TB or disseminated disease on CXR"),
bullet("Infant (<2 years) with confirmed or highly suspected TB"),
bullet("HIV-positive child with TB co-infection"),
bullet("Severe malnutrition with TB"),
bullet("Central nervous system TB (TB meningitis)"),
bullet("Unable to tolerate oral medications"),
...gap(1),
h2("5.2 Anti-TB Regimen (Standard First-Line β WHO / National Programme)"),
noteBox("Dosing is weight-based. Use Fixed-Dose Combinations (FDC) where available. All regimens below are for drug-susceptible TB (DS-TB). If RIF resistance detected on GeneXpert, refer for MDR-TB management.", LRED, RED),
...gap(1),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: STD_BORDERS,
rows: [
new TableRow({ children: [
shadedCell("Phase", RED, WHITE, true, 1, 1600),
shadedCell("Duration", RED, WHITE, true, 1, 1400),
shadedCell("Drugs (Abbreviation)", RED, WHITE, true, 1, 2200),
shadedCell("Daily Doses (mg/kg/day)", RED, WHITE, true, 1, 2200),
shadedCell("Notes", RED, WHITE, true, 1, 2600),
]}),
new TableRow({ children: [
plainCell("Intensive Phase", LRED, RED, true),
plainCell("2 months", LRED),
plainCell("HRZE (Isoniazid + Rifampicin + Pyrazinamide + Ethambutol)", LRED, RED),
plainCell("H: 10 mg/kg (max 300 mg)\nR: 15 mg/kg (max 600 mg)\nZ: 35 mg/kg (max 2 g)\nE: 20 mg/kg (max 1.2 g)", LRED),
plainCell("Add Pyridoxine (Vit B6) 10β25 mg/day with Isoniazid to prevent neuropathy", LRED),
]}),
new TableRow({ children: [
plainCell("Continuation Phase", "FFF5F5", RED, true),
plainCell("4 months", "FFF5F5"),
plainCell("HR (Isoniazid + Rifampicin)", "FFF5F5", RED),
plainCell("H: 10 mg/kg/day\nR: 15 mg/kg/day", "FFF5F5"),
plainCell("Total treatment duration: 6 months for pulmonary TB. Extend to 9β12 months for TB meningitis or bone TB.", "FFF5F5"),
]}),
]
}),
...gap(1),
h2("5.3 Monitoring During TB Treatment"),
bullet("Monthly clinical review: weight, symptoms, adherence, adverse effects"),
bullet("Liver function tests (AST/ALT) at baseline, 2 weeks, and monthly (if symptomatic)"),
bullet("Repeat CXR at 2 months (end of intensive phase) and at completion (6 months)"),
bullet("Sputum / gastric aspirate for culture at 2 months if initial positive"),
bullet("Symptom check at every visit: jaundice, rash, visual changes (Ethambutol)"),
...gap(1),
h2("5.4 DOTS and Notification"),
bullet("Notify TB case to local public health authority β mandatory in most jurisdictions"),
bullet("Initiate DOTS (Directly Observed Therapy, Short-course) β community health worker observed dosing"),
bullet("Contact tracing: screen all household contacts with TST/IGRA + CXR"),
bullet("Close contacts aged <5 years or immunocompromised β consider Isoniazid Preventive Therapy (IPT)"),
divider(),
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SECTION 7 β Management CAP
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const capManagementSection = [
h1("6. Management: Community-Acquired Pneumonia (CAP)"),
h2("6.1 Severity Assessment β PEWS / CURB-Children"),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: STD_BORDERS,
rows: [
new TableRow({ children: [
shadedCell("Parameter", NAVY, WHITE, true),
shadedCell("Mild (Outpatient)", GREEN, WHITE, true),
shadedCell("Moderate (Ward Admission)", ORANGE, WHITE, true),
shadedCell("Severe (PICU)", RED, WHITE, true),
]}),
...[
["SpO2", "β₯95% on room air", "92β94% on room air", "<92% or requiring >50% O2"],
["Respiratory rate (5β12 yrs)", "<30/min", "30β40/min", ">40/min"],
["Work of breathing", "None", "Mild subcostal recession", "Severe retractions, nasal flaring, grunting"],
["Feeding / Activity", "Normal", "Reduced intake", "Unable to feed, lethargic"],
["Heart rate", "Normal for age", "Mildly elevated", "Tachycardia with poor perfusion"],
["CXR extent", "<1 lobe", "1 lobe", ">1 lobe or bilateral"],
].map((row, i) =>
new TableRow({ children: [
plainCell(row[0], i%2===0 ? LGRAY : WHITE, "000000", true),
plainCell(row[1], i%2===0 ? LGREEN : "F0FFF4", GREEN),
plainCell(row[2], i%2===0 ? "FEF0E7" : WHITE, ORANGE),
plainCell(row[3], i%2===0 ? LRED : "FFF5F5", RED),
]})
)
]
}),
...gap(1),
h2("6.2 Antibiotic Selection (Age 5β15 Years)"),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: STD_BORDERS,
rows: [
new TableRow({ children: [
shadedCell("Severity / Suspected Organism", GREEN, WHITE, true, 1, 2800),
shadedCell("First-Line Antibiotic", GREEN, WHITE, true, 1, 2800),
shadedCell("Dose & Duration", GREEN, WHITE, true, 1, 2400),
shadedCell("Alternative", GREEN, WHITE, true, 1, 2000),
]}),
...[
["Mild CAP (outpatient)\nPresumptive Strep. pneumoniae", "Amoxicillin oral", "90 mg/kg/day Γ· 3 doses Γ 5β7 days (max 3 g/day)", "Co-amoxiclav if local resistance high"],
["Moderate CAP (admitted ward)\nStrep. pneumoniae", "Ampicillin IV OR\nBenzyl Penicillin IV", "Ampicillin: 200 mg/kg/day Γ· 4 doses\nSwitch to oral amoxicillin when improving Γ 7β10 days total", "Ceftriaxone IV 50 mg/kg/day if Penicillin allergy"],
["Atypical pneumonia (Mycoplasma)\nGradual onset, dry cough, school-age", "Azithromycin oral", "10 mg/kg Day 1, then 5 mg/kg Days 2β5\n(5-day course)", "Clarithromycin 15 mg/kg/day Γ· 2 doses Γ 10 days"],
["Severe CAP / PICU\nΒ± Staph aureus suspicion", "Ceftriaxone IV +\nVancomycin IV", "Ceftriaxone 100 mg/kg/day\nVancomycin 60 mg/kg/day Γ· 4 doses", "Add Clindamycin if necrotising pneumonia"],
["Aspiration pneumonia", "Co-amoxiclav IV", "100 mg/kg/day (amoxicillin component) Γ· 3 doses", "Add Metronidazole for anaerobic cover"],
].map((row, i) =>
new TableRow({ children: row.map((cell, j) =>
plainCell(cell, i%2===0 ? LGREEN : "F0FFF4", j===0 ? GREEN : (j===2 ? "444444" : "000000"), j===0)
)})
)
]
}),
...gap(1),
h2("6.3 Supportive Management"),
bullet("Oxygen: target SpO2 β₯95%; use nasal cannula 1β2 L/min for mild hypoxaemia; HFNC/CPAP for severe"),
bullet("Antipyretics: Paracetamol 15 mg/kg/dose 4β6 hourly (max 60 mg/kg/day) for fever and discomfort"),
bullet("Hydration: IV fluids if unable to tolerate oral; correct dehydration"),
bullet("Bronchodilators: only if wheeze or bronchospasm present; not routine in CAP"),
bullet("Physiotherapy: not recommended in acute phase; consider in post-acute recovery"),
bullet("IV to oral switch criteria: afebrile >24 h, SpO2 β₯95%, tolerating oral feeds, CRP declining"),
...gap(1),
h2("6.4 Response Assessment"),
bullet("Re-examine at 48β72 hours; failure to improve = reassess diagnosis (consider TB, abscess, empyema, resistant organism)"),
bullet("Repeat CXR only if clinically deteriorating or complications suspected β not routine at 48 hrs"),
bullet("Follow-up CXR at 4β6 weeks post-discharge to confirm radiological resolution"),
divider(),
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SECTION 8 β Complications
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const complicationsSection = [
h1("7. Complications and Escalation"),
h2("7.1 Complications of Bacterial CAP"),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: STD_BORDERS,
rows: [
new TableRow({ children: [
shadedCell("Complication", GREEN, WHITE, true, 1, 2200),
shadedCell("Clinical Features", GREEN, WHITE, true, 1, 3000),
shadedCell("Investigation", GREEN, WHITE, true, 1, 2400),
shadedCell("Management", GREEN, WHITE, true, 1, 2400),
]}),
...[
["Parapneumonic effusion", "Dullness to percussion, reduced breath sounds, fever persistence", "USG chest / CT; pleural fluid aspirate", "Small: antibiotics only; Large/Empyema: chest drain"],
["Empyema", "Persistent fever >72 hrs, toxic appearance, frank pus on aspiration", "Pleural fluid: pH <7.2, glucose <2.2, positive culture", "Chest tube drainage; VATS decortication if loculated"],
["Lung abscess", "Foul sputum, swinging fever, cavity on CXR/CT", "CT chest; Blood culture; Anaerobic sputum culture", "Prolonged antibiotics 4β6 weeks; percutaneous/surgical drainage if fails"],
["Necrotising pneumonia", "Rapid deterioration, cavity formation, Staph aureus", "CT chest (multiple cavities, pneumatoceles)", "IV Vancomycin + Clindamycin; PICU; surgical consult"],
["Pneumothorax", "Sudden worsening, tracheal deviation, absent breath sounds", "CXR / USG", "Tension: immediate needle decompression; then chest drain"],
].map((row, i) =>
new TableRow({ children: row.map((cell, j) =>
plainCell(cell, i%2===0 ? LGREEN : "F0FFF4", j===0 ? GREEN : "000000", j===0)
)})
)
]
}),
...gap(1),
h2("7.2 Complications of Pulmonary TB"),
bullet("Bronchial obstruction: enlarged hilar nodes compress bronchus β collapse-consolidation β treat with corticosteroids (Prednisolone 2 mg/kg/day Γ 4β6 weeks)"),
bullet("Pleural effusion (TB): exudative; diagnose by ADA >40 U/L; treat with standard anti-TB therapy"),
bullet("Miliary TB: haematogenous spread; bilateral micronodules; admit to PICU, add corticosteroids"),
bullet("TB meningitis: urgent LP; add Dexamethasone; treat 12 months total"),
bullet("Paradoxical reaction (IRIS): worsening after starting treatment; diagnose by exclusion; treat with short-course corticosteroids"),
divider(),
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SECTION 9 β Infection Control
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const infectionControlSection = [
h1("8. Infection Prevention and Control"),
h2("8.1 TB Infection Control"),
bullet("Isolate suspected pulmonary TB in a negative-pressure room (or single room with closed door)"),
bullet("Healthcare workers to wear N95 respirators (not surgical masks) when entering room"),
bullet("Visitors limited; must wear surgical mask minimum"),
bullet("Children with pulmonary TB are generally paucibacillary β transmission risk is lower than adults, but precautions must be maintained"),
bullet("Sputum / gastric aspirate collected in dedicated negative-pressure rooms or well-ventilated areas"),
bullet("Airborne precautions maintained until 2 weeks of effective therapy confirmed and clinical improvement"),
...gap(1),
h2("8.2 CAP Infection Control"),
bullet("Droplet precautions for bacterial CAP (surgical mask for patients when outside room; mask + eye protection for HCW within 1 m)"),
bullet("Contact precautions for Staph aureus CAP (gown + gloves)"),
bullet("Influenza / RSV CAP: cohort patients; droplet + contact precautions"),
bullet("Hand hygiene: soap and water or alcohol-based handrub before and after all patient contact"),
divider(),
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SECTION 10 β Discharge & Follow-Up
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const dischargeSection = [
h1("9. Discharge Criteria and Follow-Up"),
h2("9.1 Discharge Criteria"),
bullet("SpO2 β₯95% on room air for β₯24 hours"),
bullet("Afebrile for β₯24 hours"),
bullet("Tolerating oral fluids and medications"),
bullet("No signs of respiratory distress (normal respiratory rate for age)"),
bullet("Caregiver counselled and able to administer oral medications"),
bullet("Follow-up appointment confirmed before discharge"),
...gap(1),
h2("9.2 Follow-Up Schedule"),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: STD_BORDERS,
rows: [
new TableRow({ children: [
shadedCell("Diagnosis", NAVY, WHITE, true, 1, 2000),
shadedCell("Follow-up Visit", NAVY, WHITE, true, 1, 2200),
shadedCell("What to Assess", NAVY, WHITE, true, 1, 3000),
shadedCell("Repeat CXR?", NAVY, WHITE, true, 1, 2000),
]}),
...[
["CAP (Mild)", "1β2 weeks post-discharge", "Clinical resolution, completed antibiotics", "Only if persistent symptoms"],
["CAP (Moderate/Severe)", "1 week, then 4β6 weeks", "Radiological clearance, complications", "At 4β6 weeks"],
["Pulmonary TB", "Monthly for 6 months", "Drug adherence, weight gain, adverse effects, sputum clearance", "At 2 months and 6 months (completion)"],
].map((row, i) =>
new TableRow({ children: row.map(cell => plainCell(cell, i%2===0 ? LGRAY : WHITE)) })
)
]
}),
divider(),
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SECTION 11 β Quick Reference Summary
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const summarySection = [
h1("10. Quick Reference Summary"),
noteBox(
"STEP 1 β Assess: History (onset, fever pattern, contacts) + CXR + O2 sat\n" +
"STEP 2 β Classify: Acute β Bacterial CAP | Gradual β TB / Atypical\n" +
"STEP 3 β Investigate: Mantoux + GeneXpert (TB pathway) | Blood Cx + PCT (CAP pathway)\n" +
"STEP 4 β Treat: Amoxicillin/Ampicillin (CAP) | 2HRZEβ4HR (TB) | Azithromycin (Mycoplasma)\n" +
"STEP 5 β Review at 48β72 hrs: No response β reassess with CT Chest + Bronchoscopy\n" +
"STEP 6 β Discharge: SpO2 β₯95%, afebrile, oral tolerated | Follow-up booked",
LBLUE, NAVY
),
...gap(1),
noteBox(
"RED FLAGS β Immediate Senior Review:\n" +
"β’ SpO2 <92% β’ Severe respiratory distress β’ Bilateral / Miliary CXR\n" +
"β’ Mediastinal shift β’ No improvement in 72 hrs β’ HIV+ / Immunocompromised\n" +
"β’ Suspected TB meningitis (altered sensorium, neck stiffness, bulging fontanelle)",
LRED, RED
),
divider(),
h1("11. References"),
bullet("WHO. Guidance for national tuberculosis programmes on the management of tuberculosis in children. 3rd Ed. 2022."),
bullet("IAP Guidelines on Childhood Tuberculosis β Indian Academy of Pediatrics, 2023."),
bullet("IDSA / PIDS Guidelines for Management of Community-Acquired Pneumonia in Infants and Children. CID 2011."),
bullet("The Union. Diagnostic CXR Atlas for Tuberculosis in Children. 2nd Ed. 2022."),
bullet("Swanson's Family Medicine Review β Community-Acquired Pneumonia in Children. 9th Ed, p.584."),
bullet("PMC Article: Chest Imaging for Pulmonary TB β An Update. Pathogens 2022; 11(2):254. PMID 35215198."),
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// ASSEMBLE DOCUMENT
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const doc = new Document({
numbering: {
config: []
},
styles: {
default: {
document: {
run: { font: "Calibri", size: 20 }
}
}
},
sections: [
{
properties: {
page: {
margin: { top: 1000, bottom: 900, left: 1080, right: 1080 },
pageNumbers: { start: 1, formatType: NumberFormat.DECIMAL }
}
},
headers: {
default: new Header({
children: [new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: {
top: { style: BorderStyle.NONE, size: 0 }, bottom: { style: BorderStyle.SINGLE, size: 6, color: NAVY },
left: { style: BorderStyle.NONE, size: 0 }, right: { style: BorderStyle.NONE, size: 0 },
insideHorizontal: { style: BorderStyle.NONE, size: 0 }, insideVertical: { style: BorderStyle.NONE, size: 0 }
},
rows: [new TableRow({ children: [
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Case Management Protocol: Pediatric RUL Consolidation β TB vs CAP", bold: true, size: 16, color: NAVY })] })] }),
new TableCell({ width: { size: 2000, type: WidthType.DXA }, children: [new Paragraph({ alignment: AlignmentType.RIGHT, children: [new TextRun({ text: "Page ", size: 16, color: "777777" }), new TextRun({ children: [PageNumber.CURRENT], size: 16, color: "777777" }), new TextRun({ text: " of ", size: 16, color: "777777" }), new TextRun({ children: [PageNumber.TOTAL_PAGES], size: 16, color: "777777" })] })] })
]})]
})]
})
},
footers: {
default: new Footer({
children: [new Paragraph({
alignment: AlignmentType.CENTER,
border: { top: { style: BorderStyle.SINGLE, size: 4, color: MGRAY } },
children: [new TextRun({ text: "For clinical use only. Correlate with local epidemiology and institutional guidelines. Version 1.0 β July 2026 | Orris Medical AI", size: 16, color: "777777", italics: true })]
})]
})
},
children: [
...coverSection,
...purposeSection,
...clinicalSection,
...radiologySection,
...investigationsSection,
...tbManagementSection,
...capManagementSection,
...complicationsSection,
...infectionControlSection,
...dischargeSection,
...summarySection,
]
}
]
});
Packer.toBuffer(doc).then(buffer => {
const outPath = "/home/daytona/workspace/tb-cap-protocol/TB_vs_CAP_Case_Management_Protocol.docx";
fs.writeFileSync(outPath, buffer);
console.log("DOCX saved β", outPath);
}).catch(err => {
console.error("Error:", err.message);
process.exit(1);
});
cd /home/daytona/workspace/tb-cap-protocol && node create_protocol.js 2>&1
python3 /home/daytona/skills/docx/scripts/office/validate.py /home/daytona/worksβ¦
python3 -c " from zipfile import ZipFile z = ZipFile('/home/daytona/workspace/tbβ¦
TB vs CAP Case Management Protocol
Word Document Β· DOCX
| Section | Content |
|---|---|
| Cover Page | Title, target population, setting, version, classification table |
| 1. Purpose & Scope | Protocol goals, applicable settings, populations |
| 2. Clinical Presentation | 3-way comparison table (TB vs Bacterial CAP vs Mycoplasma) across 8 clinical features + risk factor checklist |
| 3. Radiology | CXR interpretation table, CT chest indications, clinical tips |
| 4. Investigations | First-line workup for all children; TB-specific tests (GeneXpert, Gastric lavage, IGRA, induced sputum); CAP-specific tests (Mycoplasma IgM, Urine Ag, PCT) |
| 5. TB Management | Admission criteria, 2HRZE/4HR regimen with weight-based dosing, monitoring schedule, DOTS/notification |
| 6. CAP Management | Severity scoring (Mild/Moderate/Severe), antibiotic selection table by organism, supportive care, IV-to-oral switch criteria |
| 7. Complications | CAP complications (empyema, abscess, necrotising pneumonia, pneumothorax) + TB complications (IRIS, miliary, meningitis) with management |
| 8. Infection Control | Airborne precautions for TB (N95, negative-pressure room), droplet/contact for CAP |
| 9. Discharge & Follow-Up | Discharge criteria, follow-up schedule table for CAP and TB |
| 10. Quick Reference | 6-step summary box + Red Flags box for immediate reference |
| 11. References | WHO, IAP, IDSA guidelines + key cited sources |