Assalam o alaikum wa rahmatullah wa barakatuhu Does this orris ai have limits also like before premium
Sialolithiasis notes oral pathology
| Gland | Frequency |
|---|---|
| Submandibular (Wharton's duct) | 80-90% |
| Parotid (Stensen's duct) | 10-20% |
| Sublingual | ~1% |
Note: Serum calcium and phosphate levels are NOT related to stone formation. However, hyperparathyroidism is associated with an increased incidence of sialolithiasis.
| Modality | Notes |
|---|---|
| Ultrasound | First-line; detects ~90% of stones >2 mm; cost-effective, no radiation, dynamic, operator-dependent |
| CT scan (fine cuts 1-2mm) | Extremely accurate; non-contrast preferred (contrast-opacified vessels can be confused with stones); shows enlarged gland + ductal dilatation |
| Plain radiograph (occlusal/intraoral) | Traditionally used for radiopaque stones; no longer routine - misses radiolucent stones; confuses sialoliths with phleboliths, atherosclerosis, calcified lymph nodes |
| MRI | Calculus appears as low-signal intensity focus on both T1 and T2 weighted images |
| Digital subtraction sialography | Sensitivity 95-100%; detects radiolucent stones; invasive; contraindicated in active infection and distal Wharton duct stones |
| MR sialography | Non-invasive; uses saliva as contrast; accuracy similar to digital sialography; better alternative when digital sialography is contraindicated |

| Feature | Detail |
|---|---|
| Most common gland | Submandibular (80-90%) |
| Duct involved | Wharton's duct (submandibular) |
| Stone composition | Calcium phosphate + carbonate + organic matrix |
| Hallmark symptom | Cyclical postprandial pain + swelling (salivary colic) |
| First-line imaging | Ultrasound |
| Preferred emergency imaging | CT (non-contrast) |
| First-line treatment | Conservative (sialagogues, hydration, massage) |
| Minimally invasive surgery | Sialendoscopy (gland-preserving) |
| Last resort | Gland excision |
| Long-standing complication | Acute suppurative sialadenitis / chronic sialadenitis |
Create a quick reference PDF or summary table for sialolithiasis
ls /home/daytona/workspace/ 2>/dev/null || echo "workspace is empty or does not exist"
mkdir -p /home/daytona/workspace/sialolithiasis && python3 -c "from reportlab.lib.pagesizes import A4; print('reportlab OK')" && python3 -c "from reportlab.platypus import SimpleDocTemplate; print('platypus OK')"
~/sialolithiasis/build_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, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import PageBreak
OUTPUT = "/home/daytona/workspace/sialolithiasis/Sialolithiasis_Quick_Reference.pdf"
# ββ Colour palette ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
TEAL = colors.HexColor("#006666")
TEAL_LITE = colors.HexColor("#E0F4F4")
TEAL_MID = colors.HexColor("#B2DFDF")
AMBER = colors.HexColor("#E65C00")
AMBER_LT = colors.HexColor("#FFF3E0")
GREY_HEAD = colors.HexColor("#37474F")
GREY_ROW = colors.HexColor("#F5F5F5")
WHITE = colors.white
BLACK = colors.black
RED_LT = colors.HexColor("#FFEBEE")
RED = colors.HexColor("#C62828")
GREEN_LT = colors.HexColor("#E8F5E9")
GREEN = colors.HexColor("#2E7D32")
BLUE_LT = colors.HexColor("#E3F2FD")
BLUE = colors.HexColor("#1565C0")
PURPLE_LT = colors.HexColor("#F3E5F5")
PURPLE = colors.HexColor("#6A1B9A")
styles = getSampleStyleSheet()
def sty(name, **kw):
return ParagraphStyle(name, **kw)
title_style = sty("Title2", fontSize=22, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER,
spaceAfter=4, leading=26)
subtitle_style = sty("Sub", fontSize=11, textColor=TEAL_MID,
fontName="Helvetica-Oblique", alignment=TA_CENTER,
spaceAfter=2)
section_style = sty("Sec", fontSize=12, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_LEFT,
leading=16)
body_style = sty("Body2", fontSize=9.5, textColor=BLACK,
fontName="Helvetica", leading=14, alignment=TA_JUSTIFY)
body_bold = sty("BodyBold", fontSize=9.5, textColor=BLACK,
fontName="Helvetica-Bold", leading=14)
small_style = sty("Small", fontSize=8.5, textColor=GREY_HEAD,
fontName="Helvetica", leading=12, alignment=TA_CENTER)
bullet_style = sty("Bullet", fontSize=9, textColor=BLACK,
fontName="Helvetica", leading=13, leftIndent=10,
bulletIndent=0)
table_header = sty("TH", fontSize=9, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER, leading=12)
table_cell = sty("TC", fontSize=8.8, textColor=BLACK,
fontName="Helvetica", alignment=TA_LEFT, leading=12)
table_cell_c = sty("TCC", fontSize=8.8, textColor=BLACK,
fontName="Helvetica", alignment=TA_CENTER, leading=12)
emph_cell = sty("ECc", fontSize=8.8, textColor=TEAL,
fontName="Helvetica-Bold", alignment=TA_CENTER, leading=12)
warn_style = sty("Warn", fontSize=8.5, textColor=RED,
fontName="Helvetica-Bold", alignment=TA_CENTER, leading=12)
def section_header(text, color=TEAL):
"""Return a coloured section-header table."""
t = Table([[Paragraph(text, section_style)]], colWidths=[17.5*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("ROUNDEDCORNERS", [4, 4, 4, 4]),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def build():
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=2*cm, bottomMargin=2*cm,
title="Sialolithiasis Quick Reference",
author="Orris AI β Oral Pathology"
)
story = []
W = 17.5*cm # usable width
# ββ TITLE BANNER ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
banner_data = [[
Paragraph("π¦· SIALOLITHIASIS", title_style),
Paragraph("Quick Reference Card | Oral Pathology", subtitle_style)
]]
banner = Table(banner_data, colWidths=[W])
banner.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), TEAL),
("TOPPADDING", (0,0), (-1,-1), 14),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 14),
("SPAN", (0,0), (-1,-1)),
("ALIGN", (0,0), (-1,-1), "CENTER"),
]))
story.append(banner)
story.append(Spacer(1, 6*mm))
# ββ ROW 1: Definition + Epidemiology side by side βββββββββββββββββββββ
def_lines = [
Paragraph("<b>Definition:</b> Formation of calculi (stones/sialoliths) within the ductal system of the salivary glands.", body_style),
Spacer(1, 4),
Paragraph("<b>Most common cause</b> of salivary gland inflammation (sialadenitis).", body_style),
Spacer(1, 4),
Paragraph("<b>Synonym:</b> Salivary gland stones / Salivary calculi", body_style),
]
epi_lines = [
Paragraph("<b>Age:</b> 5thβ8th decade (30β60 yrs typical)", body_style),
Spacer(1, 4),
Paragraph("<b>Sex:</b> Males > Females", body_style),
Spacer(1, 4),
Paragraph("<b>Children:</b> Rare; usually ~10 yrs of age", body_style),
Spacer(1, 4),
Paragraph("<b>Hyperparathyroidism</b> β increased risk", body_style),
]
box_style = TableStyle([
("BOX", (0,0), (-1,-1), 0.8, TEAL_MID),
("BACKGROUND", (0,0), (-1,-1), TEAL_LITE),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
def mini_box(title_text, content_items, bg=TEAL_LITE, border=TEAL_MID):
inner = [Paragraph(f"<b>{title_text}</b>", sty("MBT", fontSize=9.5,
textColor=TEAL, fontName="Helvetica-Bold", leading=14))]
inner += content_items
t = Table([[inner]], colWidths=[(W/2)-3*mm])
t.setStyle(TableStyle([
("BOX", (0,0),(-1,-1), 0.8, border),
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 8),
("RIGHTPADDING", (0,0),(-1,-1), 8),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
return t
row1 = Table(
[[mini_box("DEFINITION", def_lines),
mini_box("EPIDEMIOLOGY", epi_lines, bg=AMBER_LT, border=AMBER)]],
colWidths=[(W/2)-2*mm, (W/2)-2*mm], hAlign="LEFT"
)
row1.setStyle(TableStyle([
("ALIGN", (0,0),(-1,-1), "LEFT"),
("VALIGN", (0,0),(-1,-1), "TOP"),
("LEFTPADDING", (0,0),(-1,-1), 0),
("RIGHTPADDING", (0,0),(-1,-1), 0),
("COLPADDING", (0,0),(-1,-1), 3),
]))
story.append(row1)
story.append(Spacer(1, 5*mm))
# ββ SECTION: Gland Distribution βββββββββββββββββββββββββββββββββββββββ
story.append(section_header("GLAND DISTRIBUTION (Why Submandibular?)"))
story.append(Spacer(1, 3*mm))
gland_data = [
[Paragraph("<b>Gland</b>", table_header),
Paragraph("<b>Frequency</b>", table_header),
Paragraph("<b>Duct</b>", table_header),
Paragraph("<b>Stone Location</b>", table_header)],
[Paragraph("Submandibular", emph_cell),
Paragraph("80β90% β
", emph_cell),
Paragraph("Wharton's duct", table_cell_c),
Paragraph("Mainly PROXIMAL (duct)", table_cell_c)],
[Paragraph("Parotid", table_cell_c),
Paragraph("10β20%", table_cell_c),
Paragraph("Stensen's duct", table_cell_c),
Paragraph("Hilum / Parenchyma (mainly DISTAL)", table_cell_c)],
[Paragraph("Sublingual", table_cell_c),
Paragraph("~1%", table_cell_c),
Paragraph("Bartholin's duct", table_cell_c),
Paragraph("Rare", table_cell_c)],
]
gland_table = Table(gland_data, colWidths=[4.2*cm, 3.5*cm, 4.2*cm, 5.6*cm])
gland_table.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), TEAL),
("BACKGROUND", (0,1),(-1,1), TEAL_LITE),
("BACKGROUND", (0,2),(-1,2), GREY_ROW),
("BACKGROUND", (0,3),(-1,3), GREY_ROW),
("ROWBACKGROUNDS",(0,2),(-1,-1), [GREY_ROW, WHITE]),
("BOX", (0,0),(-1,-1), 0.7, TEAL_MID),
("INNERGRID", (0,0),(-1,-1), 0.4, TEAL_MID),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("ALIGN", (0,0),(-1,-1), "CENTER"),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(gland_table)
story.append(Spacer(1, 3*mm))
# Why submandibular?
why_items = [
"1. Wharton's duct is <b>longer, wider, more tortuous</b> and runs <b>against gravity</b> (around mylohyoid) β salivary stasis",
"2. Saliva is more <b>viscous / mucinous</b> with higher <b>CaΒ²βΊ and POβΒ³β» concentration</b>",
"3. Saliva is more <b>alkaline</b> β precipitates calcium phosphate β stone formation",
]
why_table_data = [[Paragraph(i, body_style)] for i in why_items]
why_t = Table(why_table_data, colWidths=[W])
why_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), BLUE_LT),
("BOX", (0,0),(-1,-1), 0.7, BLUE),
("INNERGRID", (0,0),(-1,-1), 0.2, TEAL_MID),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 10),
]))
story.append(why_t)
story.append(Spacer(1, 5*mm))
# ββ SECTION: Composition & Pathogenesis βββββββββββββββββββββββββββββββ
story.append(section_header("COMPOSITION & PATHOGENESIS", color=GREY_HEAD))
story.append(Spacer(1, 3*mm))
comp_items = [
["Calcium phosphate + carbonate", "MAJOR component (same as dental tartar/calculus)"],
["Calcium & magnesium phosphates", "Inorganic core"],
["Glycoproteins + mucopolysaccharides", "Organic matrix (nidus framework)"],
["MgΒ²βΊ, KβΊ, NHββΊ salts", "Minor components"],
["Serum CaΒ²βΊ / POβΒ³β» levels", "NOT related to stone formation"],
]
comp_data = [[Paragraph("<b>Component</b>", table_header),
Paragraph("<b>Role / Note</b>", table_header)]]
for r in comp_items:
comp_data.append([Paragraph(r[0], table_cell), Paragraph(r[1], table_cell)])
comp_t = Table(comp_data, colWidths=[7.5*cm, 10*cm])
comp_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), GREY_HEAD),
("ROWBACKGROUNDS",(0,1),(-1,-1), [GREY_ROW, WHITE]),
("BOX", (0,0),(-1,-1), 0.7, GREY_HEAD),
("INNERGRID", (0,0),(-1,-1), 0.3, colors.HexColor("#BDBDBD")),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(comp_t)
story.append(Spacer(1, 3*mm))
path_text = (
"<b>Pathogenesis (proposed):</b> Salivary stasis + ductal inflammation "
"β alteration of mucoid elements β <b>organic gel nidus</b> forms "
"β deposition of calcium salts β progressive calcification β <b>calculus</b>.<br/>"
"<br/>"
"<b>Submandibular:</b> Stone forms FIRST β stasis β retrograde bacterial migration β sialadenitis<br/>"
"<b>Parotid:</b> Chronic sialadenitis β ductal injury β THEN stone forms"
)
path_box = Table([[Paragraph(path_text, body_style)]], colWidths=[W])
path_box.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), PURPLE_LT),
("BOX", (0,0),(-1,-1), 0.7, PURPLE),
("TOPPADDING", (0,0),(-1,-1), 8),
("BOTTOMPADDING", (0,0),(-1,-1), 8),
("LEFTPADDING", (0,0),(-1,-1), 10),
]))
story.append(path_box)
story.append(Spacer(1, 5*mm))
# ββ SECTION: Clinical Features ββββββββββββββββββββββββββββββββββββββββ
story.append(section_header("CLINICAL FEATURES", color=AMBER))
story.append(Spacer(1, 3*mm))
cf_data = [
[Paragraph("<b>Feature</b>", table_header),
Paragraph("<b>Description</b>", table_header)],
[Paragraph("Hallmark symptom", emph_cell),
Paragraph("Cyclical <b>postprandial pain + swelling</b> of the affected gland (salivary colic)", table_cell)],
[Paragraph("Laterality", table_cell_c),
Paragraph("<b>Unilateral</b>", table_cell)],
[Paragraph("Trigger", table_cell_c),
Paragraph("Eating/smelling food (stimulates saliva β can't drain past stone)", table_cell)],
[Paragraph("Lemon juice test", table_cell_c),
Paragraph("Give lemon juice β reproduces the swelling (bedside test)", table_cell)],
[Paragraph("Palpation (Submandibular)", table_cell_c),
Paragraph("Bimanual palpation (floor of mouth) may reveal palpable stone in Wharton's duct", table_cell)],
[Paragraph("Palpation (Parotid)", table_cell_c),
Paragraph("Stone may be visible at Stensen's duct orifice or palpable along duct course", table_cell)],
[Paragraph("Salivary flow", table_cell_c),
Paragraph("Absent / reduced / cloudy / mucopurulent on massaging the gland", table_cell)],
[Paragraph("Complication", table_cell_c),
Paragraph("Acute suppurative sialadenitis β abscess; Chronic non-specific sialadenitis", table_cell)],
]
cf_table = Table(cf_data, colWidths=[4.5*cm, 13*cm])
cf_table.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), AMBER),
("ROWBACKGROUNDS",(0,1),(-1,-1), [AMBER_LT, WHITE]),
("BOX", (0,0),(-1,-1), 0.7, AMBER),
("INNERGRID", (0,0),(-1,-1), 0.3, colors.HexColor("#FFB74D")),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(cf_table)
story.append(Spacer(1, 5*mm))
# ββ SECTION: Investigations / Imaging βββββββββββββββββββββββββββββββββ
story.append(section_header("INVESTIGATIONS & IMAGING", color=BLUE))
story.append(Spacer(1, 3*mm))
img_data = [
[Paragraph("<b>Modality</b>", table_header),
Paragraph("<b>Sensitivity / Notes</b>", table_header),
Paragraph("<b>Use</b>", table_header)],
[Paragraph("Ultrasound", emph_cell),
Paragraph("Detects ~90% of stones >2 mm; no radiation; dynamic; operator-dependent", table_cell),
Paragraph("First-line", sty("G", fontSize=8.8, textColor=GREEN, fontName="Helvetica-Bold", alignment=TA_CENTER, leading=12))],
[Paragraph("CT (non-contrast, 1-2mm cuts)", table_cell_c),
Paragraph("Highly accurate; avoid contrast (opacified vessels mimic stones); shows gland enlargement + ductal dilatation", table_cell),
Paragraph("Emergency / complex cases", table_cell_c)],
[Paragraph("Plain radiograph (occlusal)", table_cell_c),
Paragraph("Only radiopaque stones; misses radiolucent stones; can confuse with phleboliths, atherosclerosis", table_cell),
Paragraph("Historical / limited", sty("R", fontSize=8.8, textColor=RED, fontName="Helvetica-Bold", alignment=TA_CENTER, leading=12))],
[Paragraph("MRI", table_cell_c),
Paragraph("Stone = low signal on BOTH T1 and T2 weighted images", table_cell),
Paragraph("Complex cases", table_cell_c)],
[Paragraph("Digital subtraction sialography", table_cell_c),
Paragraph("Sensitivity 95-100%; detects radiolucent stones; INVASIVE; <b>contraindicated</b> in active infection or distal Wharton duct stones", table_cell),
Paragraph("Complex / radiolucent stones", table_cell_c)],
[Paragraph("MR sialography", table_cell_c),
Paragraph("Non-invasive; uses saliva as contrast; accuracy β digital sialography; better when digital sialography contraindicated", table_cell),
Paragraph("When other methods contraindicated", table_cell_c)],
]
img_table = Table(img_data, colWidths=[4.2*cm, 9.3*cm, 4*cm])
img_table.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), BLUE),
("ROWBACKGROUNDS",(0,1),(-1,-1), [BLUE_LT, WHITE]),
("BOX", (0,0),(-1,-1), 0.7, BLUE),
("INNERGRID", (0,0),(-1,-1), 0.3, colors.HexColor("#90CAF9")),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(img_table)
story.append(Spacer(1, 5*mm))
# ββ SECTION: Management βββββββββββββββββββββββββββββββββββββββββββββββ
story.append(section_header("MANAGEMENT", color=GREEN))
story.append(Spacer(1, 3*mm))
mgmt_data = [
[Paragraph("<b>Approach</b>", table_header),
Paragraph("<b>Method</b>", table_header),
Paragraph("<b>Indication</b>", table_header)],
# Conservative
[Paragraph("Conservative\n(1st line)", sty("CL", fontSize=8.8, textColor=GREEN,
fontName="Helvetica-Bold", alignment=TA_CENTER, leading=12)),
Paragraph("Sialagogues (lemon drops) + hydration + local heat + gland massage + antibiotics if infected", table_cell),
Paragraph("All patients initially", table_cell_c)],
# Transoral
[Paragraph("Transoral removal", table_cell_c),
Paragraph("Milking or incision into duct (duct slitting)", table_cell),
Paragraph("Distal submandibular stones β€2 cm from duct orifice (palpable)", table_cell_c)],
# Sialendoscopy
[Paragraph("Sialendoscopy β
\n(Modern gold standard)", sty("SL", fontSize=8.8, textColor=TEAL,
fontName="Helvetica-Bold", alignment=TA_CENTER, leading=12)),
Paragraph("Miniature endoscope (0.8β1.6mm) + wire basket / holmium laser / lithotripsy; success 80β100%; gland-preserving", table_cell),
Paragraph("Stones <5mm (distal); Parotid stones <7mm; Intraparenchymal 5β7mm", table_cell_c)],
# ESWL
[Paragraph("ESWL", table_cell_c),
Paragraph("External shock wave lithotripsy; NOT suitable for stones >7β10mm", table_cell),
Paragraph("Non-palpable, non-visualised, impacted stones (submandibular / parotid)", table_cell_c)],
# Combined
[Paragraph("Combined / Hybrid", table_cell_c),
Paragraph("Endoscopy + external incision for stone localisation + removal", table_cell),
Paragraph("Impacted stones not removable endoscopically", table_cell_c)],
# Gland excision
[Paragraph("Gland excision\n(LAST RESORT)", sty("RL", fontSize=8.8, textColor=RED,
fontName="Helvetica-Bold", alignment=TA_CENTER, leading=12)),
Paragraph("Submandibular gland resection or parotidectomy", table_cell),
Paragraph("Failed all other methods; large / mega stones", table_cell_c)],
]
mgmt_table = Table(mgmt_data, colWidths=[3.8*cm, 8.5*cm, 5.2*cm])
mgmt_table.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), GREEN),
("ROWBACKGROUNDS",(0,1),(-1,-1), [GREEN_LT, WHITE]),
("BOX", (0,0),(-1,-1), 0.7, GREEN),
("INNERGRID", (0,0),(-1,-1), 0.3, colors.HexColor("#A5D6A7")),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(mgmt_table)
story.append(Spacer(1, 5*mm))
# ββ SECTION: Key Mnemonics + Quick Facts Box ββββββββββββββββββββββββββ
story.append(section_header("KEY FACTS & MNEMONICS", color=PURPLE))
story.append(Spacer(1, 3*mm))
mnemo_items = [
("<b>WHARTON's duct mnemonic for stone predisposition:</b> <b>W</b>ide + <b>H</b>igh CaΒ²βΊ + "
"<b>A</b>gainst gravity + <b>R</b>etrograde bacterial entry + <b>T</b>ortuous + "
"<b>O</b>blique course + <b>N</b>idus (organic gel) β Stone"),
"<b>Stone composition = 'dental tartar'</b> (calcium & magnesium phosphates + organic matrix)",
"<b>MRI signal:</b> LOW on <u>both</u> T1 AND T2 (calcification = dark on MRI)",
"<b>Sialography contraindications:</b> Active infection + Distal Wharton duct stones",
"<b>Serum CaΒ²βΊ levels are NOT raised</b> in sialolithiasis (local process)",
"<b>Sialendoscopy stent:</b> Left for 2β4 weeks post-procedure to prevent stricture",
]
mnemo_data = [[Paragraph(f"β’ {t}", body_style)] for t in mnemo_items]
mnemo_t = Table(mnemo_data, colWidths=[W])
mnemo_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), PURPLE_LT),
("BOX", (0,0),(-1,-1), 0.7, PURPLE),
("INNERGRID", (0,0),(-1,-1), 0.2, colors.HexColor("#CE93D8")),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 10),
]))
story.append(mnemo_t)
story.append(Spacer(1, 4*mm))
# ββ SECTION: Differentials ββββββββββββββββββββββββββββββββββββββββββββ
story.append(section_header("DIFFERENTIAL DIAGNOSIS", color=RED))
story.append(Spacer(1, 3*mm))
dd_items = [
["Parotitis / Mumps", "Usually bilateral; no calculus; viral etiology"],
["Salivary gland neoplasm", "Painless, slow-growing; no cyclical pattern; mixed tumor most common in submandibular"],
["Lymph node enlargement", "No salivary flow changes; lymphadenopathy features"],
["Phleboliths", "Calcification on X-ray; not in duct path"],
["Atherosclerosis (lingual artery)", "Vascular calcification on radiograph"],
["Calcified cervical lymph nodes", "Different location, no salivary symptoms"],
["Mucocele / Ranula", "Floor of mouth swelling; no colicky pattern"],
]
dd_data = [[Paragraph("<b>Differential</b>", table_header),
Paragraph("<b>Distinguishing Feature</b>", table_header)]]
for r in dd_items:
dd_data.append([Paragraph(r[0], table_cell), Paragraph(r[1], table_cell)])
dd_table = Table(dd_data, colWidths=[5.5*cm, 12*cm])
dd_table.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), RED),
("ROWBACKGROUNDS",(0,1),(-1,-1), [RED_LT, WHITE]),
("BOX", (0,0),(-1,-1), 0.7, RED),
("INNERGRID", (0,0),(-1,-1), 0.3, colors.HexColor("#EF9A9A")),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(dd_table)
story.append(Spacer(1, 4*mm))
# ββ FOOTER ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
footer_text = (
"Sources: Cummings Otolaryngology Head & Neck Surgery | Bailey & Love's Short Practice of Surgery 28th Ed. | "
"S. Das Manual on Clinical Surgery 13th Ed. | Robbins & Cotran Pathologic Basis of Disease "
"β Generated by Orris AI β June 2026"
)
story.append(HRFlowable(width=W, thickness=0.5, color=TEAL_MID))
story.append(Spacer(1, 2*mm))
story.append(Paragraph(footer_text, small_style))
doc.build(story)
print(f"PDF saved to: {OUTPUT}")
build()
cd /home/daytona/workspace/sialolithiasis && python3 build_pdf.py 2>&1
~/sialolithiasis/build_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/sialolithiasis/build_pdf.py'
cd /home/daytona/workspace/sialolithiasis && python3 build_pdf.py 2>&1
Sialolithiasis Quick Reference
PDF Document Β· PDF
| Section | Colour |
|---|---|
| Definition + Epidemiology | Teal / Amber boxes |
| Gland Distribution table (why submandibular is most affected) | Teal |
| Stone Composition + Pathogenesis | Charcoal / Purple |
| Clinical Features table | Amber/Orange |
| Investigations & Imaging table | Blue |
| Management table (conservative β sialendoscopy β last resort) | Green |
| Key Facts & Mnemonics | Purple |
| Differential Diagnosis | Red |
Conduct my quiz