Make a medical oncology discharge summary for supportive care for Indian patient cancer patients
mkdir -p /home/daytona/workspace/oncology-discharge && ls /home/daytona/workspac…
~/oncology-discharge/generate_discharge.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm, cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT, TA_JUSTIFY
from reportlab.platypus import BaseDocTemplate, PageTemplate, Frame
from reportlab.lib.colors import HexColor
OUTPUT_PATH = "/home/daytona/workspace/oncology-discharge/Oncology_Discharge_Summary.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
DEEP_BLUE = HexColor("#1A3A5C") # headers / title bar
MID_BLUE = HexColor("#2E6DA4") # section headings
LIGHT_BLUE = HexColor("#D6E8F7") # table header row background
ORANGE = HexColor("#E07B39") # accent line under hospital name
LIGHT_GREY = HexColor("#F5F5F5") # alternating table row bg
RED_ALERT = HexColor("#C0392B") # allergy / alert text
WHITE = colors.white
BLACK = colors.black
W, H = A4
# ── Document setup ──────────────────────────────────────────────────────────
doc = BaseDocTemplate(
OUTPUT_PATH,
pagesize=A4,
leftMargin=18*mm, rightMargin=18*mm,
topMargin=22*mm, bottomMargin=20*mm,
title="Medical Oncology Discharge Summary – Supportive Care",
author="Tata Cancer Care Centre, Mumbai",
)
content_width = W - 36*mm # usable width
frame = Frame(
doc.leftMargin, doc.bottomMargin,
content_width, H - doc.topMargin - doc.bottomMargin,
id='normal'
)
def header_footer(canvas, doc_obj):
canvas.saveState()
# Top rule
canvas.setStrokeColor(MID_BLUE)
canvas.setLineWidth(0.8)
canvas.line(18*mm, H - 14*mm, W - 18*mm, H - 14*mm)
# Footer
canvas.setFont("Helvetica", 7)
canvas.setFillColor(colors.grey)
canvas.drawString(18*mm, 12*mm, "CONFIDENTIAL – For treating physician use only")
canvas.drawRightString(W - 18*mm, 12*mm, f"Page {doc_obj.page}")
canvas.line(18*mm, 14*mm, W - 18*mm, 14*mm)
canvas.restoreState()
doc.addPageTemplates([PageTemplate(id='main', frames=[frame], onPage=header_footer)])
# ── Styles ───────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def s(name, **kw):
p = ParagraphStyle(name, parent=base['Normal'], **kw)
return p
HOSPITAL = s("hospital", fontSize=16, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_CENTER, spaceAfter=0)
HOSP_SUB = s("hsub", fontSize=8.5, fontName="Helvetica",
textColor=HexColor("#BDD9F2"), alignment=TA_CENTER, spaceAfter=0)
DOC_TITLE = s("docTitle", fontSize=13, fontName="Helvetica-Bold",
textColor=DEEP_BLUE, alignment=TA_CENTER, spaceAfter=4)
SEC_HEAD = s("secHead", fontSize=10, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_LEFT,
leftIndent=4, spaceAfter=0, spaceBefore=8)
LABEL = s("label", fontSize=8.5, fontName="Helvetica-Bold",
textColor=DEEP_BLUE, spaceAfter=1)
VALUE = s("value", fontSize=9, fontName="Helvetica",
textColor=BLACK, spaceAfter=2)
SMALL = s("small", fontSize=8, fontName="Helvetica",
textColor=colors.grey)
ALERT = s("alert", fontSize=9, fontName="Helvetica-Bold",
textColor=RED_ALERT)
BODY = s("body", fontSize=9, fontName="Helvetica",
textColor=BLACK, leading=13, spaceAfter=3,
alignment=TA_JUSTIFY)
BULLET = s("bullet", fontSize=9, fontName="Helvetica",
textColor=BLACK, leading=12, leftIndent=10, bulletIndent=0,
spaceAfter=2)
SIG_STYLE = s("sig", fontSize=8.5, fontName="Helvetica",
textColor=colors.grey, alignment=TA_CENTER)
def section_header(text):
"""Returns a full-width coloured banner for a section."""
tbl = Table([[Paragraph(text, SEC_HEAD)]], colWidths=[content_width])
tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), MID_BLUE),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (0,0), (-1,-1), 6),
]))
return tbl
def kv_table(rows, col_ratios=(0.30, 0.70)):
"""Two-column label-value table."""
cw = [content_width * r for r in col_ratios]
data = [[Paragraph(lbl, LABEL), Paragraph(val, VALUE)] for lbl, val in rows]
tbl = Table(data, colWidths=cw)
tbl.setStyle(TableStyle([
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 3),
('BOTTOMPADDING', (0,0), (-1,-1), 3),
('LEFTPADDING', (0,0), (-1,-1), 4),
('ROWBACKGROUNDS', (0,0), (-1,-1), [WHITE, LIGHT_GREY]),
('LINEBELOW', (0,-1), (-1,-1), 0.3, colors.lightgrey),
]))
return tbl
def three_col_table(rows, headers, ratios=(0.35, 0.35, 0.30)):
cw = [content_width * r for r in ratios]
head_row = [Paragraph(f"<b>{h}</b>", s("th", fontSize=8.5, fontName="Helvetica-Bold",
textColor=DEEP_BLUE)) for h in headers]
data = [head_row]
for row in rows:
data.append([Paragraph(cell, VALUE) for cell in row])
tbl = Table(data, colWidths=cw)
tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), LIGHT_BLUE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 3),
('BOTTOMPADDING', (0,0), (-1,-1), 3),
('LEFTPADDING', (0,0), (-1,-1), 4),
('GRID', (0,0), (-1,-1), 0.3, colors.lightgrey),
]))
return tbl
def four_col_table(rows, headers, ratios=(0.22, 0.22, 0.28, 0.28)):
cw = [content_width * r for r in ratios]
head_row = [Paragraph(f"<b>{h}</b>", s("th4", fontSize=8.5, fontName="Helvetica-Bold",
textColor=DEEP_BLUE)) for h in headers]
data = [head_row]
for row in rows:
data.append([Paragraph(cell, VALUE) for cell in row])
tbl = Table(data, colWidths=cw)
tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), LIGHT_BLUE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 3),
('BOTTOMPADDING', (0,0), (-1,-1), 3),
('LEFTPADDING', (0,0), (-1,-1), 4),
('GRID', (0,0), (-1,-1), 0.3, colors.lightgrey),
]))
return tbl
# ═══════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ═══════════════════════════════════════════════════════════════════════════
story = []
# ── Hospital Header Banner ───────────────────────────────────────────────────
hosp_banner = Table(
[[Paragraph("TATA CANCER CARE CENTRE", HOSPITAL)],
[Paragraph("Department of Medical Oncology | Supportive & Palliative Care Unit", HOSP_SUB)],
[Paragraph("Mumbai – 400 012, Maharashtra | Tel: 022-6750-0000 | www.tatacancercare.org", HOSP_SUB)]],
colWidths=[content_width]
)
hosp_banner.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), DEEP_BLUE),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,-1), (-1,-1), 8),
('LEFTPADDING', (0,0), (-1,-1), 4),
]))
story.append(hosp_banner)
story.append(HRFlowable(width=content_width, thickness=3, color=ORANGE, spaceAfter=6))
# Document title
story.append(Paragraph("MEDICAL ONCOLOGY DISCHARGE SUMMARY", DOC_TITLE))
story.append(Paragraph("(Supportive Care Admission)", s("subT", fontSize=9.5,
fontName="Helvetica-Oblique", textColor=MID_BLUE, alignment=TA_CENTER)))
story.append(Spacer(1, 6))
# ── SECTION 1: Patient Demographics ─────────────────────────────────────────
story.append(section_header("1. PATIENT DEMOGRAPHICS"))
story.append(Spacer(1, 3))
# Top row: two side-by-side mini tables
left_kv = [
("Patient Name:", "Smt. Sunita Ramesh Patil"),
("Age / Sex / Blood Group:", "52 Years / Female / B+ve"),
("Date of Birth:", "14 March 1974"),
("Marital Status:", "Married"),
("Religion:", "Hindu"),
("Address:", "Flat No. 7, Shivaji Nagar, Pune – 411 005"),
("Contact Number:", "+91 98765 43210"),
("Guardian / Attendant:", "Shri Ramesh Patil (Husband) – +91 98765 43211"),
("Referred By:", "Dr. P. K. Nair, MBBS MD – Nair Hospital, Pune"),
("UHID / MRD No.:", "TATA-ONC-2026-04872"),
]
right_kv = [
("Admission Date:", "30 June 2026"),
("Discharge Date:", "09 July 2026"),
("Total Days Admitted:", "10 Days"),
("Ward / Bed:", "Oncology Ward – Bed No. 14B"),
("Treating Consultant:", "Dr. Anjali Mehta, MD DM Medical Oncology"),
("Co-consultant:", "Dr. Suresh Kadam, MD Palliative Medicine"),
("Resident / JR:", "Dr. Priya Soni (Junior Resident)"),
("Nursing In-charge:", "Nurse Kavita Joshi"),
("Insurance / Ayushman:", "Ayushman Bharat PMJAY – Policy No. 0045-2026"),
("ECOG Performance Status:", "2 (at admission) → 1 (at discharge)"),
]
demo_left = kv_table(left_kv, (0.40, 0.60))
demo_right = kv_table(right_kv, (0.44, 0.56))
demo_outer = Table([[demo_left, Spacer(4,1), demo_right]],
colWidths=[content_width*0.49, 4, content_width*0.49])
demo_outer.setStyle(TableStyle([('VALIGN', (0,0), (-1,-1), 'TOP')]))
story.append(demo_outer)
story.append(Spacer(1, 6))
# ── SECTION 2: Oncological Diagnosis ────────────────────────────────────────
story.append(section_header("2. ONCOLOGICAL DIAGNOSIS"))
story.append(Spacer(1, 3))
story.append(kv_table([
("Primary Diagnosis:", "Carcinoma Left Breast – Invasive Ductal Carcinoma (IDC), Grade III"),
("Stage:", "Stage IIIB (T4b N2 M0) – Locally Advanced Breast Cancer"),
("Receptor Status:", "ER +ve (80%), PR +ve (60%), HER2 2+ (FISH Non-amplified) – Luminal B (HER2-negative)"),
("Date of Histopathology:", "12 April 2026 | Biopsy Lab Ref: TATA-PATH-2026-1122"),
("Ki-67 Index:", "35% (High Proliferative)"),
("Date of Initial Diagnosis:", "10 April 2026"),
("Comorbidities:", "Type 2 Diabetes Mellitus (on OHA), Hypertension (controlled), Iron-Deficiency Anaemia"),
("Known Allergies:", "<font color='#C0392B'><b>ALLERGIC TO PENICILLIN (Rash) – Documented on armband</b></font>"),
], (0.30, 0.70)))
story.append(Spacer(1, 6))
# ── SECTION 3: Current Admission – Reason ───────────────────────────────────
story.append(section_header("3. REASON FOR THIS ADMISSION"))
story.append(Spacer(1, 3))
story.append(Paragraph(
"Patient was admitted with <b>Grade 3 febrile neutropaenia</b> following Cycle 3 of neoadjuvant "
"chemotherapy (AC-T regimen: Doxorubicin + Cyclophosphamide). She presented with high-grade fever "
"(39.8°C), rigors, oral mucositis (WHO Grade II), nausea/vomiting (CTCAE Grade 2), and significant "
"fatigue. She also had worsening oral intake with body weight loss of 3 kg over 3 weeks, raising "
"concern for nutritional compromise. Admission was also prompted by uncontrolled pain (NRS 7/10) "
"from bone metastasis-related back pain.", BODY))
story.append(Spacer(1, 6))
# ── SECTION 4: Treatment Given During Admission ───────────────────────────────
story.append(section_header("4. TREATMENT ADMINISTERED DURING ADMISSION"))
story.append(Spacer(1, 3))
story.append(Paragraph("<b>A. Anti-infective / Neutropaenia Management</b>", LABEL))
story.append(Spacer(1,2))
story.append(four_col_table([
["Inj. Piperacillin-Tazobactam 4.5 g IV Q8H", "30 Jun – 06 Jul 2026", "7 days", "Empiric broad-spectrum; de-escalated on culture sensitivity"],
["Inj. Amikacin 15 mg/kg IV OD", "30 Jun – 03 Jul 2026", "4 days", "Gram-negative cover; stopped on Day 4 (culture guided)"],
["Inj. Fluconazole 400 mg IV OD", "30 Jun – 05 Jul 2026", "6 days", "Antifungal prophylaxis; switched to oral on Day 6"],
["Inj. Filgrastim 300 mcg SC OD", "01 Jul – 06 Jul 2026", "6 days", "G-CSF – neutropaenia recovery"],
["Inj. Acyclovir 5 mg/kg IV Q8H", "01 Jul – 04 Jul 2026", "4 days", "HSV prophylaxis in immunocompromised state"],
], ["Drug / Dose / Route / Frequency", "Duration", "No. of Days", "Remarks"],
ratios=(0.35, 0.22, 0.12, 0.31)))
story.append(Spacer(1, 4))
story.append(Paragraph("<b>B. Supportive Care – Antiemetics, Pain & Nutrition</b>", LABEL))
story.append(Spacer(1,2))
story.append(four_col_table([
["Inj. Ondansetron 8 mg IV TID", "30 Jun – 08 Jul", "9 days", "5-HT3 antagonist; nausea control"],
["Tab. Metoclopramide 10 mg TID (PO) – after Day 5", "05 Jul – 08 Jul", "4 days", "Prokinetic; gastric stasis"],
["Inj. Pantoprazole 40 mg IV OD", "30 Jun – 09 Jul", "10 days", "Gastroprotection"],
["Tab. Pantoprazole 40 mg PO OD at discharge", "Discharge Rx", "Continue", "Step-down oral PPI"],
["Inj. Tramadol 50 mg IV Q8H (PRN)", "30 Jun – 03 Jul", "4 days", "Moderate-severe pain (NRS 7/10)"],
["Tab. Oxycodone CR 10 mg PO Q12H", "04 Jul onwards", "Continue", "Opioid rotation – better pain control"],
["Tab. Pregabalin 75 mg BD", "02 Jul onwards", "Continue", "Neuropathic component"],
["Tab. Paracetamol 500 mg TID (PRN)", "30 Jun onwards", "Continue", "Adjuvant analgesic / antipyretic"],
["Ryle's Tube feeding: Ensure Plus 200 mL Q4H", "01 Jul – 05 Jul", "5 days", "Enteral nutrition support – poor oral intake"],
["High-protein oral nutritional supplement (Protinex)", "06 Jul onwards", "Continue", "Oral sip feeds – 2 servings/day"],
["IV Fluids: NS 0.9% + KCl 20 mEq @ 80 mL/hr", "30 Jun – 04 Jul", "5 days", "Hydration, electrolyte correction"],
["Inj. Iron Sucrose 200 mg IV in 100 mL NS", "02, 04, 06 Jul", "3 doses", "Iron deficiency anaemia (Hb 7.8 on admission)"],
["PRBC transfusion 2 units", "03 July 2026", "1 session", "Hb 7.2 g/dL; symptomatic anaemia"],
], ["Drug / Intervention", "Duration", "Days", "Remarks"],
ratios=(0.33, 0.17, 0.10, 0.40)))
story.append(Spacer(1, 4))
story.append(Paragraph("<b>C. Oral Care / Mucositis Management</b>", LABEL))
story.append(Spacer(1,2))
story.append(three_col_table([
["Magic Mouthwash (Lignocaine + Antacid + Diphenhydramine) 10 mL QID swish-spit", "07 days", "WHO Grade II Mucositis"],
["Benzydamine HCl 0.15% mouthwash TID", "07 days", "Anti-inflammatory rinse"],
["Clotrimazole oral lozenges 10 mg 5 x/day", "05 days", "Oral candidiasis prevention"],
["Soft / liquid diet; calorie-dense foods advised", "Ongoing", "Dietitian reviewed on Day 3"],
], ["Intervention", "Duration", "Reason / Notes"],
ratios=(0.45, 0.15, 0.40)))
story.append(Spacer(1, 4))
story.append(Paragraph("<b>D. Psycho-Social & Palliative Care Input</b>", LABEL))
story.append(Spacer(1,2))
story.append(three_col_table([
["Palliative care team review", "Day 2 & Day 8", "Goals-of-care discussion; advance care planning initiated"],
["Psychiatric / Counselling referral", "Day 4", "Moderate anxiety-depression (PHQ-9 score 14); initiated Tab. Escitalopram 10 mg OD"],
["Social worker assessment", "Day 5", "Ayushman Bharat reimbursement facilitated; home nursing arranged"],
["Patient & caregiver education (verbal + printed pamphlet in Marathi)", "Day 8 & 9", "Chemotherapy side-effects, infection precautions, diet, pain diary"],
], ["Intervention", "Timing", "Details"],
ratios=(0.28, 0.18, 0.54)))
story.append(Spacer(1, 6))
# ── SECTION 5: Investigations ────────────────────────────────────────────────
story.append(section_header("5. KEY INVESTIGATIONS"))
story.append(Spacer(1, 3))
story.append(Paragraph("<b>Haematology & Biochemistry (Admission vs Discharge)</b>", LABEL))
story.append(Spacer(1,2))
story.append(four_col_table([
["Haemoglobin (g/dL)", "7.2", "10.4", "Post 2U PRBC transfusion + Iron sucrose"],
["Total WBC (cells/µL)", "380", "4,200", "Nadir on Day 1; recovery with G-CSF"],
["ANC (cells/µL)", "80", "2,800", "Severe neutropaenia → resolved"],
["Platelets (lakh/µL)", "0.9", "1.4", "Mild thrombocytopenia; recovered spontaneously"],
["Serum Creatinine (mg/dL)", "1.1", "0.9", "Within normal limits"],
["Serum Sodium (mEq/L)", "131", "138", "Mild hyponatraemia corrected"],
["Serum Potassium (mEq/L)", "3.1", "3.9", "Hypokalaemia corrected with supplementation"],
["ALT / SGPT (U/L)", "68", "34", "Mild transaminitis; resolved"],
["Serum Albumin (g/dL)", "2.6", "2.9", "Improving with nutritional support"],
["Blood Sugar Fasting (mg/dL)","178", "112", "Glycaemic control improved; OHA adjusted"],
["Blood Culture (Day 1)", "E. coli (ESBL negative, sensitive to Pip-Taz)", "—", "Guided antibiotic therapy"],
["CXR (01 Jul 2026)", "No consolidation; small left pleural effusion", "—", "Stable at discharge"],
["ECHO (03 Jul 2026)", "EF 58%; no regional wall motion abnormality", "—", "Baseline pre-anthracycline"],
], ["Parameter", "At Admission", "At Discharge", "Remarks"],
ratios=(0.30, 0.18, 0.18, 0.34)))
story.append(Spacer(1, 6))
# ── SECTION 6: Summary of Hospital Course ────────────────────────────────────
story.append(section_header("6. SUMMARY OF HOSPITAL COURSE"))
story.append(Spacer(1, 3))
story.append(Paragraph(
"Patient was admitted with post-chemotherapy febrile neutropaenia (Grade 3) after Cycle 3 "
"of AC chemotherapy. She was started promptly on empiric broad-spectrum IV antibiotics "
"(Piperacillin-Tazobactam + Amikacin) as per institutional febrile neutropaenia protocol "
"(MASCC Score 17 – Low Risk; admitted as per patient preference and logistic considerations). "
"Blood culture grew E. coli, sensitive to the empiric regimen. Antibiotics were continued for a "
"total of 7 days and successfully de-escalated. G-CSF (Filgrastim) was administered for 6 days; "
"ANC recovered to >2,000 by Day 7.", BODY))
story.append(Paragraph(
"Symptomatic anaemia (Hb 7.2 g/dL) was managed with 2 units of packed red blood cells and "
"3 doses of IV iron sucrose. Nutritional status was supported initially via nasogastric enteral feeds "
"(5 days) and transitioned to oral sip feeds with dietitian supervision. Body weight improved by "
"1.2 kg over the admission.", BODY))
story.append(Paragraph(
"Pain was initially controlled with IV tramadol and was effectively rotated to oral sustained-release "
"oxycodone with addition of pregabalin for the neuropathic component; NRS score improved from 7/10 "
"to 2/10 at discharge. Oral mucositis healed to Grade I by Day 8. Electrolyte imbalances (hyponatraemia, "
"hypokalaemia) were corrected. Blood sugar was stabilised with dose adjustment of oral hypoglycaemics. "
"Palliative care and psychiatry teams were involved for goals-of-care planning and management of "
"anxiety-depression. Patient and caregivers were educated in Marathi and English; home nursing "
"services were arranged via the social worker.", BODY))
story.append(Spacer(1, 4))
# ── SECTION 7: Condition at Discharge ────────────────────────────────────────
story.append(section_header("7. CONDITION AT DISCHARGE"))
story.append(Spacer(1, 3))
story.append(kv_table([
("General Condition:", "Stable, afebrile (Temp 37.1°C), ambulatory"),
("ECOG Performance Status:", "1 (improved from 2 at admission)"),
("Vital Signs at Discharge:", "BP 128/80 mmHg | PR 82/min, regular | SpO₂ 98% (RA) | RR 16/min"),
("Pain (NRS):", "2/10 – well-controlled on oral opioid regimen"),
("Oral Intake:", "Tolerating soft diet + high-protein sip feeds"),
("Emotional Status:", "Improved; less anxious; engaged with counselling"),
("Caregiver Status:", "Husband present; educated and capable of home care"),
], (0.28, 0.72)))
story.append(Spacer(1, 6))
# ── SECTION 8: Discharge Medications ─────────────────────────────────────────
story.append(section_header("8. DISCHARGE MEDICATIONS (Rx)"))
story.append(Spacer(1, 3))
story.append(Paragraph(
"<font color='#C0392B'><b>ALLERGY: PENICILLIN</b></font> – ensure no beta-lactam penicillins are prescribed in the community.",
ALERT))
story.append(Spacer(1, 3))
story.append(four_col_table([
["Tab. Oxycodone CR (OxyContin) 10 mg", "Twice daily (every 12 hrs)", "14 days", "Opioid – for persistent cancer pain; do NOT crush"],
["Tab. Paracetamol 500 mg", "Three times daily (TID)", "14 days", "Adjuvant analgesic / breakthrough pain"],
["Tab. Pregabalin 75 mg", "Twice daily (BD)", "14 days", "Neuropathic pain"],
["Tab. Pantoprazole 40 mg", "Once daily (before breakfast)", "30 days", "Gastroprotection with NSAIDs/steroids"],
["Tab. Ondansetron 4 mg", "Twice daily (PRN for nausea)", "10 days", "As-needed antiemetic"],
["Tab. Metoclopramide 10 mg", "Three times daily (before meals)", "10 days", "Prokinetic – nausea/gastric stasis"],
["Tab. Escitalopram 10 mg", "Once daily (morning)", "30 days", "Anxio-depressive symptoms; psychiatry follow-up"],
["Cap. Fluconazole 150 mg", "Once weekly", "4 weeks", "Antifungal maintenance; immunosuppressed state"],
["Tab. Acyclovir 400 mg", "Twice daily", "14 days", "HSV prophylaxis"],
["Tab. Cotrimoxazole DS", "Once daily (Mon/Wed/Fri)", "Until ANC >500 sustained", "PCP prophylaxis (CD4 equivalent status)"],
["Tab. Metformin 500 mg + Glimepiride 1 mg", "Twice daily (with meals)", "Continue", "Diabetes management; BSFL 112 at discharge"],
["Tab. Amlodipine 5 mg", "Once daily (morning)", "Continue", "Antihypertensive"],
["Protinex (high-protein supplement) – 2 scoops", "Twice daily in warm milk/water", "Continue", "Nutritional support – target 1.5 g protein/kg/day"],
["Iron (Ferrous Ascorbate) 100 mg", "Twice daily (on empty stomach)", "30 days", "Iron deficiency anaemia – ongoing course"],
["Tab. Folic Acid 5 mg", "Once daily", "30 days", "Megaloblastic prevention with chemotherapy"],
], ["Drug / Formulation", "Dose / Frequency", "Duration", "Special Instructions"],
ratios=(0.32, 0.22, 0.18, 0.28)))
story.append(Spacer(1, 4))
story.append(Paragraph(
"<b>Note:</b> All opioid prescriptions have been issued with Schedule X narcotic prescription slips "
"(as per NDPS Act India). Caregiver has been counselled on safe opioid storage, "
"constipation prophylaxis, and signs of opioid toxicity.", SMALL))
story.append(Spacer(1, 6))
# ── SECTION 9: Dietary & Lifestyle Advice ─────────────────────────────────────
story.append(section_header("9. DIETARY & LIFESTYLE ADVICE (Advised by Dietitian Ms. Rekha More)"))
story.append(Spacer(1, 3))
bullets = [
"Target caloric intake: <b>2,000–2,200 kcal/day</b>; protein target: <b>75–80 g/day</b> (1.5 g/kg/day).",
"Foods encouraged: Soft-cooked lentils (dal), curd/yoghurt, mashed potato, soft idli/upma, boiled eggs, fish curry, ragi porridge, banana, papaya, seasonal fruits (washed thoroughly).",
"Foods to <b>AVOID</b> during chemotherapy: Raw salads, uncooked sprouts, street food (chaat, pani puri), unpasteurised milk/cheese (paneer from street vendors), high-fibre raw vegetables, alcohol, tobacco products.",
"Maintain oral hygiene: Rinse after every meal with warm saline or prescribed mouthwash.",
"Adequate hydration: Minimum <b>2–2.5 litres/day</b> of boiled/filtered water.",
"Light physical activity as tolerated: 15–20-minute walks twice daily (if ANC >1,000).",
"Avoid crowded places, religious gatherings, sick contacts – infection precautions during neutropaenia phase.",
"Report any fever ≥38°C immediately to oncology emergency (do not wait – come directly to casualty).",
]
for b in bullets:
story.append(Paragraph(f"• {b}", BULLET))
story.append(Spacer(1, 6))
# ── SECTION 10: Follow-up Plan ────────────────────────────────────────────────
story.append(section_header("10. FOLLOW-UP PLAN"))
story.append(Spacer(1, 3))
story.append(three_col_table([
["<b>CBC + Blood Sugar + LFT + KFT</b>", "14 July 2026 (Day 5 post-discharge)", "Community lab OR TATA OPD Lab; report to bring on follow-up"],
["<b>Medical Oncology OPD – Dr. Anjali Mehta</b>", "16 July 2026 – 10:00 AM (OPD No. 14)", "Pre-Cycle 4 evaluation; dose modification if needed"],
["<b>Palliative Medicine – Dr. Suresh Kadam</b>", "18 July 2026", "Pain assessment; opioid dose titration"],
["<b>Psychiatry OPD</b>", "20 July 2026", "Escitalopram response evaluation; counselling continuation"],
["<b>Dietitian Review</b>", "23 July 2026 (telephonic)", "Nutritional status, weight trend, sip feed compliance"],
["<b>Cycle 4 Chemotherapy (Paclitaxel 175 mg/m²)</b>", "28 July 2026 (tentative)", "Subject to ANC >1,500, Hb >9, Platelets >1,00,000"],
], ["Appointment", "Date / Time", "Details"],
ratios=(0.32, 0.28, 0.40)))
story.append(Spacer(1, 6))
# ── SECTION 11: Emergency Instructions ───────────────────────────────────────
story.append(section_header("11. EMERGENCY INSTRUCTIONS – WHEN TO COME TO HOSPITAL IMMEDIATELY"))
story.append(Spacer(1, 3))
alert_items = [
"Fever ≥38°C or chills/rigors at any time (do <b>NOT</b> give paracetamol and wait – come directly)",
"Bleeding from any site (gums, nose, urine, stool, skin bruising)",
"Sudden breathlessness, chest pain, or palpitations",
"Severe pain (NRS >6) not responding to prescribed medications",
"Inability to take oral medications or severe vomiting for >12 hours",
"Confusion, altered sensorium, fits or severe headache",
"Swelling, redness, or pus at the IV cannula site or PICC line",
"Signs of opioid overdose: excessive drowsiness, slow breathing (<8/min), pinpoint pupils",
]
for item in alert_items:
story.append(Paragraph(f"⚠ {item}", s("alertBullet", fontSize=9, fontName="Helvetica",
textColor=HexColor("#7B2D00"), leading=13, leftIndent=8, spaceAfter=2)))
story.append(Spacer(1, 3))
story.append(Paragraph(
"<b>Oncology Emergency Helpline (24×7):</b> 022-6750-0911 | "
"<b>Oncology Casualty:</b> Ground Floor, Block C, TATA Cancer Care Centre, Mumbai",
s("emHelpline", fontSize=9, fontName="Helvetica-Bold", textColor=DEEP_BLUE)))
story.append(Spacer(1, 6))
# ── SECTION 12: Signatures ────────────────────────────────────────────────────
story.append(section_header("12. SIGNATURES & CERTIFICATION"))
story.append(Spacer(1, 6))
sig_data = [
[
Paragraph("<b>Dr. Anjali Mehta</b><br/>MD, DM Medical Oncology<br/>"
"Reg. No.: MCI-2003-DM-04891<br/>Date: 09 July 2026", SIG_STYLE),
Paragraph("<b>Dr. Suresh Kadam</b><br/>MD Palliative Medicine<br/>"
"Reg. No.: MCI-2007-MD-11223<br/>Date: 09 July 2026", SIG_STYLE),
Paragraph("<b>Dr. Priya Soni</b><br/>MBBS, Junior Resident<br/>"
"Reg. No.: MMC-2022-01567<br/>Date: 09 July 2026", SIG_STYLE),
Paragraph("<b>Nurse Kavita Joshi</b><br/>B.Sc Nursing, Oncology Certified<br/>"
"Staff ID: TATA-NRS-442<br/>Date: 09 July 2026", SIG_STYLE),
]
]
sig_labels = [
Paragraph("____________________________", SIG_STYLE),
Paragraph("____________________________", SIG_STYLE),
Paragraph("____________________________", SIG_STYLE),
Paragraph("____________________________", SIG_STYLE),
]
sig_tbl = Table(
[sig_labels, sig_data[0]],
colWidths=[content_width/4]*4
)
sig_tbl.setStyle(TableStyle([
('VALIGN', (0,0), (-1,-1), 'BOTTOM'),
('TOPPADDING', (0,0), (-1,-1), 2),
('BOTTOMPADDING', (0,0), (-1,-1), 2),
('ALIGN', (0,0), (-1,-1), 'CENTER'),
]))
story.append(sig_tbl)
story.append(Spacer(1, 8))
# Patient acknowledgement
ack_tbl = Table([[
Paragraph(
"Patient / Guardian Acknowledgement:<br/>"
"I, <u>Shri Ramesh Patil</u>, have received and understood the discharge instructions, "
"medication list, and follow-up plan in <b>Marathi and English</b>.<br/><br/>"
"Signature: ____________________________ "
"Date: 09 July 2026 Relation to Patient: Husband",
s("ack", fontSize=8.5, fontName="Helvetica", textColor=BLACK, leading=13))
]], colWidths=[content_width])
ack_tbl.setStyle(TableStyle([
('BOX', (0,0), (-1,-1), 0.8, MID_BLUE),
('BACKGROUND', (0,0), (-1,-1), LIGHT_BLUE),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 8),
]))
story.append(ack_tbl)
story.append(Spacer(1, 6))
# ── Footer disclaimer ─────────────────────────────────────────────────────────
story.append(HRFlowable(width=content_width, thickness=0.5, color=colors.grey))
story.append(Spacer(1, 3))
story.append(Paragraph(
"This discharge summary is generated for clinical and documentation purposes. "
"Details are fictitious and created for demonstration / training. "
"All drug dosages and regimens should be verified against current institutional guidelines "
"and the prescribing physician's clinical judgment. "
"Orris Medical AI – July 2026.",
s("disclaimer", fontSize=7, fontName="Helvetica-Oblique",
textColor=colors.grey, alignment=TA_CENTER)))
# ═══════════════════════════════════════════════════════════════════════════
# BUILD
# ═══════════════════════════════════════════════════════════════════════════
doc.build(story)
print(f"PDF saved to: {OUTPUT_PATH}")
cd /home/daytona/workspace/oncology-discharge && python generate_discharge.py 2>…
~/oncology-discharge/generate_discharge.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/oncology-discharge/generate_discharge.py'
~/oncology-discharge/generate_discharge.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/oncology-discharge/generate_discharge.py'
~/oncology-discharge/generate_discharge.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/oncology-discharge/generate_discharge.py'
~/oncology-discharge/generate_discharge.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/oncology-discharge/generate_discharge.py'
~/oncology-discharge/generate_discharge.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/oncology-discharge/generate_discharge.py'
cd /home/daytona/workspace/oncology-discharge && python generate_discharge.py 2>…
cd /home/daytona/workspace/oncology-discharge && python -c " from reportlab.lib.…
cd /home/daytona/workspace/oncology-discharge && python -c " import traceback ex…
~/oncology-discharge/generate_discharge.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/oncology-discharge/generate_discharge.py'
~/oncology-discharge/generate_discharge.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/oncology-discharge/generate_discharge.py'
cd /home/daytona/workspace/oncology-discharge && python generate_discharge.py 2>…
Find latest ASCO guidelines on palliative care in cancer
ASCO guideline palliative care cancer
ASCO 2024 2025 palliative care oncology guideline update
PMID: 38748941
PMID: 36469839
PMID: 36122322
https://ascopubs.org/doi/10.1200/JCO.24.00542
PMID: 40029420
| Domain | 2016 Guideline | 2024 Update |
|---|---|---|
| Patient population | Advanced cancer, early integration | Extended to hematologic malignancies explicitly |
| Caregiver support | Mentioned | Now an explicit recommendation |
| Phase I trials | Not addressed | Now included |
| Equity/language | Not addressed | Explicitly addressed |
| Telehealth | Not addressed | Recognised as modality |
| Evidence base | 2009-2015 literature | 2015-2023 (52 studies) |
| Guideline | Year | Journal | PMID | Focus |
|---|---|---|---|---|
| Palliative Care Integration | 2024 | J Clin Oncol | 38748941 | Core - early integration, all advanced cancer |
| Opioids for Cancer Pain | 2023 | J Clin Oncol | 36469839 | Opioid initiation & titration |
| Integrative Medicine (SIO-ASCO) | 2022 | J Clin Oncol | 36122322 | Acupuncture, massage, hypnosis |
| Opioid Conversion (MASCC-ASCO) | 2025 | Support Care Cancer | 40029420 | Opioid rotation/switching |