Discharge summary perfect
mkdir -p /tmp/workspace/discharge-summary && ls /tmp/workspace/discharge-summary/
~/discharge-summary/build_discharge_summary.py
from docx import Document
from docx.shared import Pt, Inches, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
doc = Document()
# ── Page setup (A4) ──────────────────────────────────────────────────────────
section = doc.sections[0]
section.page_width = Inches(8.27)
section.page_height = Inches(11.69)
section.top_margin = Inches(0.75)
section.bottom_margin = Inches(0.75)
section.left_margin = Inches(1.0)
section.right_margin = Inches(1.0)
# ── Base font ────────────────────────────────────────────────────────────────
normal = doc.styles["Normal"]
normal.font.name = "Calibri"
normal.font.size = Pt(11)
# Customise heading styles
def style_heading(doc, level, size, color_hex="1F3864"):
h = doc.styles[f"Heading {level}"]
h.font.name = "Calibri"
h.font.size = Pt(size)
h.font.bold = True
r, g, b = int(color_hex[0:2],16), int(color_hex[2:4],16), int(color_hex[4:6],16)
h.font.color.rgb = RGBColor(r, g, b)
h.paragraph_format.space_before = Pt(10)
h.paragraph_format.space_after = Pt(4)
style_heading(doc, 1, 16, "1F3864")
style_heading(doc, 2, 13, "2E75B6")
style_heading(doc, 3, 11, "2E75B6")
# ── Helper: shaded table row ─────────────────────────────────────────────────
def set_cell_shading(cell, fill_hex):
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
shd = OxmlElement("w:shd")
shd.set(qn("w:val"), "clear")
shd.set(qn("w:color"), "auto")
shd.set(qn("w:fill"), fill_hex)
tcPr.append(shd)
def set_cell_borders(cell, top=None, bottom=None, left=None, right=None):
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
tcBorders = OxmlElement("w:tcBorders")
for side, val in [("top", top), ("bottom", bottom), ("left", left), ("right", right)]:
if val:
el = OxmlElement(f"w:{side}")
el.set(qn("w:val"), val.get("val","single"))
el.set(qn("w:sz"), val.get("sz","4"))
el.set(qn("w:space"),"0")
el.set(qn("w:color"),val.get("color","auto"))
tcBorders.append(el)
tcPr.append(tcBorders)
def add_field_row(table, label, value_placeholder, label_bg="D6E4F0", row_bg="FFFFFF"):
row = table.add_row()
lc = row.cells[0]
vc = row.cells[1]
lc.width = Inches(2.0)
vc.width = Inches(4.27)
set_cell_shading(lc, label_bg)
set_cell_shading(vc, row_bg)
lp = lc.paragraphs[0]
lp.clear()
run = lp.add_run(label)
run.bold = True
run.font.size = Pt(10)
run.font.color.rgb = RGBColor(0x1F,0x38,0x64)
vp = vc.paragraphs[0]
vp.clear()
vr = vp.add_run(value_placeholder)
vr.font.size = Pt(11)
vr.font.color.rgb = RGBColor(0x60,0x60,0x60)
return row
def section_table(doc, fields, label_bg="D6E4F0"):
tbl = doc.add_table(rows=0, cols=2)
tbl.style = "Table Grid"
tbl.alignment = WD_TABLE_ALIGNMENT.LEFT
for label, placeholder in fields:
add_field_row(tbl, label, placeholder, label_bg=label_bg)
return tbl
def add_section_heading(doc, title, level=2):
doc.add_heading(title, level=level)
def add_note_box(doc, text):
"""A lightly shaded paragraph acting as an info box."""
p = doc.add_paragraph()
pPr = p._p.get_or_add_pPr()
shd = OxmlElement("w:shd")
shd.set(qn("w:val"), "clear")
shd.set(qn("w:color"), "auto")
shd.set(qn("w:fill"), "EBF3FB")
pPr.append(shd)
run = p.add_run(text)
run.italic = True
run.font.size = Pt(9)
run.font.color.rgb = RGBColor(0x2E,0x75,0xB6)
p.paragraph_format.left_indent = Inches(0.1)
p.paragraph_format.right_indent = Inches(0.1)
p.paragraph_format.space_after = Pt(6)
# ════════════════════════════════════════════════════════════════════════════
# HEADER BANNER
# ════════════════════════════════════════════════════════════════════════════
title_para = doc.add_paragraph()
title_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
title_para.paragraph_format.space_before = Pt(0)
title_para.paragraph_format.space_after = Pt(2)
tr = title_para.add_run("HOSPITAL NAME / DEPARTMENT")
tr.bold = True
tr.font.size = Pt(18)
tr.font.color.rgb = RGBColor(0x1F,0x38,0x64)
tr.font.name = "Calibri"
subtitle_para = doc.add_paragraph()
subtitle_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
subtitle_para.paragraph_format.space_after = Pt(2)
sr = subtitle_para.add_run("Department of General Medicine / Internal Medicine")
sr.font.size = Pt(11)
sr.font.color.rgb = RGBColor(0x50,0x50,0x50)
sr.font.name = "Calibri"
doc_type_para = doc.add_paragraph()
doc_type_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
doc_type_para.paragraph_format.space_after = Pt(8)
dtr = doc_type_para.add_run("DISCHARGE SUMMARY")
dtr.bold = True
dtr.font.size = Pt(15)
dtr.font.color.rgb = RGBColor(0x2E,0x75,0xB6)
dtr.font.name = "Calibri"
# Horizontal rule (thin table acting as a line)
hr = doc.add_table(rows=1, cols=1)
hr_cell = hr.cell(0, 0)
set_cell_shading(hr_cell, "1F3864")
hr.rows[0].height = Pt(2)
hr_cell.paragraphs[0].clear()
doc.add_paragraph() # spacer
# ════════════════════════════════════════════════════════════════════════════
# SECTION 1 – PATIENT IDENTIFICATION
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "1. Patient Identification")
section_table(doc, [
("Patient Name", "[Full name]"),
("Date of Birth", "[DD/MM/YYYY]"),
("Age / Gender", "[Age] years | [Male / Female / Other]"),
("MRN / Hospital ID", "[Medical Record Number]"),
("Address", "[Street, City, Postcode]"),
("Contact Number", "[Phone / Mobile]"),
("Emergency Contact", "[Name] – [Relationship] – [Phone]"),
("Next of Kin", "[Name] – [Relationship]"),
("Insurance / Payer", "[Insurance provider / Self-pay / Government scheme]"),
])
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 2 – ADMISSION & DISCHARGE DETAILS
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "2. Admission & Discharge Details")
section_table(doc, [
("Date of Admission", "[DD/MM/YYYY]"),
("Time of Admission", "[HH:MM]"),
("Date of Discharge", "[DD/MM/YYYY]"),
("Time of Discharge", "[HH:MM]"),
("Length of Stay", "[X days]"),
("Admitting Ward / Unit", "[Ward name / Bed number]"),
("Admitting Physician", "[Dr. Name] – [Designation]"),
("Treating Consultant", "[Dr. Name] – [Speciality]"),
("Discharge Destination", "[Home / Transfer to facility / Nursing home / Deceased]"),
("Discharge Condition", "[Stable / Improved / Guarded / Deceased]"),
("Mode of Discharge", "[Self / Against medical advice (AMA) / Transfer / Deceased]"),
])
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 3 – PRESENTING COMPLAINT & HISTORY
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "3. Presenting Complaint & History")
add_section_heading(doc, "3a. Chief Complaint", level=3)
add_note_box(doc, "State the primary reason for admission in the patient's own words or as a brief clinical phrase.")
doc.add_paragraph("[Chief complaint]", style="List Bullet")
add_section_heading(doc, "3b. History of Presenting Illness (HPI)", level=3)
add_note_box(doc, "Chronological narrative: onset, duration, character, severity, associated symptoms, aggravating/relieving factors, prior similar episodes.")
doc.add_paragraph("[Detailed HPI narrative]")
add_section_heading(doc, "3c. Past Medical History (PMH)", level=3)
for item in [
"[Chronic condition 1 – year of diagnosis]",
"[Chronic condition 2 – year of diagnosis]",
"[Previous hospitalisations / surgeries]",
"[No significant PMH – if applicable]",
]:
doc.add_paragraph(item, style="List Bullet")
add_section_heading(doc, "3d. Surgical / Procedural History", level=3)
doc.add_paragraph("[Procedure – Year – Hospital]", style="List Bullet")
add_section_heading(doc, "3e. Drug & Allergy History", level=3)
drug_tbl = doc.add_table(rows=1, cols=4)
drug_tbl.style = "Table Grid"
headers = ["Drug / Substance", "Dose & Route", "Duration / Frequency", "Allergy / Reaction"]
hrow = drug_tbl.rows[0]
for i, h in enumerate(headers):
cell = hrow.cells[i]
set_cell_shading(cell, "1F3864")
p = cell.paragraphs[0]
p.clear()
run = p.add_run(h)
run.bold = True
run.font.color.rgb = RGBColor(0xFF,0xFF,0xFF)
run.font.size = Pt(10)
for _ in range(3):
r = drug_tbl.add_row()
for c in r.cells:
c.paragraphs[0].add_run("[...]").font.size = Pt(11)
doc.add_paragraph()
add_section_heading(doc, "3f. Family History", level=3)
doc.add_paragraph("[Relevant family history – condition – relation]", style="List Bullet")
add_section_heading(doc, "3g. Social History", level=3)
for item in [
"Smoking: [Never / Ex-smoker (X pack-years) / Current (X/day)]",
"Alcohol: [None / Occasional / Regular – X units/week]",
"Recreational drugs: [None / specify]",
"Occupation: [specify]",
"Living situation: [Lives alone / With family / Carer at home]",
"Functional status pre-admission: [Independent / Needs assistance]",
]:
doc.add_paragraph(item, style="List Bullet")
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 4 – EXAMINATION FINDINGS ON ADMISSION
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "4. Examination Findings on Admission")
add_section_heading(doc, "4a. Vital Signs", level=3)
vs_tbl = doc.add_table(rows=1, cols=6)
vs_tbl.style = "Table Grid"
vs_headers = ["BP (mmHg)", "HR (bpm)", "RR (/min)", "SpO2 (%)", "Temp (°C)", "GCS"]
vhrow = vs_tbl.rows[0]
for i, h in enumerate(vs_headers):
c = vhrow.cells[i]
set_cell_shading(c, "2E75B6")
p = c.paragraphs[0]
p.clear()
run = p.add_run(h)
run.bold = True
run.font.color.rgb = RGBColor(0xFF,0xFF,0xFF)
run.font.size = Pt(9)
vr2 = vs_tbl.add_row()
for c in vr2.cells:
c.paragraphs[0].add_run("[...]").font.size = Pt(11)
doc.add_paragraph()
add_section_heading(doc, "4b. General Examination", level=3)
for item in [
"General: [Well / Unwell / Alert / Obtunded / Cachectic / Distressed]",
"Pallor: [Absent / Present] Icterus: [Absent / Present]",
"Cyanosis: [Absent / Present] Clubbing: [Absent / Present]",
"Lymphadenopathy: [Absent / Present – specify region]",
"Oedema: [Absent / Present – pitting/non-pitting, extent]",
]:
doc.add_paragraph(item, style="List Bullet")
add_section_heading(doc, "4c. Systemic Examination", level=3)
for system in [
("Cardiovascular", "Heart sounds: [S1, S2 heard / Murmurs / Added sounds]"),
("Respiratory", "Air entry: [Bilateral / Reduced] Breath sounds: [Clear / Crepitations / Wheeze]"),
("Abdomen", "[Soft / Tender / Organomegaly / Distension / Bowel sounds]"),
("Neurological", "[Conscious / GCS: E_V_M_ / Focal deficits / Reflexes]"),
("Musculoskeletal","[Deformity / Swelling / Range of motion / Tenderness]"),
("Skin", "[Rash / Wounds / Pressure areas / Ulcers]"),
]:
p = doc.add_paragraph(style="List Bullet")
run_bold = p.add_run(f"{system[0]}: ")
run_bold.bold = True
run_bold.font.size = Pt(11)
p.add_run(system[1]).font.size = Pt(11)
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 5 – INVESTIGATIONS
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "5. Investigations")
add_section_heading(doc, "5a. Laboratory Results", level=3)
lab_tbl = doc.add_table(rows=1, cols=4)
lab_tbl.style = "Table Grid"
lab_headers = ["Investigation", "Admission Value", "Discharge Value", "Reference Range"]
lhrow = lab_tbl.rows[0]
for i, h in enumerate(lab_headers):
c = lhrow.cells[i]
set_cell_shading(c, "1F3864")
p = c.paragraphs[0]
p.clear()
run = p.add_run(h)
run.bold = True
run.font.color.rgb = RGBColor(0xFF,0xFF,0xFF)
run.font.size = Pt(10)
lab_rows = [
("Haemoglobin (Hb)", "[X g/dL]", "[X g/dL]", "12–16 g/dL"),
("WBC", "[X ×10³/µL]", "[X ×10³/µL]", "4.5–11 ×10³/µL"),
("Platelets", "[X ×10³/µL]", "[X ×10³/µL]", "150–400 ×10³/µL"),
("Sodium (Na+)", "[X mmol/L]", "[X mmol/L]", "135–145 mmol/L"),
("Potassium (K+)", "[X mmol/L]", "[X mmol/L]", "3.5–5.0 mmol/L"),
("Creatinine", "[X µmol/L]", "[X µmol/L]", "60–110 µmol/L"),
("Urea", "[X mmol/L]", "[X mmol/L]", "2.5–6.4 mmol/L"),
("Glucose (random)", "[X mmol/L]", "[X mmol/L]", "3.9–7.8 mmol/L"),
("HbA1c", "[X%]", "[X%]", "<6.5%"),
("CRP", "[X mg/L]", "[X mg/L]", "<10 mg/L"),
("Liver enzymes (ALT/AST)", "[X U/L]", "[X U/L]", "7–56 U/L"),
("Other: [specify]", "[...]", "[...]", "[...]"),
]
for lr in lab_rows:
r = lab_tbl.add_row()
for i, val in enumerate(lr):
c = r.cells[i]
if i % 2 == 0:
set_cell_shading(c, "EBF3FB")
c.paragraphs[0].clear()
rv = c.paragraphs[0].add_run(val)
rv.font.size = Pt(10)
doc.add_paragraph()
add_section_heading(doc, "5b. Microbiology / Cultures", level=3)
for item in [
"Blood culture: [No growth / Organism – Sensitivity]",
"Urine culture: [No growth / Organism – Sensitivity]",
"Sputum culture: [No growth / Organism – Sensitivity]",
"COVID-19 / Influenza / Other rapid test: [Negative / Positive]",
]:
doc.add_paragraph(item, style="List Bullet")
add_section_heading(doc, "5c. Imaging & Special Investigations", level=3)
img_tbl = doc.add_table(rows=1, cols=3)
img_tbl.style = "Table Grid"
img_headers = ["Investigation", "Date", "Key Finding"]
ihrow = img_tbl.rows[0]
for i, h in enumerate(img_headers):
c = ihrow.cells[i]
set_cell_shading(c, "2E75B6")
p = c.paragraphs[0]
p.clear()
run = p.add_run(h)
run.bold = True
run.font.color.rgb = RGBColor(0xFF,0xFF,0xFF)
run.font.size = Pt(10)
for inv in [
("Chest X-ray (CXR)", "[DD/MM/YYYY]", "[Findings]"),
("ECG", "[DD/MM/YYYY]", "[Findings]"),
("Echocardiogram", "[DD/MM/YYYY]", "[Findings]"),
("Ultrasound [organ/region]", "[DD/MM/YYYY]", "[Findings]"),
("CT [region]", "[DD/MM/YYYY]", "[Findings]"),
("MRI [region]", "[DD/MM/YYYY]", "[Findings]"),
("Spirometry / PFT", "[DD/MM/YYYY]", "[Findings]"),
("Other: [specify]", "[DD/MM/YYYY]", "[Findings]"),
]:
r = img_tbl.add_row()
for i, v in enumerate(inv):
c = r.cells[i]
if i == 0:
set_cell_shading(c, "EBF3FB")
c.paragraphs[0].clear()
c.paragraphs[0].add_run(v).font.size = Pt(10)
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 6 – DIAGNOSIS
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "6. Diagnosis")
add_section_heading(doc, "6a. Primary Diagnosis", level=3)
p = doc.add_paragraph(style="List Number")
run = p.add_run("[Primary diagnosis – ICD-10 code if applicable]")
run.bold = True; run.font.size = Pt(11)
add_section_heading(doc, "6b. Secondary / Co-morbid Diagnoses", level=3)
for item in [
"[Secondary diagnosis 1 – ICD-10]",
"[Secondary diagnosis 2 – ICD-10]",
"[Pre-existing comorbidity – stable / controlled / worsened]",
]:
doc.add_paragraph(item, style="List Number")
add_section_heading(doc, "6c. Complications During Admission", level=3)
doc.add_paragraph("[Complication / None]", style="List Bullet")
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 7 – TREATMENT GIVEN DURING ADMISSION
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "7. Treatment During Admission")
add_section_heading(doc, "7a. Medications Administered", level=3)
med_tbl = doc.add_table(rows=1, cols=5)
med_tbl.style = "Table Grid"
med_headers = ["Drug", "Dose", "Route", "Frequency", "Duration / Notes"]
mhrow = med_tbl.rows[0]
for i, h in enumerate(med_headers):
c = mhrow.cells[i]
set_cell_shading(c, "1F3864")
p = c.paragraphs[0]
p.clear()
run = p.add_run(h)
run.bold = True
run.font.color.rgb = RGBColor(0xFF,0xFF,0xFF)
run.font.size = Pt(10)
for _ in range(5):
r = med_tbl.add_row()
for c in r.cells:
c.paragraphs[0].add_run("[...]").font.size = Pt(11)
doc.add_paragraph()
add_section_heading(doc, "7b. Procedures / Interventions", level=3)
for item in [
"[Procedure / Intervention – Date – Operator – Outcome]",
"[IV access / Central line / Urinary catheter – Date – Removed on]",
"Transfusions: [Packed RBCs / FFP / Platelets – units – dates]",
"Oxygen therapy: [Method – flow rate – duration]",
"Nil by mouth (NBM): [Dates – reason]",
]:
doc.add_paragraph(item, style="List Bullet")
add_section_heading(doc, "7c. Specialist Consultations", level=3)
for item in [
"[Speciality – Consultant – Date – Recommendation]",
"[Physiotherapy / Occupational therapy / Speech therapy / Dietitian / Social work]",
]:
doc.add_paragraph(item, style="List Bullet")
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 8 – HOSPITAL COURSE & CLINICAL PROGRESS
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "8. Hospital Course & Clinical Progress")
add_note_box(doc, "Summarise the clinical course chronologically: response to treatment, complications encountered, change in management plan, and overall trajectory (improving / deteriorating / stable).")
doc.add_paragraph("[Day 1–2: ...]")
doc.add_paragraph("[Day 3–5: ...]")
doc.add_paragraph("[Day X onward: ...]")
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 9 – CONDITION AT DISCHARGE
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "9. Condition at Discharge")
section_table(doc, [
("General condition", "[Stable / Improved / Guarded]"),
("Vital signs at discharge", "BP: [X/X] HR: [X] RR: [X] SpO2: [X%] Temp: [X°C]"),
("Functional status", "[Independent / Requires assistance – specify]"),
("Mobility", "[Ambulatory / Wheelchair / Bedbound]"),
("Diet at discharge", "[Normal / Soft diet / NG feed / TPN / NBM]"),
("Wound / Drain status","[Healed / Open – dressing / Drain removed on]"),
("Cognitive status", "[Intact / Confused / Improved from admission]"),
], label_bg="D6E4F0")
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 10 – DISCHARGE MEDICATIONS
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "10. Discharge Medications")
add_note_box(doc, "List ALL medications to be taken after discharge. Highlight any NEW medications, changed doses, and STOPPED medications clearly.")
dm_tbl = doc.add_table(rows=1, cols=6)
dm_tbl.style = "Table Grid"
dm_headers = ["Drug", "Dose", "Route", "Frequency", "Duration", "New / Continued / Stopped"]
dmhrow = dm_tbl.rows[0]
for i, h in enumerate(dm_headers):
c = dmhrow.cells[i]
set_cell_shading(c, "1F3864")
p = c.paragraphs[0]
p.clear()
run = p.add_run(h)
run.bold = True
run.font.color.rgb = RGBColor(0xFF,0xFF,0xFF)
run.font.size = Pt(9)
for _ in range(5):
r = dm_tbl.add_row()
for c in r.cells:
c.paragraphs[0].add_run("[...]").font.size = Pt(10)
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 11 – FOLLOW-UP PLAN
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "11. Follow-Up Plan")
fu_tbl = doc.add_table(rows=1, cols=4)
fu_tbl.style = "Table Grid"
fu_headers = ["Provider / Clinic", "Date / Timeframe", "Location", "Purpose"]
fuhrow = fu_tbl.rows[0]
for i, h in enumerate(fu_headers):
c = fuhrow.cells[i]
set_cell_shading(c, "2E75B6")
p = c.paragraphs[0]
p.clear()
run = p.add_run(h)
run.bold = True
run.font.color.rgb = RGBColor(0xFF,0xFF,0xFF)
run.font.size = Pt(10)
for row_data in [
("GP / Primary care", "Within [X] days", "[Clinic address]", "Review, medication reconciliation"),
("[Specialist clinic]", "[DD/MM/YYYY]", "[Location]", "[Purpose]"),
("Pathology / Blood tests", "[X] days post-discharge", "[Lab]", "[Tests to be repeated]"),
("Imaging", "[Date / timeframe]","[Location]", "[Type of imaging]"),
]:
r = fu_tbl.add_row()
for i, v in enumerate(row_data):
c = r.cells[i]
if i == 0:
set_cell_shading(c, "EBF3FB")
c.paragraphs[0].clear()
c.paragraphs[0].add_run(v).font.size = Pt(10)
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 12 – PATIENT EDUCATION & DISCHARGE INSTRUCTIONS
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "12. Patient Education & Discharge Instructions")
for item in [
"Diagnosis explained to patient and family: [Yes / No / Partially]",
"Medication counselling provided: [Yes / No]",
"Diet & lifestyle advice: [Low-salt diet / Diabetic diet / Fluid restriction / Activity restriction]",
"Wound care instructions: [Yes / Not applicable]",
"Red flag symptoms – return to ED if: [Chest pain / Breathlessness / Fever >38°C / Bleeding / Worsening symptoms]",
"Written discharge instructions given: [Yes / No]",
"Language / interpreter used: [English / specify language / Interpreter arranged]",
"Patient verbalized understanding: [Yes / No]",
]:
doc.add_paragraph(item, style="List Bullet")
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 13 – PENDING RESULTS & OUTSTANDING ISSUES
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "13. Pending Results & Outstanding Issues")
add_note_box(doc, "List any results not yet available at time of discharge. GP / follow-up team must review and act on these.")
for item in [
"[Culture result pending – follow up in X days]",
"[Histopathology / Biopsy – result expected DD/MM/YYYY]",
"[Outpatient investigation to be arranged: specify]",
"[Outstanding referral: specify speciality]",
]:
doc.add_paragraph(item, style="List Bullet")
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 14 – NOTIFICATIONS & COMMUNICATIONS
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "14. Notifications & Communications")
section_table(doc, [
("GP notified", "[Yes / No / Not applicable] – Date: [DD/MM/YYYY]"),
("Family / NOK informed", "[Yes / No] – Name: [ ] – Date: [DD/MM/YYYY]"),
("Transfer letter sent", "[Yes / No / Not applicable]"),
("Reportable disease notification", "[Yes / No – Disease: specify / Not applicable]"),
("Medicolegal issues", "[Yes / No – specify if yes]"),
], label_bg="D6E4F0")
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# SECTION 15 – CLINICIAN SIGN-OFF
# ════════════════════════════════════════════════════════════════════════════
add_section_heading(doc, "15. Clinician Sign-Off")
sig_tbl = doc.add_table(rows=1, cols=2)
sig_tbl.style = "Table Grid"
sig_tbl.alignment = WD_TABLE_ALIGNMENT.LEFT
left = sig_tbl.cell(0, 0)
right = sig_tbl.cell(0, 1)
set_cell_shading(left, "F2F7FC")
set_cell_shading(right, "F2F7FC")
for cell, fields in [
(left, [
("Prepared by", "[Name – Designation – Registration No.]"),
("Signature", "______________________________"),
("Date", "[DD/MM/YYYY]"),
("Contact", "[Direct phone / Pager / Email]"),
]),
(right, [
("Reviewed / Countersigned by", "[Consultant Name – Designation]"),
("Signature", "______________________________"),
("Date", "[DD/MM/YYYY]"),
("Stamp", "[Hospital / Department Stamp]"),
]),
]:
for label, value in fields:
p = cell.add_paragraph()
rb = p.add_run(f"{label}: ")
rb.bold = True
rb.font.size = Pt(10)
rv = p.add_run(value)
rv.font.size = Pt(10)
p.paragraph_format.space_after = Pt(4)
# ── Footer note ───────────────────────────────────────────────────────────
doc.add_paragraph()
footer_p = doc.add_paragraph()
footer_p.alignment = WD_ALIGN_PARAGRAPH.CENTER
fr = footer_p.add_run(
"CONFIDENTIAL – This document contains protected health information. "
"Handle in accordance with applicable privacy legislation."
)
fr.italic = True
fr.font.size = Pt(8)
fr.font.color.rgb = RGBColor(0x80,0x80,0x80)
# ── Save ─────────────────────────────────────────────────────────────────────
out_path = "/tmp/workspace/discharge-summary/Discharge_Summary_Template_General_Medicine.docx"
doc.save(out_path)
print(f"Saved: {out_path}")
python3 /tmp/workspace/discharge-summary/build_discharge_summary.py
Discharge Summary Template General Medicine
Word Document · DOCX
| # | Section | What's covered |
|---|---|---|
| 1 | Patient Identification | Name, DOB, MRN, contacts, insurance |
| 2 | Admission & Discharge Details | Dates, times, length of stay, ward, consultant, discharge condition |
| 3 | Presenting Complaint & History | HPI, PMH, surgical history, drug/allergy table, family & social history |
| 4 | Examination on Admission | Vital signs table, general + systemic examination (CVS, Resp, Abdomen, Neuro, MSK, Skin) |
| 5 | Investigations | Lab results table (with reference ranges), microbiology, imaging & special tests |
| 6 | Diagnosis | Primary + secondary diagnoses with ICD-10 fields, complications |
| 7 | Treatment During Admission | Medications table, procedures/interventions, specialist consultations |
| 8 | Hospital Course & Progress | Chronological narrative field |
| 9 | Condition at Discharge | Vitals, functional status, mobility, diet, wound status |
| 10 | Discharge Medications | Full med table with New / Continued / Stopped column |
| 11 | Follow-Up Plan | GP, specialist, labs, imaging - with dates and purposes |
| 12 | Patient Education | Counselling checklist, red flag symptoms, language/interpreter |
| 13 | Pending Results | Outstanding investigations and referrals for GP to action |
| 14 | Notifications | GP notification, NOK, transfer letter, reportable disease |
| 15 | Clinician Sign-Off | Prepared by + countersigned by, with stamp field |
Table Grid style so formatting stays intact when edited. All placeholder text is in [square brackets] - just click and replace.Discharge summary perfect
~/discharge-summary/build_og_discharge_summary.py
from docx import Document
from docx.shared import Pt, Inches, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
doc = Document()
# ── Page setup (A4) ──────────────────────────────────────────────────────────
section = doc.sections[0]
section.page_width = Inches(8.27)
section.page_height = Inches(11.69)
section.top_margin = Inches(0.75)
section.bottom_margin = Inches(0.75)
section.left_margin = Inches(1.0)
section.right_margin = Inches(1.0)
# ── Base font ────────────────────────────────────────────────────────────────
normal = doc.styles["Normal"]
normal.font.name = "Calibri"
normal.font.size = Pt(11)
# Theme colours – soft rose/mauve palette for O&G
C_DARK = "6B2D5E" # deep plum – main headings
C_MID = "A0467E" # mid magenta – sub-headings / table headers
C_LIGHT = "F5E6F0" # pale blush – label column bg
C_ALT = "FDF2FA" # very pale – alternating row / value bg
def style_heading(doc, level, size, color_hex):
h = doc.styles[f"Heading {level}"]
h.font.name = "Calibri"
h.font.size = Pt(size)
h.font.bold = True
r, g, b = int(color_hex[0:2],16), int(color_hex[2:4],16), int(color_hex[4:6],16)
h.font.color.rgb = RGBColor(r, g, b)
h.paragraph_format.space_before = Pt(10)
h.paragraph_format.space_after = Pt(4)
style_heading(doc, 1, 16, C_DARK)
style_heading(doc, 2, 13, C_MID)
style_heading(doc, 3, 11, C_MID)
# ── XML helpers ──────────────────────────────────────────────────────────────
def set_cell_shading(cell, fill_hex):
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
shd = OxmlElement("w:shd")
shd.set(qn("w:val"), "clear")
shd.set(qn("w:color"), "auto")
shd.set(qn("w:fill"), fill_hex)
tcPr.append(shd)
def add_field_row(table, label, placeholder, label_bg=C_LIGHT, val_bg="FFFFFF"):
row = table.add_row()
lc, vc = row.cells[0], row.cells[1]
set_cell_shading(lc, label_bg)
set_cell_shading(vc, val_bg)
lp = lc.paragraphs[0]; lp.clear()
lr = lp.add_run(label); lr.bold = True; lr.font.size = Pt(10)
r, g, b = int(C_DARK[0:2],16), int(C_DARK[2:4],16), int(C_DARK[4:6],16)
lr.font.color.rgb = RGBColor(r, g, b)
vp = vc.paragraphs[0]; vp.clear()
vr = vp.add_run(placeholder); vr.font.size = Pt(11)
vr.font.color.rgb = RGBColor(0x60,0x60,0x60)
def section_table(doc, fields):
tbl = doc.add_table(rows=0, cols=2)
tbl.style = "Table Grid"
tbl.alignment = WD_TABLE_ALIGNMENT.LEFT
for label, ph in fields:
add_field_row(tbl, label, ph)
return tbl
def header_row(table, headers, bg=C_DARK):
row = table.rows[0]
r2, g2, b2 = int(bg[0:2],16), int(bg[2:4],16), int(bg[4:6],16)
for i, h in enumerate(headers):
c = row.cells[i]
set_cell_shading(c, bg)
p = c.paragraphs[0]; p.clear()
run = p.add_run(h); run.bold = True
run.font.color.rgb = RGBColor(0xFF,0xFF,0xFF)
run.font.size = Pt(10)
def add_note(doc, text):
p = doc.add_paragraph()
pPr = p._p.get_or_add_pPr()
shd = OxmlElement("w:shd")
shd.set(qn("w:val"), "clear")
shd.set(qn("w:color"), "auto")
shd.set(qn("w:fill"), "FEF4FB")
pPr.append(shd)
run = p.add_run(text)
run.italic = True; run.font.size = Pt(9)
r, g, b = int(C_MID[0:2],16), int(C_MID[2:4],16), int(C_MID[4:6],16)
run.font.color.rgb = RGBColor(r, g, b)
p.paragraph_format.left_indent = Inches(0.1)
p.paragraph_format.space_after = Pt(6)
def spacer(doc):
doc.add_paragraph()
# ════════════════════════════════════════════════════════════════════════════
# HEADER BANNER
# ════════════════════════════════════════════════════════════════════════════
t = doc.add_paragraph(); t.alignment = WD_ALIGN_PARAGRAPH.CENTER
t.paragraph_format.space_before = Pt(0); t.paragraph_format.space_after = Pt(2)
tr = t.add_run("HOSPITAL NAME")
tr.bold = True; tr.font.size = Pt(18); tr.font.name = "Calibri"
tr.font.color.rgb = RGBColor(int(C_DARK[0:2],16), int(C_DARK[2:4],16), int(C_DARK[4:6],16))
s = doc.add_paragraph(); s.alignment = WD_ALIGN_PARAGRAPH.CENTER
s.paragraph_format.space_after = Pt(2)
sr = s.add_run("Department of Obstetrics & Gynaecology")
sr.font.size = Pt(11); sr.font.name = "Calibri"
sr.font.color.rgb = RGBColor(0x50,0x50,0x50)
d = doc.add_paragraph(); d.alignment = WD_ALIGN_PARAGRAPH.CENTER
d.paragraph_format.space_after = Pt(8)
dr = d.add_run("DISCHARGE SUMMARY")
dr.bold = True; dr.font.size = Pt(15); dr.font.name = "Calibri"
dr.font.color.rgb = RGBColor(int(C_MID[0:2],16), int(C_MID[2:4],16), int(C_MID[4:6],16))
# Divider line
hr = doc.add_table(rows=1, cols=1)
set_cell_shading(hr.cell(0,0), C_DARK)
hr.rows[0].height = Pt(2)
hr.cell(0,0).paragraphs[0].clear()
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 1 – PATIENT IDENTIFICATION
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("1. Patient Identification", level=2)
section_table(doc, [
("Patient Name", "[Full name]"),
("Date of Birth", "[DD/MM/YYYY]"),
("Age", "[Age] years"),
("MRN / Hospital ID", "[Medical Record Number]"),
("Address", "[Street, City, Postcode]"),
("Contact Number", "[Phone / Mobile]"),
("Emergency Contact", "[Name] – [Relationship] – [Phone]"),
("Next of Kin / Partner","[Name] – [Relationship] – [Phone]"),
("Insurance / Payer", "[Insurance provider / Self-pay / Government scheme]"),
("GP / Primary Care", "[GP Name] – [Practice Name] – [Phone / Fax]"),
])
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 2 – ADMISSION & DISCHARGE DETAILS
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("2. Admission & Discharge Details", level=2)
section_table(doc, [
("Date of Admission", "[DD/MM/YYYY]"),
("Time of Admission", "[HH:MM]"),
("Date of Discharge", "[DD/MM/YYYY]"),
("Time of Discharge", "[HH:MM]"),
("Length of Stay", "[X days]"),
("Admitting Ward / Unit", "[Antenatal / Postnatal / Gynaecology / Labour ward / HDU]"),
("Admitting Consultant", "[Dr. Name] – [Designation]"),
("Treating Consultant", "[Dr. Name] – [O&G Speciality: MFM / Gyn-Onc / General O&G]"),
("Discharge Destination", "[Home / Transfer / Tertiary centre / Midwifery-led unit]"),
("Discharge Condition", "[Stable / Improved / Guarded]"),
("Mode of Discharge", "[Self / Transfer / Against medical advice (AMA)]"),
])
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 3 – OBSTETRIC / GYNAECOLOGICAL HISTORY
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("3. Obstetric & Gynaecological History", level=2)
doc.add_heading("3a. Current Pregnancy (if applicable)", level=3)
add_note(doc, "Complete this section for obstetric admissions. Leave N/A for purely gynaecological admissions.")
section_table(doc, [
("Gravida / Para", "[G P + ] (miscarriages / ectopics / terminations)"),
("Gestational Age on Admission", "[X weeks + X days] (by LMP / dating scan)"),
("LMP", "[DD/MM/YYYY]"),
("EDD", "[DD/MM/YYYY] (by scan / LMP)"),
("Dating Scan", "[DD/MM/YYYY] – CRL / BPD / [X weeks + X days]"),
("Fetal Number", "[Singleton / Twin / Higher-order multiples]"),
("Chorionicity (if multiple)","[MCDA / MCMA / DCDA / DCMA]"),
("Booking Blood Group", "[A+ / B+ / O+ / AB+ / A- / B- / O- / AB-]"),
("Rubella Immunity", "[Immune / Non-immune / Not tested]"),
("Antenatal Care", "[Shared care: GP + hospital / Hospital only / Midwifery-led / Unbooked]"),
])
spacer(doc)
doc.add_heading("3b. Past Obstetric History", level=3)
ob_tbl = doc.add_table(rows=1, cols=7)
ob_tbl.style = "Table Grid"
header_row(ob_tbl, ["Pregnancy #", "Year", "GA at Delivery", "Mode of Delivery", "Birth Weight", "Outcome", "Complications"], bg=C_DARK)
for _ in range(3):
r = ob_tbl.add_row()
for c in r.cells:
c.paragraphs[0].add_run("[...]").font.size = Pt(10)
spacer(doc)
doc.add_heading("3c. Gynaecological History", level=3)
section_table(doc, [
("Menstrual History", "[Regular / Irregular – cycle length – LMP]"),
("Contraception", "[Current method / None]"),
("Last Cervical Smear / Pap", "[Date] – [Result]"),
("Previous Gynaecological Surgeries", "[Procedure – Year – Indication]"),
("STI History", "[None / specify]"),
("Fertility Treatment", "[None / IVF / IUI / Clomid – cycle number]"),
])
spacer(doc)
doc.add_heading("3d. Past Medical & Surgical History", level=3)
for item in [
"[Medical condition 1 – year – current status]",
"[Medical condition 2 – year – current status]",
"[Previous non-O&G surgeries – year – hospital]",
]:
doc.add_paragraph(item, style="List Bullet")
spacer(doc)
doc.add_heading("3e. Drug & Allergy History", level=3)
da_tbl = doc.add_table(rows=1, cols=4)
da_tbl.style = "Table Grid"
header_row(da_tbl, ["Drug / Substance", "Dose & Route", "Frequency", "Allergy / Reaction"], bg=C_MID)
for _ in range(4):
r = da_tbl.add_row()
for c in r.cells:
c.paragraphs[0].add_run("[...]").font.size = Pt(11)
spacer(doc)
doc.add_heading("3f. Family & Social History", level=3)
for item in [
"Family history: [Obstetric complications / Hereditary conditions / Congenital anomalies]",
"Smoking: [Never / Ex / Current – X/day]",
"Alcohol: [None / Occasional / Regular – X units/week]",
"Recreational drugs: [None / specify]",
"Occupation: [specify]",
"Social support: [Partner / Family / Lives alone / Social services involvement]",
"Domestic violence screen: [Screened / Declined / Concerns documented]",
]:
doc.add_paragraph(item, style="List Bullet")
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 4 – PRESENTING COMPLAINT & REASON FOR ADMISSION
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("4. Presenting Complaint & Reason for Admission", level=2)
add_note(doc, "Tick one or more. Add a brief clinical narrative below.")
reason_tbl = doc.add_table(rows=0, cols=4)
reason_tbl.style = "Table Grid"
reasons = [
("☐ Labour (spontaneous)", "☐ Induction of labour", "☐ Elective LSCS", "☐ Emergency LSCS"),
("☐ Pre-eclampsia / HTD", "☐ PPROM / PROM", "☐ Antepartum haemorrhage", "☐ Postpartum haemorrhage"),
("☐ Fetal distress", "☐ Preterm labour", "☐ Reduced fetal movements", "☐ Hyperemesis gravidarum"),
("☐ Ectopic pregnancy", "☐ Miscarriage / EPAS", "☐ Gynaecological surgery", "☐ Pelvic pain"),
("☐ Ovarian cyst", "☐ Abnormal uterine bleeding", "☐ Sepsis / Infection", "☐ Other: [specify]"),
]
for row_data in reasons:
row = reason_tbl.add_row()
for i, val in enumerate(row_data):
row.cells[i].paragraphs[0].add_run(val).font.size = Pt(10)
spacer(doc)
doc.add_heading("Presenting History (Narrative)", level=3)
add_note(doc, "Chronological account: onset, duration, severity, associated symptoms, relevant context.")
doc.add_paragraph("[Detailed narrative of presenting complaint]")
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 5 – EXAMINATION FINDINGS ON ADMISSION
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("5. Examination Findings on Admission", level=2)
doc.add_heading("5a. Vital Signs", level=3)
vs_tbl = doc.add_table(rows=1, cols=6)
vs_tbl.style = "Table Grid"
header_row(vs_tbl, ["BP (mmHg)", "HR (bpm)", "RR (/min)", "SpO2 (%)", "Temp (°C)", "GCS / AVPU"], bg=C_MID)
vr = vs_tbl.add_row()
for c in vr.cells:
c.paragraphs[0].add_run("[...]").font.size = Pt(11)
spacer(doc)
doc.add_heading("5b. General & Obstetric Examination", level=3)
for item in [
"General appearance: [Well / Unwell / Distressed / Comfortable]",
"BMI at booking / admission: [X kg/m²]",
"Pallor / Icterus / Oedema (facial, hands, legs): [specify]",
"Uterine size / fundal height: [X weeks / X cm]",
"Fetal presentation: [Cephalic / Breech / Transverse / Oblique]",
"Engagement: [Engaged / Floating – X/5 palpable]",
"Fetal heart rate on auscultation: [X bpm / CTG performed – see findings]",
"Liquor / Membranes: [Intact / Ruptured – colour / volume]",
"Cervical assessment: [Closed / X cm dilated / X% effaced / Station X / Bishop score X]",
"Vaginal loss: [None / Bleeding / Discharge – specify]",
]:
doc.add_paragraph(item, style="List Bullet")
doc.add_heading("5c. Systemic Examination", level=3)
for system, detail in [
("Cardiovascular", "Heart sounds [S1 S2] / Murmurs / Oedema"),
("Respiratory", "Air entry / Breath sounds / Wheeze / Crepitations"),
("Abdomen", "Uterine tenderness / Rebound / Guarding / Bowel sounds"),
("Neurological", "Conscious / Reflexes (hyperreflexia?) / Clonus / Visual disturbance"),
]:
p = doc.add_paragraph(style="List Bullet")
rb = p.add_run(f"{system}: "); rb.bold = True; rb.font.size = Pt(11)
p.add_run(f"[{detail}]").font.size = Pt(11)
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 6 – INVESTIGATIONS
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("6. Investigations", level=2)
doc.add_heading("6a. Antenatal Bloods / Booking Bloods", level=3)
ab_tbl = doc.add_table(rows=1, cols=3)
ab_tbl.style = "Table Grid"
header_row(ab_tbl, ["Investigation", "Result / Date", "Notes / Action Taken"], bg=C_DARK)
for inv in [
("Blood group & antibody screen", "[Result]", "[Action]"),
("FBC", "[Result]", "[Action]"),
("HbA1c / GCT / OGTT", "[Result]", "[Action]"),
("Rubella IgG", "[Result]", "[Action]"),
("Syphilis serology (VDRL/TPPA)", "[Result]", "[Action]"),
("HIV serology", "[Result]", "[Action]"),
("Hepatitis B (HBsAg)", "[Result]", "[Action]"),
("Hepatitis C", "[Result]", "[Action]"),
("Varicella IgG", "[Result]", "[Action]"),
("Thyroid function (TSH/T4)", "[Result]", "[Action]"),
("GBS screening", "[Result]", "[Action]"),
("Other: [specify]", "[Result]", "[Action]"),
]:
r = ab_tbl.add_row()
for i, v in enumerate(inv):
c = r.cells[i]
if i == 0: set_cell_shading(c, C_ALT)
c.paragraphs[0].clear()
c.paragraphs[0].add_run(v).font.size = Pt(10)
spacer(doc)
doc.add_heading("6b. Admission Labs (with Discharge Comparison)", level=3)
lab_tbl = doc.add_table(rows=1, cols=4)
lab_tbl.style = "Table Grid"
header_row(lab_tbl, ["Test", "Admission Value", "Discharge Value", "Reference Range"], bg=C_DARK)
for row_data in [
("Haemoglobin", "[X g/dL]", "[X g/dL]", "12–16 g/dL"),
("WBC", "[X ×10³/µL]", "[X ×10³/µL]", "4.5–11 ×10³/µL"),
("Platelets", "[X ×10³/µL]", "[X ×10³/µL]", "150–400 ×10³/µL"),
("Sodium", "[X mmol/L]", "[X mmol/L]", "135–145 mmol/L"),
("Potassium", "[X mmol/L]", "[X mmol/L]", "3.5–5.0 mmol/L"),
("Creatinine", "[X µmol/L]", "[X µmol/L]", "45–90 µmol/L (preg)"),
("Urea", "[X mmol/L]", "[X mmol/L]", "2.5–6.4 mmol/L"),
("LFTs (ALT/AST/Bili)", "[X U/L]", "[X U/L]", "Varies"),
("LDH", "[X U/L]", "[X U/L]", "120–246 U/L"),
("Uric acid", "[X mmol/L]", "[X mmol/L]", "Varies"),
("Coagulation (PT/APTT)", "[X s]", "[X s]", "Varies"),
("CRP", "[X mg/L]", "[X mg/L]", "<10 mg/L"),
("Urinalysis / PCR", "[Result]", "[Result]", "Negative"),
("Other: [specify]", "[...]", "[...]", "[...]"),
]:
r = lab_tbl.add_row()
for i, v in enumerate(row_data):
c = r.cells[i]
if i % 2 == 0: set_cell_shading(c, C_ALT)
c.paragraphs[0].clear()
c.paragraphs[0].add_run(v).font.size = Pt(10)
spacer(doc)
doc.add_heading("6c. Imaging & Monitoring", level=3)
img_tbl = doc.add_table(rows=1, cols=3)
img_tbl.style = "Table Grid"
header_row(img_tbl, ["Investigation", "Date", "Key Findings"], bg=C_MID)
for inv in [
("Obstetric ultrasound – dating scan", "[Date]", "[CRL / EDD / Anomalies]"),
("Obstetric ultrasound – anatomy scan", "[Date]", "[Findings]"),
("Obstetric ultrasound – growth scan", "[Date]", "[EFW / AC / HC / Liquor / Placenta]"),
("Doppler studies (umbilical / MCA / uterine)","[Date]","[PI / RI / End-diastolic flow]"),
("Cardiotocography (CTG)", "[Date]", "[Reactive / Non-reactive / Category]"),
("Fetal scalp pH / lactate", "[Date]", "[pH / Lactate value]"),
("Chest X-ray", "[Date]", "[Findings]"),
("Pelvic / Abdominal USS", "[Date]", "[Findings]"),
("CT / MRI [region]", "[Date]", "[Findings – indication for radiation exposure documented if CT]"),
("Colposcopy / Hysteroscopy / Laparoscopy", "[Date]", "[Findings]"),
("Other: [specify]", "[Date]", "[Findings]"),
]:
r = img_tbl.add_row()
for i, v in enumerate(inv):
c = r.cells[i]
if i == 0: set_cell_shading(c, C_ALT)
c.paragraphs[0].clear()
c.paragraphs[0].add_run(v).font.size = Pt(10)
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 7 – DIAGNOSIS
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("7. Diagnosis", level=2)
doc.add_heading("7a. Primary Diagnosis", level=3)
p = doc.add_paragraph(style="List Number")
r2 = p.add_run("[Primary diagnosis – ICD-10 code]"); r2.bold = True; r2.font.size = Pt(11)
doc.add_heading("7b. Secondary / Co-existing Diagnoses", level=3)
for item in [
"[Secondary diagnosis – ICD-10]",
"[Pre-existing comorbidity – status during admission]",
"[Fetal / Neonatal diagnosis – ICD-10 (if applicable)]",
]:
doc.add_paragraph(item, style="List Number")
doc.add_heading("7c. Complications During Admission", level=3)
doc.add_paragraph("[Complication / None]", style="List Bullet")
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 8 – LABOUR, DELIVERY & NEONATAL OUTCOME (obstetric)
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("8. Labour, Delivery & Neonatal Outcome", level=2)
add_note(doc, "Complete for all obstetric deliveries. Mark N/A for gynaecological-only admissions.")
doc.add_heading("8a. Labour Details", level=3)
section_table(doc, [
("Onset of labour", "[Spontaneous / Induced – method / Pre-labour LSCS]"),
("IOL indication & method", "[Post-dates / Medical / Surgical – Prostaglandin / ARM / Oxytocin]"),
("Duration of labour", "1st stage: [X hrs] 2nd stage: [X mins] 3rd stage: [X mins]"),
("Analgesia", "[Epidural / CSE / Pethidine / Entonox / None]"),
("Membranes", "[SROM at X cm / AROM at X cm / Intact] – Liquor: [Clear / Meconium grade / Bloodstained]"),
("Intrapartum CTG", "[Reassuring / Category II / Category III – action taken]"),
("Oxytocin augmentation", "[Yes – rate / No]"),
("Group B Strep prophylaxis", "[Given / Not indicated / Declined]"),
])
spacer(doc)
doc.add_heading("8b. Mode of Delivery", level=3)
section_table(doc, [
("Mode of delivery", "[SVD / Forceps / Ventouse / Emergency LSCS / Elective LSCS]"),
("Indication (if operative)", "[Fetal distress / Failure to progress / Malpresentation / Maternal request]"),
("Date & time of delivery", "[DD/MM/YYYY – HH:MM]"),
("Operator", "[Dr. / Midwife Name] – [Grade]"),
("Perineum (vaginal delivery)", "[Intact / 1st / 2nd / 3rd / 4th degree tear / Episiotomy – repair method]"),
("LSCS incision type", "[Pfannenstiel / Lower segment / Classical / Not applicable]"),
("LSCS uterine incision", "[Lower segment transverse / Classical / Not applicable]"),
("EBL (estimated blood loss)", "[X mL]"),
("Placental delivery", "[Complete / Incomplete – retained products / Manual removal]"),
("Cord blood gases", "Art pH: [X] Base excess: [X] Ven pH: [X]"),
])
spacer(doc)
doc.add_heading("8c. Neonatal Outcome", level=3)
neo_tbl = doc.add_table(rows=1, cols=5)
neo_tbl.style = "Table Grid"
header_row(neo_tbl, ["Parameter", "Baby 1", "Baby 2 (if applicable)", "Baby 3 (if applicable)", "Notes"], bg=C_DARK)
for param in [
"Sex",
"Birth weight (g)",
"Gestational age at delivery",
"APGAR score (1 min / 5 min)",
"Resuscitation required",
"Paediatrician attendance",
"Admission to NICU / SCN",
"Feeding at discharge",
"Cord blood group",
"Vitamin K given",
"Newborn hearing screen",
"Metabolic / PKU screen",
"Discharge with mother",
]:
r = neo_tbl.add_row()
r.cells[0].paragraphs[0].add_run(param).font.size = Pt(10)
set_cell_shading(r.cells[0], C_LIGHT)
for c in r.cells[1:]:
c.paragraphs[0].add_run("[...]").font.size = Pt(10)
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 9 – TREATMENT DURING ADMISSION
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("9. Treatment During Admission", level=2)
doc.add_heading("9a. Medications Administered", level=3)
med_tbl = doc.add_table(rows=1, cols=5)
med_tbl.style = "Table Grid"
header_row(med_tbl, ["Drug", "Dose", "Route", "Frequency", "Duration / Notes"], bg=C_DARK)
for _ in range(6):
r = med_tbl.add_row()
for c in r.cells:
c.paragraphs[0].add_run("[...]").font.size = Pt(11)
spacer(doc)
doc.add_heading("9b. Procedures / Interventions", level=3)
for item in [
"IV access / Catheterisation: [Date – removed on]",
"Blood transfusion: [Packed RBCs – X units / FFP / Platelets – indication]",
"Magnesium sulphate: [Loading dose / Maintenance – indication: eclampsia / neuroprotection]",
"Corticosteroids for fetal lung maturity: [Drug – doses given – dates]",
"Anti-D immunoglobulin: [Dose – given on – indication]",
"Thromboprophylaxis: [LMWH – drug – dose – commenced on]",
"Uterotonics: [Oxytocin / Ergometrine / Carboprost / Misoprostol – indication]",
"Cerclage / Pessary: [Placed / Removed – date]",
"Other procedure: [specify]",
]:
doc.add_paragraph(item, style="List Bullet")
doc.add_heading("9c. Specialist Consultations", level=3)
for item in [
"[Specialty – Consultant – Date – Recommendation]",
"MFM / Perinatology: [Recommendation]",
"Anaesthetics: [Type – plan discussed]",
"Haematology: [specify]",
"Neonatology / Paediatrics: [specify]",
"Physiotherapy / Pelvic floor: [specify]",
"Social work / Lactation consultant: [specify]",
]:
doc.add_paragraph(item, style="List Bullet")
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 10 – HOSPITAL COURSE & CLINICAL PROGRESS
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("10. Hospital Course & Clinical Progress", level=2)
add_note(doc, "Summarise chronologically: response to treatment, complications, change of management plan, trajectory.")
doc.add_paragraph("[Day 1: ...]")
doc.add_paragraph("[Day 2–3: ...]")
doc.add_paragraph("[Day X onward: ...]")
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 11 – CONDITION AT DISCHARGE
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("11. Condition at Discharge", level=2)
section_table(doc, [
("General condition", "[Stable / Improved / Guarded]"),
("Vital signs at discharge", "BP: [X/X] HR: [X] Temp: [X°C] SpO2: [X%]"),
("Lochia / Wound", "Lochia: [Normal / Offensive / Heavy] Wound: [Healing well / Opened / Dressed]"),
("Uterine involution", "[Well-involuted / Tender / Boggy – at level of umbilicus / below]"),
("Breastfeeding / Feeding", "[Breastfeeding established / Mixed / Formula / Not breastfeeding – reason]"),
("Urinary / Bowel function", "[Voiding well / Catheter removed / Constipation – managed]"),
("Mobility", "[Ambulatory / Requires assistance / Limited]"),
("Mood / Mental state", "[Stable / EPDS score: X / Referred – Baby blues / PND concerns]"),
("Contraception counselled", "[Yes – method discussed / Deferred to GP]"),
("Thromboprophylaxis plan", "[LMWH – duration / Compression stockings / No longer required]"),
])
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 12 – DISCHARGE MEDICATIONS
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("12. Discharge Medications", level=2)
add_note(doc, "List ALL medications. Highlight NEW, CHANGED DOSE, and STOPPED medications. Include medications safe in breastfeeding if applicable.")
dm_tbl = doc.add_table(rows=1, cols=6)
dm_tbl.style = "Table Grid"
header_row(dm_tbl, ["Drug", "Dose", "Route", "Frequency", "Duration", "New / Continued / Stopped"], bg=C_DARK)
for _ in range(6):
r = dm_tbl.add_row()
for c in r.cells:
c.paragraphs[0].add_run("[...]").font.size = Pt(10)
doc.add_paragraph()
for item in [
"Iron supplementation: [Ferrous sulfate / dose / duration – if anaemia]",
"Folic acid: [5 mg / 0.4 mg – duration]",
"Aspirin 150 mg nocte: [Yes / No – pre-eclampsia prophylaxis until X weeks]",
"LMWH (thromboprophylaxis): [Drug – dose – duration – stop date: DD/MM/YYYY]",
"Analgesia: [Paracetamol / Ibuprofen / Codeine – as required / regular – duration]",
"Anti-D immunoglobulin: [Completed / To be arranged by GP – dose / date]",
]:
doc.add_paragraph(item, style="List Bullet")
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 13 – FOLLOW-UP PLAN
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("13. Follow-Up Plan", level=2)
fu_tbl = doc.add_table(rows=1, cols=4)
fu_tbl.style = "Table Grid"
header_row(fu_tbl, ["Provider / Clinic", "Date / Timeframe", "Location", "Purpose"], bg=C_MID)
for row_data in [
("GP", "Within [X] days", "[Practice]", "Wound check, BP review, medication reconciliation, contraception"),
("Obstetric / O&G clinic", "[DD/MM/YYYY]", "[Hospital]", "[Specify: 6-week postnatal / high-risk review]"),
("Midwife / community midwife", "Daily for [X] days", "[Home / clinic]", "Postnatal checks, breastfeeding support"),
("Maternal foetal medicine (MFM)","[Date / timeframe]", "[Hospital]", "[Indication: GDM, HTD, multiple pregnancy, etc.]"),
("Paediatrician / NICU", "[Date]", "[Hospital]", "[Neonatal follow-up]"),
("Pathology / Blood tests", "[X days post-discharge]", "[Lab]", "[Repeat FBC / iron / TFTs / LFTs – specify]"),
("Anaesthetic review", "[Date if applicable]", "[Hospital]", "[Post-spinal headache / difficult airway follow-up]"),
("Mental health / PNDA", "[Date if applicable]", "[GP / clinic]", "[EPDS follow-up / Perinatal mental health referral]"),
("Imaging", "[Date / timeframe]", "[Radiology]", "[Specify: pelvic USS, wound review USS]"),
]:
r = fu_tbl.add_row()
for i, v in enumerate(row_data):
c = r.cells[i]
if i == 0: set_cell_shading(c, C_ALT)
c.paragraphs[0].clear()
c.paragraphs[0].add_run(v).font.size = Pt(10)
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 14 – PATIENT EDUCATION & DISCHARGE INSTRUCTIONS
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("14. Patient Education & Discharge Instructions", level=2)
for item in [
"Diagnosis and management explained to patient (and partner): [Yes / No / Partially]",
"Medication counselling (including safety in breastfeeding): [Yes / No]",
"Wound care instructions (LSCS / perineal repair): [Yes / Not applicable]",
"Pelvic floor exercises: [Advised / Physiotherapy referral made]",
"Activity restrictions: [No heavy lifting for X weeks / Driving: X weeks / Return to work: X weeks]",
"Sexual intercourse: [Advised to wait X weeks]",
"Contraception: [Counselled – method: specify / Deferred to GP]",
"Breastfeeding support resources provided: [Yes / No]",
"Newborn care instructions: [Provided / Referred to MCHN]",
"Red flag symptoms – return to ED if: [Heavy bleeding / Fever >38°C / Wound breakdown / Severe headache / Visual changes / Chest pain / Leg pain/swelling / Reduced fetal movements (if ongoing pregnancy)]",
"Postnatal depression information: [Provided / EPDS planned at GP visit]",
"Written discharge instructions given: [Yes / No]",
"Language / interpreter used: [English / Specify / Interpreter present]",
"Patient verbalized understanding: [Yes / No]",
]:
doc.add_paragraph(item, style="List Bullet")
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 15 – PENDING RESULTS & OUTSTANDING ISSUES
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("15. Pending Results & Outstanding Issues", level=2)
add_note(doc, "GP and community team MUST review and act on these items.")
for item in [
"[Culture / sensitivity result – expected DD/MM/YYYY]",
"[Histopathology / placenta – expected DD/MM/YYYY]",
"[Neonatal screening result – expected DD/MM/YYYY]",
"[Genetic / chromosomal result (e.g. amniocentesis) – expected date]",
"[Outstanding referral: specify speciality]",
"[Outpatient investigation to be arranged: specify]",
]:
doc.add_paragraph(item, style="List Bullet")
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 16 – NOTIFICATIONS & COMMUNICATIONS
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("16. Notifications & Communications", level=2)
section_table(doc, [
("GP notified", "[Yes / No] – Date: [DD/MM/YYYY] – Method: [Fax / Letter / Electronic]"),
("Midwife / MCHN notified", "[Yes / No] – Date: [DD/MM/YYYY]"),
("Paediatrician / NICU notified", "[Yes / No / Not applicable]"),
("Social services notified", "[Yes / No / Not applicable – reason if yes]"),
("Stillbirth / perinatal loss notification", "[Yes / No / Not applicable – Coroner / Registry]"),
("Reportable disease notification","[Yes / No – specify disease if yes]"),
("Birth registered", "[Yes / Pending – parents advised]"),
("Medicolegal / Incident report", "[Yes / No – specify if yes]"),
("Transfer letter sent", "[Yes / No / Not applicable]"),
])
spacer(doc)
# ════════════════════════════════════════════════════════════════════════════
# SECTION 17 – CLINICIAN SIGN-OFF
# ════════════════════════════════════════════════════════════════════════════
doc.add_heading("17. Clinician Sign-Off", level=2)
sig_tbl = doc.add_table(rows=1, cols=2)
sig_tbl.style = "Table Grid"
left = sig_tbl.cell(0, 0)
right = sig_tbl.cell(0, 1)
set_cell_shading(left, "FDF2FA")
set_cell_shading(right, "FDF2FA")
for cell, fields in [
(left, [
("Prepared by", "[Name – Designation – Registration No.]"),
("Signature", "______________________________"),
("Date & Time", "[DD/MM/YYYY – HH:MM]"),
("Contact", "[Direct phone / Pager / Email]"),
]),
(right, [
("Reviewed / Countersigned by", "[Consultant Name – O&G Designation]"),
("Signature", "______________________________"),
("Date", "[DD/MM/YYYY]"),
("Hospital / Dept Stamp", "[Stamp here]"),
]),
]:
for label, value in fields:
p = cell.add_paragraph()
rb = p.add_run(f"{label}: "); rb.bold = True; rb.font.size = Pt(10)
rv = p.add_run(value); rv.font.size = Pt(10)
p.paragraph_format.space_after = Pt(4)
# ── Confidentiality footer ────────────────────────────────────────────────
spacer(doc)
fp = doc.add_paragraph(); fp.alignment = WD_ALIGN_PARAGRAPH.CENTER
fr = fp.add_run(
"CONFIDENTIAL – Contains protected health information for mother and/or neonate. "
"Handle in accordance with applicable privacy legislation."
)
fr.italic = True; fr.font.size = Pt(8)
fr.font.color.rgb = RGBColor(0x80,0x80,0x80)
# ── Save ─────────────────────────────────────────────────────────────────────
out_path = "/tmp/workspace/discharge-summary/Discharge_Summary_OandG.docx"
doc.save(out_path)
print(f"Saved: {out_path}")
python3 /tmp/workspace/discharge-summary/build_og_discharge_summary.py
Discharge Summary OandG
Word Document · DOCX
| # | Section | Key O&G-specific content |
|---|---|---|
| 1 | Patient Identification | GP details, partner/NOK contacts |
| 2 | Admission & Discharge Details | Ward type (antenatal / postnatal / labour / gynaecology / HDU) |
| 3 | Obstetric & Gynaecological History | G/P, EDD, LMP, chorionicity, booking bloods, past obstetric table, menstrual/contraception/smear history |
| 4 | Presenting Complaint | Tick-box grid covering 20 common O&G reasons for admission |
| 5 | Examination on Admission | Fundal height, presentation, engagement, FHR, liquor, cervical assessment, Bishop score |
| 6 | Investigations | Antenatal/booking bloods (rubella, HIV, HBsAg, GBS, etc.), admission labs with pregnancy reference ranges, obstetric USS, Dopplers, CTG |
| 7 | Diagnosis | Primary + secondary + fetal/neonatal diagnoses with ICD-10 fields |
| 8 | Labour, Delivery & Neonatal Outcome | Labour details, IOL method, CTG category, mode of delivery, EBL, cord gases, APGAR table, neonatal outcome table |
| 9 | Treatment During Admission | Medications, MgSO4, corticosteroids, anti-D, LMWH, uterotonics, cerclage |
| 10 | Hospital Course | Chronological narrative |
| 11 | Condition at Discharge | Lochia, involution, breastfeeding, mood/EPDS, thromboprophylaxis plan |
| 12 | Discharge Medications | Full table + specific O&G items (iron, folic acid, aspirin prophylaxis, anti-D) |
| 13 | Follow-Up Plan | GP, midwife, O&G clinic, MFM, NICU, anaesthetics, PNDA |
| 14 | Patient Education | Wound care, pelvic floor, activity/driving/sex restrictions, contraception, red flags, PND info |
| 15 | Pending Results | Cultures, histopathology, neonatal screening, genetic results |
| 16 | Notifications | GP, midwife, MCHN, social services, stillbirth/perinatal loss notification, birth registration |
| 17 | Clinician Sign-Off | Prepared by + consultant countersignature with stamp |
[square bracket] placeholders - click and replace.