Can you craete different diagnosis of fever with most common complaints that patient come to GP and which treatments should be provided along with detail analysis of CBC report and other reports that should be advised
fever differential diagnosis CBC interpretation treatment guidelines general practice 2024
Harrison's Principles of Internal Medicine 22E - Fever chapter
| System | Common (Nonemergent) | Urgent (Emergent) | Life-Threatening (Critical) |
|---|---|---|---|
| Respiratory | Pharyngitis, sinusitis, otitis media, bronchitis, influenza, COVID-19, TB | Bacterial pneumonia, peritonsillar abscess, epiglottitis | Pneumonia with respiratory failure |
| GI | Gastroenteritis/colitis | Appendicitis, cholecystitis, diverticulitis, intraabdominal abscess | Peritonitis |
| Genitourinary | Cystitis, prostatitis, epididymitis | Pyelonephritis, PID, tubo-ovarian abscess | - |
| Neurological | - | Encephalitis, brain abscess | Meningitis, cavernous sinus thrombosis |
| Skin/Soft Tissue | - | Cellulitis, soft tissue abscess, infected decubitus ulcer | Necrotizing fasciitis |
| Cardiovascular | - | Endocarditis, pericarditis | - |
| Systemic | - | Influenza, COVID-19 | Sepsis/septic shock, meningococcemia |
ROSEN's Emergency Medicine, Table 8.1
ROSEN's Emergency Medicine, Box 8.1
| Finding | Normal Range | Interpretation in Fever |
|---|---|---|
| Leukocytosis (WBC >11,000/µL) | 4,000-11,000/µL | Bacterial infection, inflammation, stress response |
| Leukopenia (WBC <4,000/µL) | - | Viral infection (dengue, typhoid), overwhelming sepsis, bone marrow suppression |
| Extreme leukocytosis (>40,000-100,000/µL) | - | Leukemoid reaction (severe infection) vs leukemia - must distinguish |
| Cell Type | Normal % | Elevation Suggests | Decrease Suggests |
|---|---|---|---|
| Neutrophils | 50-70% | Bacterial infection, acute inflammation | Viral infection, typhoid, drug toxicity |
| Lymphocytes | 20-40% | Viral infection (EBV mono, CMV, rubella) | HIV, immunosuppression |
| Monocytes | 2-8% | Chronic infection (TB, Brucella), malaria, EBV | - |
| Eosinophils | 1-4% | Parasitic/helminth infection, allergies | Acute bacterial infection, stress |
| Basophils | 0-1% | Rare; myeloproliferative disease | - |
| Bands/Immature neutrophils | <5% | Active bacterial infection ("shift to left") | - |
Robbins & Kumar Pathologic Basis of Disease - Systemic Effects of Inflammation
| Finding | Interpretation |
|---|---|
| Anemia (low Hb) | Chronic infection, hemolysis (malaria), bleeding, B12/folate deficiency |
| Low MCV (microcytic) | Iron deficiency anemia (chronic infection/blood loss) |
| High MCV (macrocytic) | B12/folate deficiency, liver disease, hypothyroidism |
| Normal MCV (normocytic) | Acute blood loss, hemolysis, chronic disease |
| Thrombocytopenia (platelets <150,000) | Dengue, malaria, sepsis, ITP - RED FLAG |
| Test | Normal | Interpretation |
|---|---|---|
| CRP (C-reactive protein) | <10 mg/L | Rises within 6 hrs of infection/inflammation; >100 mg/L suggests bacterial infection or severe inflammation. Produced in liver, stimulated by IL-6 |
| ESR (Erythrocyte Sedimentation Rate) | Males <20 mm/hr; Females <30 mm/hr | Non-specific; elevated in infection, inflammation, malignancy, autoimmune disease. Useful for monitoring chronic disease (TB, temporal arteritis) |
| Procalcitonin (PCT) | <0.1 ng/mL | >0.5 ng/mL suggests bacterial infection; >2 ng/mL indicates high probability of sepsis. More specific than CRP for bacterial vs viral distinction |
| Suspected Condition | Tests to Order |
|---|---|
| UTI / Pyelonephritis | Urine dipstick + urinalysis, urine culture & sensitivity (MC&S) |
| Pneumonia | Chest X-ray (CXR), sputum culture, blood cultures if severe |
| Malaria | Thick and thin blood film (gold standard), rapid antigen test (RDT) |
| Dengue | Dengue NS1 antigen (early <5 days), IgM/IgG serology (after 5 days) |
| Typhoid | Blood culture (gold standard), Widal test (serology - limited specificity) |
| Sepsis | Blood cultures x2, serum lactate, full metabolic panel |
| Influenza/COVID-19 | Rapid antigen test or PCR (nasopharyngeal swab) |
| TB | Sputum AFB smear + culture, Mantoux/TST or IGRA (Quantiferon), CXR |
| Infective Endocarditis | Blood cultures x3, echocardiogram (TTE/TEE) |
| Meningitis | Lumbar puncture (CSF analysis), blood cultures, CT head first if focal neuro signs |
| Autoimmune (SLE, RA) | ANA, anti-dsDNA, RF, complement levels (C3/C4) |
| Drug | Dose (Adult) | Mechanism | Notes |
|---|---|---|---|
| Paracetamol (Acetaminophen) | 500-1000 mg every 4-6 hrs (max 4g/day) | Inhibits PGE2 centrally; weak peripheral COX inhibition | First-line; safest in all patients including pregnant, liver disease caution |
| Ibuprofen (NSAID) | 400 mg every 6-8 hrs (max 1200 mg/day OTC) | Inhibits COX-1/COX-2 → blocks prostaglandin synthesis | Effective anti-inflammatory; avoid in renal disease, GI ulcers, pregnancy (3rd trimester) |
| Aspirin | 325-650 mg every 4-6 hrs | COX inhibitor; decreases PGE2 | NOT used in children <16 (Reye syndrome risk); avoid in dengue (bleeding risk) |
ROSEN's Emergency Medicine - Fever chapter; Robbins Pathologic Basis of Disease
| Diagnosis | First-Line Treatment | Notes |
|---|---|---|
| Viral URTI | Supportive - rest, hydration, paracetamol/ibuprofen | No antibiotics; zinc lozenges may shorten duration |
| Bacterial pharyngitis (Strep) | Amoxicillin 500 mg TID x 10 days (or Penicillin V) | Prevents rheumatic fever |
| Influenza | Oseltamivir (Tamiflu) 75 mg BD x 5 days (if within 48 hrs onset) | Most effective if started early; high-risk patients prioritized |
| COVID-19 (mild-moderate) | Supportive; Nirmatrelvir/ritonavir (Paxlovid) or Molnupiravir for high-risk within 5 days | Antivirals for high-risk groups |
| UTI (cystitis) | Trimethoprim 200 mg BD x 3-7 days or Nitrofurantoin 100 mg BD x 5-7 days | Culture first; adjust to sensitivity |
| Pyelonephritis | Co-amoxiclav 625 mg TID x 14 days OR Ciprofloxacin 500 mg BD x 7-10 days | IV antibiotics if vomiting/severely ill |
| Community-acquired pneumonia | Amoxicillin 500 mg TID x 5 days (mild); Add clarithromycin if atypical suspected | Use CURB-65 score to decide: hospital vs community treatment |
| Gastroenteritis (bacterial) | Most self-limiting; Azithromycin or Ciprofloxacin if severe/bloody | Rehydration is key (ORS) |
| Malaria (P. falciparum) | Artemether-lumefantrine (Coartem) x 3 days | Urgent treatment; P. vivax/ovale: Chloroquine + Primaquine |
| Dengue | Supportive only - IV fluids, paracetamol | NO NSAIDs/aspirin (bleeding risk); monitor platelets |
| Typhoid | Azithromycin 500 mg OD x 7 days (outpatient) or Ceftriaxone IV (severe) | Drug resistance common; base on local patterns |
| Cellulitis | Flucloxacillin 500 mg QID x 5-7 days; Clarithromycin if penicillin-allergic | Cover Staph/Strep |
| Meningitis (empirical) | Ceftriaxone 2g IV immediately + Dexamethasone | Do NOT delay for LP if clinically suspected |
| Sepsis (empirical) | IV Piperacillin-tazobactam or Meropenem + source control | Sepsis 6 bundle: cultures, lactate, fluids, antibiotics, O2, urine output |
Febrile patient presents
↓
Clinical history + examination → localize source
↓
CBC + CRP/ESR/Procalcitonin → bacterial vs viral
↓
Targeted tests (urine MC&S / CXR / blood film / swabs)
↓
Red flags? → Emergency referral
No red flags → Targeted treatment based on diagnosis
↓
Review in 48-72 hours if not improving
Generate a quick reference PDF with fever DDx, CBC interpretation, and treatment flowchart
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace dir does not exis…
mkdir -p /home/daytona/workspace/fever-quickref && python3 -c "import reportlab;…
~/fever-quickref/build_pdf.py
#!/usr/bin/env python3
"""
Fever Quick Reference Card - GP Edition
Generates a professional multi-page PDF with:
- Page 1: Cover + Fever DDx (Infectious & Non-Infectious)
- Page 2: CBC Interpretation
- Page 3: Treatment Flowchart + Treatment Table
- Page 4: Red Flags + Investigations
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.platypus.flowables import Flowable
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Arrow
from reportlab.graphics import renderPDF
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Polygon
from reportlab.pdfgen import canvas
# ── Colour Palette ──────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1A2E4A")
TEAL = colors.HexColor("#00838F")
TEAL_LIGHT = colors.HexColor("#E0F4F5")
RED = colors.HexColor("#C62828")
RED_LIGHT = colors.HexColor("#FFEBEE")
ORANGE = colors.HexColor("#E65100")
ORANGE_LIGHT= colors.HexColor("#FFF3E0")
GREEN = colors.HexColor("#2E7D32")
GREEN_LIGHT = colors.HexColor("#E8F5E9")
YELLOW_LIGHT= colors.HexColor("#FFFDE7")
GREY = colors.HexColor("#546E7A")
GREY_LIGHT = colors.HexColor("#ECEFF1")
WHITE = colors.white
BLACK = colors.black
W, H = A4 # 595.27 x 841.89 pts
OUTPUT = "/home/daytona/workspace/fever-quickref/Fever_Quick_Reference_GP.pdf"
# ── Custom Flowables ─────────────────────────────────────────────────────────
class ColorBar(Flowable):
"""A thin horizontal colour bar used as section divider."""
def __init__(self, width, height=3, color=TEAL):
Flowable.__init__(self)
self.bar_width = width
self.bar_height = height
self.color = color
def draw(self):
self.canv.setFillColor(self.color)
self.canv.rect(0, 0, self.bar_width, self.bar_height, fill=1, stroke=0)
def wrap(self, aw, ah):
return (self.bar_width, self.bar_height)
class SectionHeader(Flowable):
"""Coloured section header banner."""
def __init__(self, text, width, bg=NAVY, fg=WHITE, fontsize=13):
Flowable.__init__(self)
self.text = text
self.w = width
self.bg = bg
self.fg = fg
self.fontsize = fontsize
self.h = fontsize + 10
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.roundRect(0, 0, self.w, self.h, 4, fill=1, stroke=0)
c.setFillColor(self.fg)
c.setFont("Helvetica-Bold", self.fontsize)
c.drawString(8, 4, self.text)
def wrap(self, aw, ah):
return (self.w, self.h)
class FlowchartBox(Flowable):
"""Simple flowchart for the treatment decision flow."""
def __init__(self, width=500):
Flowable.__init__(self)
self.w = width
self.h = 340
def draw(self):
c = self.canv
bw = self.w
def box(x, y, w, h, text, bg, fg=WHITE, fontsize=8.5, radius=6):
c.setFillColor(bg)
c.roundRect(x, y, w, h, radius, fill=1, stroke=0)
c.setFillColor(fg)
c.setFont("Helvetica-Bold", fontsize)
lines = text.split("\n")
total_h = len(lines) * (fontsize + 3)
start_y = y + (h - total_h) / 2 + (fontsize + 3) * (len(lines) - 1)
for line in lines:
c.drawCentredString(x + w / 2, start_y, line)
start_y -= (fontsize + 3)
def arrow(x1, y1, x2, y2):
c.setStrokeColor(GREY)
c.setLineWidth(1.2)
c.line(x1, y1, x2, y2)
# arrowhead
import math
angle = math.atan2(y2 - y1, x2 - x1)
aw = 6
c.setFillColor(GREY)
c.beginPath()
c.moveTo(x2, y2)
c.lineTo(x2 - aw * math.cos(angle - 0.4), y2 - aw * math.sin(angle - 0.4))
c.lineTo(x2 - aw * math.cos(angle + 0.4), y2 - aw * math.sin(angle + 0.4))
c.closePath()
c.fill()
def label(x, y, text, color=ORANGE, fontsize=7.5):
c.setFillColor(color)
c.setFont("Helvetica-Bold", fontsize)
c.drawString(x, y, text)
# Node positions (x, y, w, h)
cx = bw / 2
# Row 1 - Start
box(cx-90, 305, 180, 28, "FEBRILE PATIENT AT GP\n(Temp > 38.0 C)", NAVY, WHITE, 8)
arrow(cx, 305, cx, 278)
# Row 2 - History & Exam
box(cx-110, 250, 220, 26, "History + Physical Examination\nLocalise source; assess severity", TEAL, WHITE, 8)
arrow(cx, 250, cx, 223)
# Row 3 - Red flags
box(cx-100, 195, 200, 26, "RED FLAGS present?\n(see Page 4)", RED, WHITE, 8)
# Yes branch - right
arrow(cx+100, 208, cx+160, 208)
box(cx+160, 195, 115, 26, "EMERGENCY\nReferral / 999", RED, WHITE, 7.5)
label(cx+105, 211, "YES", RED)
# No branch - down
arrow(cx, 195, cx, 168)
label(cx+4, 180, "NO", GREEN)
# Row 4 - CBC + Markers
box(cx-120, 140, 240, 26, "Order: CBC + CRP/PCT + ESR\n+ Targeted tests (urine/CXR/swab)", TEAL, WHITE, 8)
arrow(cx, 140, cx, 113)
# Row 5 - Decision split
box(cx-80, 85, 160, 26, "CBC Result + Clinical Picture", NAVY, WHITE, 8)
# Branch left - Bacterial
arrow(cx-40, 85, cx-120, 60)
box(cx-195, 35, 140, 26, "Neutrophilia\n+ High CRP/PCT", RED_LIGHT, RED, 8)
arrow(cx-125, 35, cx-125, 10)
box(cx-195, -15, 140, 26, "BACTERIAL\nAntibiotics", RED, WHITE, 8)
label(cx-165, 63, "Bacterial", RED, 7)
# Branch right - Viral
arrow(cx+40, 85, cx+120, 60)
box(cx+55, 35, 140, 26, "Lymphocytosis\n+ Normal/Low WBC", GREEN_LIGHT, GREEN, 8)
arrow(cx+125, 35, cx+125, 10)
box(cx+55, -15, 140, 26, "VIRAL\nSupportive Care", GREEN, WHITE, 8)
label(cx+75, 63, "Viral", GREEN, 7)
# Label
c.setFillColor(GREY)
c.setFont("Helvetica-Oblique", 7)
c.drawCentredString(cx, -30, "Review in 48-72 hrs if not improving | Consider FUO workup if fever > 7 days")
# ── Styles ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kwargs):
return ParagraphStyle(name, parent=styles["Normal"], **kwargs)
title_style = S("Title2", fontSize=22, textColor=WHITE, alignment=TA_CENTER, fontName="Helvetica-Bold", leading=28)
subtitle_style = S("Sub2", fontSize=11, textColor=TEAL_LIGHT, alignment=TA_CENTER, fontName="Helvetica-Oblique")
body_style = S("Body2", fontSize=8.5, textColor=BLACK, leading=13)
bold_style = S("Bold2", fontSize=8.5, textColor=BLACK, fontName="Helvetica-Bold", leading=13)
small_style = S("Small2", fontSize=7.5, textColor=GREY, leading=11)
heading_style = S("H3", fontSize=10, textColor=NAVY, fontName="Helvetica-Bold", leading=14, spaceAfter=2)
red_style = S("Red2", fontSize=8.5, textColor=RED, fontName="Helvetica-Bold", leading=13)
# ── Helper Functions ──────────────────────────────────────────────────────────
def tbl(data, col_widths, style_cmds, row_heights=None):
t = Table(data, colWidths=col_widths, rowHeights=row_heights)
t.setStyle(TableStyle([
("FONTNAME", (0,0), (-1,-1), "Helvetica"),
("FONTSIZE", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#B0BEC5")),
("ROWBACKGROUNDS", (0,0), (-1,-1), [WHITE, GREY_LIGHT]),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
] + style_cmds))
return t
# ── Page background callback ──────────────────────────────────────────────────
def on_first_page(canvas_obj, doc):
canvas_obj.saveState()
# Navy gradient-style header block
canvas_obj.setFillColor(NAVY)
canvas_obj.rect(0, H - 110, W, 110, fill=1, stroke=0)
# Teal accent strip
canvas_obj.setFillColor(TEAL)
canvas_obj.rect(0, H - 113, W, 3, fill=1, stroke=0)
# Footer
canvas_obj.setFillColor(GREY_LIGHT)
canvas_obj.rect(0, 0, W, 20, fill=1, stroke=0)
canvas_obj.setFillColor(GREY)
canvas_obj.setFont("Helvetica", 7)
canvas_obj.drawCentredString(W/2, 6, "Fever Quick Reference for General Practice | Sources: Harrison's 22E, ROSEN's EM, Robbins Pathology, Goldman-Cecil Medicine | For clinical guidance only")
canvas_obj.restoreState()
def on_later_pages(canvas_obj, doc):
canvas_obj.saveState()
# Thin top bar
canvas_obj.setFillColor(NAVY)
canvas_obj.rect(0, H - 22, W, 22, fill=1, stroke=0)
canvas_obj.setFillColor(WHITE)
canvas_obj.setFont("Helvetica-Bold", 8)
canvas_obj.drawString(15, H - 14, "FEVER QUICK REFERENCE | GP EDITION")
canvas_obj.setFont("Helvetica", 8)
canvas_obj.drawRightString(W - 15, H - 14, f"Page {doc.page}")
# Footer
canvas_obj.setFillColor(GREY_LIGHT)
canvas_obj.rect(0, 0, W, 20, fill=1, stroke=0)
canvas_obj.setFillColor(GREY)
canvas_obj.setFont("Helvetica", 7)
canvas_obj.drawCentredString(W/2, 6, "Fever Quick Reference for General Practice | Sources: Harrison's 22E, ROSEN's EM, Robbins Pathology, Goldman-Cecil Medicine | For clinical guidance only")
canvas_obj.restoreState()
# ── Build Content ─────────────────────────────────────────────────────────────
def build():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=18*mm, rightMargin=18*mm,
topMargin=28*mm, bottomMargin=22*mm,
title="Fever Quick Reference - GP Edition",
author="Orris Clinical Assistant",
subject="Fever DDx, CBC Interpretation, Treatment",
)
story = []
UW = W - 36*mm # usable width
# ════════════════════════════════════════════════════════════════════
# PAGE 1: COVER HEADER + FEVER DDx
# ════════════════════════════════════════════════════════════════════
# Cover header (sits over the painted navy rectangle)
story.append(Spacer(1, 14))
story.append(Paragraph("FEVER", title_style))
story.append(Paragraph("Quick Reference Card for General Practice", subtitle_style))
story.append(Spacer(1, 6))
story.append(Paragraph("Differential Diagnosis | CBC Analysis | Treatment Guide | Red Flags", subtitle_style))
story.append(Spacer(1, 22))
# ── Section 1: Definition ────────────────────────────────────────────
story.append(SectionHeader(" DEFINITION & PATHOPHYSIOLOGY", UW, NAVY))
story.append(Spacer(1, 5))
def_data = [
[Paragraph("<b>Fever</b>", bold_style),
Paragraph("Core temperature <b>>38.0°C (100.4°F)</b>. Hyperpyrexia = >41°C (neural tissue damage risk)", body_style)],
[Paragraph("<b>Mechanism</b>", bold_style),
Paragraph("Pyrogenic cytokines (IL-1, IL-6, TNF) → PGE2 → hypothalamic set point ↑ → chills → fever → sweating", body_style)],
[Paragraph("<b>Antipyresis</b>", bold_style),
Paragraph("NSAIDs/Paracetamol inhibit COX → block PGE2 synthesis → set point normalises", body_style)],
[Paragraph("<b>Treat if</b>", bold_style),
Paragraph("Temp >41°C (mandatory); symptomatic relief for moderate fever; paediatric febrile seizure risk", body_style)],
]
t_def = tbl(def_data, [38*mm, UW - 38*mm], [
("BACKGROUND", (0,0), (-1,-1), TEAL_LIGHT),
("FONTNAME", (0,0), (0,-1), "Helvetica-Bold"),
("GRID", (0,0), (-1,-1), 0.3, TEAL),
])
story.append(t_def)
story.append(Spacer(1, 10))
# ── Section 2: Infectious DDx ────────────────────────────────────────
story.append(SectionHeader(" INFECTIOUS CAUSES BY SYSTEM", UW, TEAL))
story.append(Spacer(1, 5))
inf_header = [
Paragraph("<b>System</b>", bold_style),
Paragraph("<b>Common / Nonemergent</b>", bold_style),
Paragraph("<b>Urgent / Emergent</b>", bold_style),
Paragraph("<b>Life-Threatening</b>", bold_style),
]
inf_rows = [
["Respiratory", "Pharyngitis, sinusitis, otitis media, bronchitis, influenza, COVID-19, TB", "Bacterial pneumonia, peritonsillar abscess, epiglottitis, retropharyngeal abscess", "Pneumonia + respiratory failure"],
["GI / Abdominal", "Gastroenteritis, colitis", "Appendicitis, cholecystitis, diverticulitis, intra-abdominal abscess", "Peritonitis"],
["Genitourinary", "Cystitis, prostatitis, epididymitis", "Pyelonephritis, PID, tubo-ovarian abscess", "-"],
["Neurological", "-", "Encephalitis, brain abscess", "Meningitis, cavernous sinus thrombosis"],
["Skin / Soft Tissue", "-", "Cellulitis, soft tissue abscess, infected decubitus ulcer", "Necrotizing fasciitis"],
["Cardiovascular", "-", "Endocarditis, pericarditis, myocarditis", "-"],
["Systemic", "-", "Influenza, COVID-19, malaria, dengue, typhoid", "Sepsis / septic shock, meningococcemia"],
]
inf_data = [inf_header]
for row in inf_rows:
inf_data.append([Paragraph(c, body_style) for c in row])
t_inf = tbl(inf_data,
[28*mm, 58*mm, 62*mm, 48*mm],
[
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("BACKGROUND", (3,1), (3,-1), RED_LIGHT),
("TEXTCOLOR", (3,1), (3,-1), RED),
("FONTNAME", (3,1), (3,-1), "Helvetica-Bold"),
])
story.append(t_inf)
story.append(Spacer(1, 10))
# ── Section 3: Non-Infectious DDx ─────────────────────────────────────
story.append(SectionHeader(" NON-INFECTIOUS CAUSES (Always Consider!)", UW, ORANGE))
story.append(Spacer(1, 5))
ni_data = [
[Paragraph("<b>Critical</b>", S("x", fontSize=8, textColor=RED, fontName="Helvetica-Bold")),
Paragraph("Acute MI, Pulmonary embolism, Intracranial haemorrhage/stroke, Neuroleptic malignant syndrome, Thyroid storm, Adrenal insufficiency, Transfusion reaction", body_style)],
[Paragraph("<b>Emergent</b>", S("x", fontSize=8, textColor=ORANGE, fontName="Helvetica-Bold")),
Paragraph("CHF, Dehydration, Post-seizure, Sickle cell crisis, Pancreatitis, DVT, Transplant rejection", body_style)],
[Paragraph("<b>Non-urgent</b>", S("x", fontSize=8, textColor=GREEN, fontName="Helvetica-Bold")),
Paragraph("Drug fever, Malignancy (lymphoma/leukaemia), Gout, Sarcoidosis, Crohn's disease, SLE, RA, Adult-onset Still's disease", body_style)],
]
t_ni = tbl(ni_data, [22*mm, UW - 22*mm], [
("BACKGROUND", (0,0), (0,0), RED_LIGHT),
("BACKGROUND", (0,1), (0,1), ORANGE_LIGHT),
("BACKGROUND", (0,2), (0,2), GREEN_LIGHT),
])
story.append(t_ni)
story.append(Spacer(1, 10))
# ── Section 4: Common GP Presentations ──────────────────────────────
story.append(SectionHeader(" COMMON GP PRESENTATIONS", UW, NAVY))
story.append(Spacer(1, 5))
gp_header = [Paragraph("<b>Diagnosis</b>", bold_style),
Paragraph("<b>Typical Fever</b>", bold_style),
Paragraph("<b>Key Complaints</b>", bold_style),
Paragraph("<b>Distinguishing Feature</b>", bold_style)]
gp_rows = [
["Viral URTI", "38-38.5°C", "Sore throat, runny nose, nasal congestion, mild cough", "Self-limiting; no exudate unless Strep"],
["Influenza", "39-40°C", "Abrupt myalgia, headache, dry cough, fatigue", "\"Hit by a truck\"; systemic > nasal"],
["COVID-19", "38-39°C", "Fever, dry cough, fatigue, anosmia/ageusia", "Loss of smell/taste; SpO2 monitoring"],
["Strep Pharyngitis", "38.5-40°C", "Severe sore throat, odynophagia, no cough", "Exudate + tender anterior cervical LN"],
["UTI / Cystitis", "Low-grade/none", "Dysuria, frequency, urgency, suprapubic pain", "Usually afebrile; dipstick nitrites/LE +ve"],
["Pyelonephritis", "38.5-40°C + rigors", "Flank/loin pain, nausea, vomiting, dysuria", "CVA tenderness; systemic illness"],
["Pneumonia (CAP)", "38.5-40°C", "Productive cough, pleuritic pain, dyspnoea", "Bronchial breath sounds; CXR consolidation"],
["Dengue Fever", "39-40°C abrupt", "Retro-orbital pain, severe myalgia, rash", "\"Breakbone fever\"; thrombocytopenia"],
["Malaria", "Cyclical", "Rigors, sweating, headache, hepatosplenomegaly", "P.vivax 48h / P.malariae 72h cycles"],
["Typhoid", "Stepwise rise", "Headache, relative bradycardia, abdo pain, rose spots", "Blood culture positive in week 1"],
["Cellulitis", "38-39°C", "Red, warm, swollen, tender skin + systemic fever", "No fluctuance (unlike abscess)"],
["Gastroenteritis", "38-39°C", "Nausea, vomiting, diarrhoea, abdo cramps", "Viral = watery; Bacterial = may be bloody"],
]
gp_data = [gp_header]
for row in gp_rows:
gp_data.append([Paragraph(c, body_style) for c in row])
t_gp = tbl(gp_data, [32*mm, 26*mm, 65*mm, 73*mm], [
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), TEAL),
])
story.append(t_gp)
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════
# PAGE 2: CBC INTERPRETATION
# ════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 6))
story.append(SectionHeader(" CBC INTERPRETATION IN FEVER", UW, NAVY, fontsize=13))
story.append(Spacer(1, 6))
# WBC
story.append(Paragraph("WHITE BLOOD CELL COUNT (Normal: 4,000 - 11,000 /µL)", heading_style))
wbc_data = [
[Paragraph("<b>Finding</b>", bold_style), Paragraph("<b>Value</b>", bold_style),
Paragraph("<b>Interpretation</b>", bold_style), Paragraph("<b>Common Causes</b>", bold_style)],
["Leukocytosis", "> 11,000 /µL", "Active infection / inflammation / stress",
"Bacterial infection, acute inflammation, steroid use, physiological stress"],
["Extreme leukocytosis", "> 40,000-100,000 /µL", "Leukemoid reaction (vs leukaemia - distinguish!)",
"Severe bacterial sepsis, pertussis, TB; rule out CML"],
["Leukopenia", "< 4,000 /µL", "Viral infection OR overwhelming bacterial sepsis",
"Dengue, typhoid, viral hepatitis, HIV, protozoa, drug toxicity"],
["Normal WBC", "4,000-11,000 /µL", "Does NOT exclude infection",
"Early bacterial infection, atypical organisms, viral illness"],
]
t_wbc = tbl(wbc_data, [30*mm, 28*mm, 60*mm, UW-118*mm], [
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("BACKGROUND", (0,2), (-1,2), RED_LIGHT),
], row_heights=[None,None,None,None,None])
story.append(t_wbc)
story.append(Spacer(1, 8))
# Differential
story.append(Paragraph("DIFFERENTIAL COUNT - What Each Cell Tells You", heading_style))
diff_data = [
[Paragraph("<b>Cell</b>", bold_style), Paragraph("<b>Normal %</b>", bold_style),
Paragraph("<b>Elevation (↑) Suggests</b>", bold_style), Paragraph("<b>Decrease (↓) Suggests</b>", bold_style),
Paragraph("<b>Key Point</b>", bold_style)],
["Neutrophils", "50-70%", "Bacterial infection, acute inflammation, stress", "Viral infection, typhoid, chemotherapy, drug toxicity", "SHIFT TO LEFT = band cells = active bacterial infection"],
["Lymphocytes", "20-40%", "Viral infection (EBV, CMV, rubella, HIV)", "HIV/AIDS, immunosuppression, sepsis, steroids", "Atypical lymphocytes in EBV mononucleosis"],
["Monocytes", "2-8%", "Chronic infection (TB, Brucella), malaria, EBV, CMV", "Rarely clinically significant", "Monocytosis in prolonged/granulomatous infection"],
["Eosinophils", "1-4%", "Parasitic/helminth infections, allergies, drugs", "Acute bacterial infection, corticosteroids, Cushing's", "Eosinopenia in acute severe infection = poor sign"],
["Basophils", "0-1%", "Myeloproliferative disease (rare)", "Usually not significant", "Basophilia rare; think CML if marked"],
["Band Cells", "< 5%", "> 5% = 'left shift' = active bacterial infection", "N/A", "Indicates high demand for neutrophils from marrow"],
]
t_diff = tbl(diff_data, [22*mm, 18*mm, 52*mm, 52*mm, 52*mm], [
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), TEAL),
("BACKGROUND", (0,1), (-1,1), YELLOW_LIGHT), # Neutrophils highlighted
("BACKGROUND", (0,6), (-1,6), ORANGE_LIGHT), # Bands highlighted
])
story.append(t_diff)
story.append(Spacer(1, 8))
# RBC + Platelets
story.append(Paragraph("RED CELLS, HAEMOGLOBIN & PLATELETS", heading_style))
rbc_data = [
[Paragraph("<b>Parameter</b>", bold_style), Paragraph("<b>Abnormality</b>", bold_style),
Paragraph("<b>Clinical Interpretation</b>", bold_style)],
["Haemoglobin (Hb)", "Low (Anaemia)", "Chronic infection/inflammation, haemolysis (malaria), iron deficiency"],
["MCV", "Low (< 80 fL) = Microcytic", "Iron deficiency anaemia (chronic disease/blood loss)"],
["MCV", "High (> 100 fL) = Macrocytic", "B12/folate deficiency, liver disease, hypothyroidism, alcoholism"],
["MCV", "Normal = Normocytic anaemia", "Acute blood loss, haemolysis, anaemia of chronic disease"],
["Platelets", "Low (< 150,000/µL) THROMBOCYTOPENIA", "DENGUE (hallmark), malaria, sepsis, ITP, drug-induced - RED FLAG"],
["Platelets", "High (> 400,000/µL) Thrombocytosis", "Reactive (infection, inflammation, iron deficiency) or essential thrombocythaemia"],
]
t_rbc = tbl(rbc_data, [30*mm, 48*mm, UW - 78*mm], [
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("BACKGROUND", (0,5), (-1,5), RED_LIGHT),
("TEXTCOLOR", (1,5), (1,5), RED),
("FONTNAME", (1,5), (1,5), "Helvetica-Bold"),
])
story.append(t_rbc)
story.append(Spacer(1, 8))
# Inflammatory markers
story.append(SectionHeader(" INFLAMMATORY MARKERS & INTERPRETATION", UW, TEAL, fontsize=11))
story.append(Spacer(1, 5))
im_data = [
[Paragraph("<b>Marker</b>", bold_style), Paragraph("<b>Normal</b>", bold_style),
Paragraph("<b>Bacterial Infection</b>", bold_style), Paragraph("<b>Viral Infection</b>", bold_style),
Paragraph("<b>Clinical Notes</b>", bold_style)],
["CRP", "< 10 mg/L", "> 100 mg/L (often)", "Mildly elevated (10-50)", "Rises within 6 hrs; best acute marker; produced in liver (IL-6 stimulus)"],
["ESR", "M: <20 / F: <30 mm/hr", "Elevated (non-specific)", "Elevated (non-specific)", "Slow to rise/fall; use for monitoring TB, arteritis, chronic disease"],
["Procalcitonin (PCT)", "< 0.1 ng/mL", "> 0.5 ng/mL strongly suggests bacterial; >2 = sepsis probable", "Usually <0.25 ng/mL", "More specific than CRP for bacterial vs viral; guides antibiotic stewardship"],
["Ferritin", "M: 20-500 / F: 12-300 µg/L", "Elevated (acute phase)", "May be very high in EBV, CMV", "Extreme elevation (>10,000) = haemophagocytic lymphohistiocytosis (HLH) or Adult Still's"],
["LDH", "140-280 U/L", "Elevated in tissue destruction", "Elevated in EBV, haemolysis", "High in haematological malignancy, haemolysis, liver disease"],
]
t_im = tbl(im_data, [22*mm, 28*mm, 44*mm, 38*mm, UW - 132*mm], [
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), NAVY),
("BACKGROUND", (0,3), (-1,3), YELLOW_LIGHT),
])
story.append(t_im)
story.append(Spacer(1, 8))
# Pattern recognition box
story.append(Paragraph("CBC PATTERN RECOGNITION AT A GLANCE", heading_style))
pat_data = [
[Paragraph("<b>CBC Pattern</b>", bold_style), Paragraph("<b>Think...</b>", bold_style)],
["Neutrophilia + high CRP + high PCT", "Bacterial infection - start targeted antibiotics"],
["Lymphocytosis + atypical lymphocytes + normal/low WBC", "Viral infection (EBV/CMV) - supportive care"],
["Leukopenia + thrombocytopenia + normal/low Hb", "Dengue fever - no NSAIDs, IV fluids, monitor"],
["Leukopenia + relative lymphocytosis + normal platelets", "Typhoid - blood cultures, azithromycin"],
["Neutrophilia + anaemia + thrombocytopenia", "Malaria (esp. falciparum) - blood film urgently"],
["Very high WBC (> 50,000) + all cell lines affected", "Rule out leukaemia - haematology referral"],
["Eosinophilia + fever + travel history", "Parasitic/helminth infection - serology, stool O&P"],
["Normal CBC + fever >38.5°C + no source", "Consider blood cultures, procalcitonin, urine MC&S"],
]
t_pat = tbl(pat_data, [75*mm, UW-75*mm], [
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), NAVY),
])
story.append(t_pat)
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════
# PAGE 3: TREATMENT FLOWCHART + TREATMENT TABLE
# ════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 4))
story.append(SectionHeader(" CLINICAL DECISION FLOWCHART", UW, NAVY, fontsize=13))
story.append(Spacer(1, 8))
story.append(FlowchartBox(UW))
story.append(Spacer(1, 55)) # space for flowchart height
# Antipyretics
story.append(SectionHeader(" ANTIPYRETIC TREATMENT", UW, TEAL, fontsize=11))
story.append(Spacer(1, 5))
ap_data = [
[Paragraph("<b>Drug</b>", bold_style), Paragraph("<b>Adult Dose</b>", bold_style),
Paragraph("<b>Mechanism</b>", bold_style), Paragraph("<b>Precautions / Notes</b>", bold_style)],
["Paracetamol\n(Acetaminophen)", "500-1000 mg q4-6h\n(max 4g/day)", "Inhibits PGE2 centrally; weak peripheral COX inhibition",
"FIRST-LINE. Safe in pregnancy, elderly. Caution: hepatic impairment. Do NOT exceed 4g/day."],
["Ibuprofen\n(NSAID)", "400 mg q6-8h\n(max 1200 mg/day OTC)", "COX-1/COX-2 inhibitor → blocks prostaglandin synthesis",
"Anti-inflammatory benefit. AVOID: renal disease, GI ulcers, pregnancy (3rd trimester), dengue, dehydration."],
["Aspirin", "325-650 mg q4-6h", "COX inhibitor; decreases PGE2", "AVOID in children <16 yrs (Reye syndrome risk). AVOID in dengue (bleeding risk)."],
["Tepid sponging\n+ cooling blanket", "For temp > 41°C", "Physical heat dissipation (conduction/evaporation)", "Use alongside antipyretics for hyperpyrexia. Fan + misting also effective."],
]
t_ap = tbl(ap_data, [30*mm, 32*mm, 52*mm, UW-114*mm], [
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("BACKGROUND", (0,1), (-1,1), GREEN_LIGHT),
])
story.append(t_ap)
story.append(Spacer(1, 8))
# Specific treatments
story.append(SectionHeader(" SPECIFIC TREATMENT BY DIAGNOSIS", UW, NAVY, fontsize=11))
story.append(Spacer(1, 5))
tx_data = [
[Paragraph("<b>Diagnosis</b>", bold_style), Paragraph("<b>First-Line Treatment</b>", bold_style),
Paragraph("<b>Duration / Notes</b>", bold_style)],
["Viral URTI", "Supportive: rest, hydration, paracetamol/ibuprofen", "No antibiotics. Zinc lozenges may shorten duration."],
["Strep Pharyngitis (GAS)", "Amoxicillin 500 mg TID OR Penicillin V 500 mg BD", "10 days. Prevents rheumatic fever & peritonsillar abscess."],
["Influenza", "Oseltamivir (Tamiflu) 75 mg BD x 5 days (within 48 hrs)", "Prioritise: elderly, immunocompromised, pregnancy, comorbidities."],
["COVID-19 (high-risk)", "Nirmatrelvir/ritonavir (Paxlovid) within 5 days of symptoms", "Check drug interactions. Supportive care for mild/low-risk."],
["UTI (Cystitis)", "Trimethoprim 200 mg BD x 3-7d OR Nitrofurantoin 100 mg BD x 5-7d", "Send MSU for MC&S first. Adjust per sensitivity."],
["Pyelonephritis", "Co-amoxiclav 625 mg TID x 14d OR Ciprofloxacin 500 mg BD x 7-10d", "IV antibiotics if vomiting/severe. Admit if systemic sepsis."],
["CAP (mild)", "Amoxicillin 500 mg TID x 5d (+ Clarithromycin if atypical)", "CURB-65 score: 0-1 = community; 2+ = hospital consider."],
["Gastroenteritis (bacterial)", "Rehydration (ORS). Azithromycin/Ciprofloxacin if severe/bloody", "Most self-limiting. Bloody + systemic = treat. Avoid loperamide."],
["Malaria (P. falciparum)", "Artemether-lumefantrine (Coartem) x 3 days", "URGENT. Admit if severe. P. vivax: Chloroquine + Primaquine."],
["Dengue", "Supportive ONLY: IV fluids, paracetamol (strictly)", "NO NSAIDs/aspirin (bleeding risk). Monitor platelets daily."],
["Typhoid", "Azithromycin 500 mg OD x 7d (mild/outpatient)", "Ceftriaxone IV for severe. Based on local resistance patterns."],
["Cellulitis", "Flucloxacillin 500 mg QID x 5-7d (Clarithromycin if pen-allergic)", "Mark border with pen. IV if systemically unwell or spreading."],
["Sepsis (empirical)", "IV Piperacillin-tazobactam OR Meropenem + source control", "SEPSIS 6 bundle: cultures, lactate, fluids, abx, O2, urine output."],
["Meningitis (empirical)", "Ceftriaxone 2g IV + Dexamethasone IV immediately", "Do NOT delay for LP if clinically suspected."],
]
t_tx = tbl(tx_data, [35*mm, 73*mm, UW-108*mm], [
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), TEAL),
("BACKGROUND", (0,13), (-1,13), RED_LIGHT),
("BACKGROUND", (0,14), (-1,14), RED_LIGHT),
("TEXTCOLOR", (0,13), (0,14), RED),
])
story.append(t_tx)
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════
# PAGE 4: INVESTIGATIONS + RED FLAGS + FUO
# ════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 4))
story.append(SectionHeader(" INVESTIGATIONS TO ORDER BY SUSPECTED DIAGNOSIS", UW, NAVY, fontsize=12))
story.append(Spacer(1, 5))
inv_data = [
[Paragraph("<b>Suspected Diagnosis</b>", bold_style), Paragraph("<b>First-Line Investigations</b>", bold_style),
Paragraph("<b>Additional / Confirmatory Tests</b>", bold_style)],
["All febrile patients", "CBC + differential, CRP, ESR, temperature chart", "Add procalcitonin if bacterial vs viral unclear"],
["UTI / Pyelonephritis", "Urine dipstick, urinalysis (microscopy)", "Urine MC&S (mid-stream); renal USS if pyelonephritis"],
["Pneumonia (CAP)", "Chest X-ray (CXR), pulse oximetry", "Sputum culture + sensitivity, blood cultures (if severe), CURB-65"],
["Sepsis (any source)", "Blood cultures x 2 (before antibiotics), serum lactate", "CXR, urinalysis, CBC, LFTs, coagulation, ECG"],
["Malaria", "Thick + thin blood film (gold standard)", "Rapid antigen test (RDT); repeat film if first negative"],
["Dengue", "CBC (thrombocytopenia!), dengue NS1 antigen (days 1-5)", "IgM/IgG serology after day 5; LFTs"],
["Typhoid", "Blood cultures (most sensitive week 1)", "Widal test (limited specificity); stool culture week 2-3"],
["Influenza / COVID-19", "Rapid antigen test (nasopharyngeal swab)", "PCR (more sensitive); CXR if lower respiratory symptoms"],
["EBV (Mono)", "CBC (lymphocytosis, atypical lymphs), Monospot test", "EBV IgM/IgG, LFTs, throat swab"],
["TB (suspected)", "CXR (apical cavitation), sputum AFB smear x 3", "Sputum culture (6-8 wks), IGRA/Mantoux, NAAT (GeneXpert)"],
["Endocarditis", "Blood cultures x 3 (different sites, before abx)", "Echocardiogram (TTE first, then TEE), ESR, CRP"],
["Meningitis", "Blood cultures, blood glucose", "LP (CSF: microscopy, culture, glucose, protein, PCR); CT first if focal neuro signs"],
["SLE / Autoimmune", "ANA (screening), full CBC, ESR, CRP, urinalysis", "Anti-dsDNA, complement (C3/C4), RF, anti-CCP; renal function"],
["Malignancy (FUO)", "CBC, LDH, ferritin, protein electrophoresis, LFTs", "CT chest/abdomen/pelvis, PET scan, bone marrow biopsy"],
]
t_inv = tbl(inv_data, [38*mm, 68*mm, UW-106*mm], [
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), TEAL),
("BACKGROUND", (0,1), (-1,1), TEAL_LIGHT),
])
story.append(t_inv)
story.append(Spacer(1, 10))
# RED FLAGS
story.append(SectionHeader(" RED FLAG FEATURES - IMMEDIATE ESCALATION / 999", UW, RED, fontsize=12))
story.append(Spacer(1, 5))
rf_left = [
"Temperature > 41°C (hyperpyrexia)",
"Petechiae or purpuric rash (meningococcemia?)",
"Neck stiffness, photophobia, altered GCS (meningitis)",
"Severe tachycardia (>120 bpm), hypotension, SBP <90",
"Respiratory distress, SpO2 < 94% on air",
"Rigors + high fever in returning traveller (malaria)",
]
rf_right = [
"Thrombocytopenia + rash + fever (dengue, RMSF)",
"Immunocompromised patient with ANY fever",
"Elderly + fever + new confusion (delirium = sepsis until proven otherwise)",
"Fever + focal neurological signs",
"Newborn / infant < 3 months with any fever",
"Fever > 7 days without a clear source (FUO - investigate)",
]
rf_data = []
for i in range(len(rf_left)):
rf_data.append([
Paragraph(f"<b>►</b> {rf_left[i]}", S("rf", fontSize=8.5, textColor=RED, fontName="Helvetica")),
Paragraph(f"<b>►</b> {rf_right[i]}", S("rf2", fontSize=8.5, textColor=RED, fontName="Helvetica")),
])
t_rf = Table(rf_data, colWidths=[UW/2 - 3*mm, UW/2 - 3*mm])
t_rf.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), RED_LIGHT),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("LINEBELOW", (0,0), (-1,-2), 0.3, colors.HexColor("#FFCDD2")),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(t_rf)
story.append(Spacer(1, 10))
# FUO
story.append(SectionHeader(" FEVER OF UNKNOWN ORIGIN (FUO)", UW, GREY, fontsize=11))
story.append(Spacer(1, 5))
fuo_def = Paragraph(
"<b>Definition:</b> Temperature >38.3°C on >3 occasions, lasting >3 weeks, not diagnosed after 1 week of thorough investigation.",
S("fuodef", fontSize=8.5, textColor=NAVY, fontName="Helvetica")
)
story.append(fuo_def)
story.append(Spacer(1, 5))
fuo_data = [
[Paragraph("<b>Category</b>", bold_style), Paragraph("<b>Frequency</b>", bold_style),
Paragraph("<b>Examples</b>", bold_style), Paragraph("<b>Key Investigations</b>", bold_style)],
["Infectious", "30-40%", "TB (most common), infective endocarditis, intra-abdominal abscess, CMV, EBV, brucellosis",
"Blood cultures, IGRA, ECHO, CT abdomen, serology"],
["Malignancy", "20-30%", "Hodgkin's lymphoma, Non-Hodgkin's lymphoma, leukaemia, renal cell carcinoma, hepatoma",
"LDH, ferritin, CT chest/abdomen/pelvis, PET scan, bone marrow biopsy"],
["Autoimmune / Inflammatory", "10-20%", "Adult-onset Still's disease, SLE, giant cell arteritis, vasculitis, RA, sarcoidosis, IBD",
"ANA, ANCA, ferritin (very high in Still's), ESR, CRP, temporal artery biopsy"],
["Miscellaneous / Undiagnosed", "Up to 25%", "Drug fever, factitious fever, periodic fever syndromes, Kikuchi disease",
"Medication review, genetic testing for periodic syndromes"],
]
t_fuo = tbl(fuo_data, [30*mm, 20*mm, 78*mm, UW-128*mm], [
("BACKGROUND", (0,0), (-1,0), GREY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), NAVY),
])
story.append(t_fuo)
story.append(Spacer(1, 8))
# GP Quick Reminder
story.append(SectionHeader(" GP QUICK REMINDER", UW, GREEN, fontsize=11))
story.append(Spacer(1, 5))
reminder_data = [
["1.", "Always take travel history, medication history, immunosuppression status, vaccination history, and TB contacts."],
["2.", "Blood cultures MUST be drawn BEFORE starting antibiotics in any severe/undiagnosed fever."],
["3.", "A normal CBC does NOT exclude serious infection - clinical picture is paramount."],
["4.", "In dengue and malaria, avoid NSAIDs and aspirin - use paracetamol only."],
["5.", "Children < 3 months with any fever (> 38.0°C) need urgent assessment."],
["6.", "Fever + petechiae = meningococcemia until proven otherwise - treat empirically and call 999."],
["7.", "Review all febrile patients who do not improve within 48-72 hours."],
["8.", "In elderly patients, fever may be absent or blunted despite serious infection - have a low threshold."],
]
for row in reminder_data:
reminder_data_row = [
Paragraph(f"<b>{row[0]}</b>", S("rn", fontSize=9, textColor=GREEN, fontName="Helvetica-Bold")),
Paragraph(row[1], S("rb", fontSize=8.5, textColor=BLACK))
]
t_rem = Table([[
Paragraph(f"<b>{row[0]}</b>", S(f"rn{i}", fontSize=9, textColor=GREEN, fontName="Helvetica-Bold")),
Paragraph(row[1], S(f"rb{i}", fontSize=8.5, textColor=BLACK))
] for i, row in enumerate(reminder_data)], colWidths=[8*mm, UW-8*mm])
t_rem.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREEN_LIGHT),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("LINEBELOW", (0,0), (-1,-2), 0.3, colors.HexColor("#C8E6C9")),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(t_rem)
# Build PDF
doc.build(story, onFirstPage=on_first_page, onLaterPages=on_later_pages)
print(f"PDF saved to: {OUTPUT}")
if __name__ == "__main__":
build()
cd /home/daytona/workspace/fever-quickref && python3 build_pdf.py 2>&1
~/fever-quickref/build_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/fever-quickref/build_pdf.py'
cd /home/daytona/workspace/fever-quickref && python3 build_pdf.py 2>&1
~/fever-quickref/build_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/fever-quickref/build_pdf.py'
cd /home/daytona/workspace/fever-quickref && python3 build_pdf.py 2>&1
ls -lh /home/daytona/workspace/fever-quickref/Fever_Quick_Reference_GP.pdf
Fever Quick Reference GP
PDF Document · PDF
| Page | Content |
|---|---|
| 1 | Definition & pathophysiology box, Infectious DDx table by system (nonemergent / emergent / life-threatening), Non-infectious causes (critical / emergent / non-urgent), Common GP presentations with fever pattern and distinguishing features |
| 2 | Full CBC interpretation - WBC count, differential (neutrophils, lymphocytes, monocytes, eosinophils, bands/"shift to left"), RBC/Hb/platelets, inflammatory markers (CRP, ESR, PCT, ferritin, LDH), and a CBC pattern recognition quick-look table |
| 3 | Clinical decision flowchart (febrile patient → history → red flags → CBC → bacterial vs viral branch), Antipyretic table (paracetamol / ibuprofen / aspirin with doses and contraindications), Specific treatment table for 14 diagnoses |
| 4 | Investigations by suspected diagnosis (17 conditions), Red flags panel for immediate escalation, FUO definition and causes, GP Quick Reminders checklist |
Generate a treatment protocol checklist document (DOCX) for practice wall display
ls /home/daytona/skills/docx/scripts/office/ && node --version && npm list -g do…
~/fever-quickref/build_checklist.js
// Fever Treatment Protocol Checklist - GP Practice Wall Display
// A4 Landscape, 2-column layout, colour-coded sections
const {
Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
Header, Footer, AlignmentType, PageOrientation, HeadingLevel,
BorderStyle, WidthType, ShadingType, VerticalAlign, PageNumber,
PageBreak, TabStopType, TabStopPosition, TableLayoutType
} = require('docx');
const fs = require('fs');
// ── Colour Palette ──────────────────────────────────────────────────────────
const NAVY = "1A2E4A";
const TEAL = "00838F";
const TEAL_LIGHT = "E0F4F5";
const RED = "C62828";
const RED_LIGHT = "FFEBEE";
const ORANGE = "E65100";
const ORANGE_LIGHT= "FFF3E0";
const GREEN = "2E7D32";
const GREEN_LIGHT = "E8F5E9";
const YELLOW_LIGHT= "FFFDE7";
const GREY = "546E7A";
const GREY_LIGHT = "ECEFF1";
const WHITE = "FFFFFF";
const BLACK = "000000";
// ── Helpers ─────────────────────────────────────────────────────────────────
const NO_BORDER = { style: BorderStyle.NONE, size: 0, color: "FFFFFF" };
const THIN_BORDER = (col) => ({ style: BorderStyle.SINGLE, size: 4, color: col || "B0BEC5" });
function shading(fill, type = ShadingType.CLEAR) {
return { type, fill, color: "auto" };
}
function bold(text, color = BLACK, size = 18) {
return new TextRun({ text, bold: true, color, size });
}
function run(text, opts = {}) {
return new TextRun({ text, size: opts.size || 17, color: opts.color || BLACK,
bold: opts.bold || false, italics: opts.italics || false });
}
function cell(children, opts = {}) {
return new TableCell({
children: Array.isArray(children) ? children : [
new Paragraph({
children: Array.isArray(children[0]) ? children[0] : children,
alignment: opts.align || AlignmentType.LEFT,
spacing: { before: 30, after: 30 },
})
],
shading: opts.bg ? shading(opts.bg) : undefined,
verticalAlign: VerticalAlign.CENTER,
margins: { top: 60, bottom: 60, left: 80, right: 80 },
borders: opts.borders || {
top: THIN_BORDER(opts.borderColor),
bottom: THIN_BORDER(opts.borderColor),
left: THIN_BORDER(opts.borderColor),
right: THIN_BORDER(opts.borderColor),
},
columnSpan: opts.span,
width: opts.width ? { size: opts.width, type: WidthType.DXA } : undefined,
});
}
function para(children, opts = {}) {
return new Paragraph({
children: Array.isArray(children) ? children : [children],
alignment: opts.align || AlignmentType.LEFT,
spacing: { before: opts.before || 40, after: opts.after || 40 },
indent: opts.indent ? { left: opts.indent } : undefined,
});
}
function hdr(text, bg = NAVY, fg = WHITE, size = 20) {
return new TableRow({
children: [
new TableCell({
children: [new Paragraph({
children: [new TextRun({ text: ` ${text}`, bold: true, color: fg, size, allCaps: false })],
alignment: AlignmentType.LEFT,
spacing: { before: 60, after: 60 },
})],
shading: shading(bg),
columnSpan: 99,
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER },
margins: { top: 60, bottom: 60, left: 120, right: 80 },
})
],
tableHeader: true,
});
}
// Checkbox character (unicode ballot box)
const CHK = "\u2610"; // empty checkbox
const BULL = "\u25BA"; // filled bullet
// ── Section builder: numbered checklist rows ─────────────────────────────────
function checkRow(number, action, detail, bg = WHITE, bold_action = true) {
return new TableRow({
children: [
cell(
[new TextRun({ text: ` ${CHK}`, size: 20, color: TEAL, bold: true })],
{ bg, width: 400, borders: { top: NO_BORDER, bottom: THIN_BORDER("E0F4F5"), left: NO_BORDER, right: NO_BORDER } }
),
cell(
[new TextRun({ text: `${number}. `, bold: true, size: 17, color: GREY }),
new TextRun({ text: action, bold: bold_action, size: 17, color: NAVY })],
{ bg, width: 2500, borders: { top: NO_BORDER, bottom: THIN_BORDER("E0F4F5"), left: NO_BORDER, right: NO_BORDER } }
),
cell(
[new TextRun({ text: detail, size: 16, color: BLACK })],
{ bg, borders: { top: NO_BORDER, bottom: THIN_BORDER("E0F4F5"), left: NO_BORDER, right: NO_BORDER } }
),
],
});
}
function diagRow(diagnosis, treatment, dose, notes, rowBg = WHITE) {
return new TableRow({
children: [
cell([bold(`${CHK} `, TEAL, 18), bold(diagnosis, NAVY, 17)],
{ bg: rowBg, borderColor: "CFD8DC" }),
cell([run(treatment, { bold: true, color: TEAL, size: 17 })],
{ bg: rowBg, borderColor: "CFD8DC" }),
cell([run(dose, { size: 16, color: "37474F" })],
{ bg: rowBg, borderColor: "CFD8DC" }),
cell([run(notes, { size: 15, color: GREY, italics: true })],
{ bg: rowBg, borderColor: "CFD8DC" }),
],
});
}
function redFlagRow(text) {
return new TableRow({
children: [
cell(
[new TextRun({ text: " ! ", bold: true, color: RED, size: 20 }),
new TextRun({ text, size: 17, color: RED, bold: true })],
{ bg: RED_LIGHT, borders: { top: NO_BORDER, bottom: THIN_BORDER("FFCDD2"), left: THIN_BORDER(RED), right: NO_BORDER } }
)
]
});
}
// ── Page-width table wrapper (for 2-column look per section) ──────────────────
function sectionTable(rows, widths) {
return new Table({
rows,
width: { size: 100, type: WidthType.PERCENTAGE },
columnWidths: widths,
layout: TableLayoutType.FIXED,
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER,
insideH: NO_BORDER, insideV: NO_BORDER },
});
}
// ════════════════════════════════════════════════════════════════════════════
// BUILD DOCUMENT
// ════════════════════════════════════════════════════════════════════════════
const children = [];
// ── BANNER / TITLE ────────────────────────────────────────────────────────────
children.push(new Table({
rows: [
new TableRow({ children: [
new TableCell({
children: [
new Paragraph({ children: [new TextRun({ text: "FEVER TREATMENT PROTOCOL CHECKLIST", bold: true, color: WHITE, size: 40, allCaps: true })], alignment: AlignmentType.CENTER, spacing: { before: 80, after: 20 } }),
new Paragraph({ children: [new TextRun({ text: "General Practice | Wall Display Reference | Updated 2025/26", color: "B2EBF2", size: 18, italics: true })], alignment: AlignmentType.CENTER, spacing: { before: 0, after: 80 } }),
],
shading: shading(NAVY),
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER },
margins: { top: 120, bottom: 120, left: 200, right: 200 },
})
]})
],
width: { size: 100, type: WidthType.PERCENTAGE },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER },
}));
children.push(para([new TextRun({ text: "", size: 8 })], { before: 100, after: 0 }));
// ── TEAL INFO STRIP ────────────────────────────────────────────────────────────
children.push(new Table({
rows: [new TableRow({ children: [
cell([bold("DEFINITION:", TEAL, 16), run(" Fever = Core Temp > 38.0°C | Hyperpyrexia = > 41°C (treat urgently)", { size: 16 })],
{ bg: TEAL_LIGHT }),
cell([bold("TREAT FEVER IF:", TEAL, 16), run(" > 41°C (mandatory) | Patient discomfort | Paediatric seizure risk", { size: 16 })],
{ bg: TEAL_LIGHT }),
]})],
width: { size: 100, type: WidthType.PERCENTAGE },
columnWidths: [7000, 7000],
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER },
}));
children.push(para([new TextRun({ text: "", size: 8 })], { before: 60, after: 0 }));
// ════════════════════════════════════════════════════════════════════════════
// SECTION A: INITIAL ASSESSMENT CHECKLIST
// ════════════════════════════════════════════════════════════════════════════
const assessRows = [
hdr("SECTION A | INITIAL ASSESSMENT - DO FIRST", NAVY, WHITE, 19),
checkRow(1, "Measure temperature", "Oral/tympanic preferred. Temp > 41°C = hyperpyrexia - act immediately", GREY_LIGHT),
checkRow(2, "Vital signs", "HR, BP, RR, SpO2, GCS. Tachycardia >120 + hypotension = SEPSIS - escalate", WHITE),
checkRow(3, "Full history", "Onset, duration, pattern, associated symptoms, travel, sick contacts, medications, immunocompromise", GREY_LIGHT),
checkRow(4, "Targeted examination", "Throat, ears, chest, abdomen, skin, lymph nodes, neuro, CVA tenderness", WHITE),
checkRow(5, "Red flags screen", "See RED FLAGS panel below - if ANY present, escalate immediately", GREY_LIGHT),
checkRow(6, "Age & comorbidities", "Elderly (blunted fever), immunocompromised, pregnancy, <3 months - all need lower threshold", WHITE),
];
children.push(new Table({
rows: assessRows,
width: { size: 100, type: WidthType.PERCENTAGE },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER },
}));
children.push(para([new TextRun({ text: "", size: 8 })], { before: 80, after: 0 }));
// ════════════════════════════════════════════════════════════════════════════
// SECTION B: INVESTIGATIONS CHECKLIST | RED FLAGS (2-column)
// ════════════════════════════════════════════════════════════════════════════
const invRows = [
hdr("SECTION B | INVESTIGATIONS TO ORDER", TEAL, WHITE, 18),
checkRow(1, "CBC with differential", "WBC, neutrophils, lymphocytes, bands, Hb, platelets"),
checkRow(2, "CRP + ESR + Procalcitonin", "CRP >100 = bacterial likely | PCT >0.5 = bacterial | PCT >2 = sepsis probable", GREY_LIGHT),
checkRow(3, "Urine dipstick + MC&S", "Order if any urinary symptoms OR fever without clear source", WHITE),
checkRow(4, "Chest X-ray", "If cough, dyspnoea, pleuritic pain, SpO2 low, elderly with fever", GREY_LIGHT),
checkRow(5, "Blood cultures x2", "MUST be drawn BEFORE antibiotics in any severe or undiagnosed fever", WHITE),
checkRow(6, "Blood film (malaria)", "Any fever + travel to endemic region - urgent", GREY_LIGHT),
checkRow(7, "Dengue NS1/IgM/IgG", "If dengue suspected (thrombocytopenia + retro-orbital pain + rash)", WHITE),
checkRow(8, "Rapid Ag test", "Influenza / COVID-19 NP swab - guide isolation and antiviral use", GREY_LIGHT),
checkRow(9, "LFTs + serum lactate", "If hepatitis suspected, jaundice, or sepsis (lactate >2 = organ dysfunction)", WHITE),
checkRow(10, "Further targeted tests", "ANA/dsDNA (autoimmune) | LDH/ferritin (malignancy/HLH) | IGRA/CXR (TB)", GREY_LIGHT),
];
const rfRows = [
hdr("RED FLAGS | IMMEDIATE ESCALATION / 999", RED, WHITE, 18),
redFlagRow("Temperature > 41°C (hyperpyrexia)"),
redFlagRow("Petechiae or purpuric rash - meningococcemia?"),
redFlagRow("Neck stiffness + photophobia + altered GCS"),
redFlagRow("Severe tachycardia / hypotension (septic shock)"),
redFlagRow("SpO2 < 94% on air / respiratory distress"),
redFlagRow("Rigors + fever in returning traveller (malaria)"),
redFlagRow("Thrombocytopenia + rash + fever"),
redFlagRow("Immunocompromised + ANY fever"),
redFlagRow("Elderly + fever + new confusion"),
redFlagRow("Infant < 3 months with any fever (> 38.0°C)"),
];
children.push(new Table({
rows: [new TableRow({ children: [
new TableCell({
children: [new Table({ rows: invRows, width: { size: 100, type: WidthType.PERCENTAGE },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER } })],
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: THIN_BORDER("E0E0E0"), right: NO_BORDER },
margins: { right: 200 },
}),
new TableCell({
children: [new Table({ rows: rfRows, width: { size: 100, type: WidthType.PERCENTAGE },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER } })],
borders: { top: NO_BORDER, bottom: NO_BORDER, left: THIN_BORDER("E0E0E0"), right: NO_BORDER },
margins: { left: 200 },
}),
]})],
width: { size: 100, type: WidthType.PERCENTAGE },
columnWidths: [7200, 6800],
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER },
}));
children.push(para([new TextRun({ text: "", size: 8 })], { before: 80, after: 0 }));
// ════════════════════════════════════════════════════════════════════════════
// SECTION C: CBC QUICK INTERPRETATION
// ════════════════════════════════════════════════════════════════════════════
const cbcData = [
hdr("SECTION C | CBC QUICK INTERPRETATION", NAVY, WHITE, 18),
new TableRow({ children: [
cell([bold("CBC Finding", WHITE, 16)], { bg: TEAL }),
cell([bold("Pattern", WHITE, 16)], { bg: TEAL }),
cell([bold("Interpretation", WHITE, 16)], { bg: TEAL }),
cell([bold("Action", WHITE, 16)], { bg: TEAL }),
]}),
new TableRow({ children: [
cell([bold("Neutrophilia", NAVY, 16), run(" (WBC > 11k, Neut > 70%)", { size: 15 })], { bg: YELLOW_LIGHT }),
cell([run("+ High CRP/PCT", { bold: true, color: ORANGE, size: 16 })], { bg: YELLOW_LIGHT }),
cell([run("Bacterial infection / acute inflammation / stress", { size: 16 })], { bg: YELLOW_LIGHT }),
cell([run("Target antibiotics; blood cultures before Rx", { bold: true, size: 16 })], { bg: YELLOW_LIGHT }),
]}),
new TableRow({ children: [
cell([bold("Lymphocytosis", NAVY, 16), run(" (Lymph > 40%)", { size: 15 })], { bg: WHITE }),
cell([run("Normal/Low WBC", { bold: true, color: GREEN, size: 16 })], { bg: WHITE }),
cell([run("Viral infection (EBV, CMV, rubella, influenza)", { size: 16 })], { bg: WHITE }),
cell([run("Supportive care; antivirals if indicated", { bold: true, size: 16 })], { bg: WHITE }),
]}),
new TableRow({ children: [
cell([bold("Leukopenia", NAVY, 16), run(" (WBC < 4k)", { size: 15 })], { bg: GREY_LIGHT }),
cell([run("Low platelets too", { bold: true, color: RED, size: 16 })], { bg: GREY_LIGHT }),
cell([run("Dengue fever (hallmark: WBC + platelets both low)", { size: 16 })], { bg: GREY_LIGHT }),
cell([run("No NSAIDs/aspirin - paracetamol + IV fluids only", { bold: true, color: RED, size: 16 })], { bg: GREY_LIGHT }),
]}),
new TableRow({ children: [
cell([bold("Leukopenia", NAVY, 16), run(" (WBC < 4k)", { size: 15 })], { bg: WHITE }),
cell([run("Relative lymphocytosis", { bold: true, color: GREY, size: 16 })], { bg: WHITE }),
cell([run("Typhoid (Salmonella typhi - week 1)", { size: 16 })], { bg: WHITE }),
cell([run("Blood cultures (gold standard); azithromycin", { bold: true, size: 16 })], { bg: WHITE }),
]}),
new TableRow({ children: [
cell([bold("Bands > 5%", NAVY, 16), run(" ('Shift to Left')", { size: 15 })], { bg: YELLOW_LIGHT }),
cell([run("+ Neutrophilia", { bold: true, color: ORANGE, size: 16 })], { bg: YELLOW_LIGHT }),
cell([run("Active bacterial infection - immature neutrophils released from marrow", { size: 16 })], { bg: YELLOW_LIGHT }),
cell([run("Start empirical antibiotics; identify source", { bold: true, size: 16 })], { bg: YELLOW_LIGHT }),
]}),
new TableRow({ children: [
cell([bold("Thrombocytopenia", RED, 16), run(" (Plt < 150k)", { size: 15 })], { bg: RED_LIGHT }),
cell([run("+ Fever + rash", { bold: true, color: RED, size: 16 })], { bg: RED_LIGHT }),
cell([run("Dengue, malaria, ITP, meningococcemia, HUS - RED FLAG", { size: 16, color: RED })], { bg: RED_LIGHT }),
cell([run("Urgent - hospital referral; avoid NSAIDs", { bold: true, color: RED, size: 16 })], { bg: RED_LIGHT }),
]}),
new TableRow({ children: [
cell([bold("Eosinophilia", NAVY, 16), run(" (> 4%)", { size: 15 })], { bg: WHITE }),
cell([run("+ Travel history", { bold: true, color: GREY, size: 16 })], { bg: WHITE }),
cell([run("Parasitic/helminth infection, schistosomiasis, strongyloides", { size: 16 })], { bg: WHITE }),
cell([run("Stool O&P, serology; antiparasitic treatment", { bold: true, size: 16 })], { bg: WHITE }),
]}),
new TableRow({ children: [
cell([bold("WBC > 50k", RED, 16), run(" (extreme)", { size: 15 })], { bg: RED_LIGHT }),
cell([run("All cell lines abnormal", { bold: true, color: RED, size: 16 })], { bg: RED_LIGHT }),
cell([run("Rule out leukaemia (leukemoid reaction vs leukaemia)", { size: 16, color: RED })], { bg: RED_LIGHT }),
cell([run("URGENT haematology referral + peripheral blood film", { bold: true, color: RED, size: 16 })], { bg: RED_LIGHT }),
]}),
];
children.push(new Table({
rows: cbcData,
width: { size: 100, type: WidthType.PERCENTAGE },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER },
}));
children.push(para([new TextRun({ text: "", size: 8 })], { before: 80, after: 0 }));
// ════════════════════════════════════════════════════════════════════════════
// SECTION D: TREATMENT PROTOCOL BY DIAGNOSIS
// ════════════════════════════════════════════════════════════════════════════
const txRows = [
hdr("SECTION D | TREATMENT PROTOCOL BY DIAGNOSIS", NAVY, WHITE, 18),
new TableRow({ children: [
cell([bold(" Diagnosis", WHITE, 16)], { bg: TEAL }),
cell([bold("First-Line Treatment", WHITE, 16)], { bg: TEAL }),
cell([bold("Dose / Duration", WHITE, 16)], { bg: TEAL }),
cell([bold("Key Notes", WHITE, 16)], { bg: TEAL }),
]}),
// ANTIPYRETICS
new TableRow({ children: [
new TableCell({
children: [new Paragraph({ children: [new TextRun({ text: "ANTIPYRETICS", bold: true, color: WHITE, size: 16 })], spacing: { before: 40, after: 40 } })],
shading: shading(TEAL),
columnSpan: 4,
margins: { left: 120 },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER },
})
]}),
diagRow("Paracetamol", "FIRST-LINE antipyretic", "500-1000 mg q4-6h (max 4g/day)", "Safe in pregnancy, elderly. Caution: hepatic impairment", GREEN_LIGHT),
diagRow("Ibuprofen", "Second-line / anti-inflammatory", "400 mg q6-8h (max 1200 mg/day)", "Avoid: renal disease, GI ulcers, pregnancy 3rd trim, dengue, dehydration"),
diagRow("Aspirin", "Avoid in most febrile patients", "325-650 mg q4-6h if used", "NEVER in children <16 (Reye syndrome). NEVER in dengue (bleeding risk)", RED_LIGHT),
// RESPIRATORY
new TableRow({ children: [
new TableCell({
children: [new Paragraph({ children: [new TextRun({ text: "RESPIRATORY INFECTIONS", bold: true, color: WHITE, size: 16 })], spacing: { before: 40, after: 40 } })],
shading: shading(TEAL),
columnSpan: 4,
margins: { left: 120 },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER },
})
]}),
diagRow("Viral URTI", "SUPPORTIVE CARE ONLY", "Rest, fluids, paracetamol/ibuprofen", "No antibiotics. Zinc lozenges may shorten duration", GREY_LIGHT),
diagRow("Strep Pharyngitis (GAS)", "Amoxicillin", "500 mg TID x 10 days (or Penicillin V 500 mg BD)", "Prevents rheumatic fever. Clarithromycin if penicillin-allergic"),
diagRow("Influenza", "Oseltamivir (Tamiflu)", "75 mg BD x 5 days (start within 48 hrs)", "Prioritise: elderly, immunocompromised, pregnant, comorbidities", GREY_LIGHT),
diagRow("COVID-19 (high risk)", "Nirmatrelvir/Ritonavir (Paxlovid)", "Within 5 days of symptom onset", "Check drug interactions. Supportive Rx for low-risk/mild."),
diagRow("CAP - Mild", "Amoxicillin", "500 mg TID x 5 days + Clarithromycin if atypical", "CURB-65: 0-1 = community; 2+ = consider hospital", GREY_LIGHT),
diagRow("CAP - Moderate/Severe", "Amoxicillin-clavulanate + Clarithromycin", "625 mg TID + 500 mg BD x 7-10 days", "ADMIT if CURB-65 >= 2, SpO2 <94%, elderly, no improvement in 48h"),
// URINARY
new TableRow({ children: [
new TableCell({
children: [new Paragraph({ children: [new TextRun({ text: "URINARY TRACT INFECTIONS", bold: true, color: WHITE, size: 16 })], spacing: { before: 40, after: 40 } })],
shading: shading(TEAL),
columnSpan: 4,
margins: { left: 120 },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER },
})
]}),
diagRow("UTI - Cystitis (women)", "Trimethoprim OR Nitrofurantoin", "200 mg BD x 3-7d / 100 mg BD x 5-7d", "Send MSU before Rx. Adjust per sensitivity. Avoid Nitrofurantoin in pyelonephritis", GREY_LIGHT),
diagRow("UTI - Cystitis (men)", "Trimethoprim", "200 mg BD x 7 days", "Always culture. MSU needed. Longer course than women."),
diagRow("Pyelonephritis", "Co-amoxiclav OR Ciprofloxacin", "625 mg TID x 14d / 500 mg BD x 7-10d", "IV antibiotics if vomiting/severe. Admit if systemically unwell", GREY_LIGHT),
// GI
new TableRow({ children: [
new TableCell({
children: [new Paragraph({ children: [new TextRun({ text: "GASTROINTESTINAL INFECTIONS", bold: true, color: WHITE, size: 16 })], spacing: { before: 40, after: 40 } })],
shading: shading(TEAL),
columnSpan: 4,
margins: { left: 120 },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER },
})
]}),
diagRow("Viral Gastroenteritis", "SUPPORTIVE - ORS rehydration", "ORS 200-400 mL after each loose stool", "Most self-limiting 3-5 days. Avoid loperamide in bloody diarrhoea", GREY_LIGHT),
diagRow("Bacterial Gastroenteritis", "Azithromycin OR Ciprofloxacin", "500 mg OD x 3d / 500 mg BD x 3d (if severe/bloody)", "Stool culture first. Not all need antibiotics."),
diagRow("Typhoid (mild/outpatient)", "Azithromycin", "500 mg OD x 7 days", "Ceftriaxone IV for severe. Base on local resistance patterns", GREY_LIGHT),
// TROPICAL
new TableRow({ children: [
new TableCell({
children: [new Paragraph({ children: [new TextRun({ text: "TROPICAL & VECTOR-BORNE INFECTIONS", bold: true, color: WHITE, size: 16 })], spacing: { before: 40, after: 40 } })],
shading: shading(TEAL),
columnSpan: 4,
margins: { left: 120 },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER },
})
]}),
diagRow("Malaria - P. falciparum", "Artemether-Lumefantrine (Coartem)", "Weight-based dosing x 3 days (6 doses)", "URGENT. Admit if severe. IV artesunate for severe malaria", GREY_LIGHT),
diagRow("Malaria - P. vivax/ovale", "Chloroquine + Primaquine", "Chloroquine 25 mg/kg over 3 days; Primaquine 15 mg OD x 14d", "Check G6PD before primaquine (haemolysis risk)"),
diagRow("Dengue Fever", "SUPPORTIVE ONLY", "Paracetamol + IV fluids. Strict fluid balance.", "NO NSAIDs/aspirin. Monitor platelets daily. Admit if platelets <100k or warning signs", RED_LIGHT),
// SKIN
new TableRow({ children: [
new TableCell({
children: [new Paragraph({ children: [new TextRun({ text: "SKIN & SOFT TISSUE INFECTIONS", bold: true, color: WHITE, size: 16 })], spacing: { before: 40, after: 40 } })],
shading: shading(TEAL),
columnSpan: 4,
margins: { left: 120 },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER },
})
]}),
diagRow("Cellulitis", "Flucloxacillin", "500 mg QID x 5-7 days (Clarithromycin if pen-allergic)", "Mark border with pen. IV if spreading, systemically unwell, or facial", GREY_LIGHT),
diagRow("Soft Tissue Abscess", "Incision & Drainage (I&D)", "Antibiotics: Flucloxacillin 500 mg QID if systemically unwell", "Most abscesses heal with I&D alone. Consider MRSA risk."),
// EMERGENCIES
new TableRow({ children: [
new TableCell({
children: [new Paragraph({ children: [new TextRun({ text: "EMERGENCIES (START IMMEDIATELY - DO NOT DELAY)", bold: true, color: WHITE, size: 16 })], spacing: { before: 40, after: 40 } })],
shading: shading(RED),
columnSpan: 4,
margins: { left: 120 },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER },
})
]}),
diagRow("Bacterial Meningitis", "Ceftriaxone 2g IV + Dexamethasone IV", "IMMEDIATELY. Do NOT wait for LP.", "Call 999. Do NOT delay treatment for imaging.", RED_LIGHT),
diagRow("Sepsis", "IV Piperacillin-Tazobactam OR Meropenem", "Pip-taz 4.5g IV q8h / Meropenem 1g IV q8h", "SEPSIS 6: cultures, lactate, fluids (30mL/kg), O2, urine output, abx within 1 hr", RED_LIGHT),
diagRow("Meningococcemia", "Benzylpenicillin IM/IV + 999", "1.2g IM immediately then transfer", "Do NOT wait. Give antibiotics in GP before ambulance arrives", RED_LIGHT),
];
children.push(new Table({
rows: txRows,
width: { size: 100, type: WidthType.PERCENTAGE },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER },
}));
children.push(para([new TextRun({ text: "", size: 8 })], { before: 80, after: 0 }));
// ════════════════════════════════════════════════════════════════════════════
// SECTION E: FUO + SPECIAL POPULATIONS (2-column)
// ════════════════════════════════════════════════════════════════════════════
const fuoRows = [
hdr("FEVER OF UNKNOWN ORIGIN (FUO)", GREY, WHITE, 17),
new TableRow({ children: [
cell([bold("Definition:", NAVY, 16), run(" Fever >38.3°C on >3 occasions, >3 weeks, undiagnosed after 1 week investigation", { size: 16 })],
{ bg: GREY_LIGHT, borderColor: "B0BEC5" })
]}),
new TableRow({ children: [
cell([bold("Infections (30-40%): ", TEAL, 16), run("TB, endocarditis, intra-abdominal abscess, CMV, EBV, brucellosis", { size: 16 })],
{ bg: WHITE, borderColor: "B0BEC5" })
]}),
new TableRow({ children: [
cell([bold("Malignancy (20-30%): ", NAVY, 16), run("Lymphoma (Hodgkin's/NHL), leukaemia, RCC, hepatoma", { size: 16 })],
{ bg: GREY_LIGHT, borderColor: "B0BEC5" })
]}),
new TableRow({ children: [
cell([bold("Autoimmune (10-20%): ", ORANGE, 16), run("Adult Still's disease (ferritin >10k!), SLE, GCA, vasculitis, RA, sarcoidosis", { size: 16 })],
{ bg: WHITE, borderColor: "B0BEC5" })
]}),
new TableRow({ children: [
cell([bold("Misc/Undiagnosed (25%): ", GREY, 16), run("Drug fever, factitious, periodic fever syndromes - review ALL medications", { size: 16 })],
{ bg: GREY_LIGHT, borderColor: "B0BEC5" })
]}),
new TableRow({ children: [
cell([bold("FUO Workup: ", TEAL, 16), run("CT C/A/P, PET scan, echocardiogram, bone marrow biopsy, ANA/ANCA, LDH, ferritin, IGRA", { size: 16 })],
{ bg: TEAL_LIGHT, borderColor: "B0BEC5" })
]}),
];
const remRows = [
hdr("GP QUICK REMINDERS", GREEN, WHITE, 17),
new TableRow({ children: [
cell([new TextRun({ text: `${CHK} `, color: GREEN, bold: true, size: 18 }), run("Blood cultures BEFORE antibiotics in any severe fever", { bold: true, size: 16 })],
{ bg: GREEN_LIGHT, borderColor: "C8E6C9" })
]}),
new TableRow({ children: [
cell([new TextRun({ text: `${CHK} `, color: GREEN, bold: true, size: 18 }), run("Normal CBC does NOT exclude serious infection", { bold: true, size: 16 })],
{ bg: WHITE, borderColor: "C8E6C9" })
]}),
new TableRow({ children: [
cell([new TextRun({ text: `${CHK} `, color: GREEN, bold: true, size: 18 }), run("NEVER give NSAIDs/aspirin in dengue or malaria", { bold: true, size: 16, color: RED })],
{ bg: GREEN_LIGHT, borderColor: "C8E6C9" })
]}),
new TableRow({ children: [
cell([new TextRun({ text: `${CHK} `, color: GREEN, bold: true, size: 18 }), run("Fever + petechiae = meningococcemia until proven otherwise", { bold: true, size: 16, color: RED })],
{ bg: WHITE, borderColor: "C8E6C9" })
]}),
new TableRow({ children: [
cell([new TextRun({ text: `${CHK} `, color: GREEN, bold: true, size: 18 }), run("Infants <3 months: any fever >38.0°C = urgent assessment", { bold: true, size: 16 })],
{ bg: GREEN_LIGHT, borderColor: "C8E6C9" })
]}),
new TableRow({ children: [
cell([new TextRun({ text: `${CHK} `, color: GREEN, bold: true, size: 18 }), run("Elderly: fever may be blunted - use lower threshold (>37.8°C)", { bold: true, size: 16 })],
{ bg: WHITE, borderColor: "C8E6C9" })
]}),
new TableRow({ children: [
cell([new TextRun({ text: `${CHK} `, color: GREEN, bold: true, size: 18 }), run("Review all febrile patients not improving within 48-72 hours", { bold: true, size: 16 })],
{ bg: GREEN_LIGHT, borderColor: "C8E6C9" })
]}),
new TableRow({ children: [
cell([new TextRun({ text: `${CHK} `, color: GREEN, bold: true, size: 18 }), run("Always take: travel, medication, TB contact, immunisation history", { bold: true, size: 16 })],
{ bg: WHITE, borderColor: "C8E6C9" })
]}),
];
children.push(new Table({
rows: [new TableRow({ children: [
new TableCell({
children: [new Table({ rows: fuoRows, width: { size: 100, type: WidthType.PERCENTAGE },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER } })],
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: THIN_BORDER("E0E0E0") },
margins: { right: 200 },
}),
new TableCell({
children: [new Table({ rows: remRows, width: { size: 100, type: WidthType.PERCENTAGE },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER } })],
borders: { top: NO_BORDER, bottom: NO_BORDER, left: THIN_BORDER("E0E0E0"), right: NO_BORDER },
margins: { left: 200 },
}),
]})],
width: { size: 100, type: WidthType.PERCENTAGE },
columnWidths: [7200, 6800],
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER },
}));
// ── FOOTER NOTE ───────────────────────────────────────────────────────────────
children.push(para([new TextRun({ text: "", size: 6 })], { before: 100, after: 0 }));
children.push(new Table({
rows: [new TableRow({ children: [
new TableCell({
children: [new Paragraph({
children: [
new TextRun({ text: "Sources: Harrison's Principles of Internal Medicine 22E (2025) | ROSEN's Emergency Medicine | Robbins & Kumar Pathologic Basis of Disease | Goldman-Cecil Medicine ", size: 14, color: GREY, italics: true }),
new TextRun({ text: " | For clinical guidance use only - verify doses with local formulary and BNF | Prepared 2025/26", size: 14, color: GREY, italics: true }),
],
alignment: AlignmentType.CENTER,
spacing: { before: 60, after: 60 },
})],
shading: shading(GREY_LIGHT),
borders: { top: THIN_BORDER(TEAL), bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER },
margins: { left: 120, right: 120 },
})
]})],
width: { size: 100, type: WidthType.PERCENTAGE },
borders: { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER, insideH: NO_BORDER, insideV: NO_BORDER },
}));
// ════════════════════════════════════════════════════════════════════════════
// ASSEMBLE DOCUMENT
// ════════════════════════════════════════════════════════════════════════════
const doc = new Document({
creator: "Orris Clinical Assistant",
title: "Fever Treatment Protocol Checklist - GP Wall Display",
description: "Quick reference protocol for fever management in general practice",
styles: {
default: {
document: {
run: { font: "Calibri", size: 17 },
},
},
},
sections: [{
properties: {
page: {
size: { orientation: PageOrientation.LANDSCAPE, width: 16838, height: 11906 },
margin: { top: 500, bottom: 500, left: 600, right: 600 },
},
},
headers: {
default: new Header({
children: [new Paragraph({
children: [
new TextRun({ text: "FEVER TREATMENT PROTOCOL | GP PRACTICE WALL DISPLAY", bold: true, color: WHITE, size: 16 }),
new TextRun({ text: " For clinical guidance only - verify with BNF", color: "B2EBF2", size: 14, italics: true }),
],
alignment: AlignmentType.LEFT,
shading: shading(NAVY),
spacing: { before: 80, after: 80 },
indent: { left: 200 },
})]
})
},
children,
}],
});
const OUTPUT = "/home/daytona/workspace/fever-quickref/Fever_Treatment_Protocol_Checklist.docx";
Packer.toBuffer(doc).then(buffer => {
fs.writeFileSync(OUTPUT, buffer);
console.log(`DOCX saved to: ${OUTPUT}`);
}).catch(err => {
console.error("Error:", err);
process.exit(1);
});
cd /home/daytona/workspace/fever-quickref && node build_checklist.js 2>&1
python3 /home/daytona/skills/docx/scripts/office/validate.py /home/daytona/works…
ls -lh /home/daytona/workspace/fever-quickref/Fever_Treatment_Protocol_Checklist…
Fever Treatment Protocol Checklist
Word Document · DOCX
| Section | Content |
|---|---|
| Header Banner | Full-width navy title bar with subtitle; runs on every page |
| Info Strip | Quick definition of fever and when to treat - teal highlight bar |
| Section A - Initial Assessment | 6-step checkbox checklist: temperature, vitals, history, examination, red flags screen, special populations |
| Section B - Investigations | 10-item checkbox list of tests to order (CBC, CRP/PCT, urine, CXR, blood cultures, blood film, dengue, rapid Ag, LFTs/lactate, specialist) alongside a Red Flags panel (10 items, red-highlighted, emergency escalation triggers) |
| Section C - CBC Interpretation | 8-row colour-coded table: neutrophilia, lymphocytosis, leukopenia+thrombocytopenia (dengue), leukopenia (typhoid), left shift, thrombocytopenia, eosinophilia, extreme leukocytosis - each with pattern, interpretation, and action |
| Section D - Treatment Protocol | ~30 rows across 7 sub-groups: Antipyretics, Respiratory, UTI, GI, Tropical/Vector-borne, Skin, Emergencies - each with drug, dose, duration, and key notes. Emergency rows (meningitis, sepsis, meningococcemia) in red |
| Section E - FUO + Reminders | Two-column layout: FUO causes and workup on left, 8-point GP quick reminders checklist on right |
| Footer | Source citation bar with clinical guidance disclaimer |