History taking formats

Reading File
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
I now have very comprehensive material from multiple textbooks. Let me compile the full, well-structured answer.

History Taking Format

History taking is the systematic, structured process of gathering information from a patient to understand their illness and guide diagnosis. The standard format follows a consistent sequence.

1. Patient Particulars (Biodata)

Before any complaint is discussed, record the patient's identifying details - these have direct clinical relevance:
ParticularClinical Relevance
NamePersonalizes care, psychological benefit
AgeCongenital anomalies (infancy/childhood), sarcomas (teens), carcinomas (>40 yrs), BPH and OA (old age)
SexThyroid diseases, cystitis more common in females; carcinomas of stomach/lung more common in males; haemophilia only in males
ReligionCarcinoma of penis is rare in Jews/Muslims (circumcision); intussusception can follow prolonged fasting
Social statusAppendicitis (higher social class); tuberculosis (lower social class/malnutrition)
OccupationVaricose veins (bus conductors), bladder neoplasms (aniline dye workers), scrotal carcinoma (chimney sweepers), tennis elbow (tennis players)
ResidenceGeographical disease distribution, e.g. filariasis in Orissa
(S Das A Manual on Clinical Surgery, p. 6-7)

2. Chief Complaints (CC)

  • Record the patient's complaints in chronological order of their appearance
  • Note the duration of each complaint
  • Ask: "What are your complaints?" or "What brings you here?"
  • List in order of severity if they start simultaneously
Example format (sinus in the neck):
  • (a) Swelling in the neck - 1 year
  • (b) Evening fever - 10 months
  • (c) Pain in the swelling - 6 months
  • (d) Sinus in the neck - 1 month
Always establish that the patient was entirely well before the stated duration. Patients often omit complaints they consider insignificant, which can provide important diagnostic clues.
(S Das A Manual on Clinical Surgery, p. 7)

3. History of Present Illness (HPI)

Begins from the first symptom and extends to the time of examination.
Three key components:
i. Mode of onset
  • Sudden or gradual?
  • Any precipitating cause?
  • Ask: "How did the trouble start?"
ii. Progress of disease
  • Evolution of symptoms in exact chronological order
  • Ask: "What is the next thing that happened?"
  • Record in the patient's own words, not medical jargon
  • Allow free narration; redirect gently if patient wanders
  • Avoid leading questions (e.g., do not ask "Doesn't the pain move to the right scapula?" - always use open-ended prompts)
iii. Treatment received
  • What treatment has been tried?
  • By which doctor/facility?
  • Response to treatment?
For pain (the most common acute presenting feature), use the structured SOCRATES framework:
  • Site
  • Onset (sudden or gradual)
  • Character (burning, colicky, dull, sharp)
  • Radiation
  • Associating symptoms
  • Time course / duration
  • Exacerbating and relieving factors
  • Severity
In non-acute presentations, ask specifically about: anorexia, weight loss, jaundice, altered bowel habit, blood loss, and fatigue.
(S Das A Manual on Clinical Surgery, p. 7-8; Bailey and Love's Short Practice of Surgery 28th Edition, p. 1073)

4. Past Medical History (PMH)

  • Previous similar episodes
  • Previous medical illnesses: diabetes, hypertension, tuberculosis, cardiac disease, respiratory disease, haematological conditions
  • Previous surgical operations and dates (in chronological order)
  • Anaesthetic events/problems (difficult airway, suxamethonium apnoea)
  • Previous investigations - obtain old records if possible
Key point: Past history may directly explain the current presentation. For example, adhesive bowel obstruction following a prior laparotomy, or recurrent left iliac fossa pain in a patient with known diverticulitis.
(S Das A Manual on Clinical Surgery, p. 8; Bailey and Love's, p. 1073-1074)

5. Drug History

Ask about all drugs currently and recently taken. This has anaesthetic, diagnostic, and management implications:
  • Steroids (risk of adrenal crisis - need perioperative supplementation)
  • Anticoagulants (may need reversal before surgery)
  • Beta-blockers (mask tachycardia in bleeding)
  • Insulin / oral hypoglycaemics (perioperative glycaemic control)
  • Antihypertensives / diuretics
  • Monoamine oxidase inhibitors
  • Hormone replacement therapy / oral contraceptive pill
  • Ergot derivatives
(S Das A Manual on Clinical Surgery, p. 8; Bailey and Love's, p. 1074)

6. History of Allergy

  • Must never be missed
  • Ask about allergy to any drug or food
  • Record prominently (e.g., in red on the cover of the history sheet)
  • Include adverse reactions to anaesthetics
(S Das A Manual on Clinical Surgery, p. 8)

7. Personal / Social History

  • Smoking: type (cigarette, cigar, pipe), frequency
  • Alcohol: quantity and quality (affects anaesthetic risk and outcomes)
  • Recreational drugs
  • Diet: vegetarian/non-vegetarian, regularity, spicy food
  • Marital status
  • Occupation (revisited for exposure history)
  • Domestic support and mobility: important for discharge planning and rehabilitation
In women - Menstrual/Obstetric History:
  • Regular or irregular menstruation
  • Duration of menstruation, associated pain
  • Last menstrual period (LMP)
  • Number of pregnancies, miscarriages
  • Mode of deliveries (normal / Caesarean section)
  • Any vaginal discharge
(S Das A Manual on Clinical Surgery, p. 8; Bailey and Love's, p. 1074-1075)

8. Family History

Ask about similar or related conditions in first-degree relatives:
  • Hereditary/familial diseases: haemophilia, tuberculosis, diabetes mellitus, essential hypertension, peptic ulcer, breast cancer, colorectal cancer, inflammatory bowel disease
  • Endocrine disorders: e.g., hyperparathyroidism, MEN syndromes
  • Genetic disorders or adverse reactions to anaesthetics
  • If parents deceased: age and cause of death
  • Ask about siblings and children
(S Das A Manual on Clinical Surgery, p. 8; Bailey and Love's, p. 1075)

9. Immunization History

(Especially relevant in paediatric patients)
  • Diphtheria, tetanus, whooping cough, poliomyelitis, smallpox, tuberculosis (BCG)
  • Tetanus status is important in trauma and surgical patients
(S Das A Manual on Clinical Surgery, p. 8)

10. Systems Review (Systemic Enquiry)

A brief structured screen for symptoms across all body systems to identify comorbidities not yet mentioned. Covers:
  • Cardiovascular: chest pain, palpitations, breathlessness, ankle swelling
  • Respiratory: cough, sputum, haemoptysis, wheeze
  • Gastrointestinal: nausea, vomiting, dysphagia, bowel habits, rectal bleeding
  • Genitourinary: dysuria, frequency, haematuria
  • Neurological: headache, fits, weakness, sensory changes
  • Musculoskeletal: joint pain, stiffness
  • Endocrine: polyuria, polydipsia, heat/cold intolerance
These have direct implications for the safety of surgical or other interventions.
(Bailey and Love's Short Practice of Surgery 28th Edition, p. 1075)

Key Principles of History Taking

(Summarized from Bailey and Love's, p. 1075)
  • Identify the reason for consultation - the presenting complaint
  • Start with an open question; let the patient speak without interruption (Osler's dictum)
  • Determine onset, duration, and evolution of symptoms
  • Deduce the most likely organ or system affected
  • Refine the history with relevant direct questions
  • Document important negatives
  • History can be taken "forwards and backwards," but its record must be structured
  • Introduce yourself, explain what you are doing, and obtain consent to proceed
  • Resist the temptation to rely on previous histories taken by other doctors

Create a printable history-taking template for clinical use

Reading File
Reading File
Running Command

mkdir -p /home/daytona/workspace/history-taking-template

Writing File

~/history-taking-template/generate_template.py

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.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.pdfgen import canvas

OUTPUT = "/home/daytona/workspace/history-taking-template/History_Taking_Template.pdf"

# ── Colours ──────────────────────────────────────────────────────────────────
DARK_BLUE  = colors.HexColor("#1a3a5c")
MID_BLUE   = colors.HexColor("#2e6da4")
LIGHT_BLUE = colors.HexColor("#ddeeff")
PALE_GREY  = colors.HexColor("#f5f5f5")
LINE_GREY  = colors.HexColor("#cccccc")
BLACK      = colors.black
WHITE      = colors.white

# ── Page size ─────────────────────────────────────────────────────────────────
PAGE_W, PAGE_H = A4
L_MARGIN = R_MARGIN = 18*mm
T_MARGIN = B_MARGIN = 15*mm
CONTENT_W = PAGE_W - L_MARGIN - R_MARGIN

# ── Styles ────────────────────────────────────────────────────────────────────
base_styles = getSampleStyleSheet()

def style(name, parent="Normal", **kw):
    s = ParagraphStyle(name, parent=base_styles[parent], **kw)
    return s

S_TITLE    = style("S_TITLE",    "Normal", fontSize=16, leading=20,
                   textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)
S_SUBTITLE = style("S_SUBTITLE", "Normal", fontSize=8,  leading=10,
                   textColor=colors.HexColor("#ccddee"), fontName="Helvetica", alignment=TA_CENTER)
S_SEC      = style("S_SEC",      "Normal", fontSize=9,  leading=11,
                   textColor=WHITE, fontName="Helvetica-Bold")
S_LABEL    = style("S_LABEL",    "Normal", fontSize=7.5, leading=10,
                   textColor=DARK_BLUE, fontName="Helvetica-Bold")
S_SMALL    = style("S_SMALL",    "Normal", fontSize=7,  leading=9,
                   textColor=colors.HexColor("#555555"), fontName="Helvetica")
S_HINT     = style("S_HINT",     "Normal", fontSize=6.5, leading=8,
                   textColor=colors.HexColor("#888888"), fontName="Helvetica-Oblique")
S_BODY     = style("S_BODY",     "Normal", fontSize=7.5, leading=10,
                   textColor=BLACK, fontName="Helvetica")
S_FOOTER   = style("S_FOOTER",   "Normal", fontSize=6.5, leading=8,
                   textColor=colors.HexColor("#999999"), fontName="Helvetica", alignment=TA_CENTER)

# ── Helpers ───────────────────────────────────────────────────────────────────
def section_header(text, icon=""):
    full = f"{icon}  {text}" if icon else text
    tbl = Table([[Paragraph(full, S_SEC)]], colWidths=[CONTENT_W])
    tbl.setStyle(TableStyle([
        ("BACKGROUND",   (0,0), (-1,-1), MID_BLUE),
        ("TOPPADDING",   (0,0), (-1,-1), 3),
        ("BOTTOMPADDING",(0,0), (-1,-1), 3),
        ("LEFTPADDING",  (0,0), (-1,-1), 6),
        ("RIGHTPADDING", (0,0), (-1,-1), 6),
        ("ROUNDEDCORNERS", (0,0), (-1,-1), [3,3,3,3]),
    ]))
    return tbl

def write_lines(n, label="", hint="", col_width=None):
    """Return a table row with a label and n blank writing lines."""
    cw = col_width or CONTENT_W
    rows = []
    if label:
        rows.append([Paragraph(label, S_LABEL)])
    if hint:
        rows.append([Paragraph(hint, S_HINT)])
    for _ in range(n):
        rows.append([""])   # blank line row
    tbl = Table(rows, colWidths=[cw])
    style_cmds = [
        ("TOPPADDING",    (0,0), (-1,-1), 1),
        ("BOTTOMPADDING", (0,0), (-1,-1), 1),
        ("LEFTPADDING",   (0,0), (-1,-1), 2),
        ("RIGHTPADDING",  (0,0), (-1,-1), 2),
    ]
    # underline each blank row
    start = 1 if label else 0
    start += 1 if hint else 0
    for i in range(start, len(rows)):
        style_cmds.append(("LINEBELOW", (0,i), (-1,i), 0.4, LINE_GREY))
    tbl.setStyle(TableStyle(style_cmds))
    return tbl

def labelled_field(label, hint="", width=None):
    return write_lines(1, label, hint, width)

def two_col(left_items, right_items, split=0.5):
    """Lay two lists of flowables side by side in a table."""
    lw = CONTENT_W * split - 3*mm
    rw = CONTENT_W * (1-split) - 3*mm
    rows = []
    max_len = max(len(left_items), len(right_items))
    for i in range(max_len):
        l = left_items[i] if i < len(left_items) else ""
        r = right_items[i] if i < len(right_items) else ""
        rows.append([l, r])
    tbl = Table(rows, colWidths=[lw, rw])
    tbl.setStyle(TableStyle([
        ("VALIGN",       (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",   (0,0), (-1,-1), 0),
        ("BOTTOMPADDING",(0,0), (-1,-1), 0),
        ("LEFTPADDING",  (0,0), (-1,-1), 0),
        ("RIGHTPADDING", (0,0), (-1,-1), 2),
    ]))
    return tbl

def checkbox_row(items):
    """Row of small checkboxes with labels."""
    cells = []
    for item in items:
        cells.append(Paragraph(f"[ ]  {item}", S_SMALL))
    tbl = Table([cells], colWidths=[CONTENT_W / len(items)] * len(items))
    tbl.setStyle(TableStyle([
        ("TOPPADDING",   (0,0), (-1,-1), 2),
        ("BOTTOMPADDING",(0,0), (-1,-1), 2),
        ("LEFTPADDING",  (0,0), (-1,-1), 2),
        ("RIGHTPADDING", (0,0), (-1,-1), 2),
    ]))
    return tbl

def sp(h=3):
    return Spacer(1, h*mm)

def hr():
    return HRFlowable(width="100%", thickness=0.4, color=LINE_GREY, spaceAfter=2, spaceBefore=2)

# ── Header banner (drawn on canvas) ──────────────────────────────────────────
def on_first_page(c: canvas.Canvas, doc):
    c.saveState()
    # Dark blue banner
    banner_h = 28*mm
    c.setFillColor(DARK_BLUE)
    c.rect(0, PAGE_H - banner_h, PAGE_W, banner_h, fill=1, stroke=0)
    # Accent stripe
    c.setFillColor(MID_BLUE)
    c.rect(0, PAGE_H - banner_h - 2*mm, PAGE_W, 2*mm, fill=1, stroke=0)
    # Title text
    c.setFillColor(WHITE)
    c.setFont("Helvetica-Bold", 17)
    c.drawCentredString(PAGE_W/2, PAGE_H - 15*mm, "CLINICAL HISTORY TAKING FORM")
    c.setFont("Helvetica", 8)
    c.setFillColor(colors.HexColor("#aaccee"))
    c.drawCentredString(PAGE_W/2, PAGE_H - 22*mm,
        "Complete all sections  |  Mark N/A where not applicable  |  Use black or blue ink")
    # Footer
    c.setFont("Helvetica", 6.5)
    c.setFillColor(colors.HexColor("#aaaaaa"))
    c.drawCentredString(PAGE_W/2, 8*mm, "Page 1  |  Confidential Medical Record")
    c.restoreState()

def on_later_pages(c: canvas.Canvas, doc):
    c.saveState()
    c.setFillColor(DARK_BLUE)
    c.rect(0, PAGE_H - 10*mm, PAGE_W, 10*mm, fill=1, stroke=0)
    c.setFillColor(WHITE)
    c.setFont("Helvetica-Bold", 8)
    c.drawString(L_MARGIN, PAGE_H - 6.5*mm, "CLINICAL HISTORY TAKING FORM  (continued)")
    c.setFont("Helvetica", 7)
    c.drawRightString(PAGE_W - R_MARGIN, PAGE_H - 6.5*mm,
                      f"Patient: ________________________  Date: ______________")
    c.setFont("Helvetica", 6.5)
    c.setFillColor(colors.HexColor("#aaaaaa"))
    c.drawCentredString(PAGE_W/2, 8*mm,
                        f"Page {doc.page}  |  Confidential Medical Record")
    c.restoreState()

# ── Build story ───────────────────────────────────────────────────────────────
story = []
GAP = sp(2)

# ── 1. PATIENT PARTICULARS ────────────────────────────────────────────────────
story.append(sp(32))   # space for banner
story.append(section_header("1.  PATIENT PARTICULARS"))
story.append(sp(2))

bio_left = [
    labelled_field("Patient Name", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Age", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Sex  [ ] M    [ ] F    [ ] Other", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Religion / Ethnicity", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Occupation", width=CONTENT_W*0.5 - 3*mm),
]
bio_right = [
    labelled_field("Hospital / OPD No.", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Date of Admission", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Ward / Bed No.", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Referred by", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Address / Contact", width=CONTENT_W*0.5 - 3*mm),
]
story.append(two_col(bio_left, bio_right))
story.append(GAP)

# ── 2. CHIEF COMPLAINTS ───────────────────────────────────────────────────────
story.append(section_header("2.  CHIEF COMPLAINTS"))
story.append(sp(2))
story.append(Paragraph("List complaints in chronological order of onset (earliest first)", S_HINT))
story.append(sp(1))

cc_data = [
    [Paragraph("#", S_LABEL), Paragraph("Complaint", S_LABEL), Paragraph("Duration", S_LABEL)],
]
for i in range(1, 6):
    cc_data.append([Paragraph(str(i), S_SMALL), "", ""])

cc_tbl = Table(cc_data, colWidths=[10*mm, CONTENT_W - 10*mm - 35*mm, 35*mm])
cc_tbl.setStyle(TableStyle([
    ("BACKGROUND",   (0,0), (-1,0),   LIGHT_BLUE),
    ("TEXTCOLOR",    (0,0), (-1,0),   DARK_BLUE),
    ("FONTNAME",     (0,0), (-1,0),   "Helvetica-Bold"),
    ("FONTSIZE",     (0,0), (-1,0),   7.5),
    ("LINEBELOW",    (0,0), (-1,0),   0.6, MID_BLUE),
    ("LINEBELOW",    (0,1), (-1,-1),  0.4, LINE_GREY),
    ("TOPPADDING",   (0,0), (-1,-1),  3),
    ("BOTTOMPADDING",(0,0), (-1,-1),  4),
    ("LEFTPADDING",  (0,0), (-1,-1),  4),
    ("RIGHTPADDING", (0,0), (-1,-1),  4),
    ("VALIGN",       (0,0), (-1,-1),  "MIDDLE"),
]))
story.append(cc_tbl)
story.append(GAP)

# ── 3. HISTORY OF PRESENT ILLNESS ────────────────────────────────────────────
story.append(section_header("3.  HISTORY OF PRESENT ILLNESS (HPI)"))
story.append(sp(2))

hpi_secs = [
    ("Mode of Onset", "[ ] Sudden   [ ] Gradual      Precipitating cause (if any): _______________________________________________"),
    ("Progress / Evolution", "Describe sequence of events from first symptom to present:"),
    ("Treatment Already Received", "Drugs / procedures tried, treating doctor, response:"),
]
for lbl, hint in hpi_secs:
    story.append(Paragraph(lbl, S_LABEL))
    story.append(Paragraph(hint, S_HINT))
    story.append(write_lines(3))
    story.append(sp(2))

# PAIN sub-section (SOCRATES)
story.append(Paragraph("Pain Analysis (SOCRATES)  -- complete if pain is a complaint", S_LABEL))
story.append(sp(1))

soc_left = [
    labelled_field("Site", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Onset  [ ] Sudden  [ ] Gradual", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Character (burning/colicky/dull/sharp)", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Radiation", width=CONTENT_W*0.5 - 3*mm),
]
soc_right = [
    labelled_field("Associated symptoms", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Timing / Duration", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Exacerbating / Relieving factors", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Severity (0-10 scale)", width=CONTENT_W*0.5 - 3*mm),
]
story.append(two_col(soc_left, soc_right))
story.append(GAP)

# ── 4. PAST MEDICAL HISTORY ───────────────────────────────────────────────────
story.append(section_header("4.  PAST MEDICAL HISTORY (PMH)"))
story.append(sp(2))
story.append(Paragraph("Tick all that apply and provide details below", S_HINT))
story.append(sp(1))
story.append(checkbox_row(["Diabetes", "Hypertension", "Cardiac disease", "Respiratory disease"]))
story.append(checkbox_row(["Tuberculosis", "Peptic ulcer", "Renal disease", "Thyroid disorder"]))
story.append(checkbox_row(["Epilepsy / Fits", "Stroke / TIA", "Malignancy", "Other (specify below)"]))
story.append(sp(1))
story.append(write_lines(2, "Details of above + Previous similar episodes:"))
story.append(GAP)

# Past Surgical History
story.append(Paragraph("Previous Surgical / Operative History", S_LABEL))
story.append(sp(1))
surg_data = [
    [Paragraph("Operation / Procedure", S_LABEL), Paragraph("Year", S_LABEL), Paragraph("Hospital", S_LABEL), Paragraph("Complications / Notes", S_LABEL)],
]
for _ in range(3):
    surg_data.append(["", "", "", ""])
surg_tbl = Table(surg_data, colWidths=[CONTENT_W*0.38, CONTENT_W*0.12, CONTENT_W*0.22, CONTENT_W*0.28])
surg_tbl.setStyle(TableStyle([
    ("BACKGROUND",   (0,0), (-1,0),   LIGHT_BLUE),
    ("LINEBELOW",    (0,0), (-1,0),   0.6, MID_BLUE),
    ("LINEBELOW",    (0,1), (-1,-1),  0.4, LINE_GREY),
    ("TOPPADDING",   (0,0), (-1,-1),  3),
    ("BOTTOMPADDING",(0,0), (-1,-1),  5),
    ("LEFTPADDING",  (0,0), (-1,-1),  3),
    ("FONTSIZE",     (0,1), (-1,-1),  7),
]))
story.append(surg_tbl)
story.append(GAP)

# ── 5. DRUG HISTORY ───────────────────────────────────────────────────────────
story.append(section_header("5.  DRUG HISTORY & ALLERGIES"))
story.append(sp(2))

drug_data = [
    [Paragraph("Drug Name", S_LABEL), Paragraph("Dose", S_LABEL), Paragraph("Frequency", S_LABEL), Paragraph("Duration", S_LABEL), Paragraph("Indication", S_LABEL)],
]
for _ in range(5):
    drug_data.append(["", "", "", "", ""])

drug_tbl = Table(drug_data, colWidths=[
    CONTENT_W*0.30, CONTENT_W*0.15, CONTENT_W*0.15, CONTENT_W*0.15, CONTENT_W*0.25
])
drug_tbl.setStyle(TableStyle([
    ("BACKGROUND",   (0,0), (-1,0),   LIGHT_BLUE),
    ("LINEBELOW",    (0,0), (-1,0),   0.6, MID_BLUE),
    ("LINEBELOW",    (0,1), (-1,-1),  0.4, LINE_GREY),
    ("TOPPADDING",   (0,0), (-1,-1),  3),
    ("BOTTOMPADDING",(0,0), (-1,-1),  5),
    ("LEFTPADDING",  (0,0), (-1,-1),  3),
    ("FONTSIZE",     (0,1), (-1,-1),  7),
]))
story.append(drug_tbl)
story.append(sp(2))

# Allergy box
allergy_box = Table(
    [[Paragraph("! ALLERGIES", S_SEC), ""]],
    colWidths=[30*mm, CONTENT_W - 30*mm]
)
allergy_box.setStyle(TableStyle([
    ("BACKGROUND",   (0,0), (0,0),   colors.HexColor("#c0392b")),
    ("BACKGROUND",   (1,0), (1,0),   colors.HexColor("#fdecea")),
    ("LINEBELOW",    (1,0), (1,0),   0.4, LINE_GREY),
    ("TOPPADDING",   (0,0), (-1,-1), 4),
    ("BOTTOMPADDING",(0,0), (-1,-1), 8),
    ("LEFTPADDING",  (0,0), (-1,-1), 5),
    ("FONTSIZE",     (0,0), (-1,-1), 8),
]))
story.append(allergy_box)
story.append(GAP)

# ── 6. PERSONAL / SOCIAL HISTORY ─────────────────────────────────────────────
story.append(section_header("6.  PERSONAL & SOCIAL HISTORY"))
story.append(sp(2))

ps_left = [
    Paragraph("Smoking", S_LABEL),
    checkbox_row(["Never", "Ex-smoker", "Current"]),
    labelled_field("Type / Frequency (packs/day, years)", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    Paragraph("Alcohol", S_LABEL),
    checkbox_row(["None", "Occasional", "Moderate", "Heavy"]),
    labelled_field("Units/week", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Recreational Drugs (specify)", width=CONTENT_W*0.5 - 3*mm),
]
ps_right = [
    Paragraph("Diet", S_LABEL),
    checkbox_row(["Vegetarian", "Non-veg", "Mixed"]),
    labelled_field("Dietary restrictions / notes", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Marital Status  [ ] Single  [ ] Married  [ ] Widowed", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Occupation (exposure risks)", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Domestic support / mobility", width=CONTENT_W*0.5 - 3*mm),
]
story.append(two_col(ps_left, ps_right))
story.append(sp(2))

# Menstrual (females)
men_box = Table([[
    Paragraph("Menstrual / Obstetric History  (Females)", S_LABEL),
    Paragraph("LMP: _______________   Cycle: Regular [ ]  Irregular [ ]   "
              "G ___ P ___ A ___   Last delivery: _______________   "
              "[ ] Normal   [ ] LSCS      Vaginal discharge: [ ] Yes  [ ] No", S_SMALL)
]], colWidths=[55*mm, CONTENT_W - 55*mm])
men_box.setStyle(TableStyle([
    ("BACKGROUND",   (0,0), (-1,-1), PALE_GREY),
    ("TOPPADDING",   (0,0), (-1,-1), 4),
    ("BOTTOMPADDING",(0,0), (-1,-1), 4),
    ("LEFTPADDING",  (0,0), (-1,-1), 5),
    ("VALIGN",       (0,0), (-1,-1), "MIDDLE"),
]))
story.append(men_box)
story.append(GAP)

# ── 7. FAMILY HISTORY ────────────────────────────────────────────────────────
story.append(section_header("7.  FAMILY HISTORY"))
story.append(sp(2))
story.append(Paragraph("Tick all that apply in first-degree relatives:", S_HINT))
story.append(sp(1))
story.append(checkbox_row(["Diabetes", "Hypertension", "Heart disease", "Stroke"]))
story.append(checkbox_row(["Cancer (specify below)", "Tuberculosis", "Haemophilia", "Thyroid disorder"]))
story.append(checkbox_row(["Mental illness", "IBD", "Epilepsy", "Adverse anaesthetic reaction"]))
story.append(sp(1))
story.append(write_lines(2, "Details (affected member, age of onset, cause of death if deceased):"))
story.append(GAP)

# ── 8. IMMUNIZATION HISTORY ──────────────────────────────────────────────────
story.append(section_header("8.  IMMUNIZATION HISTORY"))
story.append(sp(2))
imm_left = [
    checkbox_row(["BCG (TB)", "DPT", "Polio", "Measles/MMR"]),
    sp(1),
    checkbox_row(["Hepatitis B", "Typhoid", "Rabies", "COVID-19"]),
]
imm_right = [
    labelled_field("Tetanus status / last booster", width=CONTENT_W*0.5 - 3*mm),
    sp(1),
    labelled_field("Other vaccinations", width=CONTENT_W*0.5 - 3*mm),
]
story.append(two_col(imm_left, imm_right))
story.append(GAP)

# ── 9. SYSTEMS REVIEW ────────────────────────────────────────────────────────
story.append(section_header("9.  SYSTEMS REVIEW  (tick positives; cross negatives; circle N/A)"))
story.append(sp(2))

systems = [
    ("Cardiovascular",    ["Chest pain", "Palpitations", "Breathlessness", "Orthopnoea", "Ankle swelling", "Syncope"]),
    ("Respiratory",       ["Cough", "Sputum", "Haemoptysis", "Wheeze", "Stridor", "Dyspnoea at rest"]),
    ("GI / Abdomen",      ["Nausea/Vomiting", "Dysphagia", "Heartburn", "Abdominal pain", "Altered bowel habit", "Rectal bleeding", "Jaundice", "Weight loss"]),
    ("Genitourinary",     ["Dysuria", "Frequency", "Haematuria", "Nocturia", "Discharge", "Loin pain"]),
    ("Neurological",      ["Headache", "Fits/Seizures", "Dizziness", "Weakness", "Sensory changes", "Vision changes", "Speech difficulty"]),
    ("MSK / Skin",        ["Joint pain", "Swelling", "Rash", "Skin lesion", "Lymphadenopathy"]),
    ("Endocrine",         ["Polyuria", "Polydipsia", "Heat intolerance", "Cold intolerance", "Weight gain", "Fatigue"]),
]

sr_rows = []
for sys_name, items in systems:
    cells = [Paragraph(sys_name, S_LABEL)]
    for item in items:
        cells.append(Paragraph(f"[ ] {item}", S_SMALL))
    # pad to 8 cells
    while len(cells) < 9:
        cells.append("")
    sr_rows.append(cells[:9])

# col widths: system name wide, 8 items equal
sys_col = 28*mm
item_cols = [(CONTENT_W - sys_col) / 8] * 8
sr_tbl = Table(sr_rows, colWidths=[sys_col] + item_cols)
sr_tbl.setStyle(TableStyle([
    ("BACKGROUND",   (0,0), (0,-1),  LIGHT_BLUE),
    ("LINEBELOW",    (0,0), (-1,-1), 0.3, LINE_GREY),
    ("LINEAFTER",    (0,0), (0,-1),  0.5, MID_BLUE),
    ("TOPPADDING",   (0,0), (-1,-1), 3),
    ("BOTTOMPADDING",(0,0), (-1,-1), 3),
    ("LEFTPADDING",  (0,0), (-1,-1), 3),
    ("RIGHTPADDING", (0,0), (-1,-1), 2),
    ("FONTNAME",     (0,0), (0,-1),  "Helvetica-Bold"),
    ("FONTSIZE",     (0,0), (0,-1),  7),
    ("FONTSIZE",     (1,0), (-1,-1), 6.5),
    ("VALIGN",       (0,0), (-1,-1), "MIDDLE"),
]))
story.append(sr_tbl)
story.append(GAP)

# ── 10. PROVISIONAL DIAGNOSIS & PLAN ────────────────────────────────────────
story.append(section_header("10.  PROVISIONAL DIAGNOSIS & MANAGEMENT PLAN"))
story.append(sp(2))
story.append(write_lines(2, "Provisional Diagnosis:"))
story.append(sp(2))
story.append(write_lines(2, "Differential Diagnoses:"))
story.append(sp(2))
story.append(write_lines(2, "Investigations Ordered:"))
story.append(sp(2))
story.append(write_lines(2, "Initial Management Plan:"))
story.append(GAP)

# ── SIGNATURE BLOCK ───────────────────────────────────────────────────────────
sig_data = [[
    Paragraph("Clinician Name: ________________________________", S_SMALL),
    Paragraph("Signature: ____________________________", S_SMALL),
    Paragraph("Date: ____________________    Time: ____________", S_SMALL),
]]
sig_tbl = Table(sig_data, colWidths=[CONTENT_W*0.40, CONTENT_W*0.30, CONTENT_W*0.30])
sig_tbl.setStyle(TableStyle([
    ("BACKGROUND",   (0,0), (-1,-1), PALE_GREY),
    ("TOPPADDING",   (0,0), (-1,-1), 6),
    ("BOTTOMPADDING",(0,0), (-1,-1), 6),
    ("LEFTPADDING",  (0,0), (-1,-1), 5),
    ("LINEABOVE",    (0,0), (-1,0),  0.8, MID_BLUE),
]))
story.append(sig_tbl)

# ── Build ─────────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    leftMargin=L_MARGIN,
    rightMargin=R_MARGIN,
    topMargin=T_MARGIN + 28*mm,   # space for banner on page 1
    bottomMargin=B_MARGIN + 8*mm,
)

def build_pages(canvas_obj, doc_obj):
    if doc_obj.page == 1:
        on_first_page(canvas_obj, doc_obj)
    else:
        on_later_pages(canvas_obj, doc_obj)

doc.build(
    story,
    onFirstPage=on_first_page,
    onLaterPages=on_later_pages,
)
print("PDF created:", OUTPUT)
Running Command

cd /home/daytona/workspace/history-taking-template && python generate_template.p…

Running Command

ls -lh /home/daytona/workspace/history-taking-template/History_Taking_Template.p…

Running Command

python3 -c " from pypdf import PdfReader r = PdfReader('/home/daytona/workspace/…

Your printable A4 clinical history-taking template is ready:

History Taking Template

PDF Document · PDF


What's included (4 pages, A4):
SectionContents
1. Patient ParticularsName, Age, Sex, Religion, Occupation, OPD No., Ward, Referral, Address
2. Chief Complaints5-row table with complaint + duration, chronological order
3. HPIMode of onset, Progress/evolution, Prior treatment, full SOCRATES pain analysis grid
4. Past Medical HistoryCheckbox grid (12 conditions) + 3-row surgical history table
5. Drug History & Allergies5-drug table (name/dose/frequency/duration/indication) + prominent red allergy box
6. Personal & Social HistorySmoking, alcohol, recreational drugs, diet, marital status, occupation; menstrual/obstetric block for females
7. Family HistoryCheckbox grid (12 conditions) + free-text details
8. Immunization HistoryCheckbox grid + tetanus status
9. Systems Review7 systems (CVS, Respiratory, GI, GU, Neuro, MSK/Skin, Endocrine) in a compact tick-box table
10. Provisional Diagnosis & PlanDiagnosis, differentials, investigations, management
Signature blockClinician name, signature, date, time
The design uses a dark blue header banner, colour-coded section bars, ruled writing lines, and page headers with a patient name/date field on pages 2-4 - ready to print and write on directly.

For mbbs students symptoms wise hoping in surgery

Asking for Preferences
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Writing File

~/history-taking-template/symptom_surgical_guide.py

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether, PageBreak
)
from reportlab.pdfgen import canvas

OUTPUT = "/home/daytona/workspace/history-taking-template/Surgical_Symptom_Guide_MBBS.pdf"

# ── Palette ───────────────────────────────────────────────────────────────────
DARK       = colors.HexColor("#1a2e4a")
MID        = colors.HexColor("#2563a8")
ACCENT     = colors.HexColor("#e67e22")
LIGHT_HDR  = colors.HexColor("#dbeafe")
PALE       = colors.HexColor("#f8faff")
PALE2      = colors.HexColor("#fff8f0")
LINE       = colors.HexColor("#cbd5e1")
RED        = colors.HexColor("#c0392b")
GREEN      = colors.HexColor("#1a7a4a")
ORANGE     = colors.HexColor("#e67e22")
WHITE      = colors.white
BLACK      = colors.black

PAGE_W, PAGE_H = A4
L_MARGIN = R_MARGIN = 16*mm
T_MARGIN = B_MARGIN = 14*mm
CW = PAGE_W - L_MARGIN - R_MARGIN  # usable content width

# ── Styles ─────────────────────────────────────────────────────────────────────
bs = getSampleStyleSheet()

def S(name, parent="Normal", **kw):
    return ParagraphStyle(name, parent=bs[parent], **kw)

ST_PAGE_TITLE = S("PT", fontSize=18, leading=22, textColor=WHITE,
                  fontName="Helvetica-Bold", alignment=TA_CENTER)
ST_PAGE_SUB   = S("PS", fontSize=8, leading=10, textColor=colors.HexColor("#b8d4f8"),
                  fontName="Helvetica", alignment=TA_CENTER)
ST_SYM_TITLE  = S("SYM", fontSize=11, leading=13, textColor=WHITE,
                  fontName="Helvetica-Bold")
ST_SYM_ICON   = S("SYMI", fontSize=11, leading=13, textColor=WHITE,
                  fontName="Helvetica-Bold", alignment=TA_CENTER)
ST_COL_HEAD   = S("CH", fontSize=7.5, leading=9, textColor=WHITE,
                  fontName="Helvetica-Bold", alignment=TA_CENTER)
ST_CELL       = S("CE", fontSize=7, leading=9, textColor=BLACK,
                  fontName="Helvetica")
ST_CELL_B     = S("CEB", fontSize=7, leading=9, textColor=DARK,
                  fontName="Helvetica-Bold")
ST_HINT       = S("HN", fontSize=6, leading=7.5, textColor=colors.HexColor("#64748b"),
                  fontName="Helvetica-Oblique")
ST_LABEL      = S("LBL", fontSize=7.5, leading=9, textColor=DARK,
                  fontName="Helvetica-Bold")
ST_ALERT_RED  = S("AR", fontSize=7, leading=8.5, textColor=RED,
                  fontName="Helvetica-Bold")
ST_ALERT_GRN  = S("AG", fontSize=7, leading=8.5, textColor=GREEN,
                  fontName="Helvetica-Bold")
ST_FOOTER     = S("FT", fontSize=6, leading=7, textColor=colors.HexColor("#94a3b8"),
                  fontName="Helvetica", alignment=TA_CENTER)
ST_BODY       = S("BD", fontSize=7, leading=9, textColor=BLACK,
                  fontName="Helvetica")

# ── Page decorators ────────────────────────────────────────────────────────────
def banner(c, doc, title_line2=""):
    h = 26*mm
    c.saveState()
    c.setFillColor(DARK)
    c.rect(0, PAGE_H - h, PAGE_W, h, fill=1, stroke=0)
    c.setFillColor(ACCENT)
    c.rect(0, PAGE_H - h - 1.5*mm, PAGE_W, 1.5*mm, fill=1, stroke=0)
    c.setFillColor(WHITE)
    c.setFont("Helvetica-Bold", 15)
    c.drawCentredString(PAGE_W/2, PAGE_H - 12*mm, "SYMPTOM-WISE SURGICAL DIAGNOSIS GUIDE")
    c.setFont("Helvetica", 7.5)
    c.setFillColor(colors.HexColor("#8ab4d8"))
    c.drawCentredString(PAGE_W/2, PAGE_H - 19*mm,
        "MBBS Surgery Quick Reference  |  Symptom -> Possible Diagnoses -> Key Differentiating Features")
    # footer
    c.setFont("Helvetica", 6)
    c.setFillColor(colors.HexColor("#94a3b8"))
    c.drawCentredString(PAGE_W/2, 7*mm, f"Page {doc.page}  |  For Educational Use")
    c.restoreState()

def banner_later(c, doc):
    c.saveState()
    c.setFillColor(DARK)
    c.rect(0, PAGE_H - 9*mm, PAGE_W, 9*mm, fill=1, stroke=0)
    c.setFillColor(WHITE)
    c.setFont("Helvetica-Bold", 7.5)
    c.drawString(L_MARGIN, PAGE_H - 6*mm, "SYMPTOM-WISE SURGICAL DIAGNOSIS GUIDE  (MBBS)")
    c.setFont("Helvetica", 7)
    c.drawRightString(PAGE_W - R_MARGIN, PAGE_H - 6*mm, f"Page {doc.page}")
    c.setFont("Helvetica", 6)
    c.setFillColor(colors.HexColor("#94a3b8"))
    c.drawCentredString(PAGE_W/2, 7*mm, "For Educational Use")
    c.restoreState()

# ── Helper: symptom section header ─────────────────────────────────────────────
def sym_header(emoji, title, color=MID):
    row = Table([[Paragraph(emoji, ST_SYM_ICON),
                  Paragraph(title, ST_SYM_TITLE)]],
                colWidths=[12*mm, CW - 12*mm])
    row.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), color),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    return row

def sp(h=3): return Spacer(1, h*mm)
def hr(): return HRFlowable(width="100%", thickness=0.3, color=LINE, spaceAfter=1, spaceBefore=1)

# ── Helper: build diagnosis table ─────────────────────────────────────────────
def diag_table(col_headers, rows, col_widths, alt_color=PALE):
    data = [[Paragraph(h, ST_COL_HEAD) for h in col_headers]]
    for i, row in enumerate(rows):
        data.append([Paragraph(str(c), ST_CELL_B if j == 0 else ST_CELL)
                     for j, c in enumerate(row)])
    t = Table(data, colWidths=col_widths)
    style_cmds = [
        ("BACKGROUND",    (0,0), (-1,0),   MID),
        ("LINEBELOW",     (0,0), (-1,0),   0.6, DARK),
        ("TOPPADDING",    (0,0), (-1,-1),  2),
        ("BOTTOMPADDING", (0,0), (-1,-1),  3),
        ("LEFTPADDING",   (0,0), (-1,-1),  3),
        ("RIGHTPADDING",  (0,0), (-1,-1),  3),
        ("VALIGN",        (0,0), (-1,-1),  "TOP"),
        ("LINEBELOW",     (0,1), (-1,-1),  0.3, LINE),
        ("GRID",          (0,0), (-1,-1),  0.2, LINE),
    ]
    for i in range(1, len(data)):
        if i % 2 == 0:
            style_cmds.append(("BACKGROUND", (0,i), (-1,i), alt_color))
    t.setStyle(TableStyle(style_cmds))
    return t

def red_flags_box(flags):
    items = "  |  ".join(f"! {f}" for f in flags)
    box = Table([[Paragraph("RED FLAGS:", ST_ALERT_RED),
                  Paragraph(items, ST_ALERT_RED)]],
                colWidths=[22*mm, CW - 22*mm])
    box.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), colors.HexColor("#fef2f2")),
        ("LINEABOVE",     (0,0), (-1,-1), 0.6, RED),
        ("LINEBELOW",     (0,0), (-1,-1), 0.6, RED),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    return box

def key_box(text):
    box = Table([[Paragraph("KEY:", ST_ALERT_GRN),
                  Paragraph(text, ST_BODY)]],
                colWidths=[14*mm, CW - 14*mm])
    box.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), colors.HexColor("#f0fdf4")),
        ("LINEABOVE",     (0,0), (-1,-1), 0.6, GREEN),
        ("LINEBELOW",     (0,0), (-1,-1), 0.6, GREEN),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ]))
    return box

# ═══════════════════════════════════════════════════════════════════════════════
# CONTENT DATA
# ═══════════════════════════════════════════════════════════════════════════════

CONTENT = []

# ── INTRO ─────────────────────────────────────────────────────────────────────
CONTENT.append(sp(30))  # banner clearance

intro_tbl = Table([[
    Paragraph("HOW TO USE THIS GUIDE", ST_LABEL),
    Paragraph(
        "Step 1: Identify the patient's chief symptom.  "
        "Step 2: Find the symptom section below.  "
        "Step 3: Use the region/character column to narrow your differential.  "
        "Step 4: Apply red-flag features to rule out dangerous diagnoses first.  "
        "Step 5: Confirm with clinical examination + investigations.",
        ST_BODY)
]], colWidths=[38*mm, CW - 38*mm])
intro_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,-1), colors.HexColor("#eff6ff")),
    ("TOPPADDING",    (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("LINEALL",       (0,0), (-1,-1), 0.4, MID),
]))
CONTENT.append(intro_tbl)
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 1. ABDOMINAL PAIN
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(1)", "ABDOMINAL PAIN", DARK),
    sp(2),
    Paragraph("Differential by Region of Maximal Pain", ST_LABEL),
    sp(1),
]))

W = CW
w = [38*mm, 38*mm, W - 76*mm]
pain_region_rows = [
    ("RUQ", "Liver / GB / duodenum / right lower lobe",
     "Cholecystitis, Cholangitis, Hepatitis, Peptic ulcer (duodenal), Right pneumonia, Subphrenic abscess"),
    ("Epigastric", "Stomach / pancreas / duodenum / aorta",
     "Peptic ulcer, Gastritis, Pancreatitis, GORD, Ruptured AAA, MI (referred)"),
    ("LUQ", "Spleen / stomach / left lower lobe",
     "Splenic infarct/rupture, Gastric volvulus, Left pneumonia, Pancreatitis (tail)"),
    ("Periumbilical", "Small bowel / appendix (early) / aorta",
     "Early appendicitis (visceral), SBO, Mesenteric ischaemia, Aortic dissection"),
    ("RIF", "Appendix / caecum / right ureter / right ovary",
     "Appendicitis, Ileocaecal TB, Crohn's, Ovarian cyst/torsion (F), Ectopic (F), Ureteric colic"),
    ("LIF", "Sigmoid / descending colon / left ureter / left ovary",
     "Diverticulitis, Sigmoid volvulus, Colorectal Ca, Ovarian pathology (F), Ureteric colic"),
    ("Suprapubic / Pelvic", "Bladder / uterus / rectum",
     "UTI, Bladder retention, PID (F), Ectopic pregnancy (F), Cystitis, Prostatitis"),
    ("Loin / Flank", "Kidney / ureter / retroperitoneum",
     "Ureteric/renal colic, Pyelonephritis, Perinephric abscess, Retroperitoneal haematoma"),
    ("Diffuse", "Peritoneum / entire bowel / metabolic",
     "Peritonitis (perforated viscus), Generalised SBO, DKA, Sickle cell crisis, Mesenteric ischaemia"),
]
CONTENT.append(diag_table(
    ["Region", "Underlying Structures", "Key Differentials"],
    pain_region_rows, w))

CONTENT.append(sp(3))
CONTENT.append(Paragraph("Character of Pain -> Diagnosis Clues", ST_LABEL))
CONTENT.append(sp(1))
w2 = [30*mm, 30*mm, CW - 60*mm]
pain_char_rows = [
    ("Colicky", "Hollow viscus obstruction/spasm", "Ureteric colic, SBO, Biliary colic, Early appendicitis"),
    ("Constant burning", "Mucosal / chemical", "Peptic ulcer, Gastritis, Pancreatitis, Ischaemia"),
    ("Severe tearing", "Vascular catastrophe", "Ruptured AAA, Aortic dissection"),
    ("Sudden onset ('thunderclap')", "Perforation / vascular rupture", "Perforated duodenal ulcer, Ruptured spleen, Ruptured ectopic"),
    ("Gradual onset", "Inflammatory / infective", "Appendicitis (early), Cholecystitis, Diverticulitis"),
    ("Referred to shoulder", "Diaphragmatic irritation", "Subphrenic collection, Ruptured spleen, Ectopic"),
    ("Relieved by food", "Duodenal pattern", "Duodenal ulcer"),
    ("Worse with food", "Gastric / ischaemic pattern", "Gastric ulcer, Mesenteric ischaemia"),
]
CONTENT.append(diag_table(
    ["Character", "Mechanism", "Key Diagnoses"],
    pain_char_rows, w2))

CONTENT.append(sp(2))
CONTENT.append(red_flags_box([
    "Peritonism (rigid abdomen, guarding, rebound)",
    "Haemodynamic instability",
    "Suspected vascular catastrophe (AAA, ectopic)",
    "Obstruction with strangulation",
]))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 2. VOMITING
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(2)", "VOMITING", colors.HexColor("#7c3aed")),
    sp(2),
]))

w3 = [38*mm, CW - 38*mm]
vom_rows = [
    ("Projectile, non-bilious\n(infant)", "Pyloric stenosis (male infant 2-8 wks), Pyloric stenosis in adults"),
    ("Bilious vomiting\n(infant/child)", "Duodenal atresia, Malrotation + volvulus, Jejuno-ileal atresia (neonate)"),
    ("Large volume, faeculent", "Distal SBO or LBO (late), Gastrocolic fistula"),
    ("Bile-stained, colicky pain", "Small bowel obstruction (SBO): adhesions, hernia, intussusception (child)"),
    ("Haematemesis", "See BLEEDING section below -- GI bleed"),
    ("Vomiting + absolute constipation + distension", "Bowel obstruction (SBO or LBO) -- emergency"),
    ("Post-prandial (30-60 min)", "Peptic ulcer, Gastroparesis, Gastric outflow obstruction"),
    ("Vomiting + severe epigastric pain radiating to back", "Acute pancreatitis"),
    ("Vomiting + jaundice + RUQ pain (Charcot's triad)", "Acute cholangitis -- emergency"),
    ("Vomiting + headache (no abdominal signs)", "Raised ICP, Meningitis -- surgical if hydrocephalus"),
]
CONTENT.append(diag_table(
    ["Vomiting Character / Context", "Key Surgical Diagnoses"],
    vom_rows, w3, alt_color=colors.HexColor("#f5f0ff")))

CONTENT.append(sp(2))
CONTENT.append(red_flags_box([
    "Absolute constipation + distension = obstruction until proven otherwise",
    "Bilious vomiting in neonate = surgical emergency",
    "Haematemesis = upper GI bleed (see below)",
]))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 3. RECTAL BLEEDING / PR BLEED
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(3)", "RECTAL / PER-RECTAL (PR) BLEEDING", RED),
    sp(2),
]))

w4 = [38*mm, 30*mm, CW - 68*mm]
pr_rows = [
    ("Fresh bright red blood on paper only", "Perianal", "Fissure-in-ano, Haemorrhoids (1st/2nd degree)"),
    ("Bright red blood dripping after defaecation", "Anal canal / rectum", "Haemorrhoids (3rd/4th degree), Fissure, Rectal polyp"),
    ("Blood mixed with stool", "Colon / rectum", "Colorectal carcinoma, Diverticular disease, IBD (UC)"),
    ("Blood + mucus (\"slime\")", "Rectum / sigmoid", "Rectal carcinoma, UC, Villous adenoma"),
    ("Melaena (black tarry stool)", "Upper GI (>~Treitz lig.)", "Peptic ulcer bleed, Varices, Mallory-Weiss, Gastric Ca"),
    ("Melaena + haematemesis", "Upper GI bleed", "Duodenal ulcer (most common), Oesophageal varices"),
    ("Massive fresh PR bleed (older patient)", "Right colon / angiodysplasia", "Diverticular bleed, Angiodysplasia, Ischaemic colitis"),
    ("PR bleed + pain + change in bowel habit (>40 yrs)", "Colon / rectum", "Colorectal carcinoma -- refer urgently"),
    ("PR bleed + mucus + tenesmus (young patient)", "Rectum", "Ulcerative proctitis, Rectal polyp, Low rectal Ca"),
    ("PR bleed in child (< 2 yrs)", "Ileum", "Meckel's diverticulum (classically painless, massive)"),
    ("Blood per rectum + abdominal pain + sausage-shaped mass (child)", "Ileocaecal", "Intussusception"),
]
CONTENT.append(diag_table(
    ["Appearance / Context", "Level", "Key Diagnoses"],
    pr_rows, w4))

CONTENT.append(sp(2))
CONTENT.append(red_flags_box([
    "Melaena or haematemesis = upper GI bleed (resuscitate first)",
    "Massive bright red PR = lower GI bleed (may need urgent scope/surgery)",
    "Change in bowel habit + bleeding + weight loss (>40 yrs) = colorectal Ca until proven otherwise",
]))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 4. HAEMATEMESIS (Upper GI Bleed)
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(4)", "HAEMATEMESIS (UPPER GI BLEED)", RED),
    sp(2),
]))

w5 = [40*mm, CW - 40*mm]
haem_rows = [
    ("Fresh red blood / clots", "Active arterial bleed -- peptic ulcer (most common), varices"),
    ("Coffee-ground vomit", "Slower bleed: peptic ulcer, gastric erosions, gastric Ca"),
    ("History of NSAIDs/aspirin", "Peptic ulcer (duodenal > gastric), gastric erosions"),
    ("History of alcohol / liver disease / splenomegaly", "Oesophageal or gastric varices -- EMERGENCY"),
    ("History of forceful vomiting then haematemesis", "Mallory-Weiss tear (mucosal tear at GOJ)"),
    ("Dysphagia + weight loss + haematemesis (older)", "Oesophageal carcinoma"),
    ("Anorexia + weight loss + epigastric mass", "Gastric carcinoma"),
    ("Swallowed blood (nosebleed, haemoptysis)", "Not true haematemesis -- take full history"),
]
CONTENT.append(diag_table(
    ["Context / Character", "Key Diagnoses"],
    haem_rows, w5, alt_color=colors.HexColor("#fff5f5")))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 5. SWELLING / LUMP
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(5)", "SWELLING / LUMP", colors.HexColor("#0f766e")),
    sp(2),
]))

CONTENT.append(Paragraph("Swelling by Site", ST_LABEL))
CONTENT.append(sp(1))
w6 = [32*mm, 32*mm, CW - 64*mm]
lump_rows = [
    ("Neck -- midline", "Thyroid / thyroglossal / lymph node", "Thyroid goitre, Thyroglossal cyst (moves with tongue protrusion), Midline lymph node, Dermoid cyst"),
    ("Neck -- lateral", "Lymph nodes / branchial / carotid", "Lymphadenopathy (reactive/TB/Ca), Branchial cyst (young adult), Carotid body tumour, Sternomastoid tumour (neonate), Cystic hygroma (child)"),
    ("Breast", "Glandular / connective tissue", "Fibroadenoma (young F, rubbery), Fibrocystic change, Breast abscess (lactating), Breast carcinoma (hard, irregular, tethered)"),
    ("Groin", "Hernia / lymph node / femoral", "Inguinal hernia (above & medial to pubic tubercle), Femoral hernia (below & lateral -- strangulates more), Lymph node (reactive/TB/Ca), Saphena varix, Femoral artery aneurysm"),
    ("Scrotum", "Testis / epididymis / cord", "Hydrocoele (transilluminates), Epididymal cyst (above and behind testis, transilluminates), Varicocoele (bag of worms, left side), Testicular tumour (HARD, does NOT transilluminate), Epididymo-orchitis (tender, warm)"),
    ("Abdominal wall", "Hernia / lipoma / DSTR", "Umbilical hernia, Paraumbilical hernia, Incisional hernia, Lipoma, Desmoid tumour"),
    ("Abdominal mass", "Visceral / retroperitoneal", "See intra-abdominal section"),
    ("Perianal / perineal", "Anal canal / skin", "External haemorrhoids, Perianal abscess, Anal fistula opening, Pilonidal sinus, Anal carcinoma"),
    ("Limb", "Soft tissue / bone", "Lipoma (soft, lobulated, fluctuant), Sebaceous cyst (punctum present), Ganglion (wrist, transilluminates), Lymph node, Bone tumour"),
]
CONTENT.append(diag_table(
    ["Site", "Structures", "Key Diagnoses (differentials)"],
    lump_rows, w6))

CONTENT.append(sp(3))
CONTENT.append(Paragraph("Features of a Lump -- Assess Every Swelling Systematically", ST_LABEL))
CONTENT.append(sp(1))
feat_data = [
    [Paragraph("Site", ST_CELL_B), Paragraph("Size", ST_CELL_B), Paragraph("Shape", ST_CELL_B),
     Paragraph("Surface", ST_CELL_B), Paragraph("Consistency", ST_CELL_B),
     Paragraph("Mobility", ST_CELL_B), Paragraph("Transilluminates?", ST_CELL_B),
     Paragraph("Reducible?", ST_CELL_B), Paragraph("Pulsatile?", ST_CELL_B)],
    [Paragraph("Document precisely", ST_CELL),
     Paragraph("Measure (cm)", ST_CELL),
     Paragraph("Round / oval / irregular", ST_CELL),
     Paragraph("Smooth / nodular", ST_CELL),
     Paragraph("Soft / firm / hard / fluctuant / rubbery", ST_CELL),
     Paragraph("Free / tethered to skin / deep", ST_CELL),
     Paragraph("Fluid/cyst = yes", ST_CELL),
     Paragraph("Hernia / varix = yes", ST_CELL),
     Paragraph("Vascular tumour = yes", ST_CELL)],
]
feat_tbl = Table(feat_data, colWidths=[CW/9]*9)
feat_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  LIGHT_HDR),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 6.5),
    ("TOPPADDING",    (0,0), (-1,-1), 2),
    ("BOTTOMPADDING", (0,0), (-1,-1), 2),
    ("LEFTPADDING",   (0,0), (-1,-1), 2),
    ("GRID",          (0,0), (-1,-1), 0.3, LINE),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
]))
CONTENT.append(feat_tbl)

CONTENT.append(sp(2))
CONTENT.append(red_flags_box([
    "Hard, irregular, fixed, tethered lump = malignancy until proven otherwise",
    "Rapidly enlarging lump",
    "Testicular lump = tumour until proven otherwise (do NOT transilluminate and diagnose)",
]))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 6. DYSPHAGIA
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(6)", "DYSPHAGIA (DIFFICULTY SWALLOWING)", colors.HexColor("#b45309")),
    sp(2),
]))

w7 = [42*mm, CW - 42*mm]
dys_rows = [
    ("Solids only -> progressing to liquids\nOlder patient + weight loss", "Carcinoma of oesophagus (most common cause of progressive dysphagia in elderly)"),
    ("Solids and liquids (intermittent)\nYoung patient, worse with stress", "Achalasia cardia (failure of LOS relaxation)"),
    ("Solids and liquids (progressive)\nMidline chest pain", "Achalasia, Pharyngeal pouch, Diffuse oesophageal spasm"),
    ("Preceded by heartburn for years\nOlder patient, smoker", "Carcinoma in Barrett's oesophagus, Peptic stricture"),
    ("Foreign body sensation\nPulsatile mass in neck", "Pharyngeal pouch (Zenker's diverticulum -- regurgitation of undigested food)"),
    ("Difficulty initiating swallow, nasal regurgitation", "Neurological cause (not surgical primary) -- but consider pharyngeal pouch"),
    ("Plummer-Vinson syndrome\n(iron deficiency + glossitis + koilonychia)", "Post-cricoid web -- increased risk of post-cricoid Ca"),
    ("History of caustic ingestion", "Oesophageal stricture"),
    ("Dysphagia + mediastinal widening on CXR", "External compression: lymphoma, aortic aneurysm, goitre, Ca lung"),
]
CONTENT.append(diag_table(
    ["Clinical Context", "Key Diagnoses"],
    dys_rows, w7, alt_color=colors.HexColor("#fffbeb")))
CONTENT.append(sp(2))
CONTENT.append(key_box(
    "Progressive dysphagia solids -> liquids = mechanical (carcinoma / stricture).  "
    "Solids AND liquids from onset = motility disorder (achalasia).  "
    "All cases need endoscopy / barium swallow."))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 7. JAUNDICE
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(7)", "JAUNDICE (Surgical / Obstructive Focus)", colors.HexColor("#92400e")),
    sp(2),
]))

w8 = [36*mm, 30*mm, CW - 66*mm]
jd_rows = [
    ("Painless progressive jaundice\nPalpable gallbladder (Courvoisier's sign)", "Obstructive -- distal", "Carcinoma of head of pancreas (Courvoisier positive), Cholangiocarcinoma, Ampullary carcinoma"),
    ("Jaundice + colicky RUQ pain\n+ fever (Charcot's triad)", "Obstructive -- CBD stone", "Choledocholithiasis with cholangitis -- EMERGENCY"),
    ("Jaundice + RUQ pain + Fever + Hypotension + Confusion (Reynolds' pentad)", "Obstructive -- severe", "Suppurative cholangitis -- life-threatening"),
    ("Intermittent jaundice + pruritus\nNo pain, no fever", "Obstructive", "Benign biliary stricture, CBD stone, Choledochal cyst"),
    ("Jaundice + anorexia + weight loss + no pain", "Obstructive", "Pancreatic head Ca, Cholangiocarcinoma (Klatskin tumour at hilum)"),
    ("Pre-hepatic (haemolytic)\nDark urine absent, pale stools absent", "Pre-hepatic", "Sickle cell, G6PD, Hereditary spherocytosis -- surgical = splenectomy sometimes"),
    ("Hepatic jaundice\nTransaminases elevated", "Hepatocellular", "Hepatitis, Cirrhosis, Drug-induced -- not primarily surgical"),
    ("Neonatal jaundice\npersisting >2 wks, pale stools, dark urine", "Obstructive", "Biliary atresia -- surgical emergency (Kasai procedure <60 days)"),
]
CONTENT.append(diag_table(
    ["Clinical Pattern", "Type", "Key Diagnoses"],
    jd_rows, w8))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 8. URINARY SYMPTOMS
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(8)", "URINARY SYMPTOMS", MID),
    sp(2),
]))

w9 = [42*mm, CW - 42*mm]
uri_rows = [
    ("Haematuria (painless) -- older patient", "Carcinoma of bladder (TCC) -- refer urgently | Renal cell carcinoma"),
    ("Haematuria + loin pain + abdominal mass\n(\"classic triad\")", "Renal cell carcinoma (only 10% have all three -- late sign)"),
    ("Haematuria + severe colicky loin-to-groin pain", "Ureteric calculus (renal colic)"),
    ("Haematuria + dysuria + frequency + fever", "Pyelonephritis / UTI with haematuria -- usually not surgical unless abscess"),
    ("Poor stream + nocturia + hesitancy + post-void dribbling\n(older male)", "Benign prostatic hyperplasia (BPH) | Carcinoma of prostate"),
    ("Acute urinary retention (painful, no urine)\nOlder male", "BPH (most common), Prostate Ca, Stricture, Clot retention post-haematuria"),
    ("Chronic urinary retention (painless, large bladder)\nOverflow incontinence", "BPH, Neurogenic bladder, Posterior urethral stricture, Spinal cord pathology"),
    ("Scrotal/testicular pain + swelling\n(young male, sudden onset)", "Testicular torsion -- SURGICAL EMERGENCY (6 hrs window)"),
    ("Scrotal swelling (painless) + testicular mass", "Testicular tumour (teratoma <30 yrs, seminoma 30-40 yrs)"),
    ("Urethral discharge + dysuria\n(young sexually active)", "Urethritis (STI: gonorrhoea, chlamydia) -- not surgical primarily"),
]
CONTENT.append(diag_table(
    ["Urinary Symptom / Context", "Key Diagnoses"],
    uri_rows, w9))

CONTENT.append(sp(2))
CONTENT.append(red_flags_box([
    "Painless haematuria in any adult = bladder/renal carcinoma until proven otherwise",
    "Testicular torsion = 6-hour window -- immediate surgical exploration",
    "Acute urinary retention = catheterise then investigate",
]))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 9. CHANGE IN BOWEL HABIT
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(9)", "CHANGE IN BOWEL HABIT", colors.HexColor("#166534")),
    sp(2),
]))

w10 = [42*mm, CW - 42*mm]
bh_rows = [
    ("Alternating constipation and diarrhoea\n>40 yrs, with PR bleed / weight loss", "Colorectal carcinoma -- urgent colonoscopy"),
    ("Increasing constipation + colicky pain + distension\nGradual onset (older)", "Left-sided colonic tumour (LBO), Diverticular stricture"),
    ("Constipation only (no other features)\nYounger patient", "Functional / IBS, Hypothyroidism, Drug-induced"),
    ("Sudden onset constipation + absolute\n(no stool, no flatus)", "Bowel obstruction (SBO or LBO)"),
    ("Diarrhoea + blood + mucus + urgency + tenesmus", "Ulcerative colitis (UC) -- surgical if fulminant/toxic megacolon"),
    ("Diarrhoea + crampy RIF pain + weight loss + perianal disease", "Crohn's disease (right-sided, skip lesions, transmural)"),
    ("Explosive diarrhoea post-antibiotics (elderly)", "Clostridioides difficile colitis -- can require surgical colectomy if toxic"),
    ("Constipation since birth (neonate)\nAbdominal distension + bilious vomiting", "Hirschsprung's disease -- emergency (Hartmann's or pull-through)"),
    ("Ribbon-like stools + straining", "Anal stenosis, Low rectal carcinoma, Anal fissure (pain)"),
]
CONTENT.append(diag_table(
    ["Bowel Habit Pattern / Context", "Key Diagnoses"],
    bh_rows, w10, alt_color=colors.HexColor("#f0fdf4")))

CONTENT.append(sp(2))
CONTENT.append(key_box(
    "Left colon Ca -> obstructive (constipation, narrow stools).  "
    "Right colon Ca -> anaemia, weight loss, mass (less obstruction due to wide lumen and liquid stool).  "
    "Any change in bowel habit >4 weeks in patient >40 yrs = colonoscopy."))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 10. WEIGHT LOSS (SURGICAL CONTEXT)
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(10)", "WEIGHT LOSS (Surgical Context)", colors.HexColor("#7f1d1d")),
    sp(2),
]))

w11 = [42*mm, CW - 42*mm]
wl_rows = [
    ("Weight loss + dysphagia", "Oesophageal Ca, Gastric Ca, Achalasia"),
    ("Weight loss + painless jaundice", "Carcinoma of head of pancreas, Cholangiocarcinoma"),
    ("Weight loss + PR bleed + change in bowel habit", "Colorectal carcinoma"),
    ("Weight loss + haematuria (painless)", "Renal cell carcinoma, Bladder carcinoma"),
    ("Weight loss + haemoptysis", "Lung carcinoma (not primarily surgical, but surgical referral for lobectomy/VATS)"),
    ("Weight loss + cervical lymphadenopathy", "Lymphoma, Metastatic carcinoma, TB"),
    ("Weight loss + epigastric pain radiating to back", "Carcinoma of pancreas, Chronic pancreatitis"),
    ("Weight loss + night sweats + fever (B-symptoms)", "Lymphoma -- surgical for biopsy"),
    ("Weight loss + abdominal mass + ascites", "GI carcinoma with peritoneal spread, Lymphoma, Ovarian Ca"),
]
CONTENT.append(diag_table(
    ["Associated Feature", "Key Surgical Diagnoses"],
    wl_rows, w11))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 11. BREAST SYMPTOMS
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(11)", "BREAST SYMPTOMS", colors.HexColor("#9d174d")),
    sp(2),
]))

w12 = [42*mm, CW - 42*mm]
br_rows = [
    ("Painless hard irregular lump\nFixed to skin or deep structures\n>35 yrs", "Breast carcinoma -- URGENT referral"),
    ("Smooth, firm, rubbery, mobile lump\nYoung female (<35 yrs)", "Fibroadenoma (\"breast mouse\" -- benign)"),
    ("Tender, fluctuant lump\nLactating woman", "Breast abscess (Staph. aureus most common)"),
    ("Tender, nodular bilateral lumps\nCyclical pain", "Fibrocystic change (benign)"),
    ("Bloody / blood-stained nipple discharge", "Intraductal papilloma (most common), Ductal carcinoma"),
    ("Nipple retraction (new)\nEczematous nipple change", "Breast carcinoma (Paget's disease of nipple)"),
    ("Peau d'orange skin\nFixed hard lump, lymphadenopathy", "Advanced breast carcinoma (lymphoedema of skin)"),
    ("Breast lump + axillary lymphadenopathy", "Metastatic breast carcinoma"),
    ("Breast enlargement in male (gynaecomastia)", "Drug-induced (spironolactone, digoxin, cimetidine), Liver cirrhosis, Testicular tumour"),
]
CONTENT.append(diag_table(
    ["Clinical Feature / Context", "Key Diagnoses"],
    br_rows, w12, alt_color=colors.HexColor("#fff1f2")))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# 12. LIMB / VASCULAR SYMPTOMS
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(12)", "LIMB / VASCULAR SYMPTOMS", colors.HexColor("#1e3a5f")),
    sp(2),
]))

w13 = [42*mm, CW - 42*mm]
vasc_rows = [
    ("Intermittent claudication\n(calf pain on walking, relieved by rest)", "Peripheral arterial disease (PAD) -- atherosclerosis"),
    ("Rest pain (burning pain at night, relieved by hanging foot)", "Severe PAD (critical limb ischaemia) -- urgent revascularisation"),
    ("Sudden onset cold, painful, pale, pulseless, paraesthetic limb\n(6 Ps)", "Acute limb ischaemia -- EMERGENCY (embolus or thrombosis)"),
    ("Varicose veins + ankle ulcer + lipodermatosclerosis", "Chronic venous insufficiency"),
    ("DVT: calf pain + swelling + warmth", "Deep vein thrombosis -- risk of PE"),
    ("Pulsatile abdominal mass (>3 cm aorta)\n+ back/loin pain", "Abdominal aortic aneurysm (AAA) -- if painful, urgent; if ruptured, emergency"),
    ("Expanding pulsatile groin lump\nPost-catheterisation", "False femoral aneurysm (pseudoaneurysm)"),
    ("Limb swelling (non-pitting)\nPost-axillary dissection / filariasis", "Lymphoedema"),
    ("Diabetic foot ulcer + cellulitis", "Diabetic foot (neuropathic +/- ischaemic) -- risk of wet gangrene, amputation"),
]
CONTENT.append(diag_table(
    ["Symptom / Context", "Key Diagnoses"],
    vasc_rows, w13))

CONTENT.append(sp(2))
CONTENT.append(red_flags_box([
    "Acute limb ischaemia (6 Ps) = surgical emergency (< 6 hours)",
    "Ruptured AAA = haemodynamic emergency",
    "Wet gangrene = surgical emergency",
]))
CONTENT.append(sp(4))

# ════════════════════════════════════════════════════════════════════════════════
# QUICK-REFERENCE MNEMONICS BOX
# ════════════════════════════════════════════════════════════════════════════════
CONTENT.append(KeepTogether([
    sym_header("(*)", "QUICK MNEMONICS FOR MBBS SURGERY", colors.HexColor("#374151")),
    sp(2),
]))

mn_data = [
    ["SOCRATES",       "Site, Onset, Character, Radiation, Associated sx, Timing, Exacerbating/relieving, Severity -- for ANY pain"],
    ["ABCDE (trauma)", "Airway, Breathing, Circulation, Disability, Exposure -- primary survey order"],
    ["6 Ps of acute ischaemia", "Pain, Pallor, Pulselessness, Paraesthesia, Paralysis, Perishing cold"],
    ["Courvoisier's Law", "Palpable GB + jaundice = NOT gallstones (wall too fibrosed) -- think Ca head of pancreas"],
    ["Charcot's Triad", "RUQ pain + Fever + Jaundice = Acute cholangitis (CBD obstruction + infection)"],
    ["Reynolds' Pentad", "Charcot's triad + Hypotension + Confusion = Suppurative cholangitis (life-threatening)"],
    ["Murphy's sign", "Inspiratory arrest on deep palpation of RUQ = Acute cholecystitis"],
    ["Virchow's Triad", "Stasis + Hypercoagulability + Endothelial damage = DVT/thrombosis"],
    ["Meckel's Rule of 2s", "2 feet from ileocaecal valve, 2 inches long, 2% of population, presents in 1st 2 years of life"],
    ["Transillumination", "Hydrocoele, Epididymal cyst, Ranula, Cystic hygroma = transilluminate. Solid / blood-filled = do NOT"],
]

mn_tbl = Table([[Paragraph(r[0], ST_CELL_B), Paragraph(r[1], ST_CELL)] for r in mn_data],
               colWidths=[48*mm, CW - 48*mm])
mn_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (0,-1),  LIGHT_HDR),
    ("LINEBELOW",     (0,0), (-1,-1), 0.3, LINE),
    ("GRID",          (0,0), (-1,-1), 0.2, LINE),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
]))
CONTENT.append(mn_tbl)
CONTENT.append(sp(3))

# Footer disclaimer
CONTENT.append(Paragraph(
    "Reference: S Das A Manual on Clinical Surgery 13th Ed | Bailey and Love's Short Practice of Surgery 28th Ed | "
    "Bailey and Love's | Yamada's Textbook of Gastroenterology | ROSEN's Emergency Medicine | Symptom to Diagnosis 4th Ed  "
    "-- For educational/clinical training use only.",
    ST_FOOTER))

# ══════════════════════════════════════════════════════════════════════════════
# BUILD
# ══════════════════════════════════════════════════════════════════════════════
doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    leftMargin=L_MARGIN,
    rightMargin=R_MARGIN,
    topMargin=T_MARGIN + 28*mm,
    bottomMargin=B_MARGIN + 8*mm,
)

doc.build(
    CONTENT,
    onFirstPage=banner,
    onLaterPages=banner_later,
)
print("DONE:", OUTPUT)
Running Command

cd /home/daytona/workspace/history-taking-template && python symptom_surgical_gu…

Running Command

python3 -c " from pypdf import PdfReader r = PdfReader('/home/daytona/workspace/…

Your printable A4 guide is ready - 7 pages, colour-coded by symptom:

Surgical Symptom Guide MBBS

PDF Document · PDF


What's inside (12 symptom sections):
#SymptomWhat's covered
1Abdominal PainDifferentials by region (RUQ/Epigastric/RIF/LIF etc.) + character (colicky/tearing/gradual)
2VomitingProjectile, bilious, faeculent, obstructive, pancreatitis, cholangitis patterns
3PR / Rectal BleedingBright red vs melaena, by level (anorectal -> colon -> upper GI), incl. Meckel's & intussusception
4HaematemesisCoffee-ground vs fresh blood, varices, Mallory-Weiss, gastric Ca
5Swelling / LumpBy site (neck, breast, groin, scrotum, limb) + 9-feature lump assessment grid
6DysphagiaSolids-only vs both, progressive vs intermittent - carcinoma vs achalasia vs Zenker's
7JaundiceCourvoisier's, Charcot's triad, Reynolds' pentad, biliary atresia (neonate)
8Urinary SymptomsPainless haematuria, retention, renal colic, testicular torsion
9Change in Bowel HabitLeft vs right colon Ca patterns, SBO, Hirschsprung's, UC vs Crohn's
10Weight LossLinked to GI/urological/vascular malignancy
11Breast SymptomsFibroadenoma vs Ca vs abscess, nipple discharge, Paget's disease
12Limb / VascularClaudication, acute ischaemia (6 Ps), DVT, AAA, diabetic foot
Mnemonics page at the end: SOCRATES, 6 Ps, Courvoisier's Law, Charcot's triad, Reynolds' pentad, Murphy's sign, Virchow's triad, Meckel's Rule of 2s, Transillumination guide.
Red-flag boxes are highlighted in red throughout so you never miss an emergency.

Why pd is not downloading

You mean the PDF isn't downloading? A few quick things to check:
Most common reasons:
  1. Browser blocking the download - Some browsers (especially on mobile) block direct file downloads. Try:
    • Long-press the link -> "Save link as" / "Download link"
    • Or open it in a new tab first, then download from there
  2. Mobile device - On phones, PDFs often open in a browser viewer instead of downloading. Look for a download icon (↓) in the top-right corner of the viewer.
  3. Pop-up blocker - If your browser blocks pop-ups, the download may be silently blocked. Check your browser's address bar for a blocked download notification.
  4. Network/connection issue - Try refreshing the page and clicking again.
  5. File not rendering as a link - If the link above doesn't appear clickable, copy this path directly:
    /home/daytona/workspace/history-taking-template/Surgical_Symptom_Guide_MBBS.pdf
    

Which PDF are you trying to download?
  • The History Taking Template
  • The Symptom-wise Surgical Guide
  • Both
Let me know your device/browser and I can give more specific help.
This is a shared conversation. Sign in to Orris to start your own chat.