~/pneumonia-ppt/build_ppt.py
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
from io import BytesIO
# βββ Colour Palette ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
DARK_BLUE = RGBColor(0x0D, 0x2C, 0x54) # deep navy
MED_BLUE = RGBColor(0x1A, 0x6F, 0xA8) # mid blue
ACCENT_TEAL = RGBColor(0x00, 0xB3, 0xC6) # teal highlight
LIGHT_BG = RGBColor(0xF0, 0xF6, 0xFF) # very light blue-white
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
LIGHT_GREY = RGBColor(0xE8, 0xEE, 0xF5)
TEXT_DARK = RGBColor(0x1A, 0x1A, 0x2E)
GREEN = RGBColor(0x00, 0x96, 0x68)
RED = RGBColor(0xC0, 0x39, 0x2B)
ORANGE = RGBColor(0xE6, 0x7E, 0x22)
YELLOW_ACC = RGBColor(0xF3, 0x9C, 0x12)
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
BLANK = prs.slide_layouts[6] # blank layout
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Helper Functions
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def add_rect(slide, x, y, w, h, fill_color, line_color=None, line_width=None):
shp = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(x), Inches(y), Inches(w), Inches(h))
shp.fill.solid()
shp.fill.fore_color.rgb = fill_color
shp.line.fill.background() if line_color is None else None
if line_color:
shp.line.color.rgb = line_color
shp.line.width = Pt(line_width or 1)
else:
shp.line.fill.background()
shp.shadow.inherit = False
return shp
def add_rrect(slide, x, y, w, h, fill_color, line_color=None):
shp = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, Inches(x), Inches(y), Inches(w), Inches(h))
shp.fill.solid()
shp.fill.fore_color.rgb = fill_color
if line_color:
shp.line.color.rgb = line_color
shp.line.width = Pt(0.75)
else:
shp.line.fill.background()
shp.shadow.inherit = False
return shp
def add_text(slide, text, x, y, w, h, size=18, bold=False, italic=False,
color=TEXT_DARK, align=PP_ALIGN.LEFT, valign=MSO_ANCHOR.TOP, wrap=True):
tb = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
tf = tb.text_frame
tf.word_wrap = wrap
tf.auto_size = None
tf.vertical_anchor = valign
tf.margin_left = Pt(4)
tf.margin_right = Pt(4)
tf.margin_top = Pt(2)
tf.margin_bottom= Pt(2)
p = tf.paragraphs[0]
p.alignment = align
r = p.add_run()
r.text = text
r.font.name = "Calibri"
r.font.size = Pt(size)
r.font.bold = bold
r.font.italic= italic
r.font.color.rgb = color
return tf
def add_multiline(slide, lines, x, y, w, h, size=14, bold=False,
color=TEXT_DARK, align=PP_ALIGN.LEFT, line_spacing=None):
"""lines: list of (text, bold, color) tuples or plain strings"""
tb = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
tf = tb.text_frame
tf.word_wrap = True
tf.margin_left = Pt(4)
tf.margin_right = Pt(4)
tf.margin_top = Pt(2)
tf.margin_bottom= Pt(2)
first = True
for item in lines:
if isinstance(item, str):
txt, b, c = item, bold, color
else:
txt, b, c = item
if first:
p = tf.paragraphs[0]
first = False
else:
p = tf.add_paragraph()
p.alignment = align
if line_spacing:
from pptx.util import Pt as _Pt
p.line_spacing = _Pt(line_spacing)
r = p.add_run()
r.text = txt
r.font.name = "Calibri"
r.font.size = Pt(size)
r.font.bold = b
r.font.color.rgb = c
return tf
def slide_header(slide, title, subtitle=None):
"""Navy top bar with white title and optional subtitle."""
add_rect(slide, 0, 0, 13.333, 1.2, DARK_BLUE)
add_rect(slide, 0, 1.2, 13.333, 0.08, ACCENT_TEAL)
add_text(slide, title, 0.3, 0.1, 12.5, 0.8, size=28, bold=True,
color=WHITE, valign=MSO_ANCHOR.MIDDLE)
if subtitle:
add_text(slide, subtitle, 0.3, 0.85, 12.5, 0.38, size=14, italic=True,
color=ACCENT_TEAL, valign=MSO_ANCHOR.MIDDLE)
def slide_bg(slide):
"""Light background fill."""
add_rect(slide, 0, 0, 13.333, 7.5, LIGHT_BG)
def section_box(slide, title, x, y, w, h, title_color=DARK_BLUE, bg=WHITE, border=MED_BLUE):
add_rrect(slide, x, y, w, 0.42, title_color)
add_text(slide, title, x+0.1, y+0.04, w-0.2, 0.36, size=13, bold=True,
color=WHITE, valign=MSO_ANCHOR.MIDDLE)
add_rrect(slide, x, y+0.4, w, h-0.4, bg, border)
def footer(slide, text="Pneumonia Management | MD Medicine Reference"):
add_rect(slide, 0, 7.2, 13.333, 0.3, DARK_BLUE)
add_text(slide, text, 0.3, 7.22, 12.5, 0.25, size=9, color=LIGHT_GREY,
valign=MSO_ANCHOR.MIDDLE)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 1 β TITLE SLIDE
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
add_rect(slide, 0, 0, 13.333, 7.5, DARK_BLUE)
# decorative accent bar
add_rect(slide, 0, 3.8, 13.333, 0.12, ACCENT_TEAL)
# lung icon placeholder (text)
add_text(slide, "π«", 5.9, 0.6, 1.5, 1.5, size=60, color=WHITE, align=PP_ALIGN.CENTER)
add_text(slide, "APPROACH TO MANAGEMENT OF", 1.5, 2.0, 10.3, 0.7,
size=20, color=ACCENT_TEAL, align=PP_ALIGN.CENTER, bold=False)
add_text(slide, "PNEUMONIA", 1.5, 2.6, 10.3, 1.1,
size=54, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
add_text(slide, "A Comprehensive MD Medicine Reference", 1.5, 3.7, 10.3, 0.55,
size=18, italic=True, color=LIGHT_GREY, align=PP_ALIGN.CENTER)
add_rect(slide, 3.5, 4.2, 6.3, 0.06, ACCENT_TEAL)
add_multiline(slide, [
("Sources: Harrison's 22E | Fishman's Pulmonary Diseases | Goldman-Cecil Medicine", False, LIGHT_GREY),
("2025 SPILF/SPLF Practice Guidelines | PubMed Meta-Analysis (PMID: 40202602)", False, RGBColor(0x88,0xBB,0xDD)),
], 1.5, 4.4, 10.3, 0.9, size=12, align=PP_ALIGN.CENTER)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 2 β CLASSIFICATION & DEFINITION
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Classification of Pneumonia",
"Acute infection of pulmonary parenchyma with alveolar consolidation")
footer(slide)
types = [
("CAP", "Community-Acquired", "Outside hospital or within 48h of admission\nin non-immunocompromised host", MED_BLUE),
("HAP", "Hospital-Acquired", "Develops β₯48 hrs after\nhospital admission", DARK_BLUE),
("VAP", "Ventilator-Associated", "β₯48-72 hrs after\nendotracheal intubation", RGBColor(0x7D,0x3C,0x98)),
("HCAP", "Healthcare-Associated", "Nursing home, dialysis, recent IV therapy\nor hospitalization β₯2 days in last 90 days", ORANGE),
("Aspiration", "Aspiration Pneumonia", "Inhalation of oropharyngeal/gastric contents\nTypically RLL or posterior upper lobes", RED),
]
box_w = 2.3
start_x = 0.35
for i, (abbr, full, desc, col) in enumerate(types):
bx = start_x + i * (box_w + 0.18)
add_rrect(slide, bx, 1.45, box_w, 5.5, WHITE, col)
# top colour band
add_rrect(slide, bx, 1.45, box_w, 0.85, col)
add_text(slide, abbr, bx+0.1, 1.5, box_w-0.2, 0.45, size=22, bold=True,
color=WHITE, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE)
add_text(slide, full, bx+0.1, 1.92, box_w-0.2, 0.32, size=11, bold=True,
color=col, align=PP_ALIGN.CENTER)
add_text(slide, desc, bx+0.15, 2.3, box_w-0.3, 4.4, size=12,
color=TEXT_DARK, wrap=True)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 3 β CLINICAL PRESENTATION
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Clinical Presentation", "Symptoms, Signs & Key Physical Findings")
footer(slide)
# Symptoms column
section_box(slide, "SYMPTOMS", 0.3, 1.4, 5.8, 5.6, MED_BLUE, LIGHT_BG, MED_BLUE)
add_multiline(slide, [
("β’ Fever (may be absent in elderly/immunocompromised)", False, TEXT_DARK),
("", False, TEXT_DARK),
("β’ Productive cough:", False, TEXT_DARK),
(" - Purulent = bacterial", False, TEXT_DARK),
(" - Rusty = S. pneumoniae", False, TEXT_DARK),
(" - 'Currant jelly' = Klebsiella", False, TEXT_DARK),
(" - Dry/scanty = Atypicals (Mycoplasma, Chlamydia)", False, TEXT_DARK),
("", False, TEXT_DARK),
("β’ Dyspnea & tachypnea", False, TEXT_DARK),
("β’ Pleuritic chest pain", False, TEXT_DARK),
("β’ Rigors (especially pneumococcal)", False, TEXT_DARK),
("β’ Malaise, myalgia (atypical pneumonia)", False, TEXT_DARK),
("β’ Confusion (elderly, severe disease)", False, TEXT_DARK),
], 0.45, 1.95, 5.5, 4.9, size=13)
# Signs column
section_box(slide, "PHYSICAL EXAMINATION", 6.3, 1.4, 6.7, 5.6, DARK_BLUE, LIGHT_BG, DARK_BLUE)
exam_data = [
("Inspection", "Tachypnea, reduced chest expansion"),
("Palpation", "Increased tactile fremitus over consolidation"),
("Percussion", "Dullness over affected lobe"),
("Auscultation","Bronchial breathing, crepitations,\negophony, whispered pectoriloquy"),
]
row_y = 1.95
for label, val in exam_data:
add_rrect(slide, 6.45, row_y, 2.2, 0.55, MED_BLUE)
add_text(slide, label, 6.5, row_y+0.05, 2.1, 0.45, size=12, bold=True, color=WHITE,
valign=MSO_ANCHOR.MIDDLE)
add_text(slide, val, 8.75, row_y+0.04, 4.1, 0.55, size=12, color=TEXT_DARK, wrap=True)
row_y += 0.72
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 4 β INVESTIGATIONS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Investigations / Workup", "Minimum required + Additional for moderate-severe disease")
footer(slide)
# Left panel - Minimum
section_box(slide, "MINIMUM (ALL SUSPECTED PNEUMONIA)", 0.3, 1.4, 6.0, 5.65, GREEN, LIGHT_BG, GREEN)
inv_min = [
("Chest X-Ray PA", "Confirm, lobar vs. interstitial, complications"),
("CBC + Differential", "Leukocytosis (bacterial) or leukopenia (severe/viral)"),
("Blood cultures Γ 2", "Before antibiotics in ALL hospitalized patients"),
("Sputum Gram stain + C&S", "Before first dose; valid: β₯25 WBC, <10 epi cells/LPF"),
("Serum electrolytes/BUN/Cr", "CURB-65 scoring; renal dosing"),
("ABG or SpOβ", "Oxygenation status & severity"),
]
ry = 1.92
for name, desc in inv_min:
add_rrect(slide, 0.45, ry, 2.2, 0.5, GREEN)
add_text(slide, name, 0.5, ry+0.04, 2.1, 0.42, size=11, bold=True, color=WHITE,
valign=MSO_ANCHOR.MIDDLE, wrap=True)
add_text(slide, desc, 2.75, ry+0.05, 3.4, 0.44, size=11, color=TEXT_DARK, wrap=True)
ry += 0.62
# Right panel - Additional
section_box(slide, "ADDITIONAL (MODERATE-SEVERE / ICU)", 6.5, 1.4, 6.5, 5.65, RED, LIGHT_BG, RED)
inv_adv = [
("Urine Legionella Ag", "Severe CAP, ICU, travel history"),
("Urine Pneumococcal Ag","Severe CAP, negative cultures"),
("Respiratory viral PCR","Influenza, COVID-19, RSV"),
("Procalcitonin", "Guide start/stop antibiotics"),
("HRCT Chest", "Atypical patterns, non-resolving, immunocompromised"),
("Bronchoscopy + BAL", "Non-resolving, unusual pathogen"),
("Thoracentesis", "Effusion >1cm on lateral decubitus"),
("MRSA nasal PCR", "Risk stratification for Vancomycin/Linezolid"),
]
ry = 1.92
for name, desc in inv_adv:
add_rrect(slide, 6.6, ry, 2.2, 0.5, RED)
add_text(slide, name, 6.65, ry+0.04, 2.1, 0.42, size=10, bold=True, color=WHITE,
valign=MSO_ANCHOR.MIDDLE, wrap=True)
add_text(slide, desc, 8.9, ry+0.05, 3.9, 0.44, size=11, color=TEXT_DARK, wrap=True)
ry += 0.58
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 5 β SEVERITY SCORING (CURB-65 + PSI + IDSA/ATS)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Severity Scoring & Site-of-Care Decision",
"CURB-65 | PSI | IDSA/ATS Severe CAP Criteria")
footer(slide)
# CURB-65 box
section_box(slide, "CURB-65 SCORE", 0.3, 1.4, 5.1, 5.7, MED_BLUE, LIGHT_BG, MED_BLUE)
curb = [
("C", "Confusion (new onset)", "1 pt"),
("U", "Urea (BUN) > 7 mmol/L (>19 mg/dL)", "1 pt"),
("R", "Respiratory rate β₯ 30/min", "1 pt"),
("B", "BP systolic β€90 or diastolic β€60 mmHg", "1 pt"),
("65", "Age β₯ 65 years", "1 pt"),
]
ry = 1.93
for letter, meaning, pts in curb:
add_rrect(slide, 0.42, ry, 0.55, 0.48, DARK_BLUE)
add_text(slide, letter, 0.43, ry+0.04, 0.52, 0.4, size=16, bold=True,
color=ACCENT_TEAL, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE)
add_text(slide, meaning, 1.02, ry+0.06, 3.6, 0.4, size=12, color=TEXT_DARK, wrap=True)
add_text(slide, pts, 4.55, ry+0.06, 0.7, 0.4, size=12, bold=True, color=MED_BLUE,
align=PP_ALIGN.RIGHT)
ry += 0.56
# Score β Action table
add_text(slide, "Score β Management", 0.42, 4.78, 4.9, 0.32, size=12, bold=True, color=DARK_BLUE)
score_rows = [
("0", "1.5%", "OUTPATIENT", GREEN),
("1-2", "~8%", "HOSPITALIZE", ORANGE),
("3-4", "22%", "HOSPITAL Β± ICU",RED),
("5", "~57%", "ICU", RED),
]
headers = ["Score","Mortality","Action"]
hx = [0.42, 1.2, 2.05]
hw = [0.75, 0.82, 2.95]
ry = 5.15
# header row
for hdr, hxi, hwi in zip(headers, hx, hw):
add_rrect(slide, hxi, ry, hwi, 0.32, DARK_BLUE)
add_text(slide, hdr, hxi+0.04, ry+0.04, hwi-0.08, 0.24, size=11, bold=True,
color=WHITE, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE)
ry += 0.32
for sc, mort, action, col in score_rows:
vals = [sc, mort, action]
for val, hxi, hwi in zip(vals, hx, hw):
bg = col if val == action else LIGHT_GREY
tc = WHITE if val == action else TEXT_DARK
add_rrect(slide, hxi, ry, hwi, 0.3, bg, border=LIGHT_GREY)
add_text(slide, val, hxi+0.04, ry+0.03, hwi-0.08, 0.25, size=11, bold=(val==action),
color=tc, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE)
ry += 0.3
# IDSA/ATS severe CAP
section_box(slide, "IDSA/ATS SEVERE CAP CRITERIA (ICU ADMIT)", 5.55, 1.4, 7.5, 5.7, RED, LIGHT_BG, RED)
add_text(slide, "1 MAJOR OR β₯3 MINOR criteria", 5.7, 1.92, 7.2, 0.35,
size=13, bold=True, color=RED)
add_rrect(slide, 5.6, 2.32, 3.5, 0.32, RED)
add_text(slide, "MAJOR CRITERIA", 5.65, 2.35, 3.4, 0.26, size=12, bold=True,
color=WHITE, valign=MSO_ANCHOR.MIDDLE)
major = [
"Septic shock requiring vasopressors",
"Respiratory failure requiring mechanical ventilation",
]
ry = 2.66
for m in major:
add_text(slide, "β " + m, 5.7, ry, 3.3, 0.38, size=11, color=RED, bold=True, wrap=True)
ry += 0.4
add_rrect(slide, 9.2, 2.32, 3.7, 0.32, ORANGE)
add_text(slide, "MINOR CRITERIA", 9.25, 2.35, 3.6, 0.26, size=12, bold=True,
color=WHITE, valign=MSO_ANCHOR.MIDDLE)
minor = [
"Tachypnea β₯30 breaths/min",
"PaOβ/FiOβ β€250",
"Multilobar infiltrates",
"Confusion/disorientation",
"Uremia (BUN β₯20 mg/dL)",
"Leukopenia (WBC <4000/Β΅L)",
"Thrombocytopenia (<100,000/Β΅L)",
"Hypothermia (<36Β°C)",
"Hypotension requiring IV fluids",
]
ry = 2.66
for mn in minor:
add_text(slide, "β’ " + mn, 9.25, ry, 3.55, 0.35, size=11, color=TEXT_DARK, wrap=True)
ry += 0.36
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 6 β PATHOGENS BY CATEGORY
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Common Pathogens by Patient Category",
"Empiric antibiotic selection is guided by patient category and risk factors")
footer(slide)
pathogen_data = [
("Outpatient\n(No comorbidities)",
"S. pneumoniae, M. pneumoniae,\nC. pneumoniae, H. influenzae,\nRespiratory viruses",
MED_BLUE),
("Outpatient\n(With comorbidities)",
"Above + DRSP,\nEnteric gram-negatives,\nAnaerobes (aspiration)",
DARK_BLUE),
("Non-ICU\nInpatient",
"S. pneumoniae (incl. DRSP),\nH. influenzae, Atypicals,\nEnteric GNBs",
RGBColor(0x7D,0x3C,0x98)),
("Severe CAP\n(No Pseudomonas risk)",
"S. pneumoniae, Legionella,\nH. influenzae, GNBs,\nS. aureus, M. pneumoniae",
RED),
("HAP/VAP\n(Late/MDR risk)",
"P. aeruginosa, MRSA,\nESBL Klebsiella,\nAcinetobacter spp",
RGBColor(0x78,0x28,0x08)),
]
bw = 2.35
sx = 0.28
for i, (cat, patho, col) in enumerate(pathogen_data):
bx = sx + i*(bw+0.12)
add_rrect(slide, bx, 1.42, bw, 5.55, WHITE, col)
add_rrect(slide, bx, 1.42, bw, 0.82, col)
add_text(slide, cat, bx+0.08, 1.48, bw-0.16, 0.7, size=13, bold=True,
color=WHITE, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE, wrap=True)
add_text(slide, patho, bx+0.1, 2.32, bw-0.2, 4.45, size=12.5,
color=TEXT_DARK, wrap=True)
add_text(slide,
"MDR Risk Factors: hospitalization β₯2d in past 90d | broad-spectrum ABx in past 3 months | immunosuppression | prior MRSA/Pseudomonas isolation",
0.3, 7.05, 12.7, 0.25, size=9.5, italic=True, color=MED_BLUE)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 7 β ANTIBIOTIC THERAPY: OUTPATIENT & NON-ICU
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Empiric Antibiotic Therapy β CAP Outpatient & Non-ICU",
"Based on IDSA/ATS Guidelines | Harrison's 22E | Fishman's Pulmonary Diseases")
footer(slide)
def abx_box(slide, title, x, y, w, h, col, items):
add_rrect(slide, x, y, w, 0.38, col)
add_text(slide, title, x+0.08, y+0.04, w-0.16, 0.3, size=12, bold=True,
color=WHITE, valign=MSO_ANCHOR.MIDDLE)
add_rrect(slide, x, y+0.36, w, h-0.36, LIGHT_BG, col)
ry = y + 0.44
for drug, dose, note in items:
add_rrect(slide, x+0.08, ry, 2.8 if w>5 else 2.2, 0.32, MED_BLUE if note else col)
add_text(slide, drug, x+0.1, ry+0.02, (2.8 if w>5 else 2.2)-0.05, 0.28, size=10.5,
bold=True, color=WHITE, valign=MSO_ANCHOR.MIDDLE)
add_text(slide, dose, x+(2.95 if w>5 else 2.35), ry+0.02, w-(2.9 if w>5 else 2.3), 0.32,
size=10.5, color=TEXT_DARK, wrap=True)
if note:
ry += 0.33
add_text(slide, " β³ " + note, x+0.1, ry, w-0.2, 0.25, size=9.5, italic=True,
color=RGBColor(0x55,0x55,0x55))
ry += 0.38
# Outpatient - no comorbidities
abx_box(slide, "OUTPATIENT β No Comorbidities (CURB-65 = 0)", 0.3, 1.42, 6.1, 2.55, GREEN, [
("Amoxicillin", "1g PO TDS Γ 5 days", "1st line"),
("Doxycycline", "100mg PO BD Γ 5 days", "Atypical coverage"),
("Azithromycin", "500mg Day 1 β 250mg OD Γ 5 days", "If macrolide resistance <25%"),
])
# Outpatient - with comorbidities
abx_box(slide, "OUTPATIENT β With Comorbidities (COPD, DM, Heart/Renal/Liver disease)", 0.3, 3.97, 6.1, 2.9, ORANGE, [
("Amox-Clav + Azithromycin", "875/125mg BD + 500mg OD", "Combination regimen"),
("Amox-Clav + Doxycycline", "875/125mg BD + 100mg BD", "Alternative combination"),
("Levofloxacin", "750mg OD Γ 5 days", "Respiratory FQ monotherapy"),
("Moxifloxacin", "400mg OD Γ 5 days", "Alternative FQ"),
])
# Non-ICU inpatient
abx_box(slide, "NON-ICU INPATIENT (Moderate CAP β CURB-65 1-2)", 6.55, 1.42, 6.5, 2.55, MED_BLUE, [
("Ceftriaxone + Azithromycin", "1-2g IV OD + 500mg IV/PO OD", "Standard combination"),
("Amp-Sulbactam + Azithro", "1.5-3g IV Q6H + 500mg OD", "Ξ²-lactam/BLI combo"),
("Levofloxacin", "750mg IV/PO OD", "FQ monotherapy (if Ξ²-lactam CI)"),
])
abx_box(slide, "PENICILLIN ALLERGY (Non-ICU)", 6.55, 3.97, 6.5, 1.5, RGBColor(0x7D,0x3C,0x98), [
("Levofloxacin", "750mg IV/PO OD Γ 5-7 days", ""),
("Moxifloxacin", "400mg IV/PO OD Γ 5-7 days", ""),
])
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 8 β ANTIBIOTIC THERAPY: SEVERE CAP / ICU
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Empiric Antibiotic Therapy β Severe CAP (ICU) & HAP/VAP",
"Individualized by severity, MDR risk, MRSA/Pseudomonas status | Harrison's 22E, Goldman-Cecil")
footer(slide)
# Severe CAP left
section_box(slide, "SEVERE CAP β ICU (No MRSA/Pseudomonas risk)", 0.3, 1.42, 6.1, 2.5, RED, LIGHT_BG, RED)
add_multiline(slide, [
("Ceftriaxone 1-2g IV Q12-24H + Azithromycin 500mg IV OD", True, TEXT_DARK),
(" OR", False, MED_BLUE),
("Ceftriaxone + Levofloxacin 750mg IV OD", True, TEXT_DARK),
(" OR", False, MED_BLUE),
("Ampicillin-sulbactam 3g IV Q6H + Azithromycin", True, TEXT_DARK),
], 0.45, 1.95, 5.8, 1.75, size=12.5)
section_box(slide, "ADD FOR MRSA RISK (prior isolation or nasal PCR+)", 0.3, 4.0, 6.1, 3.2, RGBColor(0x88,0x22,0x88), LIGHT_BG, RGBColor(0x88,0x22,0x88))
add_multiline(slide, [
("Vancomycin 15-20 mg/kg IV Q8-12H", False, TEXT_DARK),
(" Target AUC/MIC 400-600 (or trough 10-15 Β΅g/mL)", False, RGBColor(0x55,0x55,0x55)),
("", False, TEXT_DARK),
("OR Linezolid 600mg IV Q12H β
PREFERRED", True, RGBColor(0x88,0x22,0x88)),
(" Better lung penetration + exotoxin inhibition", False, RGBColor(0x55,0x55,0x55)),
], 0.45, 4.5, 5.8, 2.5, size=12.5)
# Pseudomonas
section_box(slide, "ADD FOR PSEUDOMONAS RISK (bronchiectasis, severe COPD, structural lung disease)", 6.55, 1.42, 6.5, 3.1, ORANGE, LIGHT_BG, ORANGE)
add_multiline(slide, [
("Antipseudomonal Ξ²-lactam (choose 1):", True, DARK_BLUE),
("β’ Pip-Tazo 4.5g IV Q6H", False, TEXT_DARK),
("β’ Cefepime 1-2g IV Q8H", False, TEXT_DARK),
("β’ Meropenem 1g IV Q8H", False, TEXT_DARK),
("β’ Ceftazidime 2g IV Q8H", False, TEXT_DARK),
("", False, TEXT_DARK),
("PLUS (if >20% local resistance):", True, ORANGE),
("β’ Ciprofloxacin 400mg IV Q8H", False, TEXT_DARK),
("β’ OR Aminoglycoside (Amikacin/Tobramycin)", False, TEXT_DARK),
], 6.7, 1.95, 6.2, 2.45, size=12.5)
# HAP/VAP
section_box(slide, "HAP/VAP β Group A (Early onset, no MDR risk)", 6.55, 4.62, 6.5, 1.3, GREEN, LIGHT_BG, GREEN)
add_multiline(slide, [
("Ceftriaxone 1-2g IV Q24H OR Levofloxacin 750mg IV OD"),
("Amp-Sulbactam 1.5-3g IV Q6H OR Ertapenem 1g IV OD"),
], 6.7, 5.1, 6.2, 0.8, size=11.5, color=TEXT_DARK)
section_box(slide, "HAP/VAP β Group B (Late onset / MDR risk)", 6.55, 6.0, 6.5, 1.25, RED, LIGHT_BG, RED)
add_text(slide,
"Antipseudomonal cephalosporin OR carbapenem OR Pip-Tazo + Vancomycin/Linezolid (MRSA)",
6.7, 6.45, 6.2, 0.7, size=11, color=TEXT_DARK, wrap=True)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 9 β SUPPORTIVE MANAGEMENT
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Supportive Management", "Oxygenation | Fluids | Analgesia | DVT prophylaxis | Steroids")
footer(slide)
support_cols = [
("OXYGENATION\n& VENTILATION", MED_BLUE, [
"SpOβ <92%: Supplemental Oβ",
"Start: Nasal prongs 2-4 L/min",
"Persistent: HFNO 40-60 L/min",
"Moderate failure: NIV (CPAP/BiPAP)",
"Severe (PaOβ/FiOβ<200, exhaustion):",
"β Intubate + MV",
" TV 6 mL/kg IBW (lung-protective)",
]),
("FLUID\nMANAGEMENT", GREEN, [
"IV fluids if: sepsis, hemodynamic",
"compromise, unable to take PO",
"",
"Sepsis 3 protocol:",
"30mL/kg crystalloid bolus β reassess",
"",
"Avoid fluid overload",
"(worsens hypoxemia)",
]),
("ANALGESIA &\nANTIPYRETICS", ORANGE, [
"Paracetamol 1g PO/IV Q6H",
"β Fever + pleuritic pain",
"",
"NSAIDs: use with caution",
"(renal impairment, elderly)",
"",
"Adequate pain control β",
"improves respiratory effort",
]),
("DVT\nPROPHYLAXIS", RGBColor(0x7D,0x3C,0x98), [
"LMWH (Enoxaparin 40mg SC OD)",
"β All hospitalized patients",
"β Without contraindications",
"",
"UFH if eGFR <30:",
"5000U SC TDS",
]),
("ADJUNCTIVE\nSTEROIDS", RED, [
"Indications:",
"β’ Severe inflammation",
"β’ Co-existing ARDS",
"β’ Septic shock",
"",
"Hydrocortisone 200mg/d IV",
"Dexamethasone 0.15mg/kg/d Γ 4d",
]),
]
bw = 2.32
sx = 0.28
for i, (title, col, bullets) in enumerate(support_cols):
bx = sx + i*(bw+0.1)
add_rrect(slide, bx, 1.42, bw, 5.68, WHITE, col)
add_rrect(slide, bx, 1.42, bw, 0.72, col)
add_text(slide, title, bx+0.08, 1.46, bw-0.16, 0.64, size=12.5, bold=True,
color=WHITE, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE, wrap=True)
lines = [(b, False, TEXT_DARK) if b else ("", False, TEXT_DARK) for b in bullets]
add_multiline(slide, lines, bx+0.1, 2.2, bw-0.2, 4.7, size=11.5)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 10 β ANTIBIOTIC DURATION & IVβPO SWITCH
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Antibiotic Duration, De-escalation & IVβPO Switch",
"Evidence-based duration | Stewardship principles")
footer(slide)
section_box(slide, "ANTIBIOTIC DURATION", 0.3, 1.42, 6.2, 5.68, MED_BLUE, LIGHT_BG, MED_BLUE)
duration_data = [
("Outpatient CAP", "5 days (if clinically responding)"),
("Non-severe inpatient CAP", "5-7 days"),
("Severe CAP / ICU", "7-10 days"),
("Legionella pneumonia", "10-14 days"),
("S. aureus (MSSA) + bacteremia", "14-28 days"),
("MRSA pneumonia", "14-21 days"),
("HAP/VAP (uncomplicated)", "7-8 days"),
("HAP/VAP with Pseudomonas/Acinetobacter", "β₯14 days"),
]
ry = 1.95
for setting, dur in duration_data:
add_rrect(slide, 0.42, ry, 3.5, 0.42, LIGHT_GREY, MED_BLUE)
add_text(slide, setting, 0.5, ry+0.05, 3.35, 0.35, size=11.5, color=TEXT_DARK, wrap=True)
add_rrect(slide, 3.95, ry, 2.4, 0.42, MED_BLUE)
add_text(slide, dur, 4.0, ry+0.05, 2.3, 0.35, size=11.5, bold=True, color=WHITE,
align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE, wrap=True)
ry += 0.5
add_text(slide,
"β
De-escalation: Narrow spectrum once cultures available.\n"
" Procalcitonin: >80% fall from peak OR <0.25 ng/mL β consider stopping.",
0.38, 6.45, 6.0, 0.62, size=11, italic=True, color=DARK_BLUE, wrap=True)
section_box(slide, "IV β ORAL SWITCH CRITERIA (All must be met)", 6.7, 1.42, 6.3, 5.68, GREEN, LIGHT_BG, GREEN)
switch_criteria = [
"Temperature <37.8Β°C for β₯24 hours",
"Heart rate <100/min",
"Respiratory rate <24/min",
"SpOβ >92% on room air (or baseline)",
"Able to take and absorb oral medications",
"Haemodynamically stable (BP, HR normalized)",
"No evidence of complications (empyema, abscess)",
]
ry = 1.95
for crit in switch_criteria:
add_rrect(slide, 6.85, ry, 0.42, 0.38, GREEN)
add_text(slide, "β", 6.87, ry+0.03, 0.38, 0.3, size=14, bold=True,
color=WHITE, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE)
add_text(slide, crit, 7.35, ry+0.05, 5.5, 0.38, size=12, color=TEXT_DARK, wrap=True)
ry += 0.52
add_text(slide,
"Switch to oral equivalent of IV drug (same class) whenever criteria met β reduces cost, line complications, and LOS.",
6.82, 6.45, 6.1, 0.62, size=11, italic=True, color=GREEN, wrap=True)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 11 β MONITORING RESPONSE & COMPLICATIONS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Monitoring Response & Complications",
"Treatment failure defined at 72 hours | Key complications to anticipate")
footer(slide)
section_box(slide, "EXPECTED TREATMENT RESPONSE", 0.3, 1.42, 5.8, 3.7, GREEN, LIGHT_BG, GREEN)
response_data = [
("24-48 hrs", "Fever improvement; subjective improvement"),
("48-72 hrs", "Objective improvement: RR, HR, SpOβ"),
("3-5 days", "Significant improvement; consider PO switch"),
("Day 7-10", "Near-complete clinical resolution"),
("4-6 weeks", "Radiographic resolution\n(lags clinical recovery, esp. elderly)"),
]
ry = 1.95
for time, finding in response_data:
add_rrect(slide, 0.42, ry, 1.55, 0.52, MED_BLUE)
add_text(slide, time, 0.45, ry+0.04, 1.48, 0.44, size=12, bold=True, color=WHITE,
align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE)
add_text(slide, finding, 2.05, ry+0.06, 3.9, 0.5, size=11.5, color=TEXT_DARK, wrap=True)
ry += 0.6
add_text(slide,
"β Treatment failure at 72h: reassess β resistant organism? Wrong diagnosis (PE, malignancy, drug reaction)? Complication?",
0.38, 5.2, 5.65, 0.65, size=11, italic=True, color=RED, bold=True, wrap=True)
section_box(slide, "KEY COMPLICATIONS", 6.3, 1.42, 6.7, 5.68, RED, LIGHT_BG, RED)
complications = [
("Parapneumonic Effusion", "Dullness/reduced BS β Thoracentesis if >1cm"),
("Empyema", "pH <7.2, glucose <40, LDH >1000 β Chest drain + prolonged ABx"),
("Lung Abscess", "Fever >2wks, foul sputum, cavity on CXR β Clindamycin Γ 6-8wks"),
("ARDS", "PaOβ/FiOβ <200, bilateral infiltrates β Lung-protective MV (6mL/kg IBW)"),
("Septic Shock", "Hypotension + vasopressors needed β Noradrenaline 1st line + steroids"),
("Non-Resolving Pneumonia", "No response at 3 months β Consider TB, malignancy, BOOP β Bronchoscopy"),
]
ry = 1.95
for comp, mgmt in complications:
add_rrect(slide, 6.45, ry, 2.6, 0.5, RED)
add_text(slide, comp, 6.5, ry+0.04, 2.5, 0.42, size=11, bold=True, color=WHITE,
valign=MSO_ANCHOR.MIDDLE, wrap=True)
add_text(slide, mgmt, 9.15, ry+0.04, 3.65, 0.5, size=11, color=TEXT_DARK, wrap=True)
ry += 0.62
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 12 β PREVENTION
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Prevention of Pneumonia",
"Vaccinations | Infection Control | VAP Bundle | Risk Reduction")
footer(slide)
prev_items = [
("Pneumococcal Vaccine\nPCV20 / PPSV23", MED_BLUE,
"All adults β₯65 years.\nHigh-risk from β₯19 yrs:\n(DM, COPD, asplenia,\nimmunocompromised)"),
("Influenza Vaccine", MED_BLUE,
"Annual vaccination\nfor all adults.\nMost important in\nelderly + high-risk"),
("COVID-19 Vaccine", GREEN,
"Updated annual boosters.\nReduces pneumonia\nseverity and hospitalization"),
("Smoking Cessation", ORANGE,
"Removes mucosal barrier\ndamage and impaired\nmucociliary clearance.\n#1 modifiable risk"),
("Oral Hygiene", RED,
"Reduces aspiration risk\nin intubated patients.\nDaily chlorhexidine mouth\ncare in ICU"),
("VAP Bundle (ICU)", RED,
"HOB elevation β₯30Β°\nSubglottic suctioning\nDaily sedation vacation\nPVC care bundle"),
("Hand Hygiene", DARK_BLUE,
"Core infection control.\n5 moments of\nhand hygiene.\nAlcohol gel at bedside"),
]
bw = 1.72
sx = 0.28
for i, (title, col, desc) in enumerate(prev_items):
bx = sx + i*(bw+0.08)
add_rrect(slide, bx, 1.42, bw, 5.7, WHITE, col)
add_rrect(slide, bx, 1.42, bw, 0.7, col)
add_text(slide, title, bx+0.06, 1.46, bw-0.12, 0.62, size=11.5, bold=True,
color=WHITE, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE, wrap=True)
add_text(slide, desc, bx+0.08, 2.18, bw-0.16, 4.75, size=11.5,
color=TEXT_DARK, wrap=True)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 13 β MANAGEMENT FLOWCHART
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Pneumonia Management Flowchart",
"Bedside quick reference: Diagnose β Score β Treat β Monitor β Discharge")
footer(slide)
def flow_box(slide, text, x, y, w, h, fill, text_color=WHITE, size=12):
add_rrect(slide, x, y, w, h, fill, DARK_BLUE)
add_text(slide, text, x+0.08, y+0.06, w-0.16, h-0.12, size=size,
bold=True, color=text_color, align=PP_ALIGN.CENTER,
valign=MSO_ANCHOR.MIDDLE, wrap=True)
def arrow(slide, x1, y1, x2, y2):
from pptx.enum.shapes import MSO_CONNECTOR
ln = slide.shapes.add_connector(MSO_CONNECTOR.STRAIGHT,
Inches(x1), Inches(y1), Inches(x2), Inches(y2))
ln.line.color.rgb = MED_BLUE
ln.line.width = Pt(2)
# Main flow (vertical center)
flow_box(slide, "Patient: Fever + Cough + Dyspnea", 4.0, 1.42, 5.3, 0.55, DARK_BLUE, size=13)
arrow(slide, 6.65, 1.97, 6.65, 2.25)
flow_box(slide, "CXR + CBC + Blood Cultures\nSputum C&S + ABG/SpOβ", 4.0, 2.25, 5.3, 0.7, MED_BLUE, size=12)
arrow(slide, 6.65, 2.95, 6.65, 3.22)
flow_box(slide, "Calculate CURB-65", 4.75, 3.22, 3.8, 0.5, ACCENT_TEAL, TEXT_DARK, size=13)
# Three branches
arrow(slide, 4.75, 3.72, 2.5, 4.15)
arrow(slide, 6.65, 3.72, 6.65, 4.15)
arrow(slide, 8.55, 3.72, 10.8, 4.15)
flow_box(slide, "Score 0\n1.5% mortality", 1.2, 4.15, 2.6, 0.65, GREEN, size=12)
flow_box(slide, "Score 1-2\n~8% mortality", 5.35, 4.15, 2.6, 0.65, ORANGE, size=12)
flow_box(slide, "Score β₯3\nβ₯22% mortality", 9.5, 4.15, 2.6, 0.65, RED, size=12)
arrow(slide, 2.5, 4.8, 2.5, 5.15)
arrow(slide, 6.65, 4.8, 6.65, 5.15)
arrow(slide, 10.8, 4.8, 10.8, 5.15)
flow_box(slide, "OUTPATIENT\nAmoxicillin 1g TDS\nor Doxycycline 5d", 1.2, 5.15, 2.6, 0.8, GREEN, size=10.5)
flow_box(slide, "HOSPITALIZE\nCeftriaxone +\nAzithromycin 5-7d", 5.35, 5.15, 2.6, 0.8, ORANGE, size=10.5)
flow_box(slide, "ICU ADMISSION\nAntipseudomonal\nΞ²-lactam Β± MRSA cover", 9.5, 5.15, 2.6, 0.8, RED, size=10.5)
# Bottom common steps
arrow(slide, 6.65, 5.95, 6.65, 6.22)
flow_box(slide, "Review cultures at 48-72h β De-escalate β IV-to-PO switch β Discharge + Follow-up CXR at 6 weeks",
0.5, 6.22, 12.3, 0.55, DARK_BLUE, size=12)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 14 β ASPIRATION PNEUMONIA
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
slide_bg(slide)
slide_header(slide, "Aspiration Pneumonia β Special Considerations",
"Polymicrobial | Location-specific | Risk factor management")
footer(slide)
section_box(slide, "PATHOPHYSIOLOGY & LOCATION", 0.3, 1.42, 6.2, 2.85, MED_BLUE, LIGHT_BG, MED_BLUE)
add_multiline(slide, [
("Mechanism: Inhalation of oropharyngeal or gastric contents", False, TEXT_DARK),
("", False, TEXT_DARK),
("Location (dependent on posture):", True, DARK_BLUE),
("β’ Supine: Superior segment RLL + Posterior segments upper lobes", False, TEXT_DARK),
("β’ Upright: Basal segments of RLL (gravity-dependent)", False, TEXT_DARK),
("β’ Any lobe except apices possible depending on position", False, TEXT_DARK),
], 0.45, 1.92, 5.9, 2.1, size=12.5)
section_box(slide, "ORGANISMS", 0.3, 4.37, 6.2, 2.85, DARK_BLUE, LIGHT_BG, DARK_BLUE)
add_multiline(slide, [
("Community (oral anaerobes):", True, DARK_BLUE),
(" Bacteroides, Fusobacterium, Prevotella, Microaerophilic Streptococci", False, TEXT_DARK),
("", False, TEXT_DARK),
("Hospitalized / LTC patients:", True, RED),
(" Gram-negatives, P. aeruginosa, S. aureus (MRSA)", False, TEXT_DARK),
], 0.45, 4.85, 5.9, 2.1, size=12.5)
section_box(slide, "TREATMENT", 6.55, 1.42, 6.5, 2.85, GREEN, LIGHT_BG, GREEN)
add_multiline(slide, [
("Community Aspiration (outpatient):", True, DARK_BLUE),
(" Amoxicillin-clavulanate 875/125mg PO BD Γ 7-10d", False, TEXT_DARK),
("", False, TEXT_DARK),
("Hospital/ICU Aspiration:", True, RED),
(" Piperacillin-tazobactam 4.5g IV Q6H", False, TEXT_DARK),
(" OR Meropenem 1g IV Q8H", False, TEXT_DARK),
(" Β± Metronidazole for enhanced anaerobic coverage", False, TEXT_DARK),
], 6.7, 1.92, 6.2, 2.1, size=12.5)
section_box(slide, "COMPLICATIONS & PROGNOSIS", 6.55, 4.37, 6.5, 2.85, RED, LIGHT_BG, RED)
add_multiline(slide, [
("Complications:", True, DARK_BLUE),
("β’ Lung abscess (cavity + air-fluid level on CXR)", False, TEXT_DARK),
(" β Clindamycin 600mg IV Q8H Γ 6-8 weeks", False, TEXT_DARK),
("β’ Empyema β chest drain + prolonged ABx", False, TEXT_DARK),
("β’ ARDS in large-volume aspiration", False, TEXT_DARK),
("", False, TEXT_DARK),
("Mortality: 15-30% | Lung abscess: ~20%", True, RED),
("Prognosis driven by underlying predisposing condition", False, TEXT_DARK),
], 6.7, 4.85, 6.2, 2.1, size=12)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SLIDE 15 β REFERENCES & KEY TAKEAWAYS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
slide = prs.slides.add_slide(BLANK)
add_rect(slide, 0, 0, 13.333, 7.5, DARK_BLUE)
add_rect(slide, 0, 1.35, 13.333, 0.08, ACCENT_TEAL)
add_text(slide, "Key Takeaways & References", 0.4, 0.22, 12.5, 0.9,
size=30, bold=True, color=WHITE, valign=MSO_ANCHOR.MIDDLE)
add_text(slide, "Evidence-based Pneumonia Management Summary", 0.4, 1.0, 12.5, 0.38,
size=16, italic=True, color=ACCENT_TEAL)
takeaways = [
("Severity Score First", "Always calculate CURB-65 or PSI before deciding site of care"),
("Culture Before ABx", "Blood cultures Γ 2 + sputum C&S before first antibiotic dose"),
("Empiric Then Targeted", "Start broad empirically; de-escalate at 48-72h with culture data"),
("Duration Matters", "Outpatient CAP needs only 5 days if responding; avoid over-treatment"),
("Monitor for Failure", "Reassess at 72h; treatment failure demands diagnosis review"),
("MRSA PCR Guides Therapy", "Nasal MRSA PCR negative = can avoid Vancomycin in most cases"),
("Prevention Is Key", "PCV20 + annual flu vaccine + smoking cessation = best prophylaxis"),
]
ry = 1.58
for title, msg in takeaways:
add_rrect(slide, 0.4, ry, 2.7, 0.46, ACCENT_TEAL)
add_text(slide, title, 0.45, ry+0.04, 2.6, 0.38, size=12, bold=True,
color=DARK_BLUE, valign=MSO_ANCHOR.MIDDLE)
add_text(slide, msg, 3.2, ry+0.07, 9.7, 0.38, size=12, color=LIGHT_GREY, wrap=True)
ry += 0.56
add_rect(slide, 0, 6.7, 13.333, 0.8, RGBColor(0x08,0x1A,0x38))
add_multiline(slide, [
("References: Harrison's Principles of Internal Medicine 22E (2025) | Fishman's Pulmonary Diseases & Disorders | Goldman-Cecil Medicine International Edition", False, LIGHT_GREY),
("2025 SPILF/SPLF Practice Guideline (doi:10.1016/j.resmer.2025.101161) | Antimicrobial Stewardship Meta-Analysis (PMID: 40202602, Eur J Clin Microbiol Infect Dis, 2025)", False, RGBColor(0x88,0xBB,0xDD)),
], 0.4, 6.72, 12.5, 0.66, size=9.5, align=PP_ALIGN.CENTER)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# SAVE
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
out_path = "/tmp/workspace/pneumonia-ppt/Pneumonia_Management_MD_Reference.pptx"
buf = BytesIO()
prs.save(buf)
with open(out_path, "wb") as f:
f.write(buf.getvalue())
print(f"β
Saved: {out_path}")
import os
print(f" Size : {os.path.getsize(out_path):,} bytes")
print(f" Slides: {len(prs.slides)}")