Make a blood transfusion discharge summary

Asking for Preferences
Asking for Preferences
Please go ahead and type all the patient and clinical details. Include as many of the following as you have:
Patient info:
  • Full name, Age/DOB, Sex
  • MRN / Hospital ID
  • Ward / Unit
  • Admitting doctor / Consultant
  • Admission date & Discharge date
Clinical info:
  • Reason for admission / presenting complaint
  • Diagnosis (primary + any secondary)
  • Pre-transfusion Hb and blood group
  • Number of units transfused, blood product type (e.g. packed red cells, FFP, platelets)
  • Any transfusion reactions?
  • Post-transfusion Hb
  • Other investigations / findings
  • Treatment given (medications, procedures)
  • Condition at discharge
  • Discharge medications
  • Follow-up instructions / clinic date
  • Referring doctor / GP details
Type everything you have and I'll build the PDF from it.

Make a summary with real patient data

Reading File
Running Command

mkdir -p /home/daytona/workspace/discharge-summary && ls /home/daytona/workspace…

Writing File

~/discharge-summary/generate_discharge.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, KeepTogether
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT, TA_JUSTIFY
from reportlab.platypus import Flowable

OUTPUT = "/home/daytona/workspace/discharge-summary/Blood_Transfusion_Discharge_Summary.pdf"

# ── Colours ──────────────────────────────────────────────────────────────────
DARK_BLUE   = colors.HexColor("#1A3557")
MID_BLUE    = colors.HexColor("#2A6099")
LIGHT_BLUE  = colors.HexColor("#D9E8F5")
ACCENT_RED  = colors.HexColor("#C0392B")
GREY_BG     = colors.HexColor("#F4F6F8")
GREY_BORDER = colors.HexColor("#BDC3C7")
WHITE       = colors.white
BLACK       = colors.black

# ── Styles ────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

def S(name, **kw):
    return ParagraphStyle(name, **kw)

hospital_name  = S("HospName",  fontName="Helvetica-Bold",  fontSize=16, textColor=WHITE,    alignment=TA_CENTER)
hospital_addr  = S("HospAddr",  fontName="Helvetica",        fontSize=9,  textColor=LIGHT_BLUE, alignment=TA_CENTER)
doc_title      = S("DocTitle",  fontName="Helvetica-Bold",  fontSize=13, textColor=WHITE,    alignment=TA_CENTER, spaceAfter=2)
section_hdr    = S("SecHdr",    fontName="Helvetica-Bold",  fontSize=10, textColor=WHITE,    leading=14)
field_label    = S("FLabel",    fontName="Helvetica-Bold",  fontSize=9,  textColor=DARK_BLUE)
field_value    = S("FVal",      fontName="Helvetica",        fontSize=9,  textColor=BLACK)
body_text      = S("BodyTxt",   fontName="Helvetica",        fontSize=9,  textColor=BLACK,    leading=14, spaceAfter=3)
body_bold      = S("BodyBold",  fontName="Helvetica-Bold",  fontSize=9,  textColor=DARK_BLUE, leading=14)
small_italic   = S("SmItal",    fontName="Helvetica-Oblique",fontSize=8, textColor=colors.HexColor("#555555"), alignment=TA_CENTER)
footer_style   = S("Footer",    fontName="Helvetica",        fontSize=7.5,textColor=colors.HexColor("#777777"), alignment=TA_CENTER)
alert_style    = S("Alert",     fontName="Helvetica-Bold",  fontSize=9,  textColor=ACCENT_RED)
normal_val     = S("NVal",      fontName="Helvetica",        fontSize=9,  textColor=BLACK, leading=13)

# ── Helper: section header row ────────────────────────────────────────────────
def section_header(title):
    tbl = Table([[Paragraph(title, section_hdr)]], colWidths=[170*mm])
    tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
        ("TOPPADDING",  (0,0), (-1,-1), 5),
        ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("ROUNDEDCORNERS", [3, 3, 3, 3]),
    ]))
    return tbl

# ── Helper: 2-column info row ─────────────────────────────────────────────────
def info_row(pairs, col_widths=None):
    """pairs = [(label, value), ...] - up to 4 items per row"""
    if col_widths is None:
        col_widths = [32*mm, 53*mm] * (len(pairs))
    cells = []
    for label, value in pairs:
        cells.append(Paragraph(label, field_label))
        cells.append(Paragraph(str(value), field_value))
    tbl = Table([cells], colWidths=col_widths)
    tbl.setStyle(TableStyle([
        ("VALIGN",       (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",   (0,0), (-1,-1), 4),
        ("BOTTOMPADDING",(0,0), (-1,-1), 4),
        ("LEFTPADDING",  (0,0), (-1,-1), 6),
        ("RIGHTPADDING", (0,0), (-1,-1), 4),
        ("BACKGROUND",   (0,0), (-1,-1), GREY_BG),
        ("LINEBELOW",    (0,0), (-1,-1), 0.5, GREY_BORDER),
    ]))
    return tbl

# ── Helper: narrative paragraph under a section ───────────────────────────────
def narrative(text):
    return Paragraph(text, normal_val)

# ── Lab results table ─────────────────────────────────────────────────────────
def lab_table(headers, rows):
    data = [headers] + rows
    col_n = len(headers)
    cw = [170*mm / col_n] * col_n
    tbl = Table(data, colWidths=cw, repeatRows=1)
    style = [
        ("BACKGROUND",   (0,0), (-1,0), MID_BLUE),
        ("TEXTCOLOR",    (0,0), (-1,0), WHITE),
        ("FONTNAME",     (0,0), (-1,0), "Helvetica-Bold"),
        ("FONTSIZE",     (0,0), (-1,-1), 8.5),
        ("ALIGN",        (0,0), (-1,-1), "CENTER"),
        ("VALIGN",       (0,0), (-1,-1), "MIDDLE"),
        ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE, LIGHT_BLUE]),
        ("GRID",         (0,0), (-1,-1), 0.4, GREY_BORDER),
        ("TOPPADDING",   (0,0), (-1,-1), 4),
        ("BOTTOMPADDING",(0,0), (-1,-1), 4),
    ]
    tbl.setStyle(TableStyle(style))
    return tbl

# ── Transfusion details table ─────────────────────────────────────────────────
def transfusion_table():
    headers = ["Unit #", "Product", "Volume (mL)", "Blood Group", "Date / Time", "Duration", "Reaction"]
    rows = [
        ["1", "Packed Red Blood Cells (pRBC)", "350", "A +ve", "02 Jul 2026 / 14:20", "3 hrs", "None"],
        ["2", "Packed Red Blood Cells (pRBC)", "350", "A +ve", "02 Jul 2026 / 19:10", "3 hrs", "None"],
        ["3", "Packed Red Blood Cells (pRBC)", "350", "A +ve", "03 Jul 2026 / 09:45", "3 hrs", "None"],
    ]
    col_ws = [12*mm, 45*mm, 22*mm, 22*mm, 35*mm, 18*mm, 16*mm]
    data = [headers] + rows
    tbl = Table(data, colWidths=col_ws, repeatRows=1)
    tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  MID_BLUE),
        ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
        ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,-1), 8),
        ("ALIGN",         (0,0), (-1,-1), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
        ("GRID",          (0,0), (-1,-1), 0.4, GREY_BORDER),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ]))
    return tbl

# ── Medications table ─────────────────────────────────────────────────────────
def medication_table():
    headers = ["Medication", "Dose", "Route", "Frequency", "Duration", "Notes"]
    rows = [
        ["Ferrous Sulphate", "200 mg", "Oral", "TDS", "3 months", "Take with food"],
        ["Folic Acid", "5 mg", "Oral", "OD", "3 months", ""],
        ["Omeprazole", "20 mg", "Oral", "OD", "4 weeks", "Before breakfast"],
    ]
    col_ws = [38*mm, 18*mm, 15*mm, 22*mm, 22*mm, 55*mm]
    data = [headers] + rows
    tbl = Table(data, colWidths=col_ws, repeatRows=1)
    tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  MID_BLUE),
        ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
        ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,-1), 8),
        ("ALIGN",         (0,0), (-1,-1), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
        ("GRID",          (0,0), (-1,-1), 0.4, GREY_BORDER),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ]))
    return tbl

# ── Build document ─────────────────────────────────────────────────────────────
def build_pdf():
    doc = SimpleDocTemplate(
        OUTPUT,
        pagesize=A4,
        leftMargin=20*mm,
        rightMargin=20*mm,
        topMargin=15*mm,
        bottomMargin=15*mm,
        title="Blood Transfusion Discharge Summary",
        author="City General Hospital"
    )

    story = []

    # ── HEADER BANNER ──────────────────────────────────────────────────────────
    header_data = [[
        Paragraph("CITY GENERAL HOSPITAL", hospital_name),
        Paragraph("123 Medical Park Road, Springfield  |  Tel: (01) 555-7200  |  Fax: (01) 555-7201", hospital_addr),
        Paragraph("BLOOD TRANSFUSION DISCHARGE SUMMARY", doc_title),
        Paragraph("CONFIDENTIAL – For authorised medical personnel only", small_italic),
    ]]
    header_tbl = Table(header_data, colWidths=[170*mm])
    header_tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), DARK_BLUE),
        ("TOPPADDING",    (0,0), (-1,-1), 8),
        ("BOTTOMPADDING", (0,0), (-1,-1), 8),
        ("LEFTPADDING",   (0,0), (-1,-1), 10),
        ("RIGHTPADDING",  (0,0), (-1,-1), 10),
    ]))
    story.append(header_tbl)
    story.append(Spacer(1, 4*mm))

    # ── PATIENT DEMOGRAPHICS ───────────────────────────────────────────────────
    story.append(section_header("  PATIENT DEMOGRAPHICS"))
    story.append(Spacer(1, 1*mm))
    story.append(info_row([("Patient Name:", "Mrs. Sarah Jane Mitchell"), ("MRN / Hospital ID:", "CGH-2026-084712")],
                           col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("Date of Birth:", "14 March 1978  (Age 48)"), ("Sex:", "Female")],
                           col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("Address:", "42 Elmwood Avenue, Springfield, SP4 3LK"), ("Contact No:", "+44 7700 900 142")],
                           col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("Blood Group:", "A Rhesus Positive (A +ve)"), ("Allergies:", "Penicillin (rash)")],
                           col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(Spacer(1, 3*mm))

    # ── ADMISSION & DISCHARGE INFO ─────────────────────────────────────────────
    story.append(section_header("  ADMISSION & DISCHARGE INFORMATION"))
    story.append(Spacer(1, 1*mm))
    story.append(info_row([("Admission Date:", "01 July 2026"), ("Discharge Date:", "04 July 2026")],
                           col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("Ward / Unit:", "Ward 7B – Haematology"), ("Length of Stay:", "3 days")],
                           col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("Admitting Consultant:", "Dr. Aisha Okonkwo, Haematologist"), ("Registrar:", "Dr. James Carney")],
                           col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("GP / Referring Doctor:", "Dr. Peter Huang, Springfield Medical Centre"), ("Discharge Destination:", "Home")],
                           col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(Spacer(1, 3*mm))

    # ── REASON FOR ADMISSION ───────────────────────────────────────────────────
    story.append(section_header("  REASON FOR ADMISSION & PRESENTING COMPLAINT"))
    story.append(Spacer(1, 1*mm))
    story.append(Table([[narrative(
        "Mrs. Mitchell presented to the Emergency Department on 01 July 2026 with a 3-week history of "
        "progressive fatigue, exertional dyspnoea, palpitations, and light-headedness. She also reported "
        "heavy menstrual bleeding over the preceding 4 months. On examination she was pale, tachycardic "
        "(HR 108 bpm), with conjunctival pallor. Blood pressure was 108/68 mmHg. Point-of-care Hb was "
        "5.8 g/dL, prompting urgent admission for transfusion."
    )]], colWidths=[170*mm]))
    story.append(Spacer(1, 3*mm))

    # ── DIAGNOSIS ─────────────────────────────────────────────────────────────
    story.append(section_header("  DIAGNOSIS"))
    story.append(Spacer(1, 1*mm))
    diag_data = [
        [Paragraph("Primary Diagnosis:", field_label),
         Paragraph("Severe Iron Deficiency Anaemia (ICD-10: D50.9)", field_value)],
        [Paragraph("Secondary Diagnosis:", field_label),
         Paragraph("Menorrhagia secondary to uterine fibroids (ICD-10: N92.0 / D25.9)", field_value)],
        [Paragraph("Comorbidities:", field_label),
         Paragraph("Hypothyroidism (on Levothyroxine 75 mcg OD) | Mild Asthma (Salbutamol PRN)", field_value)],
    ]
    diag_tbl = Table(diag_data, colWidths=[38*mm, 132*mm])
    diag_tbl.setStyle(TableStyle([
        ("BACKGROUND",   (0,0), (-1,-1), GREY_BG),
        ("VALIGN",       (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",   (0,0), (-1,-1), 5),
        ("BOTTOMPADDING",(0,0), (-1,-1), 5),
        ("LEFTPADDING",  (0,0), (-1,-1), 8),
        ("LINEBELOW",    (0,0), (-1,-1), 0.5, GREY_BORDER),
    ]))
    story.append(diag_tbl)
    story.append(Spacer(1, 3*mm))

    # ── PRE-TRANSFUSION INVESTIGATIONS ────────────────────────────────────────
    story.append(section_header("  PRE-TRANSFUSION INVESTIGATIONS"))
    story.append(Spacer(1, 1*mm))
    story.append(lab_table(
        ["Investigation", "Result", "Reference Range", "Flag"],
        [
            ["Haemoglobin (Hb)",      "5.8 g/dL",    "12.0 – 16.0 g/dL", "↓ CRITICAL"],
            ["Haematocrit (HCT)",     "19.2%",        "36 – 46%",          "↓ Low"],
            ["MCV",                   "64 fL",        "80 – 100 fL",       "↓ Microcytic"],
            ["MCH",                   "19.4 pg",      "27 – 33 pg",        "↓ Low"],
            ["Serum Ferritin",        "4 µg/L",       "12 – 150 µg/L",     "↓ Low"],
            ["Serum Iron",            "3.1 µmol/L",   "11 – 30 µmol/L",   "↓ Low"],
            ["TIBC",                  "92 µmol/L",    "45 – 80 µmol/L",    "↑ High"],
            ["Transferrin Sat.",      "3.4%",         "20 – 50%",          "↓ Low"],
            ["WBC",                   "6.8 × 10⁹/L",  "4.0 – 11.0",        "Normal"],
            ["Platelets",             "310 × 10⁹/L",  "150 – 400",         "Normal"],
            ["Blood Group & Screen",  "A Rhesus Positive", "–",            "No alloantibodies"],
            ["CRP",                   "8 mg/L",       "< 10 mg/L",         "Normal"],
            ["Renal Function (eGFR)", "82 mL/min",    "> 60 mL/min",       "Normal"],
            ["Thyroid (TSH)",         "2.1 mU/L",     "0.4 – 4.0 mU/L",   "Normal"],
        ]
    ))
    story.append(Spacer(1, 3*mm))

    # ── TRANSFUSION DETAILS ────────────────────────────────────────────────────
    story.append(section_header("  TRANSFUSION DETAILS"))
    story.append(Spacer(1, 1*mm))
    story.append(transfusion_table())
    story.append(Spacer(1, 2*mm))
    story.append(info_row(
        [("Total Units:", "3 units Packed Red Blood Cells (pRBC)"), ("Total Volume:", "~1050 mL")],
        col_widths=[28*mm, 57*mm, 28*mm, 57*mm]
    ))
    story.append(info_row(
        [("Pre-med Given:", "IV Paracetamol 1g + Chlorphenamine 10 mg IV (unit 1)"), ("Crossmatch Type:", "Electronic (Type & Screen)")],
        col_widths=[28*mm, 57*mm, 28*mm, 57*mm]
    ))
    story.append(info_row(
        [("Transfusion Reactions:", "None reported across all 3 units"), ("Monitoring:", "Observations every 15 min (first hour), then hourly")],
        col_widths=[28*mm, 57*mm, 28*mm, 57*mm]
    ))
    story.append(Spacer(1, 3*mm))

    # ── POST-TRANSFUSION RESULTS ───────────────────────────────────────────────
    story.append(section_header("  POST-TRANSFUSION INVESTIGATIONS"))
    story.append(Spacer(1, 1*mm))
    story.append(lab_table(
        ["Investigation", "Pre-Transfusion", "Post-Transfusion (Day 3)", "Change", "Target"],
        [
            ["Haemoglobin (Hb)", "5.8 g/dL",  "9.4 g/dL",  "+3.6 g/dL", "≥ 8.0 g/dL"],
            ["Haematocrit",      "19.2%",      "30.1%",     "+10.9%",    "≥ 25%"],
            ["Heart Rate",       "108 bpm",    "78 bpm",    "-30 bpm",   "60–100 bpm"],
            ["Blood Pressure",   "108/68 mmHg","122/74 mmHg","+14/+6",   "≥ 110/70 mmHg"],
            ["Symptoms",         "Fatigue, SOB","Resolved", "Improved",  "Asymptomatic"],
        ]
    ))
    story.append(Spacer(1, 3*mm))

    # ── CLINICAL COURSE ────────────────────────────────────────────────────────
    story.append(section_header("  CLINICAL COURSE & MANAGEMENT"))
    story.append(Spacer(1, 1*mm))
    story.append(Table([[narrative(
        "Mrs. Mitchell was admitted under Dr. Okonkwo and transfused with 3 units of crossmatched packed "
        "red blood cells over 02–03 July 2026. Pre-transfusion IV paracetamol and chlorphenamine were "
        "administered prior to the first unit as per haematology protocol. All units transfused without "
        "adverse reactions. Haemoglobin response was satisfactory (5.8 → 9.4 g/dL). "
        "Symptoms of fatigue and exertional dyspnoea resolved by day 3."
        "<br/><br/>"
        "The underlying cause was identified as iron deficiency secondary to chronic menorrhagia due to "
        "uterine fibroids (confirmed on pelvic ultrasound: largest fibroid 4.2 cm intramural). She was "
        "commenced on oral iron supplementation and referred to Gynaecology for ongoing management of "
        "menorrhagia. Dietitian reviewed and provided dietary iron advice. Patient and family were "
        "counselled regarding the indication for transfusion, the process, and the need for follow-up."
    )]], colWidths=[170*mm]))
    story.append(Spacer(1, 3*mm))

    # ── DISCHARGE MEDICATIONS ─────────────────────────────────────────────────
    story.append(section_header("  DISCHARGE MEDICATIONS"))
    story.append(Spacer(1, 1*mm))
    story.append(medication_table())
    story.append(Spacer(1, 2*mm))
    story.append(Table([[
        Paragraph("NOTE: Patient to continue existing medications – Levothyroxine 75 mcg OD and Salbutamol inhaler PRN (unchanged).", alert_style)
    ]], colWidths=[170*mm]))
    story.append(Spacer(1, 3*mm))

    # ── FOLLOW-UP PLAN ────────────────────────────────────────────────────────
    story.append(section_header("  FOLLOW-UP PLAN"))
    story.append(Spacer(1, 1*mm))
    fu_data = [
        ["1.", "GP Review", "10 July 2026", "FBC, ferritin, iron studies. Review iron supplement tolerance."],
        ["2.", "Haematology OPD", "18 July 2026", "Dr. Okonkwo clinic – review response to iron therapy."],
        ["3.", "Gynaecology OPD", "25 July 2026", "Fibroid management – consider medical or surgical options for menorrhagia."],
        ["4.", "Endocrine / GP", "Routine", "Continue annual thyroid function monitoring."],
    ]
    fu_hdr = [["#", "Appointment", "Date / Target", "Instructions"]]
    fu_tbl = Table(fu_hdr + fu_data, colWidths=[8*mm, 38*mm, 32*mm, 92*mm], repeatRows=1)
    fu_tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  MID_BLUE),
        ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
        ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,-1), 8.5),
        ("ALIGN",         (0,0), (1,-1),  "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
        ("GRID",          (0,0), (-1,-1), 0.4, GREY_BORDER),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ]))
    story.append(fu_tbl)
    story.append(Spacer(1, 3*mm))

    # ── PATIENT EDUCATION & DISCHARGE ADVICE ──────────────────────────────────
    story.append(section_header("  PATIENT EDUCATION & DISCHARGE ADVICE"))
    story.append(Spacer(1, 1*mm))
    advice = [
        "Take iron tablets with orange juice (vitamin C improves absorption). Avoid taking with tea, coffee, or dairy within 1 hour.",
        "Stools may appear darker – this is expected and not a cause for concern.",
        "Gradually increase activity as tolerated; avoid strenuous exercise for 1 week.",
        "Return to ED immediately or call 999 if: chest pain, severe breathlessness, fever > 38°C, or heavy uncontrolled bleeding.",
        "Contact GP if iron supplements are not tolerated (nausea/constipation) – alternative IV iron preparations are available.",
        "Avoid NSAIDs (e.g. ibuprofen) due to gastrointestinal effects and risk of worsening menorrhagia.",
    ]
    for i, line in enumerate(advice, 1):
        story.append(Table([[Paragraph(f"{i}.  {line}", body_text)]], colWidths=[170*mm]))
    story.append(Spacer(1, 3*mm))

    # ── SIGNATURES ────────────────────────────────────────────────────────────
    story.append(section_header("  AUTHORISING CLINICIAN"))
    story.append(Spacer(1, 1*mm))
    sig_data = [
        [Paragraph("Discharging Doctor:", field_label),
         Paragraph("Dr. James Carney", field_value),
         Paragraph("Consultant:", field_label),
         Paragraph("Dr. Aisha Okonkwo, MBChB, FRCPath", field_value)],
        [Paragraph("Designation:", field_label),
         Paragraph("Haematology Registrar", field_value),
         Paragraph("Date Signed:", field_label),
         Paragraph("04 July 2026", field_value)],
        [Paragraph("Signature:", field_label),
         Paragraph("__________________________", field_value),
         Paragraph("Bleep / Ext:", field_label),
         Paragraph("Bleep 4427  |  Ext. 7283", field_value)],
    ]
    sig_tbl = Table(sig_data, colWidths=[30*mm, 55*mm, 30*mm, 55*mm])
    sig_tbl.setStyle(TableStyle([
        ("BACKGROUND",   (0,0), (-1,-1), GREY_BG),
        ("VALIGN",       (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",   (0,0), (-1,-1), 5),
        ("BOTTOMPADDING",(0,0), (-1,-1), 5),
        ("LEFTPADDING",  (0,0), (-1,-1), 8),
        ("LINEBELOW",    (0,0), (-1,-1), 0.5, GREY_BORDER),
    ]))
    story.append(sig_tbl)
    story.append(Spacer(1, 4*mm))

    # ── FOOTER ────────────────────────────────────────────────────────────────
    story.append(HRFlowable(width="100%", thickness=1, color=DARK_BLUE))
    story.append(Spacer(1, 2*mm))
    story.append(Paragraph(
        "This document is computer-generated and is valid without a wet signature unless otherwise indicated. "
        "City General Hospital – Blood Transfusion Discharge Summary  |  Document Date: 04 July 2026  |  "
        "Page 1 of 1  |  Form Ref: CGH-TRF-DS-v3.1",
        footer_style
    ))

    doc.build(story)
    print(f"PDF generated: {OUTPUT}")

build_pdf()
Running Command

cd /home/daytona/workspace/discharge-summary && python generate_discharge.py

Your discharge summary PDF is ready.

Blood Transfusion Discharge Summary

PDF Document · PDF


Here's what the document contains:
Patient: Mrs. Sarah Jane Mitchell, 48F, MRN CGH-2026-084712
Sections included:
  1. Hospital header - City General Hospital with confidentiality notice
  2. Patient Demographics - Name, DOB, address, blood group (A+ve), allergy (Penicillin)
  3. Admission & Discharge Info - 01-04 July 2026, Ward 7B Haematology, consultant Dr. Okonkwo
  4. Presenting Complaint - Fatigue, dyspnoea, palpitations from menorrhagia-related anaemia; Hb 5.8 g/dL on arrival
  5. Diagnosis - Severe Iron Deficiency Anaemia (D50.9), Menorrhagia/uterine fibroids
  6. Pre-transfusion Labs - Full FBC, iron studies, blood group & screen (14 parameters)
  7. Transfusion Details - 3 units pRBC (A+ve), dates/times, no reactions, monitoring documented
  8. Post-transfusion Results - Hb 5.8 → 9.4 g/dL, symptoms resolved
  9. Clinical Course - Narrative summary of management
  10. Discharge Medications - Ferrous sulphate, folic acid, omeprazole (with dosing)
  11. Follow-up Plan - GP (10 Jul), Haematology (18 Jul), Gynaecology (25 Jul)
  12. Patient Advice - 6 specific discharge instructions
  13. Signatures - Registrar + Consultant fields
Just let me know if you want to swap in real patient details or adjust any section.

Create same for any cancer patients in pdf form

Writing File

~/discharge-summary/generate_cancer_discharge.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_CENTER, TA_LEFT, TA_RIGHT, TA_JUSTIFY

OUTPUT = "/home/daytona/workspace/discharge-summary/Cancer_Patient_Discharge_Summary.pdf"

# ── Colours ───────────────────────────────────────────────────────────────────
DARK_TEAL   = colors.HexColor("#1A4A4A")
MID_TEAL    = colors.HexColor("#2E7D6A")
LIGHT_TEAL  = colors.HexColor("#D4EDE8")
ACCENT_ORG  = colors.HexColor("#C0392B")
GREY_BG     = colors.HexColor("#F4F6F8")
GREY_BORDER = colors.HexColor("#BDC3C7")
WHITE       = colors.white
BLACK       = colors.black
DARK_BLUE   = colors.HexColor("#1A3557")
MID_BLUE    = colors.HexColor("#2A6099")
LIGHT_BLUE  = colors.HexColor("#D9E8F5")
WARN_BG     = colors.HexColor("#FFF3CD")
WARN_BORDER = colors.HexColor("#FFC107")

# ── Styles ────────────────────────────────────────────────────────────────────
def S(name, **kw):
    return ParagraphStyle(name, **kw)

hospital_name = S("HN", fontName="Helvetica-Bold",  fontSize=16, textColor=WHITE,    alignment=TA_CENTER)
hospital_addr = S("HA", fontName="Helvetica",        fontSize=9,  textColor=colors.HexColor("#B2DFDB"), alignment=TA_CENTER)
doc_title     = S("DT", fontName="Helvetica-Bold",  fontSize=13, textColor=WHITE,    alignment=TA_CENTER, spaceAfter=2)
small_italic  = S("SI", fontName="Helvetica-Oblique",fontSize=8, textColor=colors.HexColor("#80CBC4"), alignment=TA_CENTER)
section_hdr   = S("SH", fontName="Helvetica-Bold",  fontSize=10, textColor=WHITE,    leading=14)
field_label   = S("FL", fontName="Helvetica-Bold",  fontSize=9,  textColor=DARK_TEAL)
field_value   = S("FV", fontName="Helvetica",        fontSize=9,  textColor=BLACK)
body_text     = S("BT", fontName="Helvetica",        fontSize=9,  textColor=BLACK,    leading=14, spaceAfter=3)
alert_style   = S("AS", fontName="Helvetica-Bold",  fontSize=9,  textColor=ACCENT_ORG)
footer_style  = S("FS", fontName="Helvetica",        fontSize=7.5,textColor=colors.HexColor("#777777"), alignment=TA_CENTER)
warn_style    = S("WS", fontName="Helvetica-Bold",  fontSize=8.5,textColor=colors.HexColor("#7D5A00"))
normal_val    = S("NV", fontName="Helvetica",        fontSize=9,  textColor=BLACK, leading=13)

# ── Helpers ───────────────────────────────────────────────────────────────────
def section_header(title, color=None):
    bg = color or DARK_TEAL
    tbl = Table([[Paragraph(title, section_hdr)]], colWidths=[170*mm])
    tbl.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), 8),
    ]))
    return tbl

def info_row(pairs, col_widths=None):
    if col_widths is None:
        col_widths = [32*mm, 53*mm] * len(pairs)
    cells = []
    for label, value in pairs:
        cells.append(Paragraph(label, field_label))
        cells.append(Paragraph(str(value), field_value))
    tbl = Table([cells], colWidths=col_widths)
    tbl.setStyle(TableStyle([
        ("VALIGN",       (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",   (0,0), (-1,-1), 4),
        ("BOTTOMPADDING",(0,0), (-1,-1), 4),
        ("LEFTPADDING",  (0,0), (-1,-1), 6),
        ("RIGHTPADDING", (0,0), (-1,-1), 4),
        ("BACKGROUND",   (0,0), (-1,-1), GREY_BG),
        ("LINEBELOW",    (0,0), (-1,-1), 0.5, GREY_BORDER),
    ]))
    return tbl

def narrative(text):
    return Paragraph(text, normal_val)

def data_table(headers, rows, col_ws=None, hdr_color=None):
    hc = hdr_color or MID_TEAL
    col_n = len(headers)
    if col_ws is None:
        col_ws = [170*mm / col_n] * col_n
    data = [headers] + rows
    tbl = Table(data, colWidths=col_ws, repeatRows=1)
    tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  hc),
        ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
        ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,-1), 8.5),
        ("ALIGN",         (0,0), (-1,-1), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_TEAL]),
        ("GRID",          (0,0), (-1,-1), 0.4, GREY_BORDER),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ]))
    return tbl

def warning_box(text):
    tbl = Table([[Paragraph(text, warn_style)]], colWidths=[170*mm])
    tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), WARN_BG),
        ("LEFTPADDING",   (0,0), (-1,-1), 10),
        ("TOPPADDING",    (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("BOX",           (0,0), (-1,-1), 1, WARN_BORDER),
    ]))
    return tbl

# ── Build PDF ─────────────────────────────────────────────────────────────────
def build_pdf():
    doc = SimpleDocTemplate(
        OUTPUT,
        pagesize=A4,
        leftMargin=20*mm, rightMargin=20*mm,
        topMargin=15*mm, bottomMargin=15*mm,
        title="Oncology Discharge Summary",
        author="City Cancer Centre"
    )
    story = []

    # ── HEADER BANNER ─────────────────────────────────────────────────────────
    hdr = Table([[
        Paragraph("CITY CANCER CENTRE – ONCOLOGY UNIT", hospital_name),
        Paragraph("45 Healing Way, Springfield  |  Tel: (01) 555-8300  |  Fax: (01) 555-8301  |  oncology@citycancer.nhs.uk", hospital_addr),
        Paragraph("ONCOLOGY INPATIENT DISCHARGE SUMMARY", doc_title),
        Paragraph("STRICTLY CONFIDENTIAL – For authorised medical personnel only", small_italic),
    ]], colWidths=[170*mm])
    hdr.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), DARK_TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 8),
        ("BOTTOMPADDING", (0,0), (-1,-1), 8),
        ("LEFTPADDING",   (0,0), (-1,-1), 10),
    ]))
    story.append(hdr)
    story.append(Spacer(1, 4*mm))

    # ── PATIENT DEMOGRAPHICS ──────────────────────────────────────────────────
    story.append(section_header("  PATIENT DEMOGRAPHICS"))
    story.append(Spacer(1, 1*mm))
    story.append(info_row([("Patient Name:", "Mr. Robert Thomas Hale"), ("MRN / Hospital ID:", "CCC-2026-031947")],
                            col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("Date of Birth:", "22 September 1958  (Age 67)"), ("Sex:", "Male")],
                            col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("Address:", "18 Birchwood Close, Springfield, SP2 8MN"), ("Contact No:", "+44 7700 900 387")],
                            col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("Blood Group:", "O Rhesus Positive (O +ve)"), ("Allergies:", "NKDA – No known drug allergies")],
                            col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("Next of Kin:", "Mrs. Carol Hale (Wife)  |  +44 7700 900 512"), ("Emergency Contact:", "Same as NOK")],
                            col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(Spacer(1, 3*mm))

    # ── ADMISSION & DISCHARGE INFO ────────────────────────────────────────────
    story.append(section_header("  ADMISSION & DISCHARGE INFORMATION"))
    story.append(Spacer(1, 1*mm))
    story.append(info_row([("Admission Date:", "23 June 2026"), ("Discharge Date:", "04 July 2026")],
                            col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("Ward / Unit:", "Ward 12 – Oncology / Haematology"), ("Length of Stay:", "11 days")],
                            col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("Admitting Consultant:", "Dr. Priya Menon, Consultant Oncologist"), ("Registrar:", "Dr. Luke Farrell")],
                            col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(info_row([("GP / Referring Doctor:", "Dr. Sonia Patel, Springfield Health Centre"), ("Discharge Destination:", "Home with Community Oncology Support")],
                            col_widths=[30*mm, 55*mm, 30*mm, 55*mm]))
    story.append(Spacer(1, 3*mm))

    # ── ONCOLOGY DIAGNOSIS ────────────────────────────────────────────────────
    story.append(section_header("  ONCOLOGY DIAGNOSIS & STAGING"))
    story.append(Spacer(1, 1*mm))
    diag_data = [
        [Paragraph("Primary Cancer:", field_label),
         Paragraph("Non-Small Cell Lung Cancer (NSCLC) – Adenocarcinoma  (ICD-10: C34.1)", field_value)],
        [Paragraph("Tumour Site:", field_label),
         Paragraph("Right upper lobe – 4.8 cm mass; hilar and mediastinal lymph node involvement", field_value)],
        [Paragraph("Stage:", field_label),
         Paragraph("Stage IIIB – T3 N3 M0  (AJCC 8th Edition)", field_value)],
        [Paragraph("Molecular Profile:", field_label),
         Paragraph("EGFR mutation: Exon 21 L858R substitution (positive)  |  ALK: Negative  |  PD-L1: 55%", field_value)],
        [Paragraph("Date of Diagnosis:", field_label),
         Paragraph("February 2026 (confirmed on CT-guided biopsy, right upper lobe)", field_value)],
        [Paragraph("Secondary Diagnoses:", field_label),
         Paragraph("Chemotherapy-induced anaemia  |  Neutropenia (post-cycle 3)  |  Hypertension  |  Type 2 Diabetes Mellitus", field_value)],
    ]
    d_tbl = Table(diag_data, colWidths=[38*mm, 132*mm])
    d_tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), GREY_BG),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ("LINEBELOW",     (0,0), (-1,-1), 0.5, GREY_BORDER),
    ]))
    story.append(d_tbl)
    story.append(Spacer(1, 3*mm))

    # ── REASON FOR ADMISSION ──────────────────────────────────────────────────
    story.append(section_header("  REASON FOR THIS ADMISSION"))
    story.append(Spacer(1, 1*mm))
    story.append(Table([[narrative(
        "Mr. Hale was admitted as a planned inpatient for Cycle 3, Day 1 of chemotherapy "
        "(Carboplatin + Pemetrexed). He also developed febrile neutropenia on Day 7 post-chemotherapy "
        "(temperature 38.6°C, neutrophil count 0.4 × 10⁹/L), requiring IV antibiotics and "
        "supportive care. Additionally, symptomatic anaemia (Hb 6.9 g/dL) was identified, necessitating "
        "red cell transfusion. He was kept inpatient until neutrophil recovery and haematological stability "
        "were confirmed."
    )]], colWidths=[170*mm]))
    story.append(Spacer(1, 3*mm))

    # ── CHEMOTHERAPY ADMINISTERED ─────────────────────────────────────────────
    story.append(section_header("  CHEMOTHERAPY / SYSTEMIC THERAPY ADMINISTERED"))
    story.append(Spacer(1, 1*mm))
    story.append(data_table(
        ["Drug", "Dose", "Route", "Day", "Date", "Cycle", "Notes"],
        [
            ["Carboplatin",  "AUC 5 (480 mg)",  "IV Infusion", "Day 1", "23 Jun 2026", "Cycle 3 / 4", "Over 30 min; pre-hydration given"],
            ["Pemetrexed",   "500 mg/m² (925 mg)", "IV Infusion", "Day 1", "23 Jun 2026", "Cycle 3 / 4", "Over 10 min; B12 & folic acid supplemented"],
            ["Dexamethasone","8 mg",             "IV",         "D1–D3",  "23–25 Jun 2026","Pre-med",    "Anti-emetic / skin protection"],
            ["Ondansetron",  "8 mg",             "IV",         "D1",     "23 Jun 2026",  "Pre-med",    "Anti-emetic"],
            ["G-CSF (Filgrastim)","300 mcg",     "SC",         "D3–D9",  "25 Jun – 01 Jul 2026","Support","Neutropenia prophylaxis/treatment"],
        ],
        col_ws=[28*mm, 28*mm, 18*mm, 12*mm, 26*mm, 18*mm, 40*mm]
    ))
    story.append(Spacer(1, 3*mm))

    # ── BLOOD TRANSFUSION DETAILS ─────────────────────────────────────────────
    story.append(section_header("  BLOOD TRANSFUSION DETAILS (Cancer-Related Anaemia)"))
    story.append(Spacer(1, 1*mm))
    story.append(data_table(
        ["Unit #", "Product", "Volume", "Blood Group", "Date / Time", "Duration", "Reaction"],
        [
            ["1", "Packed Red Blood Cells (pRBC)", "350 mL", "O +ve", "29 Jun 2026 / 10:00", "3 hrs", "None"],
            ["2", "Packed Red Blood Cells (pRBC)", "350 mL", "O +ve", "29 Jun 2026 / 15:00", "3 hrs", "None"],
        ],
        col_ws=[12*mm, 45*mm, 18*mm, 18*mm, 36*mm, 18*mm, 23*mm]
    ))
    story.append(Spacer(1, 2*mm))
    story.append(info_row(
        [("Total Units:", "2 units pRBC (~700 mL)"), ("Indication:", "Symptomatic anaemia – chemotherapy-induced (Hb 6.9 g/dL)")],
        col_widths=[28*mm, 57*mm, 28*mm, 57*mm]
    ))
    story.append(info_row(
        [("Pre-Transfusion Hb:", "6.9 g/dL"), ("Post-Transfusion Hb:", "9.6 g/dL  (Day 3 post-transfusion)")],
        col_widths=[28*mm, 57*mm, 28*mm, 57*mm]
    ))
    story.append(info_row(
        [("Transfusion Reactions:", "None"), ("Crossmatch:", "Electronic – Type & Screen; no alloantibodies")],
        col_widths=[28*mm, 57*mm, 28*mm, 57*mm]
    ))
    story.append(Spacer(1, 3*mm))

    # ── KEY INVESTIGATIONS ────────────────────────────────────────────────────
    story.append(section_header("  KEY INVESTIGATIONS DURING ADMISSION"))
    story.append(Spacer(1, 1*mm))
    story.append(data_table(
        ["Investigation", "Admission (23 Jun)", "Nadir / Worst", "Discharge (04 Jul)", "Reference Range"],
        [
            ["Haemoglobin (Hb)",       "7.8 g/dL",      "6.9 g/dL",       "9.6 g/dL",      "13.5–17.5 g/dL"],
            ["Neutrophils (ANC)",       "1.2 × 10⁹/L",   "0.4 × 10⁹/L",   "1.8 × 10⁹/L",   "1.8–7.5 × 10⁹/L"],
            ["Platelets",               "128 × 10⁹/L",   "78 × 10⁹/L",    "105 × 10⁹/L",   "150–400 × 10⁹/L"],
            ["WBC",                     "3.1 × 10⁹/L",   "1.4 × 10⁹/L",   "3.6 × 10⁹/L",   "4.0–11.0 × 10⁹/L"],
            ["CRP",                     "28 mg/L",        "142 mg/L",       "18 mg/L",        "< 10 mg/L"],
            ["Creatinine",              "82 µmol/L",      "91 µmol/L",      "84 µmol/L",      "64–104 µmol/L"],
            ["eGFR",                    "74 mL/min",      "68 mL/min",      "72 mL/min",      "> 60 mL/min"],
            ["Albumin",                 "32 g/L",         "29 g/L",         "31 g/L",         "35–50 g/L"],
            ["LDH",                     "312 U/L",        "388 U/L",        "290 U/L",        "135–225 U/L"],
            ["Blood Glucose (fasting)", "9.2 mmol/L",     "11.4 mmol/L",    "8.8 mmol/L",     "3.9–5.5 mmol/L"],
            ["Blood Cultures (×2)",     "Sent",           "No growth",      "–",               "Sterile"],
        ],
        col_ws=[44*mm, 28*mm, 28*mm, 28*mm, 42*mm]
    ))
    story.append(Spacer(1, 2*mm))
    story.append(Table([[narrative(
        "<b>Imaging:</b>  CT Chest/Abdomen/Pelvis (25 Jun 2026) – Stable disease compared to pre-cycle 2 scan "
        "(Mar 2026). Primary RUL mass: 4.6 cm (prev 4.8 cm). No new metastatic deposits. "
        "Mediastinal lymph nodes stable. No pleural effusion."
    )]], colWidths=[170*mm]))
    story.append(Spacer(1, 3*mm))

    # ── CLINICAL COURSE ───────────────────────────────────────────────────────
    story.append(section_header("  CLINICAL COURSE & MANAGEMENT"))
    story.append(Spacer(1, 1*mm))
    story.append(Table([[narrative(
        "<b>Cycle 3 Chemotherapy (23 Jun 2026):</b>  Carboplatin AUC 5 and Pemetrexed 500 mg/m² administered "
        "uneventfully. Pre-medicated with dexamethasone, ondansetron, and oral folic acid. Patient tolerated "
        "the infusion well with no acute infusion reactions."
        "<br/><br/>"
        "<b>Febrile Neutropenia (30 Jun 2026):</b>  On Day 7, Mr. Hale developed a temperature of 38.6°C "
        "with rigors. ANC was critically low at 0.4 × 10⁹/L. Blood cultures ×2 taken. Started empirically on "
        "IV Piperacillin-Tazobactam 4.5 g TDS and IV Gentamicin (single daily dose) per neutropenic sepsis "
        "protocol. Fever settled within 48 hours. Blood cultures showed no growth at 5 days. Antibiotics "
        "de-escalated to oral Co-Amoxiclav after 72 hours of apyrexia. G-CSF (Filgrastim) continued until "
        "ANC > 1.5 × 10⁹/L."
        "<br/><br/>"
        "<b>Transfusion (29 Jun 2026):</b>  Symptomatic anaemia (Hb 6.9 g/dL – fatigue, breathlessness at rest). "
        "2 units pRBC transfused without incident. Post-transfusion Hb 9.6 g/dL. Symptoms improved "
        "significantly."
        "<br/><br/>"
        "<b>Glycaemic Control:</b>  Hyperglycaemia noted during dexamethasone course (peak glucose 11.4 mmol/L). "
        "Sliding scale insulin used inpatient; transitioned back to Metformin at discharge with advice to "
        "monitor home glucose closely."
        "<br/><br/>"
        "<b>Palliative Care / Supportive Input:</b>  Palliative Care team reviewed on 02 Jul. Patient and wife "
        "counselled regarding prognosis and treatment goals. Goals of care documented. Patient wishes to "
        "continue active oncological treatment. DNACPR discussion deferred pending next clinic."
    )]], colWidths=[170*mm]))
    story.append(Spacer(1, 3*mm))

    # ── PERFORMANCE STATUS ────────────────────────────────────────────────────
    story.append(section_header("  PERFORMANCE STATUS & FUNCTIONAL ASSESSMENT"))
    story.append(Spacer(1, 1*mm))
    story.append(info_row(
        [("ECOG PS (Admission):", "2 – Ambulatory, capable of self-care"), ("ECOG PS (Discharge):", "1 – Restricted strenuous activity, ambulatory")],
        col_widths=[40*mm, 45*mm, 40*mm, 45*mm]
    ))
    story.append(info_row(
        [("Nutritional Status:", "Malnutrition risk (MUST score 2) – Dietitian reviewed"), ("Weight:", "71 kg (↓ 3 kg from baseline 74 kg)")],
        col_widths=[40*mm, 45*mm, 40*mm, 45*mm]
    ))
    story.append(info_row(
        [("Pain Score (NRS):", "3/10 at discharge – controlled on regular paracetamol"), ("Nausea:", "Mild (Grade 1 CTCAE) – managed with metoclopramide")],
        col_widths=[40*mm, 45*mm, 40*mm, 45*mm]
    ))
    story.append(Spacer(1, 3*mm))

    # ── DISCHARGE MEDICATIONS ─────────────────────────────────────────────────
    story.append(section_header("  DISCHARGE MEDICATIONS"))
    story.append(Spacer(1, 1*mm))
    med_headers = ["Medication", "Dose", "Route", "Freq.", "Duration", "Notes"]
    med_rows = [
        ["Pemetrexed supplementation:", "", "", "", "", ""],
        ["  Folic Acid",              "5 mg",         "Oral", "OD",   "Ongoing (throughout chemo)", "Take daily – reduce toxicity"],
        ["  Vitamin B12 (Cyanocobalamin)", "1 mg",    "IM",   "Q9 weeks", "Per chemo schedule",    "Next due 15 Aug 2026"],
        ["Dexamethasone",             "4 mg",         "Oral", "BD",   "3 days (D1–D3 post-chemo)", "Skin rash prophylaxis"],
        ["Ondansetron",               "8 mg",         "Oral", "TDS PRN", "5 days post-chemo",     "Anti-emetic"],
        ["Metoclopramide",            "10 mg",        "Oral", "TDS PRN", "As needed",             "Breakthrough nausea"],
        ["Metformin",                 "1000 mg",      "Oral", "BD",   "Ongoing",                  "Resume post-chemo; hold day of chemo"],
        ["Amlodipine",                "5 mg",         "Oral", "OD",   "Ongoing",                  "Hypertension management"],
        ["Paracetamol",               "1 g",          "Oral", "QDS",  "Ongoing PRN",              "For pain – max 4 g/day"],
        ["Loperamide",                "2 mg",         "Oral", "PRN",  "As needed",                "For chemotherapy-related diarrhoea"],
        ["Omeprazole",                "20 mg",        "Oral", "OD",   "Ongoing",                  "Gastric protection"],
    ]
    col_ws_med = [42*mm, 20*mm, 14*mm, 22*mm, 34*mm, 38*mm]
    med_data = [med_headers] + med_rows
    med_tbl = Table(med_data, colWidths=col_ws_med, repeatRows=1)
    med_tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  MID_TEAL),
        ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
        ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,-1), 8),
        ("ALIGN",         (0,0), (-1,-1), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("BACKGROUND",    (0,1), (-1,1),  colors.HexColor("#E8F5E9")),
        ("FONTNAME",      (0,1), (-1,1),  "Helvetica-Bold"),
        ("ROWBACKGROUNDS",(0,2), (-1,-1), [WHITE, LIGHT_TEAL]),
        ("GRID",          (0,0), (-1,-1), 0.4, GREY_BORDER),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ]))
    story.append(med_tbl)
    story.append(Spacer(1, 2*mm))
    story.append(warning_box(
        "⚠  IMPORTANT: Do NOT take ibuprofen, aspirin, or other NSAIDs. Avoid live vaccines during "
        "chemotherapy. Monitor blood glucose daily – contact GP if > 14 mmol/L. "
        "Cycle 4 chemotherapy planned: 21 July 2026."
    ))
    story.append(Spacer(1, 3*mm))

    # ── FOLLOW-UP PLAN ────────────────────────────────────────────────────────
    story.append(section_header("  FOLLOW-UP PLAN"))
    story.append(Spacer(1, 1*mm))
    fu_data = [
        ["1.", "GP Review",                 "11 July 2026",  "FBC, CRP, renal panel, LFTs, glucose. Review neutropenia recovery."],
        ["2.", "Oncology Clinic",            "14 July 2026",  "Dr. Menon – pre-cycle 4 assessment. Discuss CT response. DNACPR discussion."],
        ["3.", "Cycle 4 Chemotherapy",       "21 July 2026",  "Carboplatin AUC 5 + Pemetrexed Day 1 (subject to blood counts clearance)."],
        ["4.", "Vitamin B12 Injection",      "15 Aug 2026",   "IM Cyanocobalamin 1 mg – administer at GP surgery."],
        ["5.", "Dietitian / Nutrition",      "18 July 2026",  "Community dietitian follow-up – weight monitoring, nutritional supplementation."],
        ["6.", "Palliative Care",            "As needed",     "Community palliative support team engaged. Contact via key worker."],
        ["7.", "Respiratory / Thoracics",    "28 July 2026",  "Review of CT findings and discussion of radiation therapy potential."],
    ]
    fu_hdr = [["#", "Appointment", "Date / Target", "Instructions"]]
    fu_tbl = Table(fu_hdr + fu_data, colWidths=[8*mm, 40*mm, 30*mm, 92*mm], repeatRows=1)
    fu_tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  MID_TEAL),
        ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
        ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,-1), 8.5),
        ("ALIGN",         (0,0), (1,-1),  "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_TEAL]),
        ("GRID",          (0,0), (-1,-1), 0.4, GREY_BORDER),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ]))
    story.append(fu_tbl)
    story.append(Spacer(1, 3*mm))

    # ── RED FLAGS & DISCHARGE ADVICE ──────────────────────────────────────────
    story.append(section_header("  RED FLAGS – RETURN TO HOSPITAL IMMEDIATELY IF:"))
    story.append(Spacer(1, 1*mm))
    red_flags = [
        ("🌡 Fever:", "Temperature ≥ 38°C – go to ED immediately; do NOT wait for GP appointment (neutropenic sepsis risk)."),
        ("🩸 Bleeding:", "Unusual bruising, blood in urine/stool, or uncontrolled bleeding."),
        ("😮 Breathing:", "Sudden worsening of breathlessness, chest pain, or coughing up blood."),
        ("🤢 GI symptoms:", "Persistent vomiting or diarrhoea (> 4 episodes/day) – risk of dehydration."),
        ("🧠 Neurological:", "New confusion, severe headache, vision changes, or seizures."),
        ("💊 Medication concerns:", "Unable to take medications; severe side effects from new prescriptions."),
    ]
    for icon_label, text in red_flags:
        row_data = [[Paragraph(icon_label, alert_style), Paragraph(text, body_text)]]
        row_tbl = Table(row_data, colWidths=[30*mm, 140*mm])
        row_tbl.setStyle(TableStyle([
            ("BACKGROUND",   (0,0), (-1,-1), colors.HexColor("#FFF8F8")),
            ("VALIGN",       (0,0), (-1,-1), "TOP"),
            ("TOPPADDING",   (0,0), (-1,-1), 4),
            ("BOTTOMPADDING",(0,0), (-1,-1), 4),
            ("LEFTPADDING",  (0,0), (-1,-1), 8),
            ("LINEBELOW",    (0,0), (-1,-1), 0.5, GREY_BORDER),
        ]))
        story.append(row_tbl)
    story.append(Spacer(1, 3*mm))

    # ── PATIENT EDUCATION ─────────────────────────────────────────────────────
    story.append(section_header("  PATIENT & FAMILY EDUCATION"))
    story.append(Spacer(1, 1*mm))
    advice = [
        "Wash hands frequently. Avoid crowded places and people with infections during the first 2 weeks after chemotherapy.",
        "Eat small, frequent meals high in protein. Avoid raw/undercooked foods (infection risk).",
        "Fatigue is expected – rest when needed. Gentle walking is encouraged; avoid strenuous activity.",
        "Report any mouth sores, difficulty swallowing, or skin rashes to the oncology team promptly.",
        "24-hour oncology helpline: (01) 555-8399. Always mention you are a chemotherapy patient.",
        "Next chemotherapy (Cycle 4) is provisionally booked for 21 July 2026, subject to blood count recovery.",
        "Information leaflets provided: Carboplatin, Pemetrexed, Neutropenic Sepsis, Living with Lung Cancer.",
    ]
    for i, line in enumerate(advice, 1):
        story.append(Table([[Paragraph(f"{i}.  {line}", body_text)]], colWidths=[170*mm]))
    story.append(Spacer(1, 3*mm))

    # ── MULTIDISCIPLINARY TEAM ────────────────────────────────────────────────
    story.append(section_header("  MULTIDISCIPLINARY TEAM INVOLVEMENT"))
    story.append(Spacer(1, 1*mm))
    story.append(data_table(
        ["Team / Specialist", "Name", "Input / Action"],
        [
            ["Consultant Oncologist",      "Dr. Priya Menon",    "Overall cancer management, chemotherapy plan, CT review"],
            ["Haematology Registrar",      "Dr. Luke Farrell",   "Blood transfusion management, neutropenia treatment"],
            ["Palliative Care Team",        "Dr. Nina Walsh",     "Goals of care discussion, symptom management planning"],
            ["Clinical Nurse Specialist",  "Sr. Marie O'Brien",  "Patient education, key worker, community liaison"],
            ["Dietitian",                  "Ms. Tanya Brooks",   "Nutritional assessment (MUST 2), high-protein diet plan"],
            ["Pharmacist",                 "Mr. Darren Singh",   "Medication reconciliation, chemotherapy drug checking"],
            ["Physiotherapist",            "Mr. Tom Reyes",       "Mobility assessment, breathing exercises, discharge planning"],
        ],
        col_ws=[45*mm, 42*mm, 83*mm]
    ))
    story.append(Spacer(1, 3*mm))

    # ── SIGNATURES ────────────────────────────────────────────────────────────
    story.append(section_header("  AUTHORISING CLINICIAN"))
    story.append(Spacer(1, 1*mm))
    sig_data = [
        [Paragraph("Discharging Doctor:", field_label), Paragraph("Dr. Luke Farrell", field_value),
         Paragraph("Consultant:", field_label), Paragraph("Dr. Priya Menon, MBChB, FRCP, MD (Oncology)", field_value)],
        [Paragraph("Designation:", field_label), Paragraph("Oncology Registrar", field_value),
         Paragraph("Date Signed:", field_label), Paragraph("04 July 2026", field_value)],
        [Paragraph("Signature:", field_label), Paragraph("__________________________", field_value),
         Paragraph("Bleep / Ext:", field_label), Paragraph("Bleep 5512  |  Ext. 8341", field_value)],
        [Paragraph("Key Worker:", field_label), Paragraph("Sr. Marie O'Brien (CNS)", field_value),
         Paragraph("CNS Contact:", field_label), Paragraph("(01) 555-8310  |  marie.obrien@citycancer.nhs.uk", field_value)],
    ]
    sig_tbl = Table(sig_data, colWidths=[32*mm, 53*mm, 32*mm, 53*mm])
    sig_tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), GREY_BG),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ("LINEBELOW",     (0,0), (-1,-1), 0.5, GREY_BORDER),
    ]))
    story.append(sig_tbl)
    story.append(Spacer(1, 4*mm))

    # ── FOOTER ────────────────────────────────────────────────────────────────
    story.append(HRFlowable(width="100%", thickness=1, color=DARK_TEAL))
    story.append(Spacer(1, 2*mm))
    story.append(Paragraph(
        "This document is computer-generated and is valid without a wet signature unless otherwise indicated. "
        "City Cancer Centre – Oncology Discharge Summary  |  Document Date: 04 July 2026  |  Page 1 of 1  |  "
        "Form Ref: CCC-ONC-DS-v2.4  |  24-hr Oncology Helpline: (01) 555-8399",
        footer_style
    ))

    doc.build(story)
    print(f"PDF generated: {OUTPUT}")

build_pdf()
Running Command

cd /home/daytona/workspace/discharge-summary && python generate_cancer_discharge…

Your oncology discharge summary PDF is ready:

Cancer Patient Discharge Summary

PDF Document · PDF


Here's what's included:
Patient: Mr. Robert Thomas Hale, 67M, Stage IIIB NSCLC (Adenocarcinoma), MRN CCC-2026-031947
Sections:
SectionDetails
Patient DemographicsName, DOB, NOK, blood group, allergies
Admission & Discharge23 Jun – 04 Jul 2026 (11 days), Ward 12 Oncology
Oncology Diagnosis & StagingNSCLC Stage IIIB T3N3M0, EGFR Exon 21 L858R+, PD-L1 55%
Reason for AdmissionCycle 3 chemo + febrile neutropenia + symptomatic anaemia
Chemotherapy GivenCarboplatin AUC 5 + Pemetrexed 500 mg/m², pre-meds, G-CSF
Blood Transfusion2 units pRBC (Hb 6.9 → 9.6 g/dL), no reactions
InvestigationsAdmission vs nadir vs discharge: FBC, CRP, renal, glucose + CT result
Clinical CourseChemo, febrile neutropenia management, transfusion, glycaemic control, palliative input
Performance StatusECOG PS, weight, pain/nausea scores
Discharge Medications11 drugs including chemo supplements, anti-emetics, Metformin, Amlodipine
Follow-up Plan7 appointments (GP, Oncology, Chemo Cycle 4, B12, Dietitian, Palliative, Respiratory)
Red FlagsFever, bleeding, breathlessness, GI, neuro - return to ED instructions
Patient Education7 specific instructions + 24-hr helpline
MDT Involvement7 team members documented
SignaturesRegistrar + Consultant + CNS key worker
Let me know if you'd like to swap in real patient data or adjust anything.
This is a shared conversation. Sign in to Orris to start your own chat.