History taking obs gynae
| Question | Detail |
|---|---|
| LMP (Last Menstrual Period) | Date; was it normal in character? |
| Menarche | Age at first period |
| Cycle length | Normal 21-35 days |
| Duration of flow | Normal 2-7 days |
| Amount | Heavy/light; number of pads; flooding; clots |
| Regularity | Regular, irregular, or absent (amenorrhoea) |
| Dysmenorrhoea | Primary or secondary; severity |
| IMB | Intermenstrual bleeding |
| PCB | Postcoital bleeding |
| PMB | Postmenopausal bleeding (in older women) |
| Menopause status | Age of menopause if applicable; HRT use |
| Element | Detail |
|---|---|
| Gestational age | LMP, EDD (Naegele's rule: LMP + 9 months + 7 days), dating scan |
| Symptoms of pregnancy | Morning sickness, fetal movements (from ~18-20 weeks), breast changes |
| Booking bloods | Blood group, antibody screen, FBC, rubella, syphilis, HIV, HBsAg, haemoglobinopathy screen |
| Antenatal scans | Dating scan, anomaly scan (20 weeks), growth scans |
| Risk assessment | Pre-eclampsia risk, GDM screening (OGTT), VTE risk |
| Current pregnancy complications | Bleeding, pain, reduced movements, leaking fluid |
| Fetal movements | Established by ~18-24 weeks; reduced movements requires urgent assessment |
Create a quick reference checklist PDF for obs & gynae history
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace not found"
mkdir -p /home/daytona/workspace/obs-gynae-checklist && python3 -c "import reportlab; print('reportlab ok')"
~/obs-gynae-checklist/generate_checklist.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER
OUTPUT = "/home/daytona/workspace/obs-gynae-checklist/ObsGynae_History_Checklist.pdf"
# ── Colour palette ────────────────────────────────────────────────────────────
TEAL = colors.HexColor("#1A6B6B")
TEAL_LIGHT = colors.HexColor("#E8F5F5")
PINK = colors.HexColor("#C0395A")
PINK_LIGHT = colors.HexColor("#FDF0F3")
GREY_DARK = colors.HexColor("#2D2D2D")
GREY_MID = colors.HexColor("#555555")
GREY_LIGHT = colors.HexColor("#F4F4F4")
WHITE = colors.white
AMBER = colors.HexColor("#F5A623")
AMBER_LIGHT= colors.HexColor("#FFF8EE")
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=14*mm,
rightMargin=14*mm,
topMargin=12*mm,
bottomMargin=12*mm,
)
W, H = A4
usable_w = W - 28*mm
styles = getSampleStyleSheet()
# Custom paragraph styles
def ps(name, size, color=GREY_DARK, bold=False, leading=None, alignment=TA_LEFT, space_before=0, space_after=2):
return ParagraphStyle(
name,
fontName="Helvetica-Bold" if bold else "Helvetica",
fontSize=size,
textColor=color,
leading=leading or (size * 1.35),
alignment=alignment,
spaceAfter=space_after,
spaceBefore=space_before,
)
title_style = ps("title", 20, TEAL, bold=True, alignment=TA_CENTER, space_after=2)
subtitle_style = ps("subtitle", 10, GREY_MID, alignment=TA_CENTER, space_after=1)
sec_style = ps("sec", 9, WHITE, bold=True, leading=12)
item_style = ps("item", 8, GREY_DARK, leading=11, space_after=0)
note_style = ps("note", 7, GREY_MID, leading=10)
box_label = ps("box_label", 7, GREY_MID, leading=9, alignment=TA_CENTER)
tag_style = ps("tag", 7.5, WHITE, bold=True, leading=10, alignment=TA_CENTER)
CHECKBOX = "☐"
BULLET = "•"
def checkbox(text, indent=0, bold_prefix=None):
prefix = f"<b>{bold_prefix}</b> " if bold_prefix else ""
ind = " " * (indent * 4)
return Paragraph(f"{ind}{CHECKBOX} {prefix}{text}", item_style)
def bullet(text, indent=0):
ind = " " * (indent * 4)
return Paragraph(f"{ind}{BULLET} {text}", note_style)
def section_header(text, bg=TEAL):
p = Paragraph(text.upper(), sec_style)
t = Table([[p]], colWidths=[usable_w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("ROUNDEDCORNERS", [3]),
]))
return t
def note_box(text, bg=TEAL_LIGHT, text_color=TEAL):
p = Paragraph(text, ParagraphStyle("nb", fontName="Helvetica", fontSize=7.5,
textColor=text_color, leading=10))
t = Table([[p]], colWidths=[usable_w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("BOX", (0,0), (-1,-1), 0.5, text_color),
("ROUNDEDCORNERS", [3]),
]))
return t
def two_col(left_items, right_items, left_header=None, right_header=None,
left_bg=TEAL_LIGHT, right_bg=PINK_LIGHT,
left_border=TEAL, right_border=PINK):
"""Two equal columns, each with optional header and list of flowables."""
col_w = (usable_w - 4*mm) / 2
def make_cell(header, items, bg, border):
cell = []
if header:
h = Paragraph(f"<b>{header}</b>",
ParagraphStyle("ch", fontName="Helvetica-Bold", fontSize=8,
textColor=border, leading=10))
cell.append(h)
cell.extend(items)
t = Table([[cell]], colWidths=[col_w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("BOX", (0,0), (-1,-1), 0.8, border),
("ROUNDEDCORNERS", [3]),
]))
return t
left_cell = make_cell(left_header, left_items, left_bg, left_border)
right_cell = make_cell(right_header, right_items, right_bg, right_border)
outer = Table([[left_cell, right_cell]], colWidths=[col_w, col_w],
spaceBefore=2, spaceAfter=2)
outer.setStyle(TableStyle([
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING", (0,0), (-1,-1), 0),
("ALIGN", (0,0), (-1,-1), "LEFT"),
("VALIGN", (0,0), (-1,-1), "TOP"),
("COLPADDING", (0,0), (0,-1), 0), # gap between cols handled by colWidths
]))
return outer
# ── Build story ───────────────────────────────────────────────────────────────
story = []
# ── TITLE BANNER ─────────────────────────────────────────────────────────────
title_text = Paragraph("Obs & Gynae History Taking", title_style)
subtitle_text = Paragraph("Quick Reference Checklist | Clinical OSCE Aid", subtitle_style)
banner = Table([[title_text], [subtitle_text]], colWidths=[usable_w])
banner.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), TEAL_LIGHT),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 1.5, TEAL),
("LINEBELOW", (0,0), (-1,0), 0.5, TEAL),
("ROUNDEDCORNERS", [4]),
]))
story.append(banner)
story.append(Spacer(1, 4*mm))
# ── ROW 1: Patient Details + Presenting Complaint ────────────────────────────
pd_items = [
checkbox("Name, age, DOB"),
checkbox("Gravidity / Parity (note at outset)"),
checkbox("Occupation"),
checkbox("Referring clinician / setting"),
]
pc_items = [
checkbox("Chief complaint in patient's own words"),
checkbox("Duration of complaint"),
bullet("Common: bleeding, pain, discharge, prolapse,"),
bullet("subfertility, vulval sx, reduced fetal movements"),
]
story.append(two_col(pd_items, pc_items,
left_header="1. PATIENT DETAILS",
right_header="2. PRESENTING COMPLAINT",
right_bg=AMBER_LIGHT, right_border=AMBER))
story.append(Spacer(1, 2*mm))
# ── SOCRATES HPC ─────────────────────────────────────────────────────────────
story.append(section_header("3. History of Presenting Complaint — SOCRATES"))
story.append(Spacer(1, 1.5*mm))
soc_data = [
["S — Site", "Localised / generalised? Unilateral / bilateral?"],
["O — Onset", "Sudden or gradual? Relation to menstrual cycle?"],
["C — Character", "Type of pain / bleeding (fresh, dark, clots, watery)"],
["R — Radiation", "To back, shoulder tip (diaphragm → ectopic), groin"],
["A — Associated","Fever, N&V, discharge, urinary sx, bowel sx, dyspareunia"],
["T — Timing", "Cyclical vs constant; continuous vs intermittent; duration"],
["E — Exac/Relieve","Posture, activity, analgesia, menses, sex"],
["S — Severity", "VAS 0-10; impact on work, daily life, sleep"],
]
col_w1 = 36*mm
col_w2 = usable_w - col_w1
soc_table = Table(
[[Paragraph(f"<b>{r[0]}</b>", ParagraphStyle("sc", fontName="Helvetica-Bold",
fontSize=8, textColor=TEAL, leading=11)),
Paragraph(r[1], item_style)] for r in soc_data],
colWidths=[col_w1, col_w2],
spaceBefore=0, spaceAfter=2
)
soc_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREY_LIGHT),
("BACKGROUND", (0,0), (0,-1), TEAL_LIGHT),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("ROWBACKGROUNDS", (0,0), (-1,-1), [TEAL_LIGHT, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(soc_table)
story.append(Spacer(1, 3*mm))
# ── ROW 2: Menstrual History ──────────────────────────────────────────────────
story.append(section_header("4. Menstrual History", bg=PINK))
story.append(Spacer(1, 1.5*mm))
men_left = [
checkbox("LMP — date and was it normal?"),
checkbox("Age at menarche"),
checkbox("Cycle length (normal 21–35 days)"),
checkbox("Duration of flow (normal 2–7 days)"),
checkbox("Amount — pads/tampons per day, flooding, clots"),
checkbox("Regularity — regular / irregular / absent"),
]
men_right = [
checkbox("Dysmenorrhoea — primary or secondary?"),
checkbox("Intermenstrual bleeding (IMB)"),
checkbox("Postcoital bleeding (PCB)"),
checkbox("Postmenopausal bleeding (PMB)"),
checkbox("Menopausal symptoms / HRT use"),
note_box("PALM-COEIN: Polyp · Adenomyosis · Leiomyoma · Malignancy\n"
"Coagulopathy · Ovulatory · Endometrial · Iatrogenic · NEC",
bg=PINK_LIGHT, text_color=PINK),
]
story.append(two_col(men_left, men_right,
left_bg=PINK_LIGHT, right_bg=PINK_LIGHT,
left_border=PINK, right_border=PINK))
story.append(Spacer(1, 3*mm))
# ── ROW 3: Obstetric History ──────────────────────────────────────────────────
story.append(section_header("5. Obstetric History — GTPAL"))
story.append(Spacer(1, 1.5*mm))
gtpal_data = [
["G — Gravida", "Total pregnancies (including current)"],
["T — Term", "Deliveries ≥ 37 weeks"],
["P — Preterm", "Deliveries 24–36+6 weeks"],
["A — Abortions", "Miscarriages / TOPs / ectopics (< 24 wks)"],
["L — Living", "Number of living children"],
]
gtpal_table = Table(
[[Paragraph(f"<b>{r[0]}</b>", ParagraphStyle("gt", fontName="Helvetica-Bold",
fontSize=8, textColor=TEAL, leading=11)),
Paragraph(r[1], item_style)] for r in gtpal_data],
colWidths=[col_w1, col_w2],
)
gtpal_table.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [TEAL_LIGHT, WHITE]),
("BACKGROUND", (0,0), (0,-1), TEAL_LIGHT),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(gtpal_table)
story.append(Spacer(1, 2*mm))
preg_label = Paragraph("<b>For each previous pregnancy record:</b>", item_style)
story.append(preg_label)
story.append(Spacer(1, 1*mm))
preg_items_left = [
checkbox("Year and gestation at delivery"),
checkbox("Mode: SVD / instrumental / CS"),
bullet("If CS — indication, lower segment vs classical"),
checkbox("Complications in pregnancy"),
bullet("Pre-eclampsia, GDM, APH, placenta praevia"),
]
preg_items_right = [
checkbox("Complications in labour/delivery"),
bullet("PPH, perineal tears, shoulder dystocia"),
checkbox("Baby — weight, sex, Apgar, NICU admission"),
checkbox("Postnatal complications"),
checkbox("Miscarriage / TOP / ectopic — gestation, Rh status"),
]
story.append(two_col(preg_items_left, preg_items_right))
story.append(Spacer(1, 3*mm))
# ── ROW 4: Gynae + Sexual History ────────────────────────────────────────────
gyn_items = [
checkbox("Cervical smear — date, result, colposcopy?"),
checkbox("Contraception — current and past methods"),
checkbox("STI history"),
checkbox("Subfertility — duration TTC, investigations"),
checkbox("Previous PID or pelvic surgery"),
checkbox("HRT / hormonal medications"),
]
sex_items = [
checkbox("Sexually active?"),
checkbox("Gender of partner(s)"),
checkbox("Dyspareunia — superficial or deep?"),
checkbox("Postcoital bleeding"),
checkbox("Safer sex / STI screening needs"),
note_box("Ask in private; use non-judgmental language",
bg=AMBER_LIGHT, text_color=AMBER),
]
story.append(two_col(gyn_items, sex_items,
left_header="6. GYNAECOLOGICAL HISTORY",
right_header="7. SEXUAL HISTORY",
left_bg=TEAL_LIGHT, right_bg=AMBER_LIGHT,
left_border=TEAL, right_border=AMBER))
story.append(Spacer(1, 3*mm))
# ── ROW 5: PMH + Drugs ───────────────────────────────────────────────────────
pmh_items = [
checkbox("Medical conditions"),
bullet("Diabetes, hypertension, thyroid, autoimmune"),
bullet("Coagulopathies (VWD, thrombophilia)"),
checkbox("Surgical history — esp. pelvic/abdominal"),
checkbox("Previous anaesthetic problems"),
checkbox("VTE / DVT / PE history"),
]
drug_items = [
checkbox("Current medications — including OTC & herbal"),
checkbox("Hormonal meds: OCP, HRT, progestogens"),
checkbox("Anticoagulants, antiepileptics"),
checkbox("Folic acid / iron supplementation"),
checkbox("Drug allergies + nature of reaction"),
checkbox("Recreational drugs (non-judgemental)"),
]
story.append(two_col(pmh_items, drug_items,
left_header="8. PAST MEDICAL HISTORY",
right_header="9. DRUG HISTORY & ALLERGIES",
left_bg=GREY_LIGHT, right_bg=GREY_LIGHT,
left_border=GREY_MID, right_border=GREY_MID))
story.append(Spacer(1, 3*mm))
# ── ROW 6: Family + Social ───────────────────────────────────────────────────
fam_items = [
checkbox("Gynaecological cancers (ovarian, endometrial, breast)"),
bullet("BRCA1/2 mutations — offer referral"),
checkbox("Pre-eclampsia, VTE in first-degree relatives"),
checkbox("Coagulopathies — VWD"),
checkbox("DM, HTN, congenital anomalies"),
checkbox("Haemoglobinopathies (sickle cell, thalassaemia)"),
]
soc_items = [
checkbox("Occupation & impact on symptoms"),
checkbox("Smoking — pack-years"),
checkbox("Alcohol — units/week"),
checkbox("Recreational drug use"),
checkbox("Relationship status & social support"),
checkbox("Domestic violence screen — ask privately"),
checkbox("Country of origin — FGM, haemoglobinopathy risk"),
]
story.append(two_col(fam_items, soc_items,
left_header="10. FAMILY HISTORY",
right_header="11. SOCIAL HISTORY",
left_bg=TEAL_LIGHT, right_bg=TEAL_LIGHT,
left_border=TEAL, right_border=TEAL))
story.append(Spacer(1, 3*mm))
# ── Review of Systems ─────────────────────────────────────────────────────────
story.append(section_header("12. Targeted Review of Systems"))
story.append(Spacer(1, 1.5*mm))
ros_data = [
["Urinary", "Frequency, urgency, stress/urge incontinence, dysuria, haematuria, nocturia"],
["Bowel", "Constipation, rectal bleeding, tenesmus, change in bowel habit (endo / prolapse)"],
["Thyroid", "Weight change, heat/cold intolerance, palpitations (thyroid → AUB)"],
["Skin/Hair", "Acne, hirsutism, weight gain, striae (PCOS / Cushing's)"],
["Breast", "Lumps, nipple discharge, galactorrhoea (hyperprolactinaemia → amenorrhoea)"],
["VTE", "Leg swelling, calf tenderness, breathlessness (esp. in pregnancy / OCP)"],
]
ros_table = Table(
[[Paragraph(f"<b>{r[0]}</b>", ParagraphStyle("rs", fontName="Helvetica-Bold",
fontSize=8, textColor=PINK, leading=11)),
Paragraph(r[1], item_style)] for r in ros_data],
colWidths=[24*mm, usable_w - 24*mm],
)
ros_table.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [PINK_LIGHT, WHITE]),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(ros_table)
story.append(Spacer(1, 3*mm))
# ── Antenatal Additions ───────────────────────────────────────────────────────
story.append(section_header("13. Antenatal-Specific Additions (if applicable)", bg=colors.HexColor("#2E6B4F")))
story.append(Spacer(1, 1.5*mm))
ante_left = [
checkbox("Gestational age — LMP + dating scan EDD"),
bullet("Naegele's rule: LMP + 9 months + 7 days"),
checkbox("Symptoms: morning sickness, heartburn, breast changes"),
checkbox("Fetal movements — onset ~18–20 wks; any reduction?"),
checkbox("Bleeding, pain, leaking fluid"),
checkbox("Booking bloods completed?"),
bullet("Blood group, antibody screen, FBC, rubella, VDRL"),
bullet("HIV, HBsAg, haemoglobinopathy screen"),
]
ante_right = [
checkbox("Antenatal scans"),
bullet("Dating scan (11–14 wks), anomaly scan (18–22 wks)"),
bullet("Growth scans if indicated"),
checkbox("Pre-eclampsia risk factors"),
bullet("1st preg, BMI >35, age >40, multiple pregnancy, HTN"),
checkbox("GDM screening — OGTT at 24–28 wks if indicated"),
checkbox("VTE risk assessment — prophylaxis considered?"),
checkbox("Vaccinations — flu, whooping cough, COVID"),
]
GREEN = colors.HexColor("#2E6B4F")
GREEN_LIGHT= colors.HexColor("#EBF5EF")
story.append(two_col(ante_left, ante_right,
left_bg=GREEN_LIGHT, right_bg=GREEN_LIGHT,
left_border=GREEN, right_border=GREEN))
story.append(Spacer(1, 3*mm))
# ── Closing ───────────────────────────────────────────────────────────────────
story.append(section_header("14. Closing the History"))
story.append(Spacer(1, 1.5*mm))
close_items = [
checkbox("ICE — Ideas: \"What do you think is causing this?\""),
checkbox("ICE — Concerns: \"Is there anything you are particularly worried about?\""),
checkbox("ICE — Expectations: \"What were you hoping we could do for you today?\""),
checkbox("Summarise back to patient and invite corrections"),
checkbox("Safeguarding — domestic violence (ask privately), FGM, child protection concerns"),
checkbox("\"Is there anything else you would like to tell me?\""),
]
close_table = Table([[c] for c in close_items], colWidths=[usable_w])
close_table.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [TEAL_LIGHT, WHITE]),
("TOPPADDING", (0,0), (-1,-1), 2),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#CCCCCC")),
]))
story.append(close_table)
story.append(Spacer(1, 4*mm))
# ── Footer ────────────────────────────────────────────────────────────────────
story.append(HRFlowable(width=usable_w, thickness=0.5, color=TEAL))
footer = Paragraph(
"Berek & Novak's Gynecology (9th ed.) · Rosen's Emergency Medicine · For educational use only",
ParagraphStyle("footer", fontName="Helvetica", fontSize=6.5,
textColor=GREY_MID, leading=9, alignment=TA_CENTER, spaceBefore=2)
)
story.append(footer)
# ── Build ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF saved to {OUTPUT}")
python3 /home/daytona/workspace/obs-gynae-checklist/generate_checklist.py 2>&1
ls -lh /home/daytona/workspace/obs-gynae-checklist/
ObsGynae History Checklist
PDF Document · PDF
| Section | Contents |
|---|---|
| 1-2 | Patient Details + Presenting Complaint |
| 3 | SOCRATES table for HPC |
| 4 | Menstrual History with PALM-COEIN reminder |
| 5 | Obstetric History (GTPAL) + per-pregnancy checklist |
| 6-7 | Gynaecological + Sexual History |
| 8-9 | PMH + Drug History & Allergies |
| 10-11 | Family History + Social History |
| 12 | Targeted Review of Systems (6 systems) |
| 13 | Antenatal-specific additions |
| 14 | Closing the History (ICE + safeguarding) |