Acute tonsillitis
"tonsillitis" AND "treatment"
| Feature | Description |
|---|---|
| Sore throat | Short history, often with rapid onset |
| Fever | Common; history of fever is a Centor criterion |
| Dysphagia / odynophagia | Pain on swallowing |
| General malaise | Systemic upset |
| Referred otalgia | Due to IX cranial nerve |
| Tonsillar erythema & swelling | Bilateral in most cases |
| Exudates/pustules | Yellow or white on palatine tonsils ("follicular tonsillitis") |
| Tender jugulodigastric (tonsillar) lymphadenopathy | Key sign |
| Score | Probability of GABHS | Recommendation |
|---|---|---|
| 0 | 2% | No test, no antibiotic |
| 1 | 3% | No test, no antibiotic |
| 2 | 8% | Rapid antigen test (RADT) |
| 3 | 19% | Rapid antigen test (RADT) |
| 4 | 41% | Empirical antibiotic or RADT |

| Indication | Specific Criteria |
|---|---|
| Recurrent infections | ≥7 episodes/year, OR ≥5/year for 2 years, OR ≥3/year for 3 years |
| School/work absence | >2 weeks missed in 1 year |
| Hypertrophy | Causing upper airway obstruction, sleep-disordered breathing/OSA, or deglutition problems |
| Peritonsillar abscess | History of quinsy |
| Suspicion of malignancy | Unilateral enlargement, or search for unknown primary |
| Recurrent febrile seizures | Due to tonsillitis |
| Diphtheria carrier state | |
| Actinomyces infection | Refractory to antibiotics |
Generate a patient education handout on acute tonsillitis and when to seek care
ls /home/daytona/workspace/ 2>/dev/null && ls /home/daytona/skills/docx/
mkdir -p /home/daytona/workspace/tonsillitis-handout
~/tonsillitis-handout/create_handout.js
const {
Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
HeadingLevel, AlignmentType, BorderStyle, WidthType, ShadingType,
VerticalAlign, UnderlineType
} = require('docx');
const fs = require('fs');
// ── Colour palette ──────────────────────────────────────────────────────────
const TEAL = "1A7A8A"; // header / accent
const LIGHT_TEAL = "E6F4F6"; // shaded rows / info boxes
const RED = "C0392B"; // warning boxes
const LIGHT_RED = "FDECEA"; // warning box background
const ORANGE = "E67E22"; // caution accent
const LIGHT_ORANGE= "FEF5E7";
const DARK_GRAY = "2C3E50"; // body text / headings
const WHITE = "FFFFFF";
// ── Helper: no-border spec ───────────────────────────────────────────────────
const noBorder = { style: BorderStyle.NONE, size: 0, color: "FFFFFF" };
const allNoBorder = { top: noBorder, bottom: noBorder, left: noBorder, right: noBorder, insideHorizontal: noBorder, insideVertical: noBorder };
// ── Helper: coloured box (single-cell table) ─────────────────────────────────
function colorBox(paragraphs, bgColor, borderColor) {
return new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
margins: { top: 80, bottom: 80 },
borders: allNoBorder,
rows: [
new TableRow({
children: [
new TableCell({
shading: { fill: bgColor, type: ShadingType.SOLID },
borders: {
top: { style: BorderStyle.SINGLE, size: 12, color: borderColor },
bottom: { style: BorderStyle.SINGLE, size: 12, color: borderColor },
left: { style: BorderStyle.SINGLE, size: 12, color: borderColor },
right: { style: BorderStyle.SINGLE, size: 12, color: borderColor },
},
margins: { top: 100, bottom: 100, left: 120, right: 120 },
children: paragraphs,
}),
],
}),
],
});
}
// ── Helper: left-accent box ──────────────────────────────────────────────────
function accentBox(paragraphs, bgColor, leftColor) {
return new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
margins: { top: 60, bottom: 60 },
borders: allNoBorder,
rows: [
new TableRow({
children: [
new TableCell({
shading: { fill: bgColor, type: ShadingType.SOLID },
borders: {
top: noBorder,
bottom: noBorder,
right: noBorder,
left: { style: BorderStyle.SINGLE, size: 24, color: leftColor },
},
margins: { top: 80, bottom: 80, left: 160, right: 120 },
children: paragraphs,
}),
],
}),
],
});
}
// ── Helper: two-column symptom table ────────────────────────────────────────
function symptomTable(rows) {
return new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: allNoBorder,
rows: rows.map((row, i) =>
new TableRow({
children: row.map((cell) =>
new TableCell({
shading: { fill: i % 2 === 0 ? LIGHT_TEAL : WHITE, type: ShadingType.SOLID },
borders: allNoBorder,
margins: { top: 60, bottom: 60, left: 120, right: 120 },
children: [
new Paragraph({
children: [
new TextRun({ text: cell, size: 22, color: DARK_GRAY, font: "Calibri" }),
],
}),
],
})
),
})
),
});
}
// ── Helper: bullet paragraph ─────────────────────────────────────────────────
function bullet(text, bold = false, color = DARK_GRAY) {
return new Paragraph({
bullet: { level: 0 },
spacing: { after: 60 },
children: [
new TextRun({ text, size: 22, color, bold, font: "Calibri" }),
],
});
}
function subBullet(text) {
return new Paragraph({
bullet: { level: 1 },
spacing: { after: 40 },
children: [
new TextRun({ text, size: 21, color: DARK_GRAY, font: "Calibri" }),
],
});
}
// ── Helper: body paragraph ───────────────────────────────────────────────────
function body(text, bold = false, center = false) {
return new Paragraph({
alignment: center ? AlignmentType.CENTER : AlignmentType.LEFT,
spacing: { after: 80 },
children: [
new TextRun({ text, size: 22, color: DARK_GRAY, bold, font: "Calibri" }),
],
});
}
function space(pt = 100) {
return new Paragraph({ spacing: { after: pt }, children: [] });
}
// ── Helper: section heading ───────────────────────────────────────────────────
function sectionHeading(text, emoji = "") {
return new Paragraph({
spacing: { before: 160, after: 80 },
children: [
new TextRun({ text: (emoji ? emoji + " " : "") + text.toUpperCase(), size: 26, bold: true, color: TEAL, font: "Calibri" }),
],
border: {
bottom: { style: BorderStyle.SINGLE, size: 4, color: TEAL },
},
});
}
// ════════════════════════════════════════════════════════════════════════════
// BUILD DOCUMENT
// ════════════════════════════════════════════════════════════════════════════
const doc = new Document({
styles: {
default: {
document: {
run: { font: "Calibri", size: 22, color: DARK_GRAY },
},
},
},
sections: [
{
properties: {
page: {
margin: { top: 720, bottom: 720, left: 900, right: 900 },
},
},
children: [
// ── HEADER BANNER ──────────────────────────────────────────────────
colorBox(
[
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 60 },
children: [
new TextRun({ text: "PATIENT EDUCATION HANDOUT", size: 20, color: LIGHT_TEAL, bold: true, font: "Calibri" }),
],
}),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 40 },
children: [
new TextRun({ text: "Acute Tonsillitis", size: 52, bold: true, color: WHITE, font: "Calibri" }),
],
}),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 60 },
children: [
new TextRun({ text: "Sore Throat & Swollen Tonsils", size: 26, color: LIGHT_TEAL, font: "Calibri" }),
],
}),
],
TEAL, TEAL
),
space(140),
// ── WHAT IS IT ─────────────────────────────────────────────────────
sectionHeading("What Is Acute Tonsillitis?", "🔍"),
body("Your tonsils are two small glands at the back of your throat. They are part of your immune system and help fight off germs. Acute tonsillitis is when these glands become inflamed and infected, usually by a virus or bacteria."),
body("It is a very common condition that affects both children and adults, and most people recover fully within 7–10 days."),
space(80),
// ── CAUSES ─────────────────────────────────────────────────────────
sectionHeading("What Causes It?", "🦠"),
body("Most cases (more than half) are caused by viruses — the same types that cause the common cold. Bacterial causes account for about 1 in 4 cases."),
space(40),
body("Common causes include:", true),
bullet("Viruses: rhinovirus, Epstein-Barr virus (glandular fever), adenovirus"),
bullet("Bacteria: Group A Streptococcus ('strep throat') — the most important bacterial cause"),
bullet("Other bacteria: Haemophilus influenzae, Staphylococcus aureus"),
space(80),
// ── SYMPTOMS ───────────────────────────────────────────────────────
sectionHeading("Symptoms to Expect", "📋"),
body("Acute tonsillitis typically comes on quickly. Common symptoms include:"),
space(40),
symptomTable([
["😣 Sore throat", "🌡️ Fever"],
["😖 Pain when swallowing", "😴 Tiredness and general feeling unwell"],
["👂 Earache (referred pain)", "🗣️ Muffled or changed voice"],
["🦷 Tender, swollen glands in the neck", "💨 Bad breath"],
]),
space(80),
accentBox(
[
new Paragraph({
spacing: { after: 40 },
children: [new TextRun({ text: "What your doctor may see:", size: 22, bold: true, color: TEAL, font: "Calibri" })],
}),
bullet("Red, swollen tonsils"),
bullet("White or yellow spots/patches on the tonsils ('follicular tonsillitis')"),
bullet("Swollen, tender lymph nodes under the jaw or in the neck"),
],
LIGHT_TEAL, TEAL
),
space(80),
// ── HOME CARE ──────────────────────────────────────────────────────
sectionHeading("Home Care & Self-Treatment", "🏠"),
body("For most people, tonsillitis gets better on its own with simple home measures:"),
space(40),
bullet("Rest as much as possible and stay home while you have a fever"),
bullet("Drink plenty of fluids — cool water, warm honey-lemon drinks, ice lollies"),
bullet("Gargle with warm salt water several times a day to soothe your throat"),
bullet("Take paracetamol or ibuprofen as directed to relieve pain and reduce fever", false),
subBullet("Do NOT give aspirin to children under 16"),
bullet("Eat soft, cool foods if swallowing is painful (yoghurt, ice cream, soup)"),
bullet("Avoid smoking and smoke-filled environments"),
bullet("Throat lozenges may provide short-term relief"),
space(80),
// ── ANTIBIOTICS ────────────────────────────────────────────────────
sectionHeading("Do I Need Antibiotics?", "💊"),
body("Not always. Because most tonsillitis is caused by viruses, antibiotics will not help in those cases. Your doctor will decide whether antibiotics are needed based on your symptoms and examination."),
space(40),
accentBox(
[
new Paragraph({
spacing: { after: 40 },
children: [new TextRun({ text: "Your doctor may prescribe antibiotics if:", size: 22, bold: true, color: TEAL, font: "Calibri" })],
}),
bullet("Your symptoms are not improving after 48–72 hours"),
bullet("There are signs of a bacterial ('strep') infection"),
bullet("You are very unwell or at high risk of complications"),
new Paragraph({ spacing: { after: 60 }, children: [] }),
new Paragraph({
spacing: { after: 40 },
children: [new TextRun({ text: "If antibiotics are prescribed:", size: 22, bold: true, color: TEAL, font: "Calibri" })],
}),
bullet("Penicillin V (Phenoxymethylpenicillin) is the usual first choice"),
bullet("Complete the full course, even if you feel better"),
bullet("Tell your doctor if you are allergic to penicillin — alternatives are available"),
new Paragraph({
spacing: { after: 20, before: 60 },
children: [new TextRun({ text: "⚠️ Important: If you are also unwell with a fever, extreme tiredness, and swollen glands all over your body, you may have glandular fever (Epstein-Barr virus). In this case, amoxicillin and ampicillin must NOT be given — they can cause a severe rash.", size: 21, color: ORANGE, font: "Calibri", italics: true })],
}),
],
LIGHT_TEAL, TEAL
),
space(80),
// ── WHEN TO SEEK CARE ───────────────────────────────────────────────
sectionHeading("When to Seek Medical Care", "🏥"),
space(40),
// Urgency box — see GP
colorBox(
[
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 80 },
children: [new TextRun({ text: "📞 See Your Doctor or GP If…", size: 26, bold: true, color: WHITE, font: "Calibri" })],
}),
bullet("Symptoms are not improving after 3–4 days of home care", false, WHITE),
bullet("Fever persists or worsens despite paracetamol/ibuprofen", false, WHITE),
bullet("You are having significant difficulty swallowing fluids", false, WHITE),
bullet("Swollen glands in the neck are getting larger", false, WHITE),
bullet("You have a rash developing alongside your sore throat", false, WHITE),
bullet("You are concerned about your or your child's condition", false, WHITE),
bullet("This is a recurrent episode (tonsillitis that keeps coming back)", false, WHITE),
],
TEAL, TEAL
),
space(100),
// Emergency box
colorBox(
[
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 80 },
children: [new TextRun({ text: "🚨 GO TO A&E / CALL 999 IMMEDIATELY IF…", size: 26, bold: true, color: WHITE, font: "Calibri" })],
}),
bullet("You are unable to swallow even liquids or saliva", false, WHITE),
bullet("You have severe difficulty breathing or noisy breathing (stridor)", false, WHITE),
bullet("Your voice sounds very muffled ('hot potato voice') with new jaw stiffness — this may be a throat abscess", false, WHITE),
bullet("You cannot open your mouth properly (trismus)", false, WHITE),
bullet("One side of your throat looks very swollen and the uvula (little hanging flap) is pushed to one side", false, WHITE),
bullet("You have severe neck swelling or neck stiffness", false, WHITE),
bullet("High fever with rigors (violent shivering) and feeling extremely unwell", false, WHITE),
bullet("A young child is drooling excessively and unable to swallow", false, WHITE),
],
RED, RED
),
space(100),
// Peritonsillar abscess note
accentBox(
[
new Paragraph({
spacing: { after: 40 },
children: [new TextRun({ text: "About Peritonsillar Abscess (Quinsy)", size: 22, bold: true, color: ORANGE, font: "Calibri" })],
}),
body("A collection of pus can sometimes develop around a tonsil ('quinsy'). Signs include severe one-sided throat pain, difficulty opening your mouth, a muffled voice, and the uvula being pushed to one side. This requires urgent hospital treatment — usually drainage of the abscess and IV antibiotics."),
],
LIGHT_ORANGE, ORANGE
),
space(80),
// ── COMPLICATIONS ──────────────────────────────────────────────────
sectionHeading("Possible Complications", "⚠️"),
body("Complications are uncommon but can occur, particularly with untreated bacterial (streptococcal) tonsillitis:"),
space(40),
bullet("Peritonsillar abscess (quinsy) — pus around the tonsil"),
bullet("Spread of infection to the neck (parapharyngeal abscess)"),
bullet("Rheumatic fever — can affect the heart, joints, and brain (rare, prevented by antibiotics)"),
bullet("Kidney inflammation (post-streptococcal glomerulonephritis)"),
bullet("Rarely: blood infection (septicaemia)"),
space(80),
// ── RECURRENT TONSILLITIS ─────────────────────────────────────────
sectionHeading("Recurrent Tonsillitis & Tonsillectomy", "🔄"),
body("Some people get tonsillitis repeatedly. If this is happening to you or your child, speak to your doctor about a referral to an ENT (Ear, Nose & Throat) specialist."),
space(40),
body("Tonsillectomy (surgical removal of the tonsils) may be recommended if:", true),
bullet("7 or more episodes in one year"),
bullet("5 or more episodes per year for 2 consecutive years"),
bullet("3 or more episodes per year for 3 consecutive years"),
bullet("Tonsillitis is causing significant time off school or work"),
bullet("A peritonsillar abscess has developed"),
bullet("The tonsils are so large they are causing breathing problems or sleep apnoea"),
space(40),
body("Tonsillectomy is a safe, routine operation. Your ENT specialist will discuss the benefits and risks with you."),
space(80),
// ── CHILDREN NOTE ─────────────────────────────────────────────────
sectionHeading("A Note for Parents", "👶"),
accentBox(
[
bullet("Tonsillitis is very common in children aged 5–15 years"),
bullet("Streptococcal ('strep') tonsillitis is more common in children than adults"),
bullet("If a RADT (rapid strep test) or throat swab is done: a negative test in children should be backed up with a throat culture"),
bullet("Keep your child home from school until they are fever-free for 24 hours"),
bullet("Ensure they drink enough fluids — dehydration can worsen quickly in young children"),
bullet("Do NOT give aspirin to anyone under 16"),
bullet("Seek medical attention sooner if a young child is drooling, cannot swallow, or has noisy breathing"),
],
LIGHT_TEAL, TEAL
),
space(80),
// ── KEY TAKE-AWAY ──────────────────────────────────────────────────
sectionHeading("Key Points to Remember", "✅"),
symptomTable([
["✅ Most tonsillitis is viral and resolves without antibiotics", "✅ Rest, fluids, and pain relief are the mainstay of treatment"],
["✅ Only take antibiotics if prescribed by your doctor", "✅ Complete the full antibiotic course if prescribed"],
["✅ Seek care if symptoms worsen after 3–4 days", "🚨 Go to A&E if you cannot breathe or swallow"],
]),
space(120),
// ── FOOTER ────────────────────────────────────────────────────────
colorBox(
[
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 30 },
children: [
new TextRun({ text: "This handout is for general information only and does not replace advice from your healthcare provider.", size: 18, color: WHITE, italics: true, font: "Calibri" }),
],
}),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 30 },
children: [
new TextRun({ text: "If you have concerns about your health, please contact your GP, pharmacist, or call NHS 111.", size: 18, color: LIGHT_TEAL, font: "Calibri" }),
],
}),
new Paragraph({
alignment: AlignmentType.CENTER,
children: [
new TextRun({ text: "Sources: Bailey & Love's Surgery 28th Ed | Scott-Brown's ORL | Harrison's Principles 22E | Goldman-Cecil Medicine", size: 17, color: LIGHT_TEAL, italics: true, font: "Calibri" }),
],
}),
],
DARK_GRAY, DARK_GRAY
),
],
},
],
});
Packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("/home/daytona/workspace/tonsillitis-handout/Acute_Tonsillitis_Patient_Handout.docx", buffer);
console.log("Done: Acute_Tonsillitis_Patient_Handout.docx created.");
});
cd /home/daytona/workspace/tonsillitis-handout && node create_handout.js 2>&1
python /home/daytona/skills/docx/scripts/office/validate.py /home/daytona/worksp…
cd /home/daytona/workspace/tonsillitis-handout && python3 -c " import zipfile, o…
Acute Tonsillitis Patient Handout
Word Document · DOCX
Can you give details about tonsillectomy
"tonsillectomy" AND "outcomes"
| Indication | Notes |
|---|---|
| Tonsillar hypertrophy causing upper airway obstruction | Obstructive sleep apnoea, cor pulmonale, or chronic respiratory obstruction |
| Suspected tonsillar malignancy | Unilateral enlargement, or search for unknown primary |
| Indication | Notes |
|---|---|
| Recurrent acute tonsillitis | Must be well-documented (Paradise criteria - see below) |
| Chronic tonsillitis | Persistent sore throat with tonsillar debris, tonsilloliths |
| Peritonsillar abscess (quinsy) | History of one or more episodes |
| Tonsillar asymmetry | As part of work-up |
| Febrile convulsions from tonsillitis | |
| Diphtheria carrier state | |
| Systemic disease from GABHS | Rheumatic fever, glomerulonephritis |
| Surgical access | To parapharyngeal space or elongated styloid process |
Evidence from the NESTAC trial and others shows that children with less severe symptoms who do not meet the Paradise criteria do not benefit significantly from surgery over watchful waiting.

| Technique | Primary Haemorrhage (%) | Secondary Haemorrhage (%) |
|---|---|---|
| Cold steel + ties/packs | 0.8 | 1.0 (lowest) |
| Cold steel + monopolar diathermy | 0.5 | 2.4 |
| Cold steel + bipolar diathermy | 0.5 | 2.3 |
| Monopolar diathermy forceps | 1.1 | 5.5 (highest) |
| Bipolar diathermy forceps | 0.4 | 4.3 |
| Bipolar diathermy scissors | 0.6 | 4.6 |
| Coblation® | 1.0 | 3.6 |
| Complication | Details |
|---|---|
| Primary haemorrhage (within 24 h) | Most common immediate complication; local pressure for mild cases; return to theatre for significant bleeding |
| Secondary haemorrhage (24 h - 2 weeks) | NPTA readmission rate 4.57%; 1.44% required return to theatre; usually due to streptococcal infection of the granulating bed; treat with IV antibiotics ± theatre |
| Infection / Halitosis | First signs: fever and halitosis; treat according to severity |
| Pain / Referred otalgia | Sore throat expected for at least 1 week; return to school/work takes 1-2 weeks |
| Post-operative airway obstruction | Particularly in children with OSA - watch post-extubation |
| Velopharyngeal insufficiency | Rare - hypernasal speech following surgery |
| TMJ dysfunction | From excessive mouth opening during surgery |
| Glossopharyngeal nerve injury | From dissection beyond pharyngeal musculature |
| Carotid sheath injury | Rare but serious |
| Grisel syndrome | Non-traumatic atlantoaxial subluxation secondary to inflammatory neck process |
| Mortality | Approximately 1 in 25,000 (haemorrhage, airway obstruction, anaesthesia) |
Make pdf of everything said in this page
mkdir -p /home/daytona/workspace/tonsillitis-pdf && ls /home/daytona/workspace/t…
~/tonsillitis-pdf/generate_pdf.py
#!/usr/bin/env python3
"""
Comprehensive PDF: Acute Tonsillitis, Patient Education Handout, Tonsillectomy
All content from the conversation on this page.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.platypus.flowables import BalancedColumns
from reportlab.lib.colors import HexColor
import io
# ── Colours ──────────────────────────────────────────────────────────────────
TEAL = HexColor("#1A7A8A")
TEAL_LIGHT = HexColor("#E6F4F6")
TEAL_MED = HexColor("#2A9BAC")
DARK_GRAY = HexColor("#2C3E50")
MID_GRAY = HexColor("#7F8C8D")
LIGHT_GRAY = HexColor("#F5F5F5")
RED = HexColor("#C0392B")
RED_LIGHT = HexColor("#FDECEA")
ORANGE = HexColor("#E67E22")
ORANGE_LIGHT= HexColor("#FEF5E7")
WHITE = colors.white
BLACK = colors.black
ALT_ROW = HexColor("#EAF7F9")
W, H = A4
LMARGIN = 2*cm
RMARGIN = 2*cm
# ── Document ─────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
"/home/daytona/workspace/tonsillitis-pdf/Tonsillitis_Complete_Notes.pdf",
pagesize=A4,
leftMargin=LMARGIN, rightMargin=RMARGIN,
topMargin=2*cm, bottomMargin=2*cm,
title="Acute Tonsillitis – Complete Clinical Reference",
author="Orris Medical AI",
subject="Tonsillitis: Clinical Notes, Patient Education & Tonsillectomy"
)
# ── Styles ────────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def S(name, parent="Normal", **kw):
return ParagraphStyle(name, parent=base[parent], **kw)
sTitle = S("sTitle", fontSize=26, textColor=WHITE, alignment=TA_CENTER, leading=32, fontName="Helvetica-Bold")
sSubtitle = S("sSubtitle", fontSize=13, textColor=TEAL_LIGHT, alignment=TA_CENTER, leading=18, fontName="Helvetica")
sPart = S("sPart", fontSize=18, textColor=WHITE, alignment=TA_CENTER, leading=24, fontName="Helvetica-Bold")
sH1 = S("sH1", fontSize=14, textColor=TEAL, leading=20, spaceBefore=14, spaceAfter=4, fontName="Helvetica-Bold")
sH2 = S("sH2", fontSize=12, textColor=DARK_GRAY, leading=17, spaceBefore=10, spaceAfter=3, fontName="Helvetica-Bold")
sH3 = S("sH3", fontSize=11, textColor=TEAL_MED, leading=16, spaceBefore=8, spaceAfter=2, fontName="Helvetica-BoldOblique")
sBody = S("sBody", fontSize=10, textColor=DARK_GRAY, leading=15, spaceAfter=5, fontName="Helvetica", alignment=TA_JUSTIFY)
sBullet = S("sBullet", fontSize=10, textColor=DARK_GRAY, leading=14, spaceAfter=3, fontName="Helvetica", leftIndent=16, bulletIndent=4)
sSubBullet = S("sSubBullet", fontSize=9.5,textColor=DARK_GRAY, leading=13, spaceAfter=2, fontName="Helvetica", leftIndent=30, bulletIndent=18)
sNote = S("sNote", fontSize=9, textColor=MID_GRAY, leading=13, spaceAfter=3, fontName="Helvetica-Oblique", alignment=TA_CENTER)
sWarn = S("sWarn", fontSize=10, textColor=RED, leading=14, spaceAfter=3, fontName="Helvetica-Bold")
sBoxTitle = S("sBoxTitle", fontSize=11, textColor=TEAL, leading=16, spaceAfter=4, fontName="Helvetica-Bold")
sBoxBody = S("sBoxBody", fontSize=10, textColor=DARK_GRAY, leading=14, spaceAfter=3, fontName="Helvetica")
sBoxBullet = S("sBoxBullet", fontSize=10, textColor=DARK_GRAY, leading=14, spaceAfter=2, fontName="Helvetica", leftIndent=14, bulletIndent=4)
sTableHdr = S("sTableHdr", fontSize=9.5,textColor=WHITE, leading=13, fontName="Helvetica-Bold", alignment=TA_CENTER)
sTableCell = S("sTableCell", fontSize=9.5,textColor=DARK_GRAY, leading=13, fontName="Helvetica")
sTableCellC = S("sTableCellC", fontSize=9.5,textColor=DARK_GRAY, leading=13, fontName="Helvetica", alignment=TA_CENTER)
sSource = S("sSource", fontSize=8, textColor=MID_GRAY, leading=11, fontName="Helvetica-Oblique")
sTocEntry = S("sTocEntry", fontSize=11, textColor=DARK_GRAY, leading=18, fontName="Helvetica", leftIndent=10)
# ── Helpers ───────────────────────────────────────────────────────────────────
def sp(h=6):
return Spacer(1, h)
def hr(color=TEAL, thickness=1):
return HRFlowable(width="100%", thickness=thickness, color=color, spaceAfter=4, spaceBefore=4)
def bullet_para(text, style=sBullet):
return Paragraph(f"• {text}", style)
def sub_bullet(text):
return Paragraph(f"– {text}", sSubBullet)
def info_box(title, items, bg=TEAL_LIGHT, border=TEAL):
content = []
if title:
content.append(Paragraph(title, sBoxTitle))
for item in items:
if item.startswith("--"):
content.append(Paragraph(f"– {item[2:]}", sSubBullet))
elif item.startswith("•"):
content.append(Paragraph(item, sBoxBullet))
else:
content.append(Paragraph(f"• {item}", sBoxBullet))
t = Table([[content]], colWidths=[W - LMARGIN - RMARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 1.5, border),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
return t
def warn_box(title, items):
return info_box(title, items, bg=RED_LIGHT, border=RED)
def caution_box(title, items):
return info_box(title, items, bg=ORANGE_LIGHT, border=ORANGE)
def part_banner(text, sub=""):
rows = [[Paragraph(text, sPart)]]
if sub:
rows.append([Paragraph(sub, sSubtitle)])
t = Table(rows, colWidths=[W - LMARGIN - RMARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), TEAL),
("TOPPADDING", (0,0), (-1,-1), 14),
("BOTTOMPADDING", (0,0), (-1,-1), 14),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 12),
]))
return t
def section_heading(text):
return [
sp(8),
Paragraph(text.upper(), sH1),
hr(TEAL, 0.8),
sp(4),
]
def std_table(headers, rows, col_widths=None, alt=True):
cw = col_widths or [(W - LMARGIN - RMARGIN) / len(headers)] * len(headers)
data = [[Paragraph(h, sTableHdr) for h in headers]]
for i, row in enumerate(rows):
data.append([Paragraph(str(c), sTableCell) for c in row])
style = [
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [ALT_ROW, WHITE] if alt else [WHITE]),
("GRID", (0,0), (-1,-1), 0.4, HexColor("#C0D8DC")),
("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), "TOP"),
]
t = Table(data, colWidths=cw)
t.setStyle(TableStyle(style))
return t
# ═══════════════════════════════════════════════════════════════════════════════
# BUILD CONTENT
# ═══════════════════════════════════════════════════════════════════════════════
story = []
# ── COVER PAGE ────────────────────────────────────────────────────────────────
cover_data = [
[Paragraph("ACUTE TONSILLITIS", sTitle)],
[Paragraph("Complete Clinical Reference", sSubtitle)],
[Paragraph("Clinical Notes · Patient Education · Tonsillectomy", sSubtitle)],
]
cover_t = Table(cover_data, colWidths=[W - LMARGIN - RMARGIN])
cover_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), TEAL),
("TOPPADDING", (0,0), (-1,-1), 18),
("BOTTOMPADDING", (0,0), (-1,-1), 18),
("LEFTPADDING", (0,0), (-1,-1), 20),
("RIGHTPADDING", (0,0), (-1,-1), 20),
]))
story.append(cover_t)
story.append(sp(20))
story.append(Paragraph(
"This document compiles all clinical content discussed in the consultation session, "
"including a full clinical review of acute tonsillitis, a patient education handout, "
"and a detailed guide to tonsillectomy. Sources: Bailey & Love's Surgery 28th Ed, "
"Scott-Brown's ORL Head & Neck Surgery, Harrison's Principles 22E, "
"Goldman-Cecil Medicine, K.J. Lee's Essential Otolaryngology, "
"Tintinalli's Emergency Medicine, Symptom to Diagnosis 4th Ed.",
sBody
))
story.append(sp(8))
story.append(Paragraph("Date: July 12, 2026 · Prepared by Orris Medical AI", sNote))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════════════════════════
# PART 1 — ACUTE TONSILLITIS: CLINICAL NOTES
# ═══════════════════════════════════════════════════════════════════════════════
story.append(part_banner("PART 1", "Acute Tonsillitis — Clinical Notes"))
story.append(sp(14))
# Definition
story += section_heading("Definition")
story.append(Paragraph(
"Acute tonsillitis is inflammation of the palatine tonsils, presenting as a "
"short-illness sore throat with fever. It may occur as an isolated episode, "
"as part of an upper respiratory illness, or as a manifestation of a systemic "
"infection such as infectious mononucleosis. Both bacteria and viruses play a "
"part — either separately or together — and there is no evidence to suggest that "
"viral tonsillitis is more or less severe than bacterial tonsillitis. In most "
"cases, both viral and bacterial tonsillitis resolve quickly without treatment.",
sBody
))
# Aetiology
story += section_heading("Aetiology & Microbiology")
story.append(Paragraph(
"Viruses account for the majority of cases. Bacterial causes account for "
"approximately 10–23% of cases overall, with Group A beta-haemolytic "
"Streptococcus (GABHS) being the most important bacterial pathogen.",
sBody
))
story.append(sp(4))
story.append(Paragraph("<b>Viral causes (most common):</b>", sH3))
viral = [
"Rhinovirus — 15–20% of cases (most common overall)",
"Coronavirus, Adenovirus (pharyngoconjunctival fever) — ~6%",
"Epstein-Barr virus (EBV) — infectious mononucleosis",
"Parainfluenza virus (types 1–4), Influenza A/B, RSV",
"Herpes simplex virus types 1 and 2",
"Coxsackievirus A (herpangina)",
"HIV — acute retroviral syndrome (primary HIV infection)",
]
for v in viral:
story.append(bullet_para(v))
story.append(sp(6))
story.append(Paragraph("<b>Bacterial causes:</b>", sH3))
bact = [
"Group A beta-haemolytic Streptococcus / Streptococcus pyogenes (GABHS) — 10–23% of cases; most important",
"Fusobacterium necrophorum — 5–10%; associated with Lemierre's syndrome",
"Group C streptococcus (S. dysgalactiae) — 3–6%",
"Haemophilus influenzae, Streptococcus pneumoniae, Staphylococcus aureus",
"Anaerobes",
"Rare: Neisseria gonorrhoeae, Corynebacterium diphtheriae, Mycobacterium tuberculosis (immunocompromised)",
]
for b in bact:
story.append(bullet_para(b))
# Clinical Features
story += section_heading("Clinical Features")
story.append(Paragraph("Acute tonsillitis typically has a short, rapid-onset history:", sBody))
story.append(sp(4))
feat_data = [
["Symptom", "Description"],
["Sore throat", "Short history, often rapid onset; cardinal symptom"],
["Fever", "Common; important Centor criterion when present"],
["Dysphagia / Odynophagia", "Pain on swallowing"],
["General malaise", "Systemic upset, tiredness"],
["Referred otalgia", "Via glossopharyngeal nerve (CN IX)"],
["Tonsillar erythema & swelling", "Bilateral in most cases"],
["Exudates (follicular tonsillitis)", "Yellow or white pustules on palatine tonsils"],
["Tender jugulodigastric lymphadenopathy", "Tender upper cervical nodes — key sign"],
["Absence of cough", "Notable feature suggesting bacterial rather than viral aetiology"],
]
cw = [6.5*cm, 10*cm]
story.append(std_table(feat_data[0], feat_data[1:], col_widths=cw))
# Centor Criteria
story += section_heading("Centor Criteria — Predicting Streptococcal Tonsillitis")
story.append(Paragraph(
"The Centor criteria (area under the curve 0.79) stratify adult patients with "
"suspected streptococcal pharyngotonsillitis. Each criterion scores 1 point:",
sBody
))
story.append(sp(4))
centor_items = [
"History of fever",
"Absence of cough",
"Tender anterior cervical lymphadenopathy",
"Tonsillar exudate or swelling",
]
for c in centor_items:
story.append(bullet_para(c))
story.append(sp(6))
centor_data = [
["Score", "Probability of GABHS", "Recommendation"],
["0", "2%", "No test, no antibiotic"],
["1", "3%", "No test, no antibiotic"],
["2", "8%", "Rapid antigen test (RADT)"],
["3", "19%", "Rapid antigen test (RADT)"],
["4", "41%", "Empirical antibiotic OR RADT"],
]
story.append(std_table(centor_data[0], centor_data[1:], col_widths=[3*cm, 5*cm, 8.5*cm]))
story.append(sp(4))
story.append(Paragraph(
"The modified Centor (McIsaac) score adds age weighting: +1 for age 3–14 years, "
"0 for age 15–44, −1 for age ≥45.",
sBody
))
story.append(sp(6))
story.append(info_box("RADT (Rapid Antigen Detection Test)", [
"Sensitivity: 70–90% | Specificity: 90–100%",
"Negative RADT in children/adolescents: back up with throat culture (risk of rheumatic fever)",
"In adults: negative RADT does not require throat culture backup",
"Positive RADTs do not need backup culture (highly specific)",
]))
# Management
story += section_heading("Management")
story.append(Paragraph("<b>Symptomatic (all cases):</b>", sH3))
symp = [
"Analgesia — paracetamol and/or NSAIDs for pain and fever relief",
"Hydration — adequate oral fluid intake; IV fluids if severe dysphagia",
"Saline gargles — soothing; several times per day",
"Soft, cool foods if swallowing is painful",
]
for s in symp:
story.append(bullet_para(s))
story.append(sp(6))
story.append(Paragraph("<b>Antibiotics:</b>", sH3))
story.append(Paragraph(
"Most cases resolve spontaneously. Antibiotics shorten illness duration and reduce "
"the risk of sequelae. Indicated if: no improvement after 48–72 hours, or clinical "
"concern about severity at the outset.",
sBody
))
ab_data = [
["Drug", "Route", "Notes"],
["Benzylpenicillin (Penicillin G)", "IV", "Drug of choice for severe/inpatient cases"],
["Phenoxymethylpenicillin (Penicillin V)", "Oral", "First-line for outpatient treatment"],
["Cephalosporins (1st gen)", "Oral/IV", "Penicillin allergy alternative"],
["Clindamycin", "Oral/IV", "Penicillin allergy; also covers anaerobes"],
["Clarithromycin / Azithromycin", "Oral", "Penicillin allergy; note resistance rates"],
["Ampicillin / Amoxicillin", "—", "AVOID — causes severe rash in ~90% of EBV/mononucleosis patients"],
]
story.append(std_table(ab_data[0], ab_data[1:], col_widths=[5.5*cm, 2.5*cm, 8.5*cm]))
story.append(sp(4))
story.append(Paragraph(
"Antibiotic therapy reduces the risk of acute rheumatic fever by approximately 73%.",
sBody
))
story.append(sp(6))
story.append(Paragraph("<b>Corticosteroids:</b>", sH3))
story.append(Paragraph(
"Corticosteroids (oral or IM), in addition to antibiotics, expedite resolution of "
"pain and are particularly beneficial in severe cases.",
sBody
))
# Differential — Infectious Mononucleosis
story += section_heading("Key Differential: Infectious Mononucleosis (EBV)")
story.append(info_box("Infectious Mononucleosis — Key Points", [
"Caused by Epstein-Barr virus (EBV); commonly seen in young adults",
"Presents as acute tonsillitis — may be clinically indistinguishable from bacterial tonsillitis",
"Additional features: significant systemic upset, splenomegaly, deranged LFTs and FBC",
"Diagnosis: Monospot test (sensitivity <50% in children; 70–90% in adults); confirmed by specific EBV antibody titres",
"In 30% of patients, secondary bacterial tonsil infection occurs",
"CRITICAL: Ampicillin/amoxicillin MUST be avoided — causes severe maculopapular rash in ~90% of EBV patients (transient immunostimulation)",
"Safe antibiotics: high-dose IV penicillin or cephalosporins",
]))
# Complications
story += section_heading("Complications")
story.append(Paragraph("<b>Local / Suppurative:</b>", sH3))
comp_data = [
["Complication", "Features", "Management"],
["Peritonsillar Abscess (Quinsy)", "Severe unilateral sore throat, odynophagia, trismus, 'hot potato' voice, uvular deviation", "IV penicillin/cephalosporin + needle aspiration or I&D"],
["Parapharyngeal / Retropharyngeal abscess", "Neck swelling, fever, dysphagia, trismus", "IV antibiotics + surgical drainage"],
["Lemierre's Syndrome", "Severe neck pain, septicaemia; septic thrombophlebitis of IJV; caused by Fusobacterium necrophorum", "Penicillin + metronidazole (or co-amoxiclav) for 6 weeks; anticoagulation if spreading"],
["Septicaemia", "High fever, rigors, haemodynamic instability", "IV antibiotics + supportive care"],
]
story.append(std_table(comp_data[0], comp_data[1:], col_widths=[4.5*cm, 7*cm, 5*cm]))
story.append(sp(8))
story.append(Paragraph("<b>Non-suppurative (Immune Complex Disorders — GABHS only):</b>", sH3))
nc = [
"Acute Rheumatic Fever — molecular mimicry targeting cardiac antigens; prevented by penicillin treatment; affects heart, joints, and brain",
"Post-streptococcal Acute Glomerulonephritis — immune complex deposition in glomeruli",
"Psoriasis exacerbation — possible immune association with GABHS tonsillitis (evidence limited; no clear benefit from tonsillectomy)",
]
for n in nc:
story.append(bullet_para(n))
# Recurrent & Chronic
story += section_heading("Recurrent & Chronic Tonsillitis")
story.append(Paragraph(
"<b>Recurrent tonsillitis</b>: recurring acute episodes. Episodes may gradually settle "
"or continue for several years. No evidence for benefit of long-term antibiotics.",
sBody
))
story.append(Paragraph(
"<b>Chronic tonsillitis</b>: persistent throat discomfort with foul-smelling white debris "
"from tonsillar crypts (tonsilloliths if calcified). Treatment includes hydrogen "
"peroxide gargles, manual expression of debris. Long-term amoxicillin "
"(500 mg TDS × 21 days) or clindamycin (300 mg TDS × 21 days) may help. "
"Presence of Actinomyces on culture is an indication for tonsillectomy as "
"antibiotics are unlikely to eradicate it.",
sBody
))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════════════════════════
# PART 2 — PATIENT EDUCATION HANDOUT
# ═══════════════════════════════════════════════════════════════════════════════
story.append(part_banner("PART 2", "Patient Education Handout — Acute Tonsillitis"))
story.append(sp(14))
# What is it
story += section_heading("What Is Acute Tonsillitis?")
story.append(Paragraph(
"Your tonsils are two small glands at the back of your throat. They are part of "
"your immune system and help fight off germs. Acute tonsillitis is when these glands "
"become inflamed and infected, usually by a virus or bacteria.",
sBody
))
story.append(Paragraph(
"It is a very common condition affecting both children and adults. Most people "
"recover fully within 7–10 days.",
sBody
))
# Causes
story += section_heading("What Causes It?")
story.append(Paragraph(
"More than half of cases are caused by viruses — the same types that cause the "
"common cold. Bacteria cause about 1 in 4 cases. Common causes include:",
sBody
))
story.append(bullet_para("Viruses: rhinovirus, Epstein-Barr virus (glandular fever), adenovirus"))
story.append(bullet_para("Bacteria: Group A Streptococcus ('strep throat') — most important bacterial cause"))
story.append(bullet_para("Other bacteria: Haemophilus influenzae, Staphylococcus aureus"))
# Symptoms
story += section_heading("Symptoms")
symp_data = [
["Symptom", "Symptom"],
["😣 Sore throat", "🌡️ Fever"],
["😖 Pain when swallowing", "😴 Tiredness and feeling unwell"],
["👂 Earache (referred pain)", "🗣️ Muffled or changed voice"],
["🦷 Tender, swollen glands in the neck", "💨 Bad breath"],
]
story.append(std_table(symp_data[0], symp_data[1:], col_widths=[8.25*cm, 8.25*cm]))
story.append(sp(6))
story.append(info_box("What your doctor may see on examination:", [
"Red, swollen tonsils (bilateral in most cases)",
"White or yellow spots/patches on the tonsils ('follicular tonsillitis')",
"Swollen, tender lymph nodes under the jaw or in the neck",
]))
# Home Care
story += section_heading("Home Care & Self-Treatment")
story.append(Paragraph(
"For most people, tonsillitis gets better on its own with simple home measures:",
sBody
))
home = [
"Rest as much as possible; stay home while you have a fever",
"Drink plenty of fluids — cool water, warm honey-lemon drinks, ice lollies",
"Gargle with warm salt water several times a day to soothe your throat",
"Take paracetamol or ibuprofen as directed to relieve pain and reduce fever",
"--Do NOT give aspirin to children under 16",
"Eat soft, cool foods if swallowing is painful (yoghurt, ice cream, soup)",
"Avoid smoking and smoke-filled environments",
"Throat lozenges may provide short-term relief",
]
for h in home:
if h.startswith("--"):
story.append(sub_bullet(h[2:]))
else:
story.append(bullet_para(h))
# Antibiotics
story += section_heading("Do I Need Antibiotics?")
story.append(Paragraph(
"Not always. Because most tonsillitis is caused by viruses, antibiotics will not "
"help in those cases. Your doctor will decide based on your symptoms and examination.",
sBody
))
story.append(sp(4))
story.append(info_box("Your doctor may prescribe antibiotics if:", [
"Your symptoms are not improving after 48–72 hours",
"There are signs of a bacterial ('strep') infection",
"You are very unwell or at high risk of complications",
]))
story.append(sp(6))
story.append(info_box("If antibiotics are prescribed:", [
"Penicillin V (Phenoxymethylpenicillin) is the usual first choice",
"Complete the full course, even if you feel better",
"Tell your doctor if you are allergic to penicillin — alternatives are available",
]))
story.append(sp(6))
story.append(caution_box(
"⚠️ Important — Glandular Fever Warning:",
["If you are also extremely tired, have swollen glands all over your body, and a high "
"fever, you may have glandular fever (Epstein-Barr virus). In this case, amoxicillin "
"and ampicillin MUST NOT be given — they can cause a severe widespread rash in almost "
"all patients with this condition."]
))
# When to seek care
story += section_heading("When to Seek Medical Care")
story.append(sp(4))
story.append(info_box("📞 See Your Doctor or GP If…", [
"Symptoms are not improving after 3–4 days of home care",
"Fever persists or worsens despite paracetamol/ibuprofen",
"You are having significant difficulty swallowing fluids",
"Swollen glands in the neck are getting larger",
"You have a rash developing alongside your sore throat",
"This is a recurrent episode (tonsillitis that keeps coming back)",
"You are concerned about your or your child's condition",
]))
story.append(sp(8))
story.append(warn_box("🚨 GO TO A&E / CALL 999 IMMEDIATELY IF:", ""))
story.append(warn_box("", [
"You are unable to swallow even liquids or saliva",
"You have severe difficulty breathing or noisy breathing (stridor)",
"Your voice sounds very muffled ('hot potato voice') with new jaw stiffness — may indicate a throat abscess",
"You cannot open your mouth properly (trismus)",
"One side of your throat looks very swollen and the uvula is pushed to one side",
"You have severe neck swelling or neck stiffness",
"High fever with rigors (violent shivering) and feeling extremely unwell",
"A young child is drooling excessively and unable to swallow",
]))
story.append(sp(6))
story.append(caution_box("About Peritonsillar Abscess (Quinsy):", [
"A collection of pus can sometimes develop around a tonsil ('quinsy'). Signs include "
"severe one-sided throat pain, difficulty opening your mouth, a muffled voice, and "
"the uvula being pushed to one side. This requires urgent hospital treatment — usually "
"drainage of the abscess and IV antibiotics."
]))
# Parents
story += section_heading("A Note for Parents")
parents = [
"Tonsillitis is very common in children aged 5–15 years",
"Streptococcal ('strep') tonsillitis is more common in children than adults — up to 35% of childhood sore throats may be GABHS",
"If a rapid strep test (RADT) is done: a negative test in children should be backed up with a throat culture",
"Keep your child home from school until they are fever-free for 24 hours",
"Ensure they drink enough fluids — dehydration can worsen quickly in young children",
"Do NOT give aspirin to anyone under 16",
"Seek medical attention sooner if a young child is drooling, cannot swallow, or has noisy breathing",
]
for p in parents:
story.append(bullet_para(p))
# Recurrent / Tonsillectomy section
story += section_heading("Recurrent Tonsillitis & Tonsillectomy")
story.append(Paragraph(
"Some people get tonsillitis repeatedly. If this is happening to you or your child, "
"speak to your doctor about a referral to an ENT (Ear, Nose & Throat) specialist.",
sBody
))
story.append(Paragraph("Tonsillectomy (surgical removal) may be recommended if:", sBody))
tonsil_ind = [
"7 or more episodes in one year",
"5 or more episodes per year for 2 consecutive years",
"3 or more episodes per year for 3 consecutive years",
"Tonsillitis causing significant time off school or work",
"A peritonsillar abscess has developed",
"The tonsils are so large they are causing breathing problems or sleep apnoea",
]
for t in tonsil_ind:
story.append(bullet_para(t))
story.append(Paragraph(
"Tonsillectomy is a safe, routine operation. Your ENT specialist will discuss the "
"benefits and risks with you in detail.",
sBody
))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════════════════════════
# PART 3 — TONSILLECTOMY: DETAILED CLINICAL GUIDE
# ═══════════════════════════════════════════════════════════════════════════════
story.append(part_banner("PART 3", "Tonsillectomy — Detailed Clinical Guide"))
story.append(sp(14))
# Overview
story += section_heading("Overview")
story.append(Paragraph(
"Tonsillectomy is surgical removal of the palatine tonsils and is one of the most "
"commonly performed ENT operations worldwide. In the UK, approximately 50,000 "
"procedures are performed annually. The proportion done for obstructive indications "
"(vs infection) has been rising year on year, partly due to increasing recognition of "
"obstructive sleep apnoea (OSA) and its consequences in children.",
sBody
))
# Indications
story += section_heading("Indications")
story.append(Paragraph("<b>Absolute Indications:</b>", sH3))
abs_data = [
["Indication", "Notes"],
["Tonsillar hypertrophy causing upper airway obstruction", "Obstructive sleep apnoea, cor pulmonale, or chronic respiratory obstruction"],
["Suspected tonsillar malignancy", "Unilateral enlargement; search for unknown primary; treatment of early-stage cancer (e.g. TORS)"],
]
story.append(std_table(abs_data[0], abs_data[1:], col_widths=[7*cm, 9.5*cm]))
story.append(sp(8))
story.append(Paragraph("<b>Relative Indications:</b>", sH3))
rel_data = [
["Indication", "Notes"],
["Recurrent acute tonsillitis", "Must meet Paradise frequency criteria (see below); must be well-documented"],
["Chronic tonsillitis", "Persistent sore throat, tonsillar debris, tonsilloliths, Actinomyces infection"],
["Peritonsillar abscess (quinsy)", "History of one or more episodes"],
["Tonsillar asymmetry", "Part of work-up; exclude malignancy"],
["Febrile convulsions from tonsillitis", "Recurrent fever-associated seizures"],
["Diphtheria carrier state", "Chronic asymptomatic carriage"],
["Systemic disease from GABHS", "Rheumatic fever, glomerulonephritis"],
["Surgical access", "To parapharyngeal space or elongated styloid process"],
]
story.append(std_table(rel_data[0], rel_data[1:], col_widths=[5.5*cm, 11*cm]))
# Paradise Criteria
story += section_heading("The Paradise Criteria")
story.append(Paragraph(
"Derived from Paradise's landmark 1984 RCT and adopted in SIGN/ENTUK guidelines, "
"these define when surgery for recurrent infection is justified. "
"<b>All of the following must be met:</b>",
sBody
))
story.append(bullet_para("Sore throats are due to tonsillitis (not other causes)"))
story.append(bullet_para("Episodes are disabling and prevent normal functioning"))
story.append(bullet_para("Frequency — any ONE of the following:"))
story.append(sub_bullet("≥7 well-documented, clinically significant episodes in the preceding year"))
story.append(sub_bullet("≥5 such episodes in each of the preceding 2 years"))
story.append(sub_bullet("≥3 such episodes in each of the preceding 3 years"))
story.append(sp(6))
story.append(info_box("Evidence Base", [
"The NESTAC multicentre RCT broadly confirmed the Paradise criteria threshold",
"Children NOT meeting the criteria showed no significant benefit from surgery over watchful waiting",
"Adenotonsillectomy is treatment of choice for paediatric OSA — improvement in 90% of cases, including behaviour, growth and development",
"Scottish Tonsillectomy Audit (>5,000 patients): 97% satisfaction rate at 1 year post-tonsillectomy",
"Quality of life studies consistently show significant pre-operative impairment and significant post-operative improvement",
"In adults: many improve spontaneously; risk-benefit must be carefully weighed",
]))
# Pre-operative
story += section_heading("Pre-operative Considerations")
pre = [
"Ideally performed when tonsils are NOT acutely infected (wait at least 4–6 weeks after an acute episode)",
"Discuss factors that may increase bleeding tendency (anticoagulants, bleeding disorders, NSAIDs)",
"Blood group and screen for children under 15 kg",
"Blood transfusion is rarely required but should be available",
"Informed consent: discuss and quantify risk of post-operative haemorrhage (use surgeon's own/departmental figures if available)",
]
for p in pre:
story.append(bullet_para(p))
# Technique
story += section_heading("Surgical Techniques")
story.append(Paragraph(
"The patient is positioned supine under general anaesthesia with the mouth held open "
"by a Boyle-Davis gag.",
sBody
))
story.append(Paragraph("<b>1. Cold Steel Dissection (Gold Standard)</b>", sH3))
story.append(Paragraph(
"The most common and best-evidenced technique. The mucosa of the anterior faucial "
"pillar is incised and the tonsil capsule identified. Blunt dissection separates the "
"tonsil from the pharyngeal muscles in the plane of loose areolar tissue. The tonsil "
"is excised completely down to a small inferior pedicle, then separated from the "
"lingual tonsil. Haemostasis is achieved with ties (ligatures) and/or bipolar "
"diathermy. The NPTA and Swedish registry data confirm cold steel with ties has the "
"lowest secondary haemorrhage rate of all techniques.",
sBody
))
story.append(Paragraph("<b>2. Diathermy Tonsillectomy</b>", sH3))
story.append(Paragraph(
"Bipolar dissection reduces intra-operative bleeding but increases post-operative "
"pain vs cold steel. Monopolar diathermy has the highest secondary haemorrhage and "
"pain rates — the NPTA recommends against its use; surgeons should switch to "
"alternative techniques.",
sBody
))
story.append(Paragraph("<b>3. Coblation® Tonsillectomy</b>", sH3))
story.append(Paragraph(
"A bipolar radiofrequency probe simultaneously coagulates and cuts tissue at "
"relatively low temperatures. Post-operative pain may be less, but the NPTA found "
"post-operative bleeding rates were unacceptably high. NICE permits Coblation® "
"provided surgeons are appropriately trained.",
sBody
))
story.append(Paragraph("<b>4. Ultrasonic Dissection</b>", sH3))
story.append(Paragraph(
"Oscillating blade acts as both cutter and coagulator. Some studies claim reduced "
"pain; overall evidence of benefit is lacking.",
sBody
))
story.append(Paragraph("<b>5. Laser Tonsillectomy</b>", sH3))
story.append(Paragraph(
"Evidence shows greater secondary bleeding rates and more pain compared to cold steel. "
"Not widely recommended as a primary technique.",
sBody
))
story.append(Paragraph("<b>6. Tonsillotomy (Intracapsular / Partial Tonsillectomy)</b>", sH3))
story.append(Paragraph(
"Removes part of the lymphoid tissue leaving the capsule intact. Techniques include "
"microdebrider, laser, or radiofrequency Coblation®. Particularly used in young "
"children with OSA to debulk tonsils while preserving functioning lymphoid tissue. "
"Some studies show better recovery (faster pain resolution, lower secondary "
"haemorrhage) vs total tonsillectomy for obstructive indications.",
sBody
))
story.append(sp(8))
# Haemorrhage table
story.append(Paragraph("<b>Haemorrhage Rates by Technique (NPTA, n = 33,921):</b>", sH3))
hae_data = [
["Surgical Technique", "Primary Haemorrhage (%)", "Secondary Haemorrhage (%)"],
["Cold steel + ties/packs", "0.8", "1.0 ✓ (lowest)"],
["Cold steel + monopolar diathermy", "0.5", "2.4"],
["Cold steel + bipolar diathermy", "0.5", "2.3"],
["Monopolar diathermy forceps", "1.1", "5.5 ✗ (highest)"],
["Bipolar diathermy forceps", "0.4", "4.3"],
["Bipolar diathermy scissors", "0.6", "4.6"],
["Coblation®", "1.0", "3.6"],
]
story.append(std_table(hae_data[0], hae_data[1:], col_widths=[8.5*cm, 4*cm, 4*cm]))
# Post-operative care
story += section_heading("Post-operative Care")
postop = [
"Close observation for haemorrhage: regular pulse and BP monitoring; watch for excessive swallowing (sign of concealed bleeding)",
"Position patient on their side (tonsillar/recovery position) to reduce aspiration risk",
"Encourage normal eating post-operatively — chewing helps healing and reduces post-op adhesions",
"Regular oral analgesics (paracetamol, NSAIDs — concerns about NSAIDs and bleeding have been shown unfounded)",
"Most patients go home the same day or the following day",
"Warn about referred otalgia (ear pain from glossopharyngeal nerve — not an ear infection)",
"Warn about secondary haemorrhage — can occur up to 10 days post-operatively",
"White slough in the tonsillar fossa is normal and expected",
]
for p in postop:
story.append(bullet_para(p))
# Complications
story += section_heading("Complications")
comp2_data = [
["Complication", "Timing / Details", "Management"],
["Primary haemorrhage", "Within 24 hours; most common immediate complication", "Local pressure (mild); return to theatre (significant)"],
["Secondary haemorrhage", "24 h – 2 weeks; NPTA readmission rate 4.57%; 1.44% required return to theatre; usually streptococcal infection of granulating bed", "IV broad-spectrum antibiotics; theatre if severe; hydrogen peroxide gargles; remove residual clot"],
["Infection / halitosis", "Post-operative", "Antibiotics according to severity"],
["Pain / referred otalgia", "Expected ≥1 week; return to school/work: 1–2 weeks", "Regular analgesia; NSAIDs preferred"],
["Post-operative airway obstruction", "Especially in children with OSA", "Monitor post-extubation; consider HDU/ICU"],
["Velopharyngeal insufficiency", "Rare — hypernasal speech", "Speech therapy; surgical correction if persistent"],
["TMJ dysfunction", "From excessive mouth opening", "Conservative management"],
["Glossopharyngeal nerve injury", "From over-dissection", "Usually temporary"],
["Grisel syndrome", "Non-traumatic C1-C2 atlantoaxial subluxation secondary to inflammatory neck process", "Imaging, orthopaedic/neurosurgical review"],
["Carotid sheath injury", "Rare; dissection beyond pharyngeal muscles", "Emergency vascular surgery"],
["Mortality", "~1 in 25,000", "Causes: haemorrhage, airway obstruction, anaesthesia"],
]
story.append(std_table(comp2_data[0], comp2_data[1:], col_widths=[4.5*cm, 6*cm, 6*cm]))
# Anaesthesia
story += section_heading("Peri-operative Anaesthesia & Analgesia")
story.append(Paragraph("<b>Anaesthesia:</b>", sH3))
ana = [
"Total IV anaesthesia (TIVA) with propofol + remifentanil — fast wake-up; propofol has useful antiemetic effect",
"Inhalational agents for intubation avoid the need for muscle relaxants and speed up reversal",
]
for a in ana:
story.append(bullet_para(a))
story.append(sp(4))
story.append(Paragraph("<b>Analgesia:</b>", sH3))
analg_data = [
["Agent", "Role / Notes"],
["Paracetamol", "Drug of choice — safe and efficacious"],
["NSAIDs (e.g. ibuprofen, diclofenac)", "Cause less PONV than narcotics; concerns about platelet-related bleeding have been shown unfounded"],
["Opioids / Narcotics", "Potent emetic effect — use with caution; not first-line"],
["Corticosteroids (e.g. dexamethasone)", "Reduce PONV and pain; given peri-operatively"],
["Dexmedetomidine (paediatric)", "Emerging evidence for use in paediatric tonsillectomy (2025 meta-analysis)"],
]
story.append(std_table(analg_data[0], analg_data[1:], col_widths=[6*cm, 10.5*cm]))
story.append(sp(6))
# NPTA Recommendations
story += section_heading("NPTA Recommendations (Royal College of Surgeons of England)")
npta = [
"Surgeons must explain and quantify the risk of post-operative haemorrhage during consent — use surgeon's own/departmental figures where possible",
"Monopolar diathermy should be abandoned — no advantages over other methods; associated with highest secondary haemorrhage and pain rates",
"All trainees must become competent in cold steel dissection with ties before learning other techniques",
"Trainees must be supervised by a senior surgeon until competency is achieved",
"Surgeons adopting new techniques (e.g. Coblation®) must undergo appropriate training first",
"All ENT departments should hold regular morbidity and mortality meetings to monitor adverse tonsillectomy outcomes",
"Data should include: technique used, instruments, power settings, difficulties encountered",
]
for n in npta:
story.append(bullet_para(n))
# Recent Evidence
story += section_heading("Recent Evidence (2024–2026)")
re_data = [
["PMID", "Year", "Title / Focus"],
["39789114", "2025", "Systematic review & meta-analysis of pain management after tonsillectomy (Sci Rep)"],
["40646381", "2025", "Dexmedetomidine in paediatric tonsillectomy — systematic review with meta-analysis (Can J Anaesth)"],
["41420409", "2026", "Effects of pain-controlling agents in paediatric tonsillectomy — network meta-analysis (Clin Otolaryngol)"],
["40851448", "2025", "Laser vs. cold steel dissection tonsillectomy in recurrent acute tonsillitis — meta-analysis (Lasers Surg Med)"],
["39501298", "2024", "Treatment of acute pharyngitis in children — Italian intersociety consensus (Ital J Pediatr)"],
["39243792", "2025", "Optimal antibiotic duration for upper & lower respiratory tract infections — umbrella review (Lancet Infect Dis)"],
]
story.append(std_table(re_data[0], re_data[1:], col_widths=[2.5*cm, 1.8*cm, 12.2*cm]))
story.append(sp(16))
story.append(hr(MID_GRAY, 0.5))
story.append(sp(4))
story.append(Paragraph(
"Sources: Scott-Brown's Otorhinolaryngology Head & Neck Surgery Vol 2 · Bailey and Love's Short Practice of Surgery 28th Ed · "
"Harrison's Principles of Internal Medicine 22E · Goldman-Cecil Medicine · K.J. Lee's Essential Otolaryngology · "
"Tintinalli's Emergency Medicine · Symptom to Diagnosis 4th Ed · NPTA (Royal College of Surgeons of England) · PubMed 2024–2026",
sSource
))
story.append(Paragraph(
"This document was generated by Orris Medical AI on July 12, 2026. For clinical use, always verify against current local guidelines.",
sNote
))
# ── BUILD ─────────────────────────────────────────────────────────────────────
doc.build(story)
print("PDF created successfully.")
cd /home/daytona/workspace/tonsillitis-pdf && python3 generate_pdf.py 2>&1
python3 -c " from pypdf import PdfReader r = PdfReader('/home/daytona/workspace/…
Tonsillitis Complete Notes
PDF Document · PDF