I want to learn about history taking of patients clinically. How normally history is taken and how history is taken in different types of patients and diseases. Give me a high yield note about history taking so that my clinical exposure reaches on the next level
Sources: S Das Manual on Clinical Surgery (13th Ed) | Adams & Victor's Principles of Neurology (12th Ed) | Kaplan & Sadock's Comprehensive Textbook of Psychiatry | Sleisenger & Fordtran's GI and Liver Disease | Scott-Brown's Otorhinolaryngology | Campbell-Walsh-Wein Urology | Berek & Novak's Gynecology | Bailey & Love's Surgery (28th Ed)
| Parameter | Clinical Relevance |
|---|---|
| Name | Establishes rapport; patients respond better when called by name |
| Age | Congenital anomalies present early (cystic hygroma, cleft palate). Sarcomas peak in teenagers. Appendicitis peaks at 14-25 years in girls. Carcinomas mostly after 40. BPH and osteoarthritis are diseases of old age. Wilms' tumour - infants |
| Sex | Thyroid disease, visceroptosis, movable kidney, cystitis - commoner in females. Carcinoma of stomach, lung, kidney - commoner in males. Haemophilia is X-linked, affects males |
| Religion | Carcinoma of penis is rare in Jews and Muslims (circumcision). Intussusception sometimes seen after Ramadan fast |
| Social status | Acute appendicitis - higher social status. Tuberculosis - low social status, poor living conditions |
| Occupation | Varicose veins - bus conductors. Bladder tumours - aniline dye workers. Scrotal carcinoma - chimney sweepers, tar workers. Tennis elbow - tennis players. Medial meniscus injury - footballers and miners |
| Residence | Filariasis - endemic regions. Gallbladder disease - Bengal/Bangladesh. Peptic ulcer distribution by region |
"The patient is known by name, not by their disease." - S Das Manual on Clinical Surgery
| Mnemonic | What to Ask |
|---|---|
| O - Onset | When did it start? Sudden or gradual? What were you doing? |
| P - Provocation / Palliation | What makes it worse? What makes it better? |
| Q - Quality / Character | What does it feel like? (burning, stabbing, colicky, dull, throbbing) |
| R - Radiation | Does it move anywhere? (Never suggest the location - ask "Does it move at all?") |
| S - Severity | Rate 1-10. Does it interrupt sleep or daily activities? |
| T - Timing | Continuous or intermittent? Frequency? Duration of each episode? |
| U/A - Associated symptoms | What else do you notice when this happens? |
Physician (looking at chart): "Was the pain like before?" Patient: "Yes, well almost..." Physician (interrupting): "Was it made worse by food?"
Physician: "How can I help you?" Patient: "I developed a flare of my Crohn's... when I came back from vacation." Physician: "Yes?" Patient: "I was about to start my new position as floor supervisor and thought I'd take a vacation..."
| Feature | Implication |
|---|---|
| Sudden, tearing, radiating to back | Aortic dissection |
| Crushing, left arm/jaw radiation, sweating | MI (STEMI/ACS) |
| Sharp, pleuritic, worse on breathing | PE, pleuritis, pericarditis |
| Burning, worse after meals/lying | GORD |
| Positional (better leaning forward) | Pericarditis |
P - Patient identification (name, age, sex, occupation, residence, religion)
C - Chief complaint (chronological, with duration)
H - History of present illness (onset, progress, treatment)
A - Associated diseases (comorbidities)
P - Past history (previous illnesses and operations)
D - Drug history (current medications)
A - Allergy history (NEVER miss this - mark in RED)
P - Personal history (smoking, alcohol, diet, menstrual, bowel/bladder)
F - Family history (heritable and familial conditions)
I - Immunization history (especially in children)
Generate a downloadable PDF quick-reference guide for the complete PCHAPDAPFI framework
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace does not exist yet"
mkdir -p /home/daytona/workspace/history-taking-guide && python3 -c "import reportlab; print('reportlab ok')" && python3 -c "from reportlab.lib.pagesizes import A4; print('A4 ok')"
~/history-taking-guide/generate_pdf.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_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.platypus.flowables import BalancedColumns
from reportlab.graphics.shapes import Drawing, Rect, String
from reportlab.graphics import renderPDF
import os
OUTPUT = "/home/daytona/workspace/history-taking-guide/PCHAPDAPFI_Quick_Reference.pdf"
# ── Palette ─────────────────────────────────────────────────────────────────
NAVY = colors.HexColor("#0D2B55")
TEAL = colors.HexColor("#0A7A8F")
AMBER = colors.HexColor("#E07B00")
LIGHT_BG = colors.HexColor("#F0F6FA")
MINT_BG = colors.HexColor("#E8F8F5")
WARN_BG = colors.HexColor("#FFF3E0")
WHITE = colors.white
DARK_GRAY = colors.HexColor("#2C2C2C")
MID_GRAY = colors.HexColor("#555555")
LIGHT_RULE= colors.HexColor("#CBD5E0")
RED_ALERT = colors.HexColor("#C0392B")
W, H = A4 # 595.28 x 841.89 pts
# ── Document ─────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=18*mm,
rightMargin=18*mm,
topMargin=22*mm,
bottomMargin=18*mm,
title="PCHAPDAPFI Clinical History Taking - Quick Reference",
author="Orris Medical AI",
subject="Clinical History Taking Framework",
)
# ── Styles ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
TITLE_STYLE = S("DocTitle",
fontSize=22, leading=28, textColor=WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, spaceAfter=4)
SUBTITLE_STYLE = S("DocSubtitle",
fontSize=11, leading=14, textColor=colors.HexColor("#A8D8EA"),
fontName="Helvetica", alignment=TA_CENTER, spaceAfter=2)
SECTION_HEADER = S("SectionHeader",
fontSize=13, leading=17, textColor=WHITE, fontName="Helvetica-Bold",
alignment=TA_LEFT, spaceBefore=0, spaceAfter=0,
leftIndent=4, rightIndent=4)
LETTER_STYLE = S("LetterBig",
fontSize=28, leading=32, textColor=AMBER, fontName="Helvetica-Bold",
alignment=TA_CENTER)
LETTER_LABEL = S("LetterLabel",
fontSize=10, leading=13, textColor=NAVY, fontName="Helvetica-Bold",
alignment=TA_CENTER)
BODY = S("Body",
fontSize=9.5, leading=14, textColor=DARK_GRAY, fontName="Helvetica",
spaceAfter=3, spaceBefore=1)
BODY_BOLD = S("BodyBold",
fontSize=9.5, leading=14, textColor=DARK_GRAY, fontName="Helvetica-Bold",
spaceAfter=2, spaceBefore=1)
BULLET = S("Bullet",
fontSize=9, leading=13, textColor=DARK_GRAY, fontName="Helvetica",
leftIndent=12, firstLineIndent=-8, spaceAfter=1)
MINI = S("Mini",
fontSize=8, leading=11, textColor=MID_GRAY, fontName="Helvetica",
spaceAfter=1)
MINI_BOLD = S("MiniBold",
fontSize=8, leading=11, textColor=NAVY, fontName="Helvetica-Bold")
WARNING_TEXT = S("WarnText",
fontSize=9, leading=13, textColor=RED_ALERT, fontName="Helvetica-Bold",
alignment=TA_CENTER)
TIP_TEXT = S("TipText",
fontSize=8.5, leading=12, textColor=colors.HexColor("#1A5276"),
fontName="Helvetica-Oblique", leftIndent=6)
FOOTER_STYLE = S("Footer",
fontSize=7.5, leading=10, textColor=MID_GRAY, fontName="Helvetica",
alignment=TA_CENTER)
SOURCE_STYLE = S("Source",
fontSize=7, leading=9, textColor=colors.HexColor("#7F8C8D"),
fontName="Helvetica-Oblique", alignment=TA_CENTER)
# ── Helper builders ──────────────────────────────────────────────────────────
def section_header(text, bg=NAVY):
tbl = Table([[Paragraph(text, SECTION_HEADER)]], colWidths=[W - 36*mm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("ROUNDEDCORNERS", [4]),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return tbl
def colored_box(content_list, bg=LIGHT_BG, border=TEAL, radius=4):
"""Wraps a list of flowables in a single-cell table with colored background."""
inner = []
for item in content_list:
inner.append(item)
tbl = Table([[inner]], colWidths=[W - 36*mm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 1.2, border),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return tbl
def two_col_table(rows, col1_w=38*mm, col2_w=None):
cw2 = col2_w or (W - 36*mm - col1_w)
tbl = Table(rows, colWidths=[col1_w, cw2])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), LIGHT_BG),
("BACKGROUND", (1,0), (1,-1), WHITE),
("FONTNAME", (0,0), (0,-1), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("LEADING", (0,0), (-1,-1), 12),
("TEXTCOLOR", (0,0), (0,-1), NAVY),
("TEXTCOLOR", (1,0), (1,-1), DARK_GRAY),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("ROWBACKGROUNDS",(0,0), (-1,-1), [LIGHT_BG, colors.HexColor("#F7FBFD")]),
("GRID", (0,0), (-1,-1), 0.5, LIGHT_RULE),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return tbl
def mnemonic_card(letter, title, items, bg=LIGHT_BG, letter_color=AMBER):
# letter box
letter_cell = Paragraph(f'<font color="{letter_color.hexval() if hasattr(letter_color,"hexval") else "#E07B00"}">{letter}</font>', LETTER_STYLE)
label_cell = Paragraph(title, LETTER_LABEL)
bullet_text = "".join(f'• {i}<br/>' for i in items)
content_cell = Paragraph(bullet_text, MINI)
tbl = Table([
[letter_cell],
[label_cell],
[content_cell],
], colWidths=[38*mm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 1, TEAL),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ALIGN", (0,0), (0,1), "CENTER"),
]))
return tbl
# ── Page callbacks ───────────────────────────────────────────────────────────
def header_footer(canvas, doc):
canvas.saveState()
# Top bar
canvas.setFillColor(NAVY)
canvas.rect(0, H - 10*mm, W, 10*mm, fill=1, stroke=0)
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica-Bold", 8)
canvas.drawString(18*mm, H - 6.5*mm, "PCHAPDAPFI | Clinical History Taking Quick Reference")
canvas.setFont("Helvetica", 8)
canvas.drawRightString(W - 18*mm, H - 6.5*mm, f"Page {doc.page}")
# Bottom bar
canvas.setFillColor(NAVY)
canvas.rect(0, 0, W, 8*mm, fill=1, stroke=0)
canvas.setFillColor(colors.HexColor("#A8D8EA"))
canvas.setFont("Helvetica-Oblique", 7)
canvas.drawCentredString(W/2, 2.8*mm,
"Sources: S Das Manual on Clinical Surgery (13e) | Adams & Victor's Neurology (12e) | "
"Kaplan & Sadock's Psychiatry | Sleisenger & Fordtran's GI | Scott-Brown's ENT | Berek & Novak's Gynecology")
canvas.restoreState()
def first_page(canvas, doc):
canvas.saveState()
# Full-width hero banner
canvas.setFillColor(NAVY)
canvas.rect(0, H - 68*mm, W, 68*mm, fill=1, stroke=0)
# Teal accent stripe
canvas.setFillColor(TEAL)
canvas.rect(0, H - 68*mm, W, 3*mm, fill=1, stroke=0)
# Amber left accent bar
canvas.setFillColor(AMBER)
canvas.rect(0, H - 68*mm + 3*mm, 5*mm, 65*mm - 3*mm, fill=1, stroke=0)
# Title
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica-Bold", 26)
canvas.drawCentredString(W/2, H - 28*mm, "PCHAPDAPFI")
canvas.setFont("Helvetica-Bold", 14)
canvas.drawCentredString(W/2, H - 38*mm, "Clinical History Taking — Quick Reference Guide")
canvas.setFillColor(colors.HexColor("#A8D8EA"))
canvas.setFont("Helvetica-Oblique", 10)
canvas.drawCentredString(W/2, H - 48*mm, "A framework for complete, systematic history taking in every specialty")
canvas.setFillColor(AMBER)
canvas.setFont("Helvetica-Bold", 8)
canvas.drawCentredString(W/2, H - 58*mm, "Please Call Her — A Perfect Doctor Always Puts First Interest")
# Bottom bar
canvas.setFillColor(NAVY)
canvas.rect(0, 0, W, 8*mm, fill=1, stroke=0)
canvas.setFillColor(colors.HexColor("#A8D8EA"))
canvas.setFont("Helvetica-Oblique", 7)
canvas.drawCentredString(W/2, 2.8*mm,
"Sources: S Das Manual on Clinical Surgery (13e) | Adams & Victor's Neurology (12e) | "
"Kaplan & Sadock's Psychiatry | Sleisenger & Fordtran's GI | Scott-Brown's ENT | Berek & Novak's Gynecology")
canvas.restoreState()
# ── Content ──────────────────────────────────────────────────────────────────
story = []
# ── PAGE 1 hero spacer (content starts below the banner) ────────────────────
story.append(Spacer(1, 70*mm)) # push below the drawn hero
# ── MNEMONIC OVERVIEW ────────────────────────────────────────────────────────
story.append(section_header(" THE PCHAPDAPFI MNEMONIC — AT A GLANCE", NAVY))
story.append(Spacer(1, 4))
cards_data = [
("P", "Patient ID", ["Name, Age, Sex", "Occupation, Religion", "Residence, Social status"]),
("C", "Chief Complaint", ["Chronological order", "With duration each", "Most severe first"]),
("H", "Hx Present Illness",["Mode of onset", "Progress / evolution", "Treatment received"]),
("A", "Assoc. Diseases", ["Diabetes, HTN", "Asthma, bleeding d/o", "Tropical diseases"]),
("P", "Past History", ["Previous illnesses", "Previous operations", "Accidents / trauma"]),
("D", "Drug History", ["All current meds", "Steroids, anticoags", "OCP / HRT / MAOI"]),
("A", "Allergy", ["Mark in RED", "Drug + food allergy", "Type of reaction"]),
("P", "Personal History", ["Smoking & alcohol", "Diet & bowel/bladder", "Menstrual (women)"]),
("F", "Family History", ["Hereditary diseases", "Parents & siblings", "Cause of death"]),
("I", "Immunization", ["Especially children", "Vaccinations listed", "Travel vaccines"]),
]
# 5 cards per row × 2 rows
row1 = [mnemonic_card(l, t, items) for l, t, items in cards_data[:5]]
row2 = [mnemonic_card(l, t, items) for l, t, items in cards_data[5:]]
card_w = (W - 36*mm) / 5
grid1 = Table([row1], colWidths=[card_w]*5)
grid1.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),
]))
grid2 = Table([row2], colWidths=[card_w]*5)
grid2.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),
]))
story.append(grid1)
story.append(Spacer(1, 4))
story.append(grid2)
story.append(Spacer(1, 8))
# Memory aid
story.append(colored_box([
Paragraph('<b>Memory Aid:</b> <font color="#E07B00">"Please Call Her — A Perfect Doctor Always Puts First Interest"</font>', BODY),
Paragraph("P-C-H-A-P-D-A-P-F-I | 10 components | Universal across all specialties", MINI),
], bg=MINT_BG, border=TEAL))
story.append(Spacer(1, 8))
# ── PATIENT IDENTIFICATION ───────────────────────────────────────────────────
story.append(section_header(" P — PATIENT IDENTIFICATION (Demographics)"))
story.append(Spacer(1, 4))
id_rows = [
[Paragraph("Parameter", MINI_BOLD), Paragraph("Clinical Relevance", MINI_BOLD)],
["Name", "Establishes rapport; call patients by name for psychological benefit (pre- and post-op)"],
["Age", "Congenital anomalies: birth. Wilms' tumour: infants. Sarcomas: teens. Appendicitis: 14-25 yrs. Carcinomas: >40 yrs. BPH/Osteoarthritis: old age"],
["Sex", "Thyroid disease, cystitis, visceroptosis: commoner in females. Carcinoma stomach/lung/kidney: commoner in males. Haemophilia: males only"],
["Religion", "Ca penis rare in Jews & Muslims (circumcision). Intussusception after Ramadan fast"],
["Social status","Acute appendicitis: higher status. Tuberculosis: low socioeconomic status"],
["Occupation", "Varicose veins: bus conductors. Bladder tumours: aniline dye workers. Scrotal Ca: chimney sweeps/tar workers. Tennis elbow: racquet sports. Meniscus injury: footballers/miners"],
["Residence", "Filariasis: endemic areas. Gallbladder disease: Bengal/Bangladesh. Geographic distribution key for tropical diseases"],
]
id_rows_fmt = [[Paragraph(str(r[0]), MINI_BOLD), Paragraph(str(r[1]), MINI)] for r in id_rows]
id_tbl = Table(id_rows_fmt, colWidths=[30*mm, W - 36*mm - 30*mm])
id_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_BG, WHITE]),
("GRID", (0,0), (-1,-1), 0.5, LIGHT_RULE),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
]))
story.append(id_tbl)
story.append(Spacer(1, 8))
# ── CHIEF COMPLAINT ──────────────────────────────────────────────────────────
story.append(section_header(" C — CHIEF COMPLAINTS"))
story.append(Spacer(1, 4))
cc_content = [
Paragraph("• Record in <b>chronological order of appearance</b> with duration of each", BULLET),
Paragraph("• Ask: <i>\"What are your complaints?\"</i> or <i>\"What brings you here?\"</i>", BULLET),
Paragraph("• If multiple complaints start together, list in order of <b>severity</b>", BULLET),
Paragraph("• Always ask: <i>\"Were you perfectly well before [first symptom]?\"</i> — catches hidden prior symptoms", BULLET),
Spacer(1, 3),
Paragraph("<b>Example format:</b>", MINI_BOLD),
Paragraph("(a) Swelling in neck — 1 year (b) Evening fever — 10 months (c) Pain in swelling — 6 months (d) Sinus discharge — 1 month", MINI),
]
story.append(colored_box(cc_content, bg=LIGHT_BG))
story.append(Spacer(1, 8))
# ── HPI ─────────────────────────────────────────────────────────────────────
story.append(section_header(" H — HISTORY OF PRESENT ILLNESS (HPI)"))
story.append(Spacer(1, 4))
hpi_rows = [
[Paragraph("Component", MINI_BOLD), Paragraph("Key Questions & Notes", MINI_BOLD)],
["Mode of onset", "How did the trouble start? Sudden vs. gradual. Precipitating cause?"],
["Progress", "\"What is the next thing that happened?\" — Record evolution of symptoms chronologically in patient's own language"],
["Treatment", "What treatment was tried? By whom? What was the response?"],
]
hpi_fmt = [[Paragraph(str(r[0]), MINI_BOLD), Paragraph(str(r[1]), MINI)] for r in hpi_rows]
hpi_tbl = Table(hpi_fmt, colWidths=[35*mm, W - 36*mm - 35*mm])
hpi_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_BG, WHITE]),
("GRID", (0,0), (-1,-1), 0.5, LIGHT_RULE),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
]))
story.append(hpi_tbl)
story.append(Spacer(1, 5))
# OPQRST table
story.append(Paragraph("<b>OPQRST / SOCRATES — Analyzing Every Symptom (especially pain):</b>", BODY_BOLD))
story.append(Spacer(1, 3))
opqrst = [
[Paragraph("Letter", MINI_BOLD), Paragraph("Stands For", MINI_BOLD), Paragraph("What to Ask", MINI_BOLD)],
["O", "Onset", "When did it start? What were you doing? Sudden or gradual?"],
["P", "Provocation", "What makes it WORSE? What makes it BETTER?"],
["Q", "Quality", "Describe it: burning / stabbing / colicky / dull / throbbing / crushing?"],
["R", "Radiation", "\"Does it ever move?\" → \"Where does it go?\" (Never suggest the site!)"],
["S", "Severity", "Rate 1-10. Does it wake you from sleep? Stop daily activities?"],
["T", "Timing", "Continuous or intermittent? How long does each episode last? Frequency?"],
["A", "Associated", "What else happens at the same time? Nausea? Fever? Sweating?"],
]
opqrst_fmt = [
[Paragraph(str(r[0]), MINI_BOLD), Paragraph(str(r[1]), MINI_BOLD), Paragraph(str(r[2]), MINI)]
for r in opqrst
]
op_tbl = Table(opqrst_fmt, colWidths=[8*mm, 24*mm, W - 36*mm - 32*mm])
op_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), AMBER),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,1), (0,-1), colors.HexColor("#FFF3E0")),
("TEXTCOLOR", (0,1), (0,-1), AMBER),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("ROWBACKGROUNDS",(1,1), (-1,-1), [WHITE, LIGHT_BG]),
("GRID", (0,0), (-1,-1), 0.5, LIGHT_RULE),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
]))
story.append(op_tbl)
story.append(Spacer(1, 4))
story.append(colored_box([
Paragraph('<b>Golden Rule:</b> NEVER use leading questions. Do NOT ask: <i>"Does the pain go to the right scapula?"</i>', BODY),
Paragraph('Instead ask: <i>"Does the pain ever move anywhere?"</i> → <i>"Where does it go?"</i>', MINI),
Paragraph('<b>Negative answers are just as important</b> — absence of watery discharge at mealtimes in a cheek sinus rules out parotid fistula.', MINI),
], bg=WARN_BG, border=AMBER))
story.append(Spacer(1, 8))
# ── PAGE 2 ───────────────────────────────────────────────────────────────────
story.append(PageBreak())
# ── A — ASSOCIATED DISEASES ──────────────────────────────────────────────────
story.append(section_header(" A — ASSOCIATED DISEASES (Comorbidities)"))
story.append(Spacer(1, 4))
story.append(colored_box([
Paragraph("Ask about: Diabetes • Hypertension • Asthma • Bleeding disorders • Rheumatic fever • Tuberculosis • Tropical diseases", BULLET),
Paragraph("These affect <b>management, prognosis, and anaesthetic risk</b> — always document before any operative intervention.", MINI),
], bg=LIGHT_BG))
story.append(Spacer(1, 7))
# ── P — PAST HISTORY ─────────────────────────────────────────────────────────
story.append(section_header(" P — PAST HISTORY"))
story.append(Spacer(1, 4))
ph_items = [
"All previous illnesses in chronological order with dates and duration",
"Previous operations — type, date, indication",
"Previous accidents or trauma",
"Key conditions: peptic ulcer, pancreatitis, TB, gallbladder disease, appendicitis",
"Previous similar episodes of the current complaint",
]
story.append(colored_box([Paragraph("• " + i, BULLET) for i in ph_items], bg=LIGHT_BG))
story.append(Spacer(1, 7))
# ── D — DRUG HISTORY ─────────────────────────────────────────────────────────
story.append(section_header(" D — DRUG HISTORY"))
story.append(Spacer(1, 4))
drug_rows = [
[Paragraph("Category", MINI_BOLD), Paragraph("Examples & Relevance", MINI_BOLD)],
["Steroids", "Adrenal suppression, impaired wound healing — perioperative cover needed"],
["Anticoagulants", "Warfarin / heparin / NOACs — bleeding risk, reversal agents, bridging therapy"],
["Antidiabetics", "Insulin, metformin — peri-operative glucose management"],
["Antihypertensives","Beta-blockers, ACE inhibitors, ARBs — drug interactions, perioperative hypotension"],
["OCP / HRT", "DVT risk, drug interactions; ask about last dose"],
["MAOI", "Dangerous anaesthetic interactions — potentially fatal with pethidine/sympathomimetics"],
["Ergot derivatives","Vasoconstriction, interactions with anaesthetics"],
["In elderly", "Review full list — benzodiazepines & anticholinergics may cause or worsen cognitive impairment; stopping them can resolve symptoms"],
]
drug_fmt = [[Paragraph(str(r[0]), MINI_BOLD), Paragraph(str(r[1]), MINI)] for r in drug_rows]
drug_tbl = Table(drug_fmt, colWidths=[30*mm, W - 36*mm - 30*mm])
drug_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_BG, WHITE]),
("GRID", (0,0), (-1,-1), 0.5, LIGHT_RULE),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
]))
story.append(drug_tbl)
story.append(Spacer(1, 7))
# ── A — ALLERGY ───────────────────────────────────────────────────────────────
story.append(section_header(" A — ALLERGY HISTORY", RED_ALERT))
story.append(Spacer(1, 4))
story.append(colored_box([
Paragraph('<b>⚠ NEVER MISS THIS. Mark prominently in RED on the case sheet.</b>', WARNING_TEXT),
Paragraph("• Drug allergies — which drug? What reaction? (rash / anaphylaxis / angioedema?)", BULLET),
Paragraph("• Food allergies (latex cross-reactivity: avocado, banana, kiwi)", BULLET),
Paragraph("• Environmental allergens — pollen, dust mites, animal dander", BULLET),
Paragraph("• Contrast dye / iodine allergy — critical before imaging procedures", BULLET),
], bg=colors.HexColor("#FDEDEC"), border=RED_ALERT))
story.append(Spacer(1, 7))
# ── P — PERSONAL HISTORY ─────────────────────────────────────────────────────
story.append(section_header(" P — PERSONAL HISTORY"))
story.append(Spacer(1, 4))
personal_rows = [
[Paragraph("Item", MINI_BOLD), Paragraph("What to Record", MINI_BOLD)],
["Smoking", "Type (cigarettes/cigar/pipe/vaping), quantity, duration. Calculate Pack-Years = (packs/day) × (years smoked)"],
["Alcohol", "Quantity (units/week), type, duration. >14 units/week (women) or >21 units/week (men) = harmful use"],
["Diet", "Regular vs. irregular, vegetarian vs. non-vegetarian, spicy food, nutritional deficiencies"],
["Bowel habits", "Frequency, consistency, blood/mucus in stool, constipation vs. diarrhoea, tenesmus"],
["Bladder habits", "Frequency, nocturia, dysuria, haematuria, stream, hesitancy, terminal dribbling"],
["Menstrual (F)", "Age at menarche, cycle length (normal ~28 days), duration of flow, quantity, dysmenorrhoea, LMP"],
["Obstetric (F)", "GPAL: Gravida / Para / Abortions / Living children. Mode of delivery. Indication for LSCS"],
["Marital status", "Single / married / widowed / divorced. Sexual history if relevant"],
["Exercise", "Exercise tolerance — NYHA class if cardiac symptoms present"],
]
personal_fmt = [[Paragraph(str(r[0]), MINI_BOLD), Paragraph(str(r[1]), MINI)] for r in personal_rows]
personal_tbl = Table(personal_fmt, colWidths=[25*mm, W - 36*mm - 25*mm])
personal_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_BG, WHITE]),
("GRID", (0,0), (-1,-1), 0.5, LIGHT_RULE),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
]))
story.append(personal_tbl)
story.append(Spacer(1, 7))
# ── F — FAMILY HISTORY ───────────────────────────────────────────────────────
story.append(section_header(" F — FAMILY HISTORY"))
story.append(Spacer(1, 4))
fh_content = [
Paragraph("<b>Ask about:</b> Parents (alive/dead, cause of death), siblings, children", BODY),
Spacer(1, 3),
Paragraph("<b>Conditions with strong familial tendency:</b>", MINI_BOLD),
Paragraph("Haemophilia • Tuberculosis • Diabetes mellitus • Essential hypertension • Peptic ulcer • Colorectal cancer • Breast cancer • Fissure-in-ano / Haemorrhoids • Depression • Schizophrenia • Bipolar disorder • Familial hypercholesterolaemia • IHD / sudden cardiac death", MINI),
]
story.append(colored_box(fh_content, bg=LIGHT_BG))
story.append(Spacer(1, 7))
# ── I — IMMUNIZATION ─────────────────────────────────────────────────────────
story.append(section_header(" I — IMMUNIZATION HISTORY"))
story.append(Spacer(1, 4))
imm_content = [
Paragraph("<b>Especially important in children and travel history.</b>", BODY_BOLD),
Paragraph("Core vaccines: BCG (TB) • DTP (Diphtheria-Tetanus-Pertussis) • OPV / IPV (Polio) • Hepatitis B • MMR (Measles-Mumps-Rubella) • Varicella • Typhoid • Hib (H. influenzae type b)", MINI),
Paragraph("Adolescent / adult: HPV • Meningococcal • Influenza • Pneumococcal • COVID-19 boosters", MINI),
Paragraph("Travel vaccines: Yellow fever • Rabies • Japanese encephalitis • Hepatitis A", MINI),
]
story.append(colored_box(imm_content, bg=MINT_BG, border=TEAL))
story.append(Spacer(1, 10))
# ── PAGE 3 ───────────────────────────────────────────────────────────────────
story.append(PageBreak())
# ── INTERVIEWING TECHNIQUE ───────────────────────────────────────────────────
story.append(section_header(" THE ART OF CLINICAL INTERVIEWING — Communication Principles"))
story.append(Spacer(1, 4))
int_rules = [
("1", "Start open-ended", "Begin with open questions to generate hypotheses — \"How can I help you?\""),
("2", "Facilitate", "Use: \"Yes?\", \"Can you tell me more?\", head nodding, silent expectant pauses"),
("3", "Avoid closed Qs early","Yes/No questions come LATER to characterize symptoms — not at the start"),
("4", "No leading questions", "Never bias the patient's answer — ask open alternatives instead"),
("5", "Don't interrupt", "Let the patient narrate the first 2 minutes uninterrupted — most diagnostic info is here"),
("6", "No diagnostic language","Never ask \"What are you suffering from?\" — they give you a diagnosis, not symptoms"),
("7", "Psychosocial context", "Medical + social history together — setting of onset is always relevant"),
("8", "Watch nonverbal cues", "Pauses, looking down, hesitation signal sensitive psychosocial topics"),
]
int_fmt = [
[
Paragraph(f'<font color="#E07B00"><b>{r[0]}</b></font>', MINI_BOLD),
Paragraph(f'<b>{r[1]}</b>', MINI_BOLD),
Paragraph(r[2], MINI)
]
for r in int_rules
]
int_tbl = Table(int_fmt, colWidths=[8*mm, 36*mm, W - 36*mm - 44*mm])
int_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS",(0,0), (-1,-1), [LIGHT_BG, WHITE]),
("GRID", (0,0), (-1,-1), 0.5, LIGHT_RULE),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (0,0), (0,-1), "CENTER"),
]))
story.append(int_tbl)
story.append(Spacer(1, 7))
# ── SPECIAL POPULATIONS ──────────────────────────────────────────────────────
story.append(section_header(" HISTORY TAKING IN SPECIAL POPULATIONS & SPECIALTIES"))
story.append(Spacer(1, 4))
pop_data = [
("NEUROLOGICAL\nPATIENTS\n(Adams & Victor)",
[
"Assess reliability FIRST — cognitive impairment changes validity of history",
"Mode of onset is the most critical clue: Sudden → vascular | Gradual → tumour/degeneration | Episodic → epilepsy/migraine",
"Never suggest symptoms — ask patient to choose their own words",
"Collateral history essential: comatose / confused / very young patients",
"Functional timeline: what could they do 6 months ago vs. now?",
"Patient's own interpretation reveals hidden anxiety, depression, delusional thinking",
]
),
("PSYCHIATRIC\nPATIENTS\n(Kaplan & Sadock)",
[
"Components: ID data • CC (voluntary or brought?) • HPI • Past psych Hx • Medical Hx • Medications • Alcohol/substances • Work & living • Family Hx",
"Open-ended interview first; structured questions after",
"Relate symptom onset to life events: loss, retirement, loneliness, medical illness",
"Assess suicidal ideation, self-harm, violence (risk assessment mandatory)",
"Multiple somatic complaints: avoid premature psychological labelling; independent assessment each time",
]
),
("ELDERLY\nPATIENTS\n(Geriatric)",
[
"Treat with respect — expect direct inquiry and examination",
"Hearing impairment: move to good ear, speak slowly; written questions if needed",
"Cognitive impairment: explain tests, take frequent breaks",
"Collateral history from family/caregivers is often essential",
"MANDATORY: Full medication review — polypharmacy causes iatrogenic disease",
"Benzodiazepines & anticholinergics → cognitive symptoms that resolve when stopped",
"Initial session may need two visits; keep diagnosis open to revision",
]
),
("ENT / RHINOLOGY\n(Scott-Brown)",
[
"For nasal symptoms: duration, periodicity, nocturnal variation, laterality, seasonal effects",
"Key symptoms: obstruction, facial pain, anosmia/hyposmia, rhinorrhoea (clear vs. mucopurulent), post-nasal drip, epistaxis",
"RED FLAG: Unilateral obstruction + epistaxis + facial pain → suspect neoplasia → urgent assessment",
"Ask about allergies, asthma, aspirin hypersensitivity, prior nasal trauma/surgery, smoking, cocaine use",
"Systemic diseases with nasal manifestations: GPA (Wegener's), sarcoidosis, Churg-Strauss, Behcet's",
"Psychological aspects: stress and anxiety contribute to many rhinological symptoms",
]
),
("GASTROINTESTINAL\n(Sleisenger &\nFordtran)",
[
"Medical and social history together — psychosocial context of symptom onset is always relevant",
"Pain: site, radiation, relationship to food, timing (before/after/during meals)",
"Bowel habit change: frequency, consistency (Bristol stool scale), blood, mucus, tenesmus",
"Dysphagia: solids vs. liquids? Progressive? (progressive solids → carcinoma; solids AND liquids → motility disorder)",
"Jaundice: dark urine + pale stools = obstructive. Fever + rigors = cholangitis",
"Weight loss: intentional vs. unintentional (alarm symptom for malignancy)",
"Travel history: infections, parasites, tropical hepatitis",
]
),
("GYNAECOLOGICAL\n(Berek & Novak;\nCampbell-Walsh)",
[
"Menstrual: menarche age, cycle length, duration, quantity, dysmenorrhoea, LMP",
"Obstetric: GPAL (Gravida/Para/Abortions/Living). Mode of delivery. Indication for LSCS",
"Vaginal discharge: colour, odour, amount, associated itch/burning",
"Urinary incontinence subtype: Stress (coughing/sneezing/laughing/running) vs. Urgency (urgency precipitates leakage, triggered by cold/running water)",
"Sexual history: physician must initiate — only ~18% of patients with sexual dysfunction volunteer information",
"Medications affecting lower urinary tract: diuretics, anticholinergics, benzodiazepines, alpha-blockers",
]
),
]
for pop_name, pop_items in pop_data:
bullet_block = "".join(f"• {i}<br/>" for i in pop_items)
row = [
[Paragraph(pop_name.replace("\n", "<br/>"), MINI_BOLD)],
[Paragraph(bullet_block, MINI)],
]
pop_tbl = Table([[
Paragraph(pop_name.replace("\n", "<br/>"), MINI_BOLD),
Paragraph(bullet_block, MINI),
]], colWidths=[36*mm, W - 36*mm - 36*mm])
pop_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), NAVY),
("TEXTCOLOR", (0,0), (0,0), WHITE),
("BACKGROUND", (1,0), (1,0), LIGHT_BG),
("BOX", (0,0), (-1,-1), 0.5, LIGHT_RULE),
("LINEAFTER", (0,0), (0,-1), 1, TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("LEADING", (0,0), (-1,-1), 12),
]))
story.append(pop_tbl)
story.append(Spacer(1, 3))
story.append(Spacer(1, 6))
# ── PAGE 4 ───────────────────────────────────────────────────────────────────
story.append(PageBreak())
# ── DISEASE-SPECIFIC PEARLS ───────────────────────────────────────────────────
story.append(section_header(" DISEASE-SPECIFIC HISTORY PEARLS — High-Yield Differentials"))
story.append(Spacer(1, 4))
dx_data = [
("CHEST PAIN", [
("Sudden, tearing, radiates to back", "Aortic dissection — BP both arms, CXR widened mediastinum"),
("Crushing, left arm/jaw, sweating, nausea", "MI / ACS — ECG within 10 min, troponins"),
("Sharp, pleuritic, worse on inspiration", "PE, pleuritis, or pericarditis"),
("Burning, worse after meals / lying down", "GORD / oesophageal reflux"),
("Better leaning forward", "Pericarditis — pericardial friction rub"),
("Reproduced by palpation", "Musculoskeletal — costochondritis"),
]),
("DYSPNOEA", [
("Sudden onset + pleuritic pain + haemoptysis","Pulmonary embolism"),
("Orthopnoea + PND + ankle oedema", "Left ventricular failure"),
("Wheeze + atopy + nocturnal episodes", "Asthma — ask about triggers"),
("Wheeze + smoking history + barrel chest", "COPD"),
("Inspiratory stridor", "Upper airway obstruction — emergency"),
]),
("HEADACHE", [
("Thunderclap — worst headache of life", "Subarachnoid haemorrhage — urgent CT head"),
("Unilateral, throbbing, nausea, photophobia", "Migraine — ask about aura"),
("Band-like, bilateral, end of day", "Tension headache"),
("Severe, periorbital, unilateral, nocturnal", "Cluster headache — \"suicide headache\""),
("Temporal + jaw claudication + age >50", "Giant cell arteritis — ESR/CRP, temporal artery biopsy"),
("Worse on waking, projectile vomiting", "Raised ICP — papilloedema on fundoscopy"),
]),
("JAUNDICE", [
("Dark urine + pale stools + no pain", "Obstructive jaundice — painless → Ca head of pancreas"),
("Dark urine + pale stools + severe pain + fever + rigors (Charcot's triad)", "Ascending cholangitis — emergency"),
("Fever + RUQ pain + jaundice", "Acute cholecystitis / cholangitis"),
("IV drug use / tattoo / blood transfusion", "Viral hepatitis B or C"),
("Alcohol history", "Alcoholic hepatitis / cirrhosis"),
("Travel to tropics", "Hepatitis A/E, malaria, leptospirosis"),
("Drugs (antibiotics, NSAIDs, statins)", "Drug-induced liver injury"),
]),
("ABDOMINAL PAIN", [
("Periumbilical → RIF migration + nausea", "Acute appendicitis — Rovsing's, psoas sign"),
("RUQ colicky after fatty meals", "Biliary colic / cholecystitis — Murphy's sign"),
("Epigastric, hunger pain, relieved by food", "Peptic ulcer disease"),
("Sudden epigastric → generalised rigidity", "Perforated viscus — erect CXR: free air"),
("Central, radiates to back, alcohol/gallstones","Acute pancreatitis — serum amylase/lipase"),
("Colicky + distension + absolute constipation","Intestinal obstruction — ask about hernia, prev surgery"),
]),
]
for condition, findings in dx_data:
rows = [[Paragraph(f[0], MINI), Paragraph(f[1], MINI_BOLD)] for f in findings]
tbl = Table(rows, colWidths=[(W - 36*mm)*0.55, (W - 36*mm)*0.45])
tbl.setStyle(TableStyle([
("ROWBACKGROUNDS",(0,0), (-1,-1), [WHITE, LIGHT_BG]),
("GRID", (0,0), (-1,-1), 0.4, LIGHT_RULE),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTSIZE", (0,0), (-1,-1), 8),
]))
header_tbl = Table([[Paragraph(condition, MINI_BOLD)]], colWidths=[W - 36*mm])
header_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), TEAL),
("TEXTCOLOR", (0,0), (-1,-1), WHITE),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
("FONTSIZE", (0,0), (-1,-1), 9),
("FONTNAME", (0,0), (-1,-1), "Helvetica-Bold"),
]))
story.append(header_tbl)
story.append(tbl)
story.append(Spacer(1, 5))
story.append(Spacer(1, 6))
# ── TOP 8 CLINICAL TIPS ───────────────────────────────────────────────────────
story.append(section_header(" 8 GOLDEN TIPS FOR NEXT-LEVEL HISTORY TAKING"))
story.append(Spacer(1, 4))
tips = [
("1", "Never interrupt in the first 2 minutes",
"Research shows physicians interrupt patients within 18 seconds on average. Those first 2 minutes contain the most diagnostically valuable information."),
("2", "Negative answers are powerful",
"Absence of a symptom rules out diagnoses as powerfully as its presence. Always record relevant negatives."),
("3", "Begin the neurological exam in the waiting room",
"Observe gait, manner, how the patient tells their story — all yield clues to cognitive and motor dysfunction before formal examination."),
("4", "Resist the thick-chart bias",
"Perform an independent assessment every time. Prior clinicians' diagnoses should inform, not determine, your own conclusions."),
("5", "Use functional status as a timeline",
"When patients cannot quantify progression, ask: What could you do 6 months ago that you cannot do now?"),
("6", "Always ask about sexual health",
"Only ~18% of patients with sexual dysfunction volunteer this. The physician must create a safe space for this discussion."),
("7", "Medication review in every elderly patient",
"Iatrogenic disease is vastly under-recognised. Cognitive symptoms, falls, and incontinence may resolve when offending drugs are stopped."),
("8", "Note non-verbal communication",
"Pauses, looking down, and hesitation often signal psychosocial or sensitive issues that deserve gentle exploration."),
]
tip_rows = []
for num, title, detail in tips:
tip_rows.append([
Paragraph(f'<font color="#0A7A8F"><b>{num}</b></font>', MINI_BOLD),
Paragraph(f'<b>{title}</b><br/><font size="8" color="#555555">{detail}</font>', MINI),
])
tip_tbl = Table(tip_rows, colWidths=[8*mm, W - 36*mm - 8*mm])
tip_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS",(0,0), (-1,-1), [MINT_BG, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, LIGHT_RULE),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ALIGN", (0,0), (0,-1), "CENTER"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
]))
story.append(tip_tbl)
story.append(Spacer(1, 8))
# ── SOURCES ────────────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=1, color=LIGHT_RULE))
story.append(Spacer(1, 3))
story.append(Paragraph(
"<b>Sources:</b> S Das Manual on Clinical Surgery 13e (pp. 6-12) | Adams & Victor's Principles of Neurology 12e (pp. 6-8) | "
"Kaplan & Sadock's Comprehensive Textbook of Psychiatry (Geriatric section, pp. 12490-12492) | "
"Sleisenger & Fordtran's GI & Liver Disease (pp. 5-12) | Scott-Brown's Otorhinolaryngology Head & Neck Surgery Vol 1 & 2 | "
"Berek & Novak's Gynecology (p. 847) | Campbell-Walsh-Wein Urology (p. 2164)",
SOURCE_STYLE
))
# ── BUILD ─────────────────────────────────────────────────────────────────────
doc.build(story, onFirstPage=first_page, onLaterPages=header_footer)
print(f"PDF generated: {OUTPUT}")
cd /home/daytona/workspace/history-taking-guide && python3 generate_pdf.py 2>&1
~/history-taking-guide/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/history-taking-guide/generate_pdf.py'
cd /home/daytona/workspace/history-taking-guide && python3 generate_pdf.py 2>&1
~/history-taking-guide/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/history-taking-guide/generate_pdf.py'
cd /home/daytona/workspace/history-taking-guide && python3 generate_pdf.py 2>&1
~/history-taking-guide/generate_pdf.py
Error: String not found in file: 'int_fmt = [
[
Paragraph(f'<font color="#E07B00"><b>{r[0]}</b></font>', MINI_BOLD),
Paragraph(f'<b>{r[1]}</b>', MINI_BOLD),
Paragraph(r[2], MINI),
]
for r in int_rules
]
int_tbl = Table(int_fmt, colWidths=[8*mm, 36*mm, W - 36*mm - 44*mm])
int_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS",(0,0), (-1,-1), [LIGHT_BG, WHITE]),
("GRID", (0,0), (-1,-1), 0.5, LIGHT_RULE),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (0,0), (0,-1), "CENTER"),
]))
story.append(int_tbl)'"int_tbl" in ~/history-taking-guide
~/history-taking-guide/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/history-taking-guide/generate_pdf.py'
cd /home/daytona/workspace/history-taking-guide && python3 generate_pdf.py 2>&1
cd /home/daytona/workspace/history-taking-guide && python3 -c " from reportlab.lib.pagesizes import A4 W, H = A4 from reportlab.lib.units import mm # Jaundice has 7 rows, Abdominal pain has 6 rows - Let me check dx_data dx_data_sizes = { 'CHEST PAIN': 6, 'DYSPNOEA': 5, 'HEADACHE': 6, 'JAUNDICE': 7, 'ABDOMINAL PAIN': 6, } for k,v in dx_data_sizes.items(): print(f'{k}: {v} rows') print(f'Page usable height: {H - 10*mm - 8*mm - 22*mm - 18*mm:.1f} pts = {(H - 10*mm - 8*mm - 22*mm - 18*mm)/mm:.1f}mm') print('The error says 8 rows x 3 cols - check dx tables: none has 8 rows') print('Check int_rules - has 8 entries, 3 cols - this must be the STILL failing one') " 2>&1
"int_rules" in ~/history-taking-guide
grep -n "colored_box" /home/daytona/workspace/history-taking-guide/generate_pdf.py
~/history-taking-guide/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/history-taking-guide/generate_pdf.py'
cd /home/daytona/workspace/history-taking-guide && sed -i 's/story\.append(colored_box(/story.extend(colored_box(/g' generate_pdf.py && python3 generate_pdf.py 2>&1