Thyroplasty essay answer for PG exam with Images-diagrams- flowcharts under 800 words
thyroplasty laryngeal framework surgery vocal cord medialization
Isshiki thyroplasty types classification laryngeal framework
┌─────────────────────────────────────────────────────────────────┐
│ ISSHIKI CLASSIFICATION OF THYROPLASTY │
├──────────┬──────────────────────┬───────────────────────────── │
│ TYPE │ PROCEDURE │ INDICATION │
├──────────┼──────────────────────┼───────────────────────────── │
│ Type I │ Medialization │ Unilateral vocal fold │
│ │ (implant via window) │ paralysis / paralytic │
│ │ │ dysphonia │
├──────────┼──────────────────────┼───────────────────────────── │
│ Type II │ Lateralization │ Spasmodic dysphonia / │
│ │ (vocal fold pushed │ adductor spasm │
│ │ laterally) │ │
├──────────┼──────────────────────┼───────────────────────────── │
│ Type III │ Relaxation │ High pitch voice / mutational │
│ │ (shorten AP diameter)│ falsetto / MTD │
├──────────┼──────────────────────┼───────────────────────────── │
│ Type IV │ Tension increase │ Low pitch / female-to-male │
│ │ (lengthen AP diam.) │ gender dysphoria │
└──────────┴──────────────────────┴───────────────────────────── ┘
Most commonly tested = Type I (Medialization Thyroplasty)
DYSPHONIA / ASPIRATION
│
Laryngoscopy + LEMG
│
┌────────────┴────────────┐
│ │
Recovery No recovery
anticipated? anticipated
│ │
Yes Medialization
│ Thyroplasty
Observe ≤6 months
│
No improvement
│
Injection or Thyroplasty


| Material | Notes |
|---|---|
| Silastic (Silicone) | Most widely used; VoCoM system (3–8 mm range) |
| Gore-Tex (ePTFE) | Flexible, adjustable; placed as strip via inferior approach |
| Hydroxyapatite | Prefabricated system; bioinert |
| Titanium | Montgomery implant; stable, MRI-compatible |

Type I Thyroplasty
+
Arytenoid Adduction ──► Corrects posterior glottic gap
+
Laryngeal Reinnervation ─► Maintains vocal fold tone long-term
| Complication | Management |
|---|---|
| Airway compromise / hematoma | Drain, airway support |
| Implant extrusion / migration | Revision surgery |
| Infection | Antibiotics ± implant removal |
| Suboptimal voice (under/over-medialization) | Revision; adjust implant size |
| Persistent posterior glottic gap | Add arytenoid adduction |

Thyroplasty essay answer
thyroplasty medialization vocal cord paralysis surgery implant
Isshiki thyroplasty type III type IV arytenoid adduction laryngeal surgery diagram
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace not found"
mkdir -p /home/daytona/workspace/thyroplasty && echo "created"
~/thyroplasty/build_pdf.py
#!/usr/bin/env python3
"""Build Thyroplasty PG Exam Essay PDF using reportlab."""
import urllib.request
import os
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
Image, HRFlowable, KeepTogether
)
from reportlab.platypus.flowables import PageBreak
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Polygon, Group
from reportlab.graphics.charts.textlabels import Label
from reportlab.graphics import renderPDF
# ── Styles ─────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
DARK_BLUE = colors.HexColor("#1a3a5c")
MID_BLUE = colors.HexColor("#2e6da4")
LIGHT_BLUE = colors.HexColor("#dce8f5")
ACCENT = colors.HexColor("#c0392b")
TABLE_HDR = colors.HexColor("#2e6da4")
TABLE_ALT = colors.HexColor("#eaf2fb")
GRAY = colors.HexColor("#555555")
GREEN = colors.HexColor("#1e7e44")
ORANGE = colors.HexColor("#e67e22")
title_style = ParagraphStyle(
"TitleStyle", parent=styles["Title"],
fontSize=22, textColor=DARK_BLUE, spaceAfter=4,
fontName="Helvetica-Bold", alignment=TA_CENTER
)
subtitle_style = ParagraphStyle(
"SubtitleStyle", parent=styles["Normal"],
fontSize=11, textColor=MID_BLUE, spaceAfter=14,
fontName="Helvetica-Oblique", alignment=TA_CENTER
)
h1_style = ParagraphStyle(
"H1", parent=styles["Heading1"],
fontSize=13, textColor=colors.white, spaceAfter=6, spaceBefore=14,
fontName="Helvetica-Bold", backColor=DARK_BLUE,
leftIndent=-6, rightIndent=-6, borderPad=4
)
h2_style = ParagraphStyle(
"H2", parent=styles["Heading2"],
fontSize=11, textColor=DARK_BLUE, spaceAfter=4, spaceBefore=10,
fontName="Helvetica-Bold", borderPad=2,
borderWidth=0, leftIndent=0
)
body_style = ParagraphStyle(
"Body", parent=styles["Normal"],
fontSize=9.5, textColor=colors.HexColor("#222222"),
leading=14, spaceAfter=6, fontName="Helvetica", alignment=TA_JUSTIFY
)
bullet_style = ParagraphStyle(
"Bullet", parent=body_style,
leftIndent=14, bulletIndent=6, spaceAfter=3
)
caption_style = ParagraphStyle(
"Caption", parent=styles["Normal"],
fontSize=8, textColor=GRAY, alignment=TA_CENTER,
fontName="Helvetica-Oblique", spaceAfter=8, spaceBefore=2
)
bold_inline = ParagraphStyle(
"BoldInline", parent=body_style,
fontName="Helvetica-Bold"
)
key_box = ParagraphStyle(
"KeyBox", parent=body_style,
backColor=colors.HexColor("#fff8e1"),
borderColor=colors.HexColor("#f0ad00"),
borderWidth=1, borderPad=6,
leftIndent=8, rightIndent=8
)
# ── Image helper ────────────────────────────────────────────────────────────
IMG_DIR = "/home/daytona/workspace/thyroplasty/imgs"
os.makedirs(IMG_DIR, exist_ok=True)
IMAGE_URLS = {
"window_marking": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_88915221ccc6a3749bb2489294191207de781af56aa2bfc17b800016af753846.jpg",
"sizer": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_fdcd1f5d2da41fa7f402f0159bf60a8f8fb798e111f303463e5292bfe17f5ae2.jpg",
"cartilage_graft":"https://cdn.orris.care/cdss_images/pmc_clinical_VQA_692510aedb363f0a53fe2203c070bbd70dbc51ebfab593dbebd91641cdc9e121.jpg",
"post_op": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_31436d2e168ac6455b67521e2632dea74cfd5634b153a9d95185e705d7301f77.jpg",
"vois_system": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_0288033403b87c2afc7345ccf2645d5e694791e56bae8b275a67bff47e13d534.jpg",
}
def fetch_image(key):
path = os.path.join(IMG_DIR, key + ".jpg")
if not os.path.exists(path):
try:
urllib.request.urlretrieve(IMAGE_URLS[key], path)
except Exception as e:
print(f" [WARN] Could not fetch {key}: {e}")
return None
return path
# Pre-fetch all
print("Fetching images...")
for k in IMAGE_URLS:
r = fetch_image(k)
print(f" {'OK' if r else 'FAIL'} {k}")
def make_img(key, width=7*cm, caption=""):
path = fetch_image(key)
if not path or not os.path.exists(path):
return []
elems = [Image(path, width=width, height=width*0.72, kind="proportional")]
if caption:
elems.append(Paragraph(caption, caption_style))
return elems
# ── Flowchart: Isshiki Classification ───────────────────────────────────────
def isshiki_flowchart():
d = Drawing(480, 180)
boxes = [
(0, "TYPE I\nMEDIALIZATION", "Unilateral VF paralysis\nVF bowing • Sulcus vocalis", MID_BLUE),
(120, "TYPE II\nLATERALIZATION","Spasmodic dysphonia\nAdductor spasm", colors.HexColor("#8e44ad")),
(240, "TYPE III\nRELAXATION", "Mutational falsetto\nHigh pitch voice", GREEN),
(360, "TYPE IV\nTENSION ↑", "Low pitch\nTransgender (FTM)", ORANGE),
]
for x, title, desc, col in boxes:
# box
d.add(Rect(x+2, 10, 108, 160, fillColor=col, strokeColor=colors.white, strokeWidth=1.5, rx=6, ry=6))
# title
for i, line in enumerate(title.split("\n")):
lbl = String(x+56, 155-(i*14), line, textAnchor="middle",
fontSize=8.5, fillColor=colors.white, fontName="Helvetica-Bold")
d.add(lbl)
# separator line
d.add(Line(x+12, 128, x+100, 128, strokeColor=colors.white, strokeWidth=0.8))
# desc
for i, line in enumerate(desc.split("\n")):
lbl = String(x+56, 110-(i*14), line, textAnchor="middle",
fontSize=7.5, fillColor=colors.white, fontName="Helvetica")
d.add(lbl)
return d
# ── Flowchart: Patient Selection ─────────────────────────────────────────────
def patient_selection_flowchart():
d = Drawing(440, 310)
def box(x, y, w, h, text, col, tcol=colors.white, fs=8):
d.add(Rect(x, y, w, h, fillColor=col, strokeColor=colors.HexColor("#aaaaaa"), strokeWidth=0.8, rx=5, ry=5))
lines = text.split("\n")
cy = y + h/2 + (len(lines)-1)*5
for line in lines:
d.add(String(x+w/2, cy, line, textAnchor="middle", fontSize=fs,
fillColor=tcol, fontName="Helvetica-Bold" if col!=colors.white else "Helvetica"))
cy -= 12
def arrow(x1, y1, x2, y2):
d.add(Line(x1, y1, x2, y2, strokeColor=GRAY, strokeWidth=1.2))
# arrowhead
d.add(Polygon([x2, y2, x2-4, y2+7, x2+4, y2+7], fillColor=GRAY, strokeColor=GRAY))
def label(x, y, text, col=GRAY):
d.add(String(x, y, text, textAnchor="middle", fontSize=7.5, fillColor=col, fontName="Helvetica-Oblique"))
# Start
box(145, 270, 150, 28, "DYSPHONIA / ASPIRATION", DARK_BLUE)
arrow(220, 270, 220, 248)
box(130, 220, 180, 28, "Laryngoscopy + LEMG", MID_BLUE)
arrow(220, 220, 220, 198)
# Diamond
d.add(Polygon([220,198, 290,175, 220,152, 150,175], fillColor=LIGHT_BLUE, strokeColor=MID_BLUE, strokeWidth=1.2))
d.add(String(220, 181, "Recovery", textAnchor="middle", fontSize=7.5, fontName="Helvetica-Bold", fillColor=DARK_BLUE))
d.add(String(220, 169, "Anticipated?", textAnchor="middle", fontSize=7.5, fontName="Helvetica-Bold", fillColor=DARK_BLUE))
# YES branch (left)
arrow(150, 175, 100, 175)
label(125, 180, "YES", GREEN)
box(20, 161, 80, 28, "Observe\n≤ 6 months", colors.HexColor("#d5f5e3"), colors.HexColor("#1e7e44"))
arrow(60, 161, 60, 139)
box(10, 111, 100, 28, "No improvement?\nVoice therapy", colors.HexColor("#fdebd0"), ORANGE)
arrow(60, 111, 60, 89)
box(10, 61, 100, 28, "Injection\nthyroplasty", MID_BLUE)
# NO branch (right)
arrow(290, 175, 340, 175)
label(316, 180, "NO", ACCENT)
box(310, 161, 120, 28, "Medialization\nThyroplasty Type I", DARK_BLUE)
arrow(370, 161, 370, 139)
d.add(Rect(310, 100, 120, 39, fillColor=colors.HexColor("#fef9e7"), strokeColor=ORANGE, strokeWidth=1.2, rx=4, ry=4))
d.add(String(370, 126, "± Arytenoid Adduction", textAnchor="middle", fontSize=7.5, fillColor=ORANGE, fontName="Helvetica-Bold"))
d.add(String(370, 113, "± Reinnervation", textAnchor="middle", fontSize=7.5, fillColor=ORANGE, fontName="Helvetica-Bold"))
return d
# ── Flowchart: Surgical Steps ──────────────────────────────────────────────
def surgical_steps_flowchart():
d = Drawing(480, 52)
steps = [
"Supine\nLocal anaes.",
"5 cm\nincision",
"Expose thyroid\nlamina",
"Create\nwindow\n6×10mm",
"Elevate inner\nperichondrium",
"Size implant\n(phonate test)",
"Insert &\nsecure implant",
"Drain +\nClose",
]
cols = [MID_BLUE, MID_BLUE, DARK_BLUE, ACCENT, DARK_BLUE, GREEN, DARK_BLUE, MID_BLUE]
w = 56
for i, (step, col) in enumerate(zip(steps, cols)):
x = i * (w + 4)
d.add(Rect(x, 2, w, 48, fillColor=col, strokeColor=colors.white, strokeWidth=1, rx=4, ry=4))
lines = step.split("\n")
cy = 36 - (len(lines)-1)*9
for line in lines:
d.add(String(x+w/2, cy, line, textAnchor="middle", fontSize=6.8,
fillColor=colors.white, fontName="Helvetica-Bold"))
cy -= 10
if i < len(steps)-1:
ax = x + w + 2
d.add(Line(ax-1, 26, ax+2, 26, strokeColor=colors.white, strokeWidth=1.5))
return d
# ── Build document ──────────────────────────────────────────────────────────
OUTPUT = "/home/daytona/workspace/thyroplasty/Thyroplasty_PG_Essay.pdf"
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm, topMargin=2*cm, bottomMargin=2*cm
)
story = []
# ── Title ──
story.append(Paragraph("THYROPLASTY", title_style))
story.append(Paragraph("Laryngeal Framework Surgery — PG Exam Essay", subtitle_style))
story.append(HRFlowable(width="100%", thickness=2, color=DARK_BLUE, spaceAfter=10))
# ── 1. Introduction ──
story.append(Paragraph("1. DEFINITION & INTRODUCTION", h1_style))
story.append(Paragraph(
"<b>Thyroplasty</b> (Laryngeal Framework Surgery / Phonosurgery) refers to a group of "
"external surgical procedures performed on the thyroid cartilage to alter vocal fold "
"<b>position, tension, or length</b> — thereby correcting dysphonia or aspiration. "
"The concept was first described by <b>Payr (1915)</b> and later systematically classified "
"into four types by <b>Isshiki et al. (1974)</b>. It is now considered the procedure of choice "
"for permanent unilateral vocal fold paralysis.",
body_style
))
# ── 2. Isshiki Classification ──
story.append(Paragraph("2. ISSHIKI CLASSIFICATION (1974)", h1_style))
story.append(isshiki_flowchart())
story.append(Spacer(1, 4))
iso_data = [
[Paragraph("<b>Type</b>", bold_inline), Paragraph("<b>Procedure</b>", bold_inline),
Paragraph("<b>Mechanism</b>", bold_inline), Paragraph("<b>Indications</b>", bold_inline)],
["Type I", "Medialization", "Implant pushes VF medially", "Unilateral VF paralysis, VF bowing, sulcus vocalis"],
["Type II", "Lateralization", "VF pushed laterally", "Spasmodic dysphonia, adductor spasm"],
["Type III", "Relaxation", "Shorten A-P diameter → ↓ tension → ↓ pitch", "Mutational falsetto, high pitch, MTD"],
["Type IV", "Tension ↑", "Lengthen A-P diameter → ↑ tension → ↑ pitch", "Low pitch, transgender (FTM) voice"],
]
t = Table(iso_data, colWidths=[1.4*cm, 2.8*cm, 6.2*cm, 6.4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TABLE_HDR),
("TEXTCOLOR", (0,0), (-1,0), colors.white),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, TABLE_ALT]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#c0c0c0")),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING",(0,0), (-1,-1), 5),
]))
story.append(t)
story.append(Spacer(1, 6))
story.append(Paragraph(
"⭐ <b>Most frequently examined = Type I (Medialization Thyroplasty)</b>",
key_box
))
story.append(Spacer(1, 6))
# ── 3. Type I — Medialization Thyroplasty ──
story.append(Paragraph("3. TYPE I — MEDIALIZATION THYROPLASTY", h1_style))
story.append(Paragraph("Indications", h2_style))
ind_data = [
[Paragraph("<b>Primary Indications</b>", bold_inline), Paragraph("<b>Other Indications</b>", bold_inline)],
["• Unilateral vocal fold paralysis (permanent)\n• Paralytic dysphonia with aspiration",
"• Vocal fold bowing (presbylaryngis / aging)\n• Sulcus vocalis\n• Cricothyroid joint fixation\n• Soft tissue defect post tumour excision"],
]
t2 = Table(ind_data, colWidths=[8.5*cm, 8.5*cm])
t2.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), LIGHT_BLUE),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#c0c0c0")),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story.append(t2)
story.append(Spacer(1, 6))
story.append(Paragraph("Advantages & Disadvantages", h2_style))
adv_data = [
[Paragraph("<b>Advantages</b>", bold_inline), Paragraph("<b>Disadvantages</b>", bold_inline)],
["✔ Local anaesthesia → real-time voice monitoring\n✔ Reversible (implant removable)\n✔ Structural integrity of VF preserved\n✔ Outpatient procedure possible\n✔ Durable, long-term result",
"✗ Open surgical procedure\n✗ Technically demanding\n✗ Posterior glottic closure may be limited\n✗ Cannot correct arytenoid malposition alone"],
]
t3 = Table(adv_data, colWidths=[8.5*cm, 8.5*cm])
t3.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), LIGHT_BLUE),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#c0c0c0")),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story.append(t3)
story.append(Spacer(1, 8))
# ── Patient selection flowchart ──
story.append(Paragraph("4. PATIENT SELECTION ALGORITHM", h1_style))
story.append(patient_selection_flowchart())
story.append(Spacer(1, 6))
# ── 5. Surgical Technique ──
story.append(Paragraph("5. SURGICAL TECHNIQUE", h1_style))
story.append(Paragraph("Anaesthesia: <b>Local anaesthesia + sedation</b> (NO general anaesthesia — patient must phonate intraoperatively)", body_style))
story.append(Spacer(1, 4))
story.append(surgical_steps_flowchart())
story.append(Spacer(1, 8))
story.append(Paragraph("Step-by-Step Details", h2_style))
steps_text = [
("<b>1. Position & incision:</b>", "Supine. 5-cm paramedian horizontal skin incision over middle thyroid lamina. Platysma divided. Subplatysmal flaps elevated to expose thyroid notch and inferior border."),
("<b>2. Exposure:</b>", "Strap muscles split in midline, retracted laterally. Outer perichondrium preserved intact. Ipsilateral lamina exposed."),
("<b>3. Window creation:</b>", "Cartilage window marked and excised: <b>6 mm (V) × 10 mm (H)</b> (VoCoM system) or 6 × 13 mm (Netterville). Window positioned <b>5–8 mm posterior to midline in women, 8–10 mm in men</b>. Superior border at the level of the true vocal fold (midpoint between anterior-inferior thyroid border and thyroid notch). Ossified cartilage removed with Kerrison punch or drill."),
("<b>4. Inner perichondrium:</b>", "Preserved and elevated circumferentially with laryngeal elevator to create a pocket in the paraglottic space."),
("<b>5. Sizing & voice testing:</b>", "Sizer templates (3–8 mm) inserted through window, rotated 90° (bevel superiorly). All retractors removed — patient phonates while sizer is repositioned in all four quadrants to identify optimal medialization. Voice monitored continuously."),
("<b>6. Implant insertion:</b>", "Definitive implant placed and secured with shim. If cartilage is thin → suture over titanium mini-plate. Overcorrection preferred (Isshiki) as post-op edema resolution may reduce medialization."),
("<b>7. Closure:</b>", "Suction drain deep to strap muscles. Strap muscles + platysma: 4-0 absorbable. Skin: 5-0 subcuticular. IV dexamethasone given."),
]
for bold, detail in steps_text:
story.append(Paragraph(f"{bold} {detail}", bullet_style))
story.append(Spacer(1, 8))
# ── Images row 1 ──
img1 = fetch_image("window_marking")
img2 = fetch_image("sizer")
if img1 and img2:
row = [[
[Image(img1, width=8*cm, height=5.5*cm), Paragraph("Thyroid cartilage exposed with window markings (blue lines)", caption_style)],
[Image(img2, width=8*cm, height=5.5*cm), Paragraph("Montgomery sizer inserted through thyroid window to determine implant size", caption_style)],
]]
img_table = Table([[
[Image(img1, width=7.8*cm, height=5.5*cm, kind="proportional"),
Paragraph("<i>Fig 1.</i> Exposed thyroid lamina with blue surgical markings delineating the window position.", caption_style)],
[Image(img2, width=7.8*cm, height=5.5*cm, kind="proportional"),
Paragraph("<i>Fig 2.</i> Montgomery sizer being placed through the thyroid window — determines implant size intraoperatively.", caption_style)],
]], colWidths=[8.5*cm, 8.5*cm])
img_table.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("ALIGN", (0,0), (-1,-1), "CENTER"),
]))
story.append(img_table)
story.append(Spacer(1, 6))
img3 = fetch_image("cartilage_graft")
img4 = fetch_image("post_op")
if img3 and img4:
img_table2 = Table([[
[Image(img3, width=7.8*cm, height=5.5*cm, kind="proportional"),
Paragraph("<i>Fig 3.</i> Autologous cartilage graft for medialization: (A) exposed lamina, (B) window creation, (C) harvested crescent graft, (D) implant insertion.", caption_style)],
[Image(img4, width=7.8*cm, height=5.5*cm, kind="proportional"),
Paragraph("<i>Fig 4.</i> Post-op outcomes: (a,b,d,e) laryngoscopy confirming vocal fold medialization; (c,f) CT scan showing implant in paraglottic space at 3–4 years.", caption_style)],
]], colWidths=[8.5*cm, 8.5*cm])
img_table2.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("ALIGN", (0,0), (-1,-1), "CENTER"),
]))
story.append(img_table2)
story.append(Spacer(1, 6))
# ── 6. Implant Materials ──
story.append(Paragraph("6. IMPLANT MATERIALS", h1_style))
impl_data = [
[Paragraph("<b>Material</b>", bold_inline), Paragraph("<b>System</b>", bold_inline), Paragraph("<b>Notes</b>", bold_inline)],
["Silastic (Silicone)", "VoCoM / Netterville", "Most widely used; customizable; 3–8 mm range"],
["Gore-Tex (ePTFE)", "McCulloch-Hoffman", "Flexible strip; layered into paraglottic space; easy revision"],
["Hydroxyapatite", "Cummings system", "Bioinert; pre-fabricated; 3–7 mm range; stabilized with shim"],
["Titanium", "Montgomery / APrevent VOIS", "Stable; MRI compatible; adjustable saline-filled cushion (VOIS)"],
["Autologous cartilage", "—", "Thyroid / auricular cartilage; no foreign body reaction"],
]
t4 = Table(impl_data, colWidths=[4.2*cm, 4.2*cm, 8.6*cm])
t4.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TABLE_HDR),
("TEXTCOLOR", (0,0), (-1,0), colors.white),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, TABLE_ALT]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#c0c0c0")),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING",(0,0), (-1,-1), 5),
]))
story.append(t4)
story.append(Spacer(1, 8))
# ── VOIS image ──
img5 = fetch_image("vois_system")
if img5:
story.append(Image(img5, width=13*cm, height=9*cm, kind="proportional"))
story.append(Paragraph("<i>Fig 5.</i> APrevent® VOIS system: (a) titanium-silicone implant, (b) tool set, (c,d) intraoperative videolaryngoscopy for glottal assessment, (e) saline injection to adjust medialization, (f) final implant placement.", caption_style))
story.append(Spacer(1, 8))
# ── 7. Combined Procedures ──
story.append(Paragraph("7. COMBINED PROCEDURES", h1_style))
story.append(Paragraph(
"Type I thyroplasty may fail to close the <b>posterior glottic gap</b> when the arytenoid "
"is displaced or rotated. In such cases, adjunct procedures are added:",
body_style
))
combo_data = [
[Paragraph("<b>Procedure</b>", bold_inline), Paragraph("<b>Indication</b>", bold_inline), Paragraph("<b>Mechanism</b>", bold_inline)],
["Arytenoid Adduction", "Posterior glottic gap; arytenoid malposition",
"Suture on muscular process simulates lateral cricoarytenoid muscle action → medial rotation of vocal process"],
["Laryngeal Reinnervation", "Flaccid paralysis; maintain VF tone",
"Ansa cervicalis → RLN reanastomosis; prevents VF atrophy; superior long-term results"],
["Vocal Fold Injection", "Temporary (recovery anticipated)",
"Hyaluronic acid / fat / Radiesse injected lateral to VF; effect 3–12 months"],
]
t5 = Table(combo_data, colWidths=[4*cm, 5*cm, 8*cm])
t5.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TABLE_HDR),
("TEXTCOLOR", (0,0), (-1,0), colors.white),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, TABLE_ALT]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#c0c0c0")),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING",(0,0), (-1,-1), 5),
]))
story.append(t5)
story.append(Spacer(1, 6))
story.append(Paragraph(
"🔬 <b>Evidence:</b> Animal models show arytenoid adduction + thyroplasty produces "
"<b>superior acoustic and aerodynamic results</b> vs thyroplasty alone in flaccid paralysis "
"(Isshiki; Cummings Key Points).",
key_box
))
story.append(Spacer(1, 8))
# ── 8. Complications ──
story.append(Paragraph("8. COMPLICATIONS", h1_style))
comp_data = [
[Paragraph("<b>Complication</b>", bold_inline), Paragraph("<b>Cause</b>", bold_inline), Paragraph("<b>Management</b>", bold_inline)],
["Airway compromise / haematoma", "Post-op swelling, haematoma", "Drain wound; airway support; ICU if needed"],
["Implant extrusion / migration", "Poorly secured shim; thin cartilage", "Revision surgery; suture over titanium plate"],
["Wound infection", "Contamination", "Antibiotics ± implant removal"],
["Suboptimal voice — under-medialization", "Implant too small / positioned incorrectly", "Revision thyroplasty; larger implant"],
["Suboptimal voice — over-medialization", "Implant too large", "Implant exchange; reduce size"],
["Persistent posterior gap", "Arytenoid displacement uncorrected", "Add arytenoid adduction"],
["Dysphagia / aspiration", "Overcorrection / implant bulk effect", "Usually resolves; revision if persistent"],
]
t6 = Table(comp_data, colWidths=[4.8*cm, 5.2*cm, 7*cm])
t6.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), ACCENT),
("TEXTCOLOR", (0,0), (-1,0), colors.white),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, colors.HexColor("#fdf0ef")]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#c0c0c0")),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("LEFTPADDING",(0,0), (-1,-1), 5),
]))
story.append(t6)
story.append(Spacer(1, 8))
# ── 9. Key Exam Points ──
story.append(Paragraph("9. HIGH-YIELD EXAM POINTS", h1_style))
key_points = [
"Isshiki classified thyroplasty into <b>Types I–IV (1974)</b>; Type I = Medialization = most common/tested",
"Done under <b>local anaesthesia</b> — patient phonates intraoperatively to guide implant positioning",
"Window dimensions: <b>6 × 10 mm</b> (VoCoM) | <b>6 × 13 mm</b> (Netterville)",
"Window position: <b>5–10 mm from midline</b> (♀ 5–8 mm; ♂ 8–10 mm); superior border at level of true fold",
"True fold level = midpoint between <b>anterior-inferior border</b> and <b>thyroid notch</b>",
"Implant bevel oriented <b>superiorly</b> for best voice outcome",
"<b>Overcorrection preferred</b> — post-op edema resolution reduces medialization",
"Implants: Silastic (most common), Gore-Tex, Hydroxyapatite, Titanium, Autologous cartilage",
"Arytenoid adduction added when <b>posterior glottic gap</b> persists",
"Complications: Airway compromise, extrusion, suboptimal voice, persistent posterior gap",
"Type III thyroplasty = <b>relaxation</b> → shorten A-P diameter → lower pitch (mutational falsetto, FTM transgender)",
"Type IV = <b>tension ↑</b> → lengthen A-P diameter → raise pitch (FTM → MTF controversial; Wendler glottoplasty preferred now)",
]
for kp in key_points:
story.append(Paragraph(f"▶ {kp}", bullet_style))
story.append(Spacer(1, 10))
story.append(HRFlowable(width="100%", thickness=1, color=GRAY))
story.append(Spacer(1, 4))
story.append(Paragraph(
"<i>Sources: Cummings Otolaryngology Head and Neck Surgery (7th Ed.) | KJ Lee's Essential Otolaryngology</i>",
caption_style
))
# ── Build ──
doc.build(story)
print(f"\nPDF created: {OUTPUT}")