Is it normal
python3 -c " import pdfplumber with pdfplumber.open('/home/daytona/workspace/attachments/a0f79364-d0c8-4a25-a03b-5d7c19184704/Whatsapp Scan 8 July 2026 at 17.26.09.pdf') as pdf: print(f'Pages: {len(pdf.pages)}') for i, page in enumerate(pdf.pages): text = page.extract_text() print(f'--- Page {i+1} ---') print(text) "
python3 -c " from pypdf import PdfReader import base64 reader = PdfReader('/home/daytona/workspace/attachments/a0f79364-d0c8-4a25-a03b-5d7c19184704/Whatsapp Scan 8 July 2026 at 17.26.09.pdf') print(f'Pages: {len(reader.pages)}') # Convert pages to images import subprocess result = subprocess.run(['pdftoppm', '-r', '150', '-png', '/home/daytona/workspace/attachments/a0f79364-d0c8-4a25-a03b-5d7c19184704/Whatsapp Scan 8 July 2026 at 17.26.09.pdf', '/home/daytona/workspace/attachments/scan_page'], capture_output=True, text=True) print('stdout:', result.stdout) print('stderr:', result.stderr) print('returncode:', result.returncode) import os files = os.listdir('/home/daytona/workspace/attachments/') print('Files:', files) "
cd /home/daytona/workspace/attachments && python3 -c " import base64 with open('scan_page-1.png', 'rb') as f: data = base64.b64encode(f.read()).decode() print(f'Page 1 size: {len(data)} chars') with open('scan_page-2.png', 'rb') as f: data = base64.b64encode(f.read()).decode() print(f'Page 2 size: {len(data)} chars') "
cd /home/daytona/workspace/attachments && python3 -c " # Serve the image via a simple HTTP approach - copy to a web-accessible location import shutil shutil.copy('scan_page-1.png', '/home/daytona/workspace/scan_page-1.png') shutil.copy('scan_page-2.png', '/home/daytona/workspace/scan_page-2.png') print('Copied') "
python3 -c " import pytesseract from PIL import Image img = Image.open('/home/daytona/workspace/attachments/scan_page-1.png') text = pytesseract.image_to_string(img) print(text) " 2>&1 | head -200
What are the typical treatment options for pancreatic cancer?
"pancreatic ductal adenocarcinoma"[MeSH Terms] AND "treatment"[MeSH Terms]
"pancreatic cancer"[MeSH Terms] AND "chemotherapy"[MeSH Terms]
| Category | Definition | Proportion of Patients |
|---|---|---|
| Resectable | No major vessel involvement; can be surgically removed | ~15-20% |
| Borderline Resectable | Tumor contacts (but doesn't surround) major vessels | ~15-20% |
| Locally Advanced | Tumor wraps around major vessels (>180° of SMA, celiac artery, or aorta); no distant spread | ~30-35% |
| Metastatic | Spread to liver, lungs, peritoneum | ~50-55% |
| Mutation/Marker | Drug | Notes |
|---|---|---|
| BRCA1/2 mutation | Olaparib (PARP inhibitor) | Maintenance therapy after platinum-based chemo |
| NTRK gene fusion | Larotrectinib or Entrectinib | Rare, ~1% of PDAC |
| MSI-High / dMMR | Pembrolizumab (immunotherapy) | Rare in PDAC (~1-2%), but responds well |
| KRAS G12C | Sotorasib / Adagrasib | Emerging trials |
Sources: Current Surgical Therapy 14e; Yamada's Textbook of Gastroenterology 7e; Sabiston Textbook of Surgery; Fischer's Mastery of Surgery 8e
Create a summary guide of pancreatic cancer treatment options
What format would you like the summary guide in? · Who is the intended audience?
mkdir -p /home/daytona/workspace/pancreatic-cancer-guide && ls /home/daytona/workspace/pancreatic-cancer-guide/
~/pancreatic-cancer-guide/generate_guide.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_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import BaseDocTemplate, PageTemplate, Frame
from reportlab.pdfgen import canvas
OUTPUT = "/home/daytona/workspace/pancreatic-cancer-guide/Pancreatic_Cancer_Treatment_Guide.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
TEAL = colors.HexColor("#006D77")
TEAL_LIGHT = colors.HexColor("#E8F5F5")
ORANGE = colors.HexColor("#E29148")
ORANGE_LIGHT= colors.HexColor("#FDF3E7")
GREY_DARK = colors.HexColor("#2D3142")
GREY_MID = colors.HexColor("#4F5D75")
GREY_LIGHT = colors.HexColor("#F4F6F8")
GREY_RULE = colors.HexColor("#D0D9E0")
WHITE = colors.white
GREEN = colors.HexColor("#2A9D8F")
GREEN_LIGHT = colors.HexColor("#E6F5F3")
PURPLE = colors.HexColor("#6C4C9E")
PURPLE_LIGHT= colors.HexColor("#F2EDF9")
RED_SOFT = colors.HexColor("#C0392B")
PAGE_W, PAGE_H = A4
MARGIN = 18 * mm
# ── Header / Footer canvas callback ─────────────────────────────────────────
def on_page(c: canvas.Canvas, doc):
c.saveState()
# header bar
c.setFillColor(TEAL)
c.rect(0, PAGE_H - 14*mm, PAGE_W, 14*mm, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 9)
c.drawString(MARGIN, PAGE_H - 9*mm, "PANCREATIC CANCER | TREATMENT GUIDE FOR PATIENTS & FAMILIES")
# footer
c.setFillColor(GREY_MID)
c.setFont("Helvetica", 7.5)
c.drawString(MARGIN, 8*mm, "This guide is for informational purposes only. Always follow your doctor's advice.")
c.drawRightString(PAGE_W - MARGIN, 8*mm, f"Page {doc.page}")
c.restoreState()
# ── Document setup ───────────────────────────────────────────────────────────
doc = BaseDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=20*mm, bottomMargin=18*mm,
)
frame = Frame(MARGIN, 18*mm, PAGE_W - 2*MARGIN, PAGE_H - 38*mm, id="main")
template = PageTemplate(id="main", frames=[frame], onPage=on_page)
doc.addPageTemplates([template])
# ── Styles ───────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def S(name, parent="Normal", **kw):
s = ParagraphStyle(name, parent=base[parent], **kw)
return s
style_title = S("Title2", fontName="Helvetica-Bold", fontSize=22, textColor=TEAL,
leading=28, spaceAfter=4)
style_subtitle = S("Sub", fontName="Helvetica", fontSize=11, textColor=GREY_MID,
leading=15, spaceAfter=12)
style_section = S("Section", fontName="Helvetica-Bold", fontSize=13, textColor=WHITE,
leading=17, spaceBefore=14, spaceAfter=4)
style_body = S("Body2", fontName="Helvetica", fontSize=9.5, textColor=GREY_DARK,
leading=14, spaceAfter=5, alignment=TA_JUSTIFY)
style_body_small = S("BodySm", fontName="Helvetica", fontSize=8.5, textColor=GREY_DARK,
leading=13, spaceAfter=4, alignment=TA_JUSTIFY)
style_bullet = S("Bullet2", fontName="Helvetica", fontSize=9.5, textColor=GREY_DARK,
leading=14, spaceAfter=3, leftIndent=10, firstLineIndent=-10)
style_label = S("Label", fontName="Helvetica-Bold", fontSize=9, textColor=TEAL, leading=13)
style_note = S("Note", fontName="Helvetica-Oblique", fontSize=8, textColor=GREY_MID,
leading=12, spaceAfter=6)
style_callout_title = S("CTitle", fontName="Helvetica-Bold", fontSize=10, textColor=TEAL,
leading=14, spaceAfter=2)
style_callout_body = S("CBody", fontName="Helvetica", fontSize=9, textColor=GREY_DARK,
leading=13, spaceAfter=3)
style_orange_title = S("OTitle", fontName="Helvetica-Bold", fontSize=10, textColor=ORANGE,
leading=14, spaceAfter=2)
style_toc_item = S("TOC", fontName="Helvetica", fontSize=9.5, textColor=TEAL,
leading=15, spaceAfter=1)
# ── Helpers ──────────────────────────────────────────────────────────────────
def section_header(text, color=TEAL):
"""Coloured section header bar."""
data = [[Paragraph(text, style_section)]]
t = Table(data, colWidths=[PAGE_W - 2*MARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), color),
("LEFTPADDING", (0, 0), (-1, -1), 8),
("RIGHTPADDING", (0, 0), (-1, -1), 8),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING",(0, 0), (-1, -1), 5),
("ROUNDEDCORNERS", [4]),
]))
return t
def info_box(title, body_paras, bg=TEAL_LIGHT, title_color=TEAL):
"""Rounded info box."""
content = [Paragraph(title, S("IBT", fontName="Helvetica-Bold", fontSize=10,
textColor=title_color, leading=14))]
for p in body_paras:
content.append(Paragraph(p, style_callout_body))
data = [[content]]
t = Table(data, colWidths=[PAGE_W - 2*MARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), bg),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("RIGHTPADDING", (0, 0), (-1, -1), 10),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING",(0, 0), (-1, -1), 8),
("BOX", (0, 0), (-1, -1), 0.5, title_color),
]))
return t
def two_col(left_items, right_items, left_bg=TEAL_LIGHT, right_bg=ORANGE_LIGHT,
left_title="", right_title="", col_w=None):
if col_w is None:
col_w = (PAGE_W - 2*MARGIN - 4*mm) / 2
def make_cell(title, items, title_color):
parts = []
if title:
parts.append(Paragraph(title, S("CT2", fontName="Helvetica-Bold", fontSize=9.5,
textColor=title_color, leading=13, spaceAfter=3)))
for item in items:
parts.append(Paragraph(f"<bullet>\u2022</bullet> {item}", style_bullet))
return parts
data = [[make_cell(left_title, left_items, TEAL),
make_cell(right_title, right_items, ORANGE)]]
t = Table(data, colWidths=[col_w, col_w])
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (0, -1), left_bg),
("BACKGROUND", (1, 0), (1, -1), right_bg),
("LEFTPADDING", (0, 0), (-1, -1), 8),
("RIGHTPADDING", (0, 0), (-1, -1), 8),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING",(0, 0), (-1, -1), 8),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("BOX", (0, 0), (0, -1), 0.4, TEAL),
("BOX", (1, 0), (1, -1), 0.4, ORANGE),
("LINEAFTER", (0, 0), (0, -1), 1.5, WHITE),
]))
return t
def bullet(text, color=TEAL):
return Paragraph(f'<font color="{color.hexval()}">●</font> {text}', style_bullet)
# ═══════════════════════════════════════════════════════════════════════════
# BUILD CONTENT
# ═══════════════════════════════════════════════════════════════════════════
story = []
# ── COVER block ─────────────────────────────────────────────────────────────
story.append(Spacer(1, 6*mm))
story.append(Paragraph("Understanding Your Diagnosis", style_subtitle))
story.append(Paragraph("Pancreatic Cancer", style_title))
story.append(Paragraph("A Guide to Treatment Options for Patients & Families",
S("ST2", fontName="Helvetica", fontSize=12, textColor=GREY_MID,
leading=16, spaceAfter=6)))
story.append(HRFlowable(width="100%", thickness=2, color=TEAL, spaceAfter=10))
story.append(Paragraph(
"This guide explains, in plain language, the treatment options available for pancreatic "
"cancer. Every patient's situation is different - this guide is meant to help you ask the "
"right questions and understand what your doctors are discussing with you.",
S("Intro", fontName="Helvetica", fontSize=10, textColor=GREY_DARK, leading=15,
spaceAfter=6, alignment=TA_JUSTIFY)))
story.append(Spacer(1, 4*mm))
# ── Quick facts strip ────────────────────────────────────────────────────────
facts_data = [
[Paragraph("<b>Most common type</b>", style_body_small),
Paragraph("<b>Only cure</b>", style_body_small),
Paragraph("<b>Key first step</b>", style_body_small)],
[Paragraph("Ductal Adenocarcinoma\n(~90% of cases)", style_body_small),
Paragraph("Surgery, when\nthe tumour can be removed", style_body_small),
Paragraph("Staging scan (CT/MRI)\nto plan treatment", style_body_small)],
]
facts_w = (PAGE_W - 2*MARGIN) / 3
facts_t = Table(facts_data, colWidths=[facts_w]*3)
facts_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), TEAL),
("BACKGROUND", (0, 1), (-1, 1), TEAL_LIGHT),
("TEXTCOLOR", (0, 0), (-1, 0), WHITE),
("TEXTCOLOR", (0, 1), (-1, 1), GREY_DARK),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 9),
("ALIGN", (0, 0), (-1, -1), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("TOPPADDING", (0, 0), (-1, -1), 6),
("BOTTOMPADDING",(0, 0), (-1, -1), 6),
("GRID", (0, 0), (-1, -1), 0.4, WHITE),
]))
story.append(facts_t)
story.append(Spacer(1, 8*mm))
# ─────────────────────────────────────────────────────────────────────────────
# SECTION 1 – WHAT IS PANCREATIC CANCER?
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_header("1. What is Pancreatic Cancer?"))
story.append(Spacer(1, 3*mm))
story.append(Paragraph(
"The pancreas is a gland behind the stomach that makes digestive juices and hormones "
"(including insulin). Cancer starts when abnormal cells grow out of control inside it. "
"The most common type - <b>ductal adenocarcinoma (PDAC)</b> - grows from the cells that "
"line the small tubes (ducts) inside the pancreas.",
style_body))
story.append(Paragraph(
"The pancreas has three parts: the <b>head</b> (right side), <b>body</b> (middle), and "
"<b>tail</b> (left side near the spleen). Where the tumour sits affects which operation "
"is possible.",
style_body))
story.append(Spacer(1, 4*mm))
# ─────────────────────────────────────────────────────────────────────────────
# SECTION 2 – STAGING
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_header("2. How is the Cancer Staged?", color=GREEN))
story.append(Spacer(1, 3*mm))
story.append(Paragraph(
"Staging means finding out how far the cancer has spread. This is the single most "
"important step because it determines every treatment decision. A <b>CT scan</b> of the "
"chest, abdomen and pelvis (with contrast dye) is the standard staging test.",
style_body))
story.append(Spacer(1, 3*mm))
stage_data = [
[Paragraph("<b>Stage</b>", style_body_small),
Paragraph("<b>What it means</b>", style_body_small),
Paragraph("<b>Proportion</b>", style_body_small)],
[Paragraph("Resectable", S("G", fontName="Helvetica-Bold", fontSize=9, textColor=GREEN, leading=13)),
Paragraph("Tumour has not grown into major blood vessels. Surgery is possible.", style_body_small),
Paragraph("~15-20%", style_body_small)],
[Paragraph("Borderline\nResectable", S("O", fontName="Helvetica-Bold", fontSize=9, textColor=ORANGE, leading=13)),
Paragraph("Tumour touches (but does not fully surround) major vessels. "
"Chemotherapy first, then surgery may become possible.", style_body_small),
Paragraph("~15-20%", style_body_small)],
[Paragraph("Locally\nAdvanced", S("R", fontName="Helvetica-Bold", fontSize=9, textColor=RED_SOFT, leading=13)),
Paragraph("Tumour wraps around major vessels but has NOT spread to other organs. "
"Surgery is usually not possible straight away.", style_body_small),
Paragraph("~30-35%", style_body_small)],
[Paragraph("Metastatic", S("Rd", fontName="Helvetica-Bold", fontSize=9, textColor=RED_SOFT, leading=13)),
Paragraph("Cancer has spread to the liver, lungs, or lining of the abdomen.", style_body_small),
Paragraph("~50-55%", style_body_small)],
]
col_ws = [32*mm, PAGE_W - 2*MARGIN - 32*mm - 20*mm, 20*mm]
stage_t = Table(stage_data, colWidths=col_ws)
stage_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), TEAL),
("TEXTCOLOR", (0, 0), (-1, 0), WHITE),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 9),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [WHITE, GREY_LIGHT]),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING",(0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 7),
("RIGHTPADDING",(0, 0), (-1, -1), 7),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("GRID", (0, 0), (-1, -1), 0.3, GREY_RULE),
("BOX", (0, 0), (-1, -1), 0.5, TEAL),
]))
story.append(stage_t)
story.append(Spacer(1, 8*mm))
# ─────────────────────────────────────────────────────────────────────────────
# SECTION 3 – SURGERY
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_header("3. Surgery - The Only Potential Cure"))
story.append(Spacer(1, 3*mm))
story.append(info_box(
"Why Surgery Matters",
["Surgery is the only treatment that can permanently remove the cancer and offer a chance "
"of cure. For patients whose tumour is fully removed, 5-year survival is 20-60% depending "
"on whether it was caught early. Without surgery it is less than 10%."],
bg=TEAL_LIGHT, title_color=TEAL))
story.append(Spacer(1, 4*mm))
ops_data = [
[Paragraph("<b>Operation</b>", style_body_small),
Paragraph("<b>Used for</b>", style_body_small),
Paragraph("<b>What is removed</b>", style_body_small)],
[Paragraph("Distal\nPancreatectomy", S("Op", fontName="Helvetica-Bold", fontSize=9, textColor=TEAL, leading=13)),
Paragraph("Body or tail of pancreas", style_body_small),
Paragraph("Tail (and usually body) of pancreas + spleen", style_body_small)],
[Paragraph("Whipple\nProcedure\n(Pancreaticoduodenectomy)", S("Op", fontName="Helvetica-Bold", fontSize=9, textColor=TEAL, leading=13)),
Paragraph("Head of pancreas", style_body_small),
Paragraph("Pancreatic head, duodenum (first part of small bowel), part of bile duct, "
"sometimes part of stomach", style_body_small)],
[Paragraph("Total\nPancreatectomy", S("Op", fontName="Helvetica-Bold", fontSize=9, textColor=TEAL, leading=13)),
Paragraph("Tumour involving entire pancreas", style_body_small),
Paragraph("Entire pancreas + spleen + duodenum. Patient will need insulin injections "
"for life.", style_body_small)],
]
ops_t = Table(ops_data, colWidths=[35*mm, 35*mm, PAGE_W - 2*MARGIN - 70*mm])
ops_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), TEAL),
("TEXTCOLOR", (0, 0), (-1, 0), WHITE),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 9),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [WHITE, GREY_LIGHT]),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING",(0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 7),
("RIGHTPADDING",(0, 0), (-1, -1), 7),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("GRID", (0, 0), (-1, -1), 0.3, GREY_RULE),
("BOX", (0, 0), (-1, -1), 0.5, TEAL),
]))
story.append(ops_t)
story.append(Spacer(1, 3*mm))
story.append(Paragraph(
"<b>Neoadjuvant therapy</b> (chemotherapy given <i>before</i> surgery) is now often "
"recommended first - it shrinks the tumour, treats any microscopic spread early, and "
"helps doctors confirm the cancer is responding before a major operation.",
style_body))
story.append(Spacer(1, 8*mm))
# ─────────────────────────────────────────────────────────────────────────────
# SECTION 4 – CHEMOTHERAPY
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_header("4. Chemotherapy", color=PURPLE))
story.append(Spacer(1, 3*mm))
story.append(Paragraph(
"Chemotherapy uses medicines to kill cancer cells or stop them dividing. It is used "
"before surgery (neoadjuvant), after surgery (adjuvant), or as the main treatment when "
"surgery is not possible.",
style_body))
story.append(Spacer(1, 4*mm))
# Chemo regimens table
chemo_data = [
[Paragraph("<b>Regimen</b>", style_body_small),
Paragraph("<b>Drugs included</b>", style_body_small),
Paragraph("<b>When used</b>", style_body_small),
Paragraph("<b>Key fact</b>", style_body_small)],
[Paragraph("FOLFIRINOX\n(or mFOLFIRINOX)", S("CR", fontName="Helvetica-Bold", fontSize=9, textColor=PURPLE, leading=13)),
Paragraph("5-FU, Leucovorin,\nIrinotecan, Oxaliplatin", style_body_small),
Paragraph("Fit patients\n(good health,\nECOG 0-1)", style_body_small),
Paragraph("Most active regimen. Median survival 11 months in advanced disease; "
"up to 54 months after surgery (PRODIGE-24 trial).", style_body_small)],
[Paragraph("Gemcitabine +\nnab-Paclitaxel\n(Abraxane)", S("CR", fontName="Helvetica-Bold", fontSize=9, textColor=PURPLE, leading=13)),
Paragraph("Gemcitabine\n+ nab-Paclitaxel", style_body_small),
Paragraph("Fit patients;\nalternative to\nFOLFIRINOX", style_body_small),
Paragraph("Easier to tolerate than FOLFIRINOX. Good option for older patients or "
"those with certain health conditions.", style_body_small)],
[Paragraph("Gemcitabine\nalone", S("CR", fontName="Helvetica-Bold", fontSize=9, textColor=PURPLE, leading=13)),
Paragraph("Gemcitabine", style_body_small),
Paragraph("Patients with\nweaker health\n(ECOG 2+)", style_body_small),
Paragraph("First chemotherapy drug approved specifically for pancreatic cancer. "
"Less side effects but also less potent.", style_body_small)],
[Paragraph("2nd-line:\nnal-IRI +\n5-FU/Leucovorin", S("CR", fontName="Helvetica-Bold", fontSize=9, textColor=PURPLE, leading=13)),
Paragraph("Nanoliposomal\nIrinotecan + 5-FU", style_body_small),
Paragraph("After\ngemcitabine\nhas stopped working", style_body_small),
Paragraph("FDA-approved second-line option (NAPOLI trial). Improves survival vs "
"5-FU alone when gemcitabine fails.", style_body_small)],
]
chemo_t = Table(chemo_data, colWidths=[30*mm, 30*mm, 28*mm, PAGE_W - 2*MARGIN - 88*mm])
chemo_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), PURPLE),
("TEXTCOLOR", (0, 0), (-1, 0), WHITE),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 8.5),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [WHITE, PURPLE_LIGHT]),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING",(0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("RIGHTPADDING",(0, 0), (-1, -1), 6),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("GRID", (0, 0), (-1, -1), 0.3, GREY_RULE),
("BOX", (0, 0), (-1, -1), 0.5, PURPLE),
]))
story.append(chemo_t)
story.append(Spacer(1, 3*mm))
story.append(Paragraph(
"<b>Common side effects of chemotherapy:</b> Tiredness, nausea, hair thinning, low "
"blood counts (risk of infection), tingling in hands/feet (neuropathy). Your team will "
"give you medicines to manage these.",
style_note))
story.append(Spacer(1, 6*mm))
# ─────────────────────────────────────────────────────────────────────────────
# SECTION 5 – RADIATION
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_header("5. Radiation Therapy", color=ORANGE))
story.append(Spacer(1, 3*mm))
story.append(Paragraph(
"Radiation uses high-energy X-rays to destroy cancer cells. It is <b>not used alone</b> "
"in pancreatic cancer (local failure rates exceed 70% with radiation alone). It is always "
"combined with chemotherapy - called <b>chemoradiation (CRT)</b>.",
style_body))
story.append(Spacer(1, 3*mm))
story.append(two_col(
left_items=[
"Combined with chemotherapy (chemoradiation)",
"Locally advanced cancer that cannot be surgically removed",
"Sometimes used before surgery to shrink borderline-resectable tumours",
"Can reduce local recurrence after surgery in some cases",
],
right_items=[
"<b>SBRT</b> (Stereotactic Body Radiation Therapy) - newer, very precise, fewer sessions",
"<b>IMRT</b> (Intensity Modulated RT) - standard external beam, shaped to tumour",
"<b>Proton therapy</b> - available at specialist centres; spares surrounding tissue",
],
left_title="When radiation is used",
right_title="Types of radiation",
))
story.append(Spacer(1, 8*mm))
# ─────────────────────────────────────────────────────────────────────────────
# SECTION 6 – TARGETED & IMMUNOTHERAPY
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_header("6. Targeted Therapy & Immunotherapy"))
story.append(Spacer(1, 3*mm))
story.append(Paragraph(
"Unlike chemotherapy (which affects all fast-dividing cells), targeted therapies attack "
"specific features of the cancer cell. These only work if the tumour has the specific "
"genetic change - which is why <b>molecular testing of the biopsy</b> is now recommended "
"for all patients with locally advanced or metastatic disease.",
style_body))
story.append(Spacer(1, 4*mm))
target_data = [
[Paragraph("<b>Genetic change</b>", style_body_small),
Paragraph("<b>How common</b>", style_body_small),
Paragraph("<b>Drug(s) available</b>", style_body_small),
Paragraph("<b>Plain explanation</b>", style_body_small)],
[Paragraph("BRCA1 or BRCA2\nmutation", style_body_small),
Paragraph("~5-7%\nof PDAC", style_body_small),
Paragraph("Olaparib\n(PARP inhibitor)", style_body_small),
Paragraph("Inherited gene change (can run in families). Olaparib is a maintenance "
"pill taken after platinum-based chemotherapy responds.", style_body_small)],
[Paragraph("MSI-High /\ndMMR", style_body_small),
Paragraph("~1-2%\nof PDAC", style_body_small),
Paragraph("Pembrolizumab\n(immunotherapy)", style_body_small),
Paragraph("The tumour has a faulty DNA repair system. Immunotherapy (which "
"boosts the body's own defences) works very well in these cases.", style_body_small)],
[Paragraph("NTRK gene\nfusion", style_body_small),
Paragraph("Very rare\n(~1%)", style_body_small),
Paragraph("Larotrectinib\nor Entrectinib", style_body_small),
Paragraph("A specific chromosomal rearrangement that these targeted pills can block. "
"Works regardless of where the cancer originated.", style_body_small)],
[Paragraph("KRAS G12C\nmutation", style_body_small),
Paragraph("~1-2%\nof PDAC", style_body_small),
Paragraph("Sotorasib,\nAdagrasib\n(clinical trials)", style_body_small),
Paragraph("A newly targetable form of the most common mutation in pancreatic cancer. "
"Drugs are available in trials.", style_body_small)],
]
target_t = Table(target_data, colWidths=[32*mm, 20*mm, 30*mm, PAGE_W - 2*MARGIN - 82*mm])
target_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), TEAL),
("TEXTCOLOR", (0, 0), (-1, 0), WHITE),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 8.5),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [WHITE, TEAL_LIGHT]),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING",(0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("RIGHTPADDING",(0, 0), (-1, -1), 6),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("GRID", (0, 0), (-1, -1), 0.3, GREY_RULE),
("BOX", (0, 0), (-1, -1), 0.5, TEAL),
]))
story.append(target_t)
story.append(Spacer(1, 3*mm))
story.append(Paragraph(
"<i>Ask your doctor: \"Has my tumour been tested for BRCA, MSI status, and NTRK "
"fusions?\" This testing is now a standard recommendation.</i>",
style_note))
story.append(Spacer(1, 8*mm))
# ─────────────────────────────────────────────────────────────────────────────
# SECTION 7 – SUPPORTIVE / PALLIATIVE CARE
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_header("7. Supportive & Palliative Care", color=GREEN))
story.append(Spacer(1, 3*mm))
story.append(Paragraph(
"Supportive care does NOT mean giving up - it means actively managing the symptoms and "
"side effects of cancer and its treatment. It can be given alongside curative treatment "
"and improves both quality of life and, in many studies, survival.",
style_body))
story.append(Spacer(1, 4*mm))
supp_left = [
"<b>Pain:</b> Celiac plexus nerve block is a procedure that can dramatically reduce "
"severe pancreatic pain and reduce the need for strong painkillers",
"<b>Jaundice:</b> A small metal tube (stent) placed in the bile duct by endoscopy (ERCP) "
"relieves blockage and yellowing",
"<b>Nutrition:</b> Pancreatic enzyme tablets taken with meals replace digestive enzymes "
"the damaged pancreas can no longer make",
]
supp_right = [
"<b>Blood clots:</b> Pancreatic cancer increases clot risk significantly. Blood-thinning "
"injections (low-molecular-weight heparin) are often prescribed",
"<b>Blood sugar:</b> If the pancreas is damaged or removed, insulin may be needed to "
"control blood sugar (diabetes)",
"<b>Emotional support:</b> Counselling, support groups, and palliative care teams help "
"patients and families cope",
]
story.append(two_col(
left_items=supp_left,
right_items=supp_right,
left_title="Physical symptom management",
right_title="Other important support",
left_bg=GREEN_LIGHT, right_bg=ORANGE_LIGHT,
))
story.append(Spacer(1, 8*mm))
# ─────────────────────────────────────────────────────────────────────────────
# SECTION 8 – TREATMENT OVERVIEW FLOWCHART (text-based)
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_header("8. Treatment Decision Overview", color=GREY_DARK))
story.append(Spacer(1, 4*mm))
flow_data = [
[Paragraph("<b>STAGING SCANS (CT Chest + Abdomen + Pelvis)</b>",
S("FH", fontName="Helvetica-Bold", fontSize=9.5, textColor=WHITE,
leading=13, alignment=TA_CENTER))],
]
flow_t = Table(flow_data, colWidths=[PAGE_W - 2*MARGIN])
flow_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), TEAL),
("TOPPADDING", (0, 0), (-1, -1), 7),
("BOTTOMPADDING",(0, 0), (-1, -1), 7),
("LEFTPADDING", (0, 0), (-1, -1), 10),
]))
story.append(flow_t)
arrow_row = [
Paragraph("↓", S("AR", fontName="Helvetica-Bold", fontSize=18, textColor=TEAL,
alignment=TA_CENTER)),
Paragraph("↓", S("AR", fontName="Helvetica-Bold", fontSize=18, textColor=ORANGE,
alignment=TA_CENTER)),
Paragraph("↓", S("AR", fontName="Helvetica-Bold", fontSize=18, textColor=RED_SOFT,
alignment=TA_CENTER)),
Paragraph("↓", S("AR", fontName="Helvetica-Bold", fontSize=18, textColor=RED_SOFT,
alignment=TA_CENTER)),
]
arrow_t = Table([arrow_row], colWidths=[(PAGE_W - 2*MARGIN)/4]*4)
arrow_t.setStyle(TableStyle([("TOPPADDING",(0,0),(-1,-1),2),("BOTTOMPADDING",(0,0),(-1,-1),2)]))
story.append(arrow_t)
box_colors = [GREEN, ORANGE, colors.HexColor("#E67E22"), RED_SOFT]
box_titles = ["Resectable", "Borderline\nResectable", "Locally\nAdvanced", "Metastatic"]
box_texts = [
"Direct surgery\nOR\nNeoadjuvant chemo\n+ then surgery\n+\nAdjuvant chemo after",
"Chemotherapy first\n(FOLFIRINOX or Gem/nab-P)\nRe-stage after 4-6 cycles\n-\nSurgery if possible",
"Chemotherapy\n+/- Radiation therapy\n(Chemoradiation)\nRe-assess for surgery",
"Chemotherapy to\ncontrol cancer &\nimprove quality of life\n+\nFull supportive care",
]
boxes_data = [[
Paragraph(f"<b>{t}</b>", S(f"BT{i}", fontName="Helvetica-Bold", fontSize=9,
textColor=WHITE, leading=12, alignment=TA_CENTER))
for i, t in enumerate(box_titles)
],[
Paragraph(txt, S(f"BB{i}", fontName="Helvetica", fontSize=8.5,
textColor=GREY_DARK, leading=13, alignment=TA_CENTER))
for i, txt in enumerate(box_texts)
]]
box_t = Table(boxes_data, colWidths=[(PAGE_W - 2*MARGIN)/4]*4)
box_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (0, 0), GREEN),
("BACKGROUND", (1, 0), (1, 0), ORANGE),
("BACKGROUND", (2, 0), (2, 0), colors.HexColor("#E67E22")),
("BACKGROUND", (3, 0), (3, 0), RED_SOFT),
("BACKGROUND", (0, 1), (0, 1), GREEN_LIGHT),
("BACKGROUND", (1, 1), (1, 1), ORANGE_LIGHT),
("BACKGROUND", (2, 1), (2, 1), colors.HexColor("#FDEBD0")),
("BACKGROUND", (3, 1), (3, 1), colors.HexColor("#FADBD8")),
("TOPPADDING", (0, 0), (-1, -1), 6),
("BOTTOMPADDING",(0, 0), (-1, -1), 6),
("LEFTPADDING", (0, 0), (-1, -1), 5),
("RIGHTPADDING",(0, 0), (-1, -1), 5),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("GRID", (0, 0), (-1, -1), 1, WHITE),
]))
story.append(box_t)
story.append(Spacer(1, 8*mm))
# ─────────────────────────────────────────────────────────────────────────────
# SECTION 9 – QUESTIONS TO ASK YOUR DOCTOR
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_header("9. Questions to Ask Your Doctor"))
story.append(Spacer(1, 3*mm))
questions = [
"What is the exact stage of my cancer, and which organs or blood vessels are involved?",
"Has my tumour been tested for BRCA, MSI status, NTRK fusions, and KRAS mutations?",
"Is surgery possible for me, either now or after chemotherapy?",
"What chemotherapy regimen do you recommend, and why?",
"Are there any clinical trials I might be eligible for?",
"What supportive care services (dietitian, pain specialist, counsellor) are available?",
"What are the signs that the treatment is working? How will we check (scans, CA 19-9)?",
"If surgery is done, what is the recovery time, and what changes to daily life should I expect?",
]
q_items = []
for i, q in enumerate(questions, 1):
q_items.append(Paragraph(
f'<font color="{TEAL.hexval()}"><b>{i}.</b></font> {q}',
S(f"QA{i}", fontName="Helvetica", fontSize=9.5, textColor=GREY_DARK,
leading=14, spaceAfter=5, leftIndent=12, firstLineIndent=-12)
))
q_data = [[q_items]]
q_t = Table(q_data, colWidths=[PAGE_W - 2*MARGIN])
q_t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), TEAL_LIGHT),
("LEFTPADDING", (0, 0), (-1, -1), 12),
("RIGHTPADDING",(0, 0), (-1, -1), 12),
("TOPPADDING", (0, 0), (-1, -1), 10),
("BOTTOMPADDING",(0, 0), (-1, -1), 10),
("BOX", (0, 0), (-1, -1), 0.5, TEAL),
]))
story.append(q_t)
story.append(Spacer(1, 8*mm))
# ─────────────────────────────────────────────────────────────────────────────
# SECTION 10 – KEY TERMS GLOSSARY
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_header("10. Key Terms Glossary", color=GREY_MID))
story.append(Spacer(1, 3*mm))
glossary = [
("Adenocarcinoma", "Cancer that starts in gland-forming cells. The most common type of pancreatic cancer."),
("Adjuvant therapy", "Treatment (usually chemotherapy) given after surgery to reduce the chance of the cancer coming back."),
("Biopsy / FNB", "A small sample of tissue taken from the tumour using a needle to confirm the diagnosis under a microscope."),
("CA 19-9", "A protein released by some cancer cells. A blood test that measures it is used to track how well treatment is working."),
("Chemoradiation", "Chemotherapy and radiation given together at the same time, which makes each treatment more effective."),
("ECOG Performance Status", "A scale (0-5) that measures how well a patient can carry out daily activities. Guides which chemotherapy is safe to use."),
("FOLFIRINOX", "A combination of four chemotherapy drugs. The most powerful regimen for fit patients with pancreatic cancer."),
("MDT (Multidisciplinary Team)", "A team of specialists - surgeons, oncologists, radiologists, pathologists - who review each patient together before decisions are made."),
("Metastasis", "When cancer spreads from the original tumour to other organs, most commonly the liver or lungs."),
("Neoadjuvant therapy", "Treatment given before surgery to shrink the tumour."),
("PARP inhibitor", "A targeted drug (like Olaparib) that works in cancers with BRCA gene changes."),
("Resectable", "A tumour that surgeons can completely remove with an operation."),
]
gloss_data = [[
Paragraph(f"<b>{term}</b>", S("GT", fontName="Helvetica-Bold", fontSize=8.5,
textColor=TEAL, leading=13)),
Paragraph(defn, S("GD", fontName="Helvetica", fontSize=8.5, textColor=GREY_DARK,
leading=13)),
] for term, defn in glossary]
g_t = Table(gloss_data, colWidths=[42*mm, PAGE_W - 2*MARGIN - 42*mm])
g_t.setStyle(TableStyle([
("ROWBACKGROUNDS", (0, 0), (-1, -1), [WHITE, GREY_LIGHT]),
("TOPPADDING", (0, 0), (-1, -1), 4),
("BOTTOMPADDING",(0, 0), (-1, -1), 4),
("LEFTPADDING", (0, 0), (-1, -1), 7),
("RIGHTPADDING",(0, 0), (-1, -1), 7),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("GRID", (0, 0), (-1, -1), 0.3, GREY_RULE),
("BOX", (0, 0), (-1, -1), 0.5, GREY_MID),
]))
story.append(g_t)
story.append(Spacer(1, 8*mm))
# ─────────────────────────────────────────────────────────────────────────────
# DISCLAIMER
# ─────────────────────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=1, color=GREY_RULE, spaceAfter=4))
story.append(Paragraph(
"<b>Important notice:</b> This guide is for educational purposes only and does not "
"replace professional medical advice. Treatment decisions must always be made by your "
"medical team based on your individual situation. Sources: <i>Current Surgical Therapy "
"14e, Yamada's Textbook of Gastroenterology 7e, Sabiston Textbook of Surgery, "
"Fischer's Mastery of Surgery 8e.</i>",
S("Disc", fontName="Helvetica-Oblique", fontSize=7.5, textColor=GREY_MID,
leading=11, alignment=TA_JUSTIFY)))
# ─── BUILD ───────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT}")