Patient has anddometrial car inoma of lungs dmmr positive and msi stable and . previously no radiation was given
"endometrial carcinoma" AND "dMMR" AND "MSI-stable" AND treatment
endometrial carcinoma dMMR MSI-stable discordant management immunotherapy 2024 2025
"endometrial carcinoma" AND "dMMR" AND immunotherapy
https://pmc.ncbi.nlm.nih.gov/articles/PMC11640124
"endometrial cancer" AND "dMMR" AND "MSI discordant"
dMMR MSI-stable discordant endometrial cancer pembrolizumab efficacy 2024
PMID: 41371509
| Regimen | Trial | Key Outcome (dMMR subgroup) |
|---|---|---|
| Dostarlimab 500 mg Q3W + Carboplatin/Paclitaxel x6 cycles, then dostarlimab 1000 mg Q6W maintenance | RUBY / ENGOT-EN6 | 4-yr PFS ~49% vs ~19% placebo; OS benefit sustained; median OS not reached at 69 months follow-up (2026 data) |
| Pembrolizumab 200 mg Q3W + Carboplatin/Paclitaxel x6 cycles, then pembrolizumab maintenance | KEYNOTE-868 | Significant PFS/OS benefit in dMMR group |
| Durvalumab + Carboplatin/Paclitaxel, then durvalumab ± Olaparib maintenance | DUO-E | PFS benefit, especially dMMR; Olaparib adds further benefit |
Doctor has advised dostarlimab alone
"dostarlimab" AND "endometrial cancer" AND monotherapy
dostarlimab monotherapy dMMR endometrial cancer first line approval dose efficacy 2024 2025
PMID: 37917058
PMID: 40382973
| Phase | Dose | Frequency | Route |
|---|---|---|---|
| Loading (first 4 doses) | 500 mg | Every 3 weeks (Q3W) | IV infusion |
| Maintenance (dose 5 onward) | 1000 mg | Every 6 weeks (Q6W) | IV infusion |
| Outcome | Result |
|---|---|
| Objective Response Rate (ORR) | 44.0% (95% CI 38.6-49.6%) |
| Complete Response (CR) | ~13% |
| Partial Response (PR) | ~31% |
| Median Duration of Response | Not reached (range up to 47+ months) |
| Responses lasting ≥12 months | 72.2% of responders |
| Median PFS | 6.9 months; 40.6% PFS at 24 months |
| Median OS | Not reached (≥31.6 months) |
| Outcome | Result |
|---|---|
| ORR | 53.6% (even higher than trial) |
| Complete Response | 21.6% |
| Partial Response | 32% |
| Median Time to Response | 2.9 months |
| Response durability at 12 months | 85% |
| Discontinuation due to toxicity | only 4.7% |
| Parameter | Frequency |
|---|---|
| Clinical assessment + labs (LFTs, TFTs, FBS, creatinine) | Every 3-6 weeks before each dose |
| CT chest/abdomen/pelvis imaging | Every 8-12 weeks to assess response |
| Thyroid function (TSH, FT4) | Every cycle - hypothyroidism is most common irAE |
| Blood glucose | Each visit - immune-mediated diabetes possible |
| Liver enzymes (ALT/AST) | Each cycle |
| Signs of pneumonitis | Symptom review every visit; low threshold for CT chest |
Doctor has said he will add tablet as well
"dostarlimab" AND "endometrial cancer" AND "olaparib" OR "niraparib" OR "lenvatinib"
dostarlimab plus oral tablet endometrial cancer dMMR lenvatinib olaparib niraparib combination 2024 2025
"dostarlimab" AND "niraparib" AND "endometrial cancer" RUBY
"lenvatinib" AND "dostarlimab" AND "endometrial"
RUBY Part 2 niraparib dostarlimab endometrial cancer results 2024 2025 dMMR
| Outcome | Dostarlimab + Niraparib | Placebo | Benefit |
|---|---|---|---|
| Median PFS (overall) | 14.5 months | 8.3 months | +6.2 months |
| Risk reduction (HR) | HR 0.60 | - | 40% reduction in progression/death |
| PFS in pMMR/MSS | Significant benefit | - | Particularly meaningful in non-dMMR |
| PFS in dMMR | Benefit maintained | - | Additive to immunotherapy |
| Parameter | Detail |
|---|---|
| Starting dose | 200 mg or 300 mg orally once daily (based on body weight and platelet count) |
| Weight-based dosing | <77 kg OR baseline platelets <150,000/μL → 200 mg/day; ≥77 kg AND platelets ≥150,000/μL → 300 mg/day |
| Timing | Same time every day, with or without food; best taken at bedtime to reduce nausea |
| Formulation | Capsules (100 mg each) |
| Duration | Maintenance - continue until progression or unacceptable toxicity |
| Side Effect | Frequency | Management |
|---|---|---|
| Thrombocytopenia (low platelets) | Most common - ~30% any grade | Check CBC weekly for first month, then monthly; dose reduce if Grade 3-4 |
| Anemia | ~25% | Monitor CBC; transfuse if symptomatic |
| Neutropenia | ~20% | Monitor CBC; hold/reduce dose if Grade 3-4 |
| Nausea/vomiting | ~40-50% | Bedtime dosing; antiemetics if needed |
| Fatigue | ~30% | Supportive care |
| Hypertension | ~20% | Monitor BP; antihypertensives if needed |
| Headache, dizziness | Common | Usually mild |
| MDS/AML | Rare (~1%) | Long-term risk; report unusual bruising or fatigue |
| Period | Monitoring |
|---|---|
| First month | CBC weekly |
| Month 2-3 | CBC monthly |
| Ongoing | CBC monthly for duration of treatment |
Ok give me aise effects monitoring schedule in pdf format
ls -la /home/daytona/workspace/ 2>/dev/null || mkdir -p /home/daytona/workspace …
mkdir -p /home/daytona/workspace/endometrial-ca && python3 -c "from reportlab.li…
~/endometrial-ca/generate_monitoring_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.lib.colors import HexColor
import datetime
OUTPUT = "/home/daytona/workspace/endometrial-ca/AE_Monitoring_Schedule.pdf"
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=1.8*cm,
leftMargin=1.8*cm,
topMargin=2*cm,
bottomMargin=2*cm
)
# ── Colours ──────────────────────────────────────────────────────────────────
DARK_BLUE = HexColor("#1a3a5c")
MID_BLUE = HexColor("#2563a8")
LIGHT_BLUE = HexColor("#dbeafe")
TEAL = HexColor("#0f766e")
LIGHT_TEAL = HexColor("#ccfbf1")
ORANGE = HexColor("#c2410c")
LIGHT_ORG = HexColor("#ffedd5")
YELLOW_HDR = HexColor("#fef9c3")
GREY_HDR = HexColor("#f1f5f9")
WHITE = colors.white
RED_ALERT = HexColor("#dc2626")
GREEN_OK = HexColor("#16a34a")
styles = getSampleStyleSheet()
title_style = ParagraphStyle(
"Title", parent=styles["Normal"],
fontSize=18, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_CENTER, spaceAfter=4
)
subtitle_style = ParagraphStyle(
"Subtitle", parent=styles["Normal"],
fontSize=10, fontName="Helvetica",
textColor=HexColor("#bfdbfe"), alignment=TA_CENTER
)
section_style = ParagraphStyle(
"Section", parent=styles["Normal"],
fontSize=12, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_LEFT,
spaceBefore=6, spaceAfter=4,
leftIndent=6, leading=16
)
body_style = ParagraphStyle(
"Body", parent=styles["Normal"],
fontSize=8.5, fontName="Helvetica",
textColor=HexColor("#1e293b"),
leading=12, spaceAfter=2
)
bold_body = ParagraphStyle(
"BoldBody", parent=styles["Normal"],
fontSize=8.5, fontName="Helvetica-Bold",
textColor=HexColor("#1e293b"), leading=12
)
cell_style = ParagraphStyle(
"Cell", parent=styles["Normal"],
fontSize=8, fontName="Helvetica",
textColor=HexColor("#1e293b"), leading=11
)
cell_bold = ParagraphStyle(
"CellBold", parent=styles["Normal"],
fontSize=8, fontName="Helvetica-Bold",
textColor=HexColor("#1e293b"), leading=11
)
red_cell = ParagraphStyle(
"RedCell", parent=styles["Normal"],
fontSize=8, fontName="Helvetica-Bold",
textColor=RED_ALERT, leading=11
)
green_cell = ParagraphStyle(
"GreenCell", parent=styles["Normal"],
fontSize=8, fontName="Helvetica-Bold",
textColor=GREEN_OK, leading=11
)
alert_style = ParagraphStyle(
"Alert", parent=styles["Normal"],
fontSize=8, fontName="Helvetica-Bold",
textColor=ORANGE, leading=11
)
def section_header(text, bg=DARK_BLUE):
data = [[Paragraph(text, section_style)]]
tbl = Table(data, colWidths=[17.2*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("ROUNDEDCORNERS", [4,4,4,4]),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return tbl
def make_table(headers, rows, col_widths, header_bg=MID_BLUE, alt_bg=LIGHT_BLUE):
header_para_style = ParagraphStyle(
"TH", parent=styles["Normal"],
fontSize=8, fontName="Helvetica-Bold",
textColor=WHITE, leading=11, alignment=TA_CENTER
)
data = [[Paragraph(h, header_para_style) for h in headers]]
for row in rows:
data.append([Paragraph(str(c), cell_style) if not isinstance(c, Paragraph) else c for c in row])
tbl = Table(data, colWidths=col_widths, repeatRows=1)
style_cmds = [
("BACKGROUND", (0,0), (-1,0), header_bg),
("GRID", (0,0), (-1,-1), 0.4, HexColor("#cbd5e1")),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_HDR]),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
]
tbl.setStyle(TableStyle(style_cmds))
return tbl
# ── Build Story ───────────────────────────────────────────────────────────────
story = []
# ── TITLE BANNER ─────────────────────────────────────────────────────────────
title_data = [[
Paragraph("Adverse Effects & Monitoring Schedule", title_style),
Paragraph("Dostarlimab (IV) + Niraparib (Oral)<br/>Endometrial Carcinoma (dMMR) — Metastatic", subtitle_style)
]]
title_tbl = Table(title_data, colWidths=[17.2*cm])
title_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 12),
("LEFTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [6,6,6,6]),
]))
story.append(title_tbl)
story.append(Spacer(1, 0.3*cm))
date_str = datetime.date.today().strftime("%d %B %Y")
story.append(Paragraph(f"<i>Generated: {date_str} | For clinical reference only — individualise based on patient status</i>",
ParagraphStyle("Date", parent=styles["Normal"], fontSize=7.5, textColor=HexColor("#64748b"), alignment=TA_CENTER)))
story.append(Spacer(1, 0.4*cm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 1 — DOSING QUICK REFERENCE
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("1. Dosing Quick Reference"))
story.append(Spacer(1, 0.2*cm))
dosing_data = [
["Drug", "Dose", "Route", "Schedule", "Duration"],
[Paragraph("<b>Dostarlimab</b>\n(Jemperli)", cell_bold),
"500 mg (doses 1–4)\n1000 mg (dose 5+)",
"IV infusion\n30 min",
"Q3W × 4 doses\nthen Q6W",
"Until progression\nor 2 years"],
[Paragraph("<b>Niraparib</b>\n(Zejula)", cell_bold),
Paragraph("<b>200 mg/day</b> if <77 kg\nOR platelets <150k\n<b>300 mg/day</b> if ≥77 kg\nAND platelets ≥150k", cell_style),
"Oral capsules\n(100 mg each)",
"Once daily\n(bedtime preferred)",
"Maintenance until\nprogression"],
]
story.append(make_table(
["Drug", "Dose", "Route", "Schedule", "Duration"],
dosing_data[1:],
[3.2*cm, 4.2*cm, 3*cm, 3.3*cm, 3.5*cm],
header_bg=MID_BLUE
))
story.append(Spacer(1, 0.5*cm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 2 — MONITORING SCHEDULE
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("2. Monitoring Schedule by Timepoint"))
story.append(Spacer(1, 0.2*cm))
monitoring_rows = [
[Paragraph("<b>Baseline\n(Before Cycle 1)</b>", cell_bold),
"CBC + differential, CMP (LFTs, creatinine, electrolytes), blood glucose, HbA1c, TSH + Free T4, cortisol (if indicated), ECHO/MUGA (cardiac), BP, ECOG performance status, CT chest/abdomen/pelvis, urinalysis, serum β-hCG (if fertile age), weight"],
[Paragraph("<b>Week 1, 2, 3, 4\n(Every week,\nMonth 1)</b>", cell_bold),
Paragraph("<b>CBC with differential WEEKLY</b> — critical for niraparib haematologic toxicity\nBlood pressure weekly\nSymptom review (fatigue, nausea, bruising, bleeding)", cell_style)],
[Paragraph("<b>Each Dostarlimab\nCycle (Q3W or Q6W)</b>", cell_bold),
"CBC + differential, CMP (ALT/AST/bilirubin/creatinine), TSH, fasting glucose, BP\nSymptom screen for irAEs: cough/dyspnoea, diarrhoea, rash, joint pain, headache, visual changes\nECOG status"],
[Paragraph("<b>Monthly\n(Months 2–6)</b>", cell_bold),
"CBC monthly (niraparib), CMP monthly, TSH monthly for first 6 months\nBP monthly, weight monthly\nirAE symptom review"],
[Paragraph("<b>Every 8–12 Weeks\n(Imaging)</b>", cell_bold),
"CT chest/abdomen/pelvis (RECIST 1.1 assessment)\nNote: Do NOT stop treatment for apparent pseudoprogression if patient is clinically stable — repeat imaging in 4–6 weeks to confirm\nConsider PET-CT if ambiguous CT findings"],
[Paragraph("<b>Every 3 Months\n(Ongoing)</b>", cell_bold),
"CBC, CMP, TSH every 3 months after Month 6\nReview cumulative toxicity, dose modifications\nCardiac reassessment if symptoms develop\nAssess for secondary malignancy (long-term PARP inhibitor use: MDS/AML risk <1%)"],
[Paragraph("<b>End of Treatment /\nAs Needed</b>", cell_bold),
"Full panel + imaging at treatment discontinuation\nMonitor irAEs for ≥5 months after last dostarlimab dose (immune activation persists)\nLong-term thyroid function (hypothyroidism may be permanent)"],
]
story.append(make_table(
["Timepoint", "Tests / Actions Required"],
monitoring_rows,
[3.8*cm, 13.4*cm],
header_bg=TEAL
))
story.append(Spacer(1, 0.5*cm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 3 — NIRAPARIB irAEs & DOSE MODIFICATIONS
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("3. Niraparib — Haematologic Toxicity & Dose Modifications", bg=TEAL))
story.append(Spacer(1, 0.2*cm))
nira_heme_rows = [
[Paragraph("<b>Platelets</b>", cell_bold),
"< 100,000/μL",
Paragraph("<b>HOLD niraparib</b>\nRecheck CBC in 1 week", red_cell),
Paragraph("Resume at reduced dose (−100 mg/day) when ≥100,000/μL\nMax 2 dose reductions (300→200→100 mg)\nDiscontinue if unable to tolerate 100 mg", cell_style)],
[Paragraph("<b>Neutropenia</b>", cell_bold),
"ANC < 1000/μL (Grade 3–4)",
Paragraph("<b>HOLD niraparib</b>\nG-CSF if indicated", red_cell),
"Resume at reduced dose when ANC ≥1500/μL\nConsider G-CSF prophylaxis"],
[Paragraph("<b>Anaemia</b>", cell_bold),
"Hgb < 8 g/dL or symptomatic",
Paragraph("<b>HOLD niraparib</b>\nTransfuse if symptomatic", red_cell),
"Resume at reduced dose when Hgb ≥9 g/dL\nEPO agents may be considered"],
[Paragraph("<b>Any Grade 3–4\nHaematologic</b>", cell_bold),
"Persisting >28 days after hold",
Paragraph("<b>DISCONTINUE niraparib</b>", red_cell),
"Do not rechallenge; continue dostarlimab if tolerated"],
]
story.append(make_table(
["Parameter", "Trigger Value", "Immediate Action", "Dose Modification / Re-initiation"],
nira_heme_rows,
[2.8*cm, 3.2*cm, 4.2*cm, 7*cm],
header_bg=TEAL
))
story.append(Spacer(1, 0.5*cm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 4 — DOSTARLIMAB irAE MANAGEMENT
# ══════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_header("4. Dostarlimab — Immune-Related Adverse Events (irAEs)", bg=MID_BLUE),
Spacer(1, 0.2*cm),
]))
irae_rows = [
# [irAE, frequency, grade, action, steroid]
[Paragraph("<b>Hypothyroidism</b>", cell_bold),
"Most common\n~6.9%",
Paragraph("Grade 1–2", cell_style),
"Continue dostarlimab\nStart levothyroxine",
"No steroids needed"],
[Paragraph("<b>Hyperthyroidism /\nThyroiditis</b>", cell_bold),
"Less common",
Paragraph("Grade 1–2", cell_style),
"Continue; beta-blocker for symptoms\nMay evolve to hypothyroidism",
"Steroids if severe"],
[Paragraph("<b>Pneumonitis</b>", cell_bold),
"Uncommon but serious",
Paragraph("Grade 1: Monitor\nGrade 2: <b>HOLD</b>\nGrade 3–4: <b>STOP</b>", cell_style),
"CT chest immediately\nGrade 2: prednisolone 1–2 mg/kg/day\nGrade 3–4: IV methylprednisolone 1–2 mg/kg/day",
"Grade 2+: steroids mandatory"],
[Paragraph("<b>Hepatitis\n(↑ALT/AST)</b>", cell_bold),
"~5.8%",
Paragraph("Grade 1: Monitor\nGrade 2: <b>HOLD</b>\nGrade 3–4: <b>STOP</b>", cell_style),
"Grade 2: prednisolone 0.5–1 mg/kg\nGrade 3–4: IV methylprednisolone 1–2 mg/kg\nAdd mycophenolate if no improvement in 3 days",
"Grade 2+: steroids"],
[Paragraph("<b>Colitis /\nDiarrhoea</b>", cell_bold),
"Uncommon",
Paragraph("Grade 1: Loperamide\nGrade 2: <b>HOLD</b>\nGrade 3–4: <b>STOP</b>", cell_style),
"Rule out infection (C. diff, CMV)\nGrade 2+: prednisolone 1–2 mg/kg\nGrade 3–4: infliximab if steroid-refractory",
"Grade 2+: steroids"],
[Paragraph("<b>Immune-Mediated\nDiabetes</b>", cell_bold),
"Rare",
Paragraph("Check glucose\nevery cycle", cell_style),
"Insulin therapy (often type 1 DM pattern)\nContinue dostarlimab with insulin management",
"No steroids"],
[Paragraph("<b>Adrenal\nInsufficiency</b>", cell_bold),
"Rare",
Paragraph("Check morning\ncortisol if fatigued", cell_style),
"Hydrocortisone replacement\nContinue dostarlimab with hormone replacement",
"Physiologic steroids only"],
[Paragraph("<b>Arthralgia /\nArthritis</b>", cell_bold),
"~4.7%",
Paragraph("Grade 1–2: NSAIDs\nGrade 3: <b>HOLD</b>", cell_style),
"Grade 2+: prednisolone 0.5–1 mg/kg\nRheumatology consult for Grade 3+",
"Grade 2+: steroids"],
[Paragraph("<b>Rash /\nDermatitis</b>", cell_bold),
">20% any grade",
Paragraph("Grade 1–2: Topical\nGrade 3: <b>HOLD</b>", cell_style),
"Topical steroids/emollients for Grade 1–2\nSystemic steroids Grade 3+\nDermatology if SJS/TEN suspected",
"Grade 3+: steroids"],
]
story.append(make_table(
["irAE", "Frequency", "Grading / Trigger", "Management", "Steroids"],
irae_rows,
[2.6*cm, 2.2*cm, 3.2*cm, 5.8*cm, 3.4*cm],
header_bg=MID_BLUE
))
story.append(Spacer(1, 0.5*cm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 5 — STEROID TAPERING PROTOCOL
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("5. Steroid Taper Protocol for Grade 2+ irAEs", bg=HexColor("#7c3aed")))
story.append(Spacer(1, 0.2*cm))
taper_rows = [
["Step 1", "Start prednisolone 1–2 mg/kg/day orally (or IV methylprednisolone for Grade 3–4)"],
["Step 2", "Maintain until improvement to Grade 1 or below (usually 1–2 weeks)"],
["Step 3", "Taper by 10 mg/week (or 10% total dose/week) over ≥4–6 weeks minimum"],
["Step 4", "Do NOT restart dostarlimab until ≤10 mg/day prednisolone equivalent"],
["Step 5", "Prophylactic PCP cover (co-trimoxazole) if >20 mg/day prednisolone for >4 weeks"],
["Caution", "Rapid tapering (< 4 weeks) associated with irAE flare — taper slowly"],
]
taper_tbl = Table(taper_rows, colWidths=[2.5*cm, 14.7*cm])
taper_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), HexColor("#ede9fe")),
("BACKGROUND", (1,0), (1,-1), WHITE),
("ROWBACKGROUNDS", (1,0), (1,-1), [WHITE, GREY_HDR]),
("GRID", (0,0), (-1,-1), 0.4, HexColor("#cbd5e1")),
("FONTNAME", (0,0), (0,-1), "Helvetica-Bold"),
("FONTNAME", (1,0), (1,-1), "Helvetica"),
("FONTSIZE", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("TEXTCOLOR", (0,5), (0,5), ORANGE),
]))
story.append(taper_tbl)
story.append(Spacer(1, 0.5*cm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 6 — RED FLAG SYMPTOMS (PATIENT ALERT CARD)
# ══════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_header("6. Red Flag Symptoms — Seek Immediate Medical Attention", bg=HexColor("#b91c1c")),
Spacer(1, 0.2*cm),
]))
red_flags = [
["🔴 Breathing difficulty or new dry cough", "→ Possible immune pneumonitis — URGENT CT chest"],
["🔴 Severe diarrhoea (>4 stools/day) or bloody stool", "→ Possible immune colitis — HOLD drug, steroids"],
["🔴 Yellow skin / eyes or dark urine", "→ Possible immune hepatitis — URGENT LFTs"],
["🔴 Severe headache, visual changes, confusion", "→ Possible hypophysitis or meningitis — URGENT MRI"],
["🔴 Unexplained bruising, bleeding, or petechiae", "→ Possible thrombocytopenia — URGENT CBC"],
["🔴 Extreme fatigue, dizziness, fainting", "→ Possible adrenal insufficiency — URGENT cortisol"],
["🔴 Chest pain or irregular heartbeat", "→ Possible immune myocarditis — URGENT ECG + troponin"],
["🔴 Fever > 38.5°C with low neutrophils", "→ Febrile neutropenia — URGENT FBC + blood cultures"],
]
rf_tbl = Table(red_flags, colWidths=[8.2*cm, 9*cm])
rf_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), HexColor("#fff1f2")),
("GRID", (0,0), (-1,-1), 0.4, HexColor("#fca5a5")),
("FONTNAME", (0,0), (0,-1), "Helvetica-Bold"),
("FONTNAME", (1,0), (1,-1), "Helvetica"),
("FONTSIZE", (0,0), (-1,-1), 8),
("TEXTCOLOR", (0,0), (0,-1), HexColor("#b91c1c")),
("TEXTCOLOR", (1,0), (1,-1), HexColor("#1e293b")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(rf_tbl)
story.append(Spacer(1, 0.5*cm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 7 — NIRAPARIB NON-HAEM AEs
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("7. Niraparib — Non-Haematologic Adverse Effects", bg=TEAL))
story.append(Spacer(1, 0.2*cm))
nira_non_heme = [
["Nausea / Vomiting", "40–50%", "Take at bedtime; antiemetics (ondansetron, metoclopramide); usually improves after 1st month"],
["Fatigue", "~30%", "Supportive; exclude anaemia as cause; dose reduce if Grade 3"],
["Hypertension", "~20%", "Monitor BP weekly (Month 1), then each cycle; antihypertensives if BP >140/90 persistently"],
["Headache / Dizziness", "~15–20%", "Usually mild; analgesics; rule out CNS metastasis if new or severe"],
["Constipation", "~15%", "Fibre, hydration, laxatives"],
["Abdominal pain / Mucositis", "~10–15%", "Symptomatic; dose reduce if Grade 3"],
["MDS / AML", "<1% (long-term)", "Annual CBC; report unexplained cytopenias; bone marrow biopsy if suspected"],
["Secondary Primary Malignancy", "Rare", "Long-term surveillance; no cases of MDS/AML reported in RUBY Part 2"],
]
story.append(make_table(
["Side Effect", "Frequency", "Management"],
nira_non_heme,
[4.2*cm, 2.5*cm, 10.5*cm],
header_bg=TEAL
))
story.append(Spacer(1, 0.5*cm))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 8 — SUMMARY SCHEDULE AT A GLANCE
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("8. At-a-Glance Summary Monitoring Calendar"))
story.append(Spacer(1, 0.2*cm))
summary_rows = [
[Paragraph("<b>Test</b>", cell_bold),
Paragraph("<b>Wk 1–4\n(Weekly)</b>", cell_bold),
Paragraph("<b>Each\nCycle</b>", cell_bold),
Paragraph("<b>Monthly\n(Mo 2–6)</b>", cell_bold),
Paragraph("<b>Every\n3 Mo</b>", cell_bold),
Paragraph("<b>Every\n8–12 Wk</b>", cell_bold)],
["CBC + Differential",
Paragraph("✅ Weekly", green_cell),
Paragraph("✅", green_cell), Paragraph("✅", green_cell), Paragraph("✅", green_cell), "—"],
["LFTs (ALT/AST/Bili)", "—",
Paragraph("✅", green_cell), Paragraph("✅", green_cell), Paragraph("✅", green_cell), "—"],
["Renal Function (Cr, eGFR)", "—",
Paragraph("✅", green_cell), Paragraph("✅", green_cell), Paragraph("✅", green_cell), "—"],
["TSH + Free T4", "—",
Paragraph("✅", green_cell), Paragraph("✅ (Mo 1–6)", green_cell), Paragraph("✅", green_cell), "—"],
["Fasting Blood Glucose", "—",
Paragraph("✅", green_cell), "—", Paragraph("✅", green_cell), "—"],
["Blood Pressure", Paragraph("✅ Weekly", green_cell),
Paragraph("✅", green_cell), Paragraph("✅", green_cell), "—", "—"],
["irAE Symptom Review", Paragraph("✅", green_cell),
Paragraph("✅", green_cell), Paragraph("✅", green_cell), Paragraph("✅", green_cell), "—"],
["CT Chest/Abdomen/Pelvis", "—", "—", "—", "—",
Paragraph("✅ RECIST", green_cell)],
["ECHO / Cardiac (if symptoms)", "—", "As needed", "—", "As needed", "—"],
]
summary_tbl = Table(summary_rows, colWidths=[4.5*cm, 2.5*cm, 2.2*cm, 2.8*cm, 2.2*cm, 3*cm])
summary_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("GRID", (0,0), (-1,-1), 0.4, HexColor("#cbd5e1")),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_HDR]),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8),
("ALIGN", (1,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(summary_tbl)
story.append(Spacer(1, 0.5*cm))
# ── FOOTER NOTE ───────────────────────────────────────────────────────────────
footer_data = [[Paragraph(
"<b>References:</b> GARNET trial (André T et al., JAMA Netw Open 2023); RUBY trial Parts 1 & 2 "
"(Mirza MR et al., NEJM 2023; Ann Oncol 2024); DORA real-world study (Gallego A et al., Int J Gynecol Cancer 2025); "
"Niraparib prescribing information (GSK/Zejula); Xi Y et al. dMMR/MSS discordance, Hum Pathol 2026. "
"This document is for clinical reference. Individual patient decisions should be guided by the treating oncologist.",
ParagraphStyle("Footer", parent=styles["Normal"], fontSize=6.5, textColor=HexColor("#64748b"), leading=10)
)]]
footer_tbl = Table(footer_data, colWidths=[17.2*cm])
footer_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREY_HDR),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
story.append(footer_tbl)
# ── BUILD ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF saved to: {OUTPUT}")
Failed to create session: unauthorized: authentication failed: Bearer token is invalid
We encountered an error while processing your request. Please try again or reach out to us for help.