Serum protein electophoresis and all detailed of this including all abnormal findings and how to see the report explain in detail in ppt

Reading File
Reading File
Reading File
Finding Sources
Searching Images

serum protein electrophoresis pattern normal abnormal

Reading File
Reading File
Reading File
Reading File
Reading File
Running Command

mkdir -p /tmp/workspace/spep-ppt && ls /tmp/workspace/spep-ppt/

Writing File

~/spep-ppt/build_spep.py


from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.util import Inches, Pt
import json, subprocess, base64
from io import BytesIO

prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)

blank = prs.slide_layouts[6]

# ---- COLOR PALETTE ----
DARK_BLUE   = RGBColor(0x1A, 0x35, 0x5E)   # title bar bg
MID_BLUE    = RGBColor(0x1F, 0x6D, 0xA6)   # accent / subheading
LIGHT_BLUE  = RGBColor(0xD6, 0xEA, 0xF8)   # content box bg
WHITE       = RGBColor(0xFF, 0xFF, 0xFF)
DARK_GRAY   = RGBColor(0x2C, 0x3E, 0x50)
YELLOW_ACC  = RGBColor(0xFF, 0xD7, 0x00)
GREEN_ACC   = RGBColor(0x27, 0xAE, 0x60)
RED_ACC     = RGBColor(0xC0, 0x39, 0x2B)
ORANGE_ACC  = RGBColor(0xE6, 0x7E, 0x22)
LIGHT_GREEN = RGBColor(0xD5, 0xF5, 0xE3)
LIGHT_RED   = RGBColor(0xFD, 0xED, 0xEC)
LIGHT_ORANGE= RGBColor(0xFE, 0xF9, 0xE7)
LIGHT_GRAY  = RGBColor(0xF2, 0xF3, 0xF4)
TEAL        = RGBColor(0x11, 0x7A, 0x65)

# ---- HELPER FUNCTIONS ----

def add_rect(slide, x, y, w, h, fill_color=None, line_color=None, line_width=Pt(0)):
    from pptx.util import Pt as _Pt
    shape = slide.shapes.add_shape(1, Inches(x), Inches(y), Inches(w), Inches(h))
    if fill_color:
        shape.fill.solid()
        shape.fill.fore_color.rgb = fill_color
    else:
        shape.fill.background()
    if line_color:
        shape.line.color.rgb = line_color
        shape.line.width = line_width
    else:
        shape.line.fill.background()
    return shape

def add_text(slide, text, x, y, w, h, font_size=18, bold=False, color=DARK_GRAY,
             align=PP_ALIGN.LEFT, italic=False, word_wrap=True, v_anchor=MSO_ANCHOR.TOP):
    tb = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
    tf = tb.text_frame
    tf.word_wrap = word_wrap
    tf.vertical_anchor = v_anchor
    tf.margin_left = Inches(0.05)
    tf.margin_right = Inches(0.05)
    tf.margin_top = Inches(0.03)
    tf.margin_bottom = Inches(0.03)
    p = tf.paragraphs[0]
    p.alignment = align
    run = p.add_run()
    run.text = text
    run.font.size = Pt(font_size)
    run.font.bold = bold
    run.font.italic = italic
    run.font.color.rgb = color
    run.font.name = "Calibri"
    return tf

def add_multiline_textbox(slide, lines, x, y, w, h, font_size=15, bold_first=False,
                          color=DARK_GRAY, bullet_char="•", word_wrap=True):
    """lines: list of (text, bold, color, size, indent) tuples or plain strings"""
    tb = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
    tf = tb.text_frame
    tf.word_wrap = word_wrap
    tf.margin_left = Inches(0.08)
    tf.margin_right = Inches(0.05)
    tf.margin_top = Inches(0.05)
    tf.margin_bottom = Inches(0.03)
    first = True
    for line in lines:
        if isinstance(line, str):
            text = line; b = False; c = color; s = font_size; indent = 0
        else:
            text, b, c, s, indent = line
        if first:
            p = tf.paragraphs[0]
            first = False
        else:
            p = tf.add_paragraph()
        p.alignment = PP_ALIGN.LEFT
        p.level = indent
        if indent > 0:
            p.space_before = Pt(2)
        run = p.add_run()
        run.text = text
        run.font.size = Pt(s)
        run.font.bold = b
        run.font.color.rgb = c
        run.font.name = "Calibri"
    return tf

def add_title_bar(slide, title, subtitle=None):
    # Full-width dark blue header bar
    add_rect(slide, 0, 0, 13.333, 1.15, fill_color=DARK_BLUE)
    add_text(slide, title, 0.3, 0.08, 12.5, 0.65, font_size=30, bold=True, color=WHITE,
             align=PP_ALIGN.LEFT)
    if subtitle:
        add_text(slide, subtitle, 0.3, 0.72, 12.5, 0.4, font_size=16, bold=False,
                 color=RGBColor(0xAE, 0xCC, 0xEE), align=PP_ALIGN.LEFT)
    # Bottom accent line
    add_rect(slide, 0, 1.15, 13.333, 0.05, fill_color=YELLOW_ACC)

def add_footer(slide, text="Serum Protein Electrophoresis (SPEP) | Clinical Pathology Reference"):
    add_rect(slide, 0, 7.25, 13.333, 0.25, fill_color=DARK_BLUE)
    add_text(slide, text, 0.3, 7.26, 12.5, 0.22, font_size=9, color=RGBColor(0xAA, 0xBB, 0xCC),
             align=PP_ALIGN.LEFT)

def add_section_box(slide, title, x, y, w, h, bg=LIGHT_BLUE, title_color=DARK_BLUE):
    add_rect(slide, x, y, w, 0.38, fill_color=bg, line_color=MID_BLUE, line_width=Pt(1.5))
    add_text(slide, title, x+0.08, y+0.03, w-0.16, 0.33, font_size=14, bold=True, color=title_color)
    return y + 0.38

def fetch_image_b64(url):
    result = json.loads(subprocess.check_output(
        ["python", "/tmp/skills/shared/scripts/fetch_images.py", url]
    ))
    if result and result[0]["base64"]:
        return result[0]["base64"]
    return None

def add_image_from_url(slide, url, x, y, w, h=None):
    b64 = fetch_image_b64(url)
    if b64:
        mime, data = b64.split(";base64,", 1)
        raw = base64.b64decode(data)
        buf = BytesIO(raw)
        pic = slide.shapes.add_picture(buf, Inches(x), Inches(y), width=Inches(w))
        if h:
            pic.height = Inches(h)
        return pic
    return None

# ============================================================
# SLIDE 1: TITLE SLIDE
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=DARK_BLUE)
add_rect(slide, 0, 2.8, 13.333, 0.08, fill_color=YELLOW_ACC)
add_rect(slide, 0, 4.5, 13.333, 0.08, fill_color=YELLOW_ACC)

add_text(slide, "Serum Protein Electrophoresis", 0.8, 1.1, 11.8, 1.2,
         font_size=44, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
add_text(slide, "(SPEP)", 0.8, 2.25, 11.8, 0.55,
         font_size=32, bold=False, color=YELLOW_ACC, align=PP_ALIGN.CENTER)
add_text(slide, "Principles • Methodology • Normal & Abnormal Patterns", 0.8, 3.05, 11.8, 0.55,
         font_size=18, bold=False, color=RGBColor(0xAE, 0xCC, 0xEE), align=PP_ALIGN.CENTER)
add_text(slide, "How to Read & Interpret the SPEP Report", 0.8, 3.7, 11.8, 0.45,
         font_size=16, bold=True, color=YELLOW_ACC, align=PP_ALIGN.CENTER)
add_text(slide, "Source: Quick Compendium of Clinical Pathology, 5th Edition", 0.8, 4.75, 11.8, 0.4,
         font_size=13, color=RGBColor(0x88, 0xAA, 0xCC), align=PP_ALIGN.CENTER)
add_text(slide, "Clinical Pathology | Laboratory Medicine", 0.8, 5.15, 11.8, 0.4,
         font_size=14, color=RGBColor(0xCC, 0xDD, 0xEE), align=PP_ALIGN.CENTER)

# ============================================================
# SLIDE 2: WHAT IS SPEP?
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "What is Serum Protein Electrophoresis (SPEP)?")
add_footer(slide)

# Left column
add_rect(slide, 0.3, 1.3, 6.1, 5.7, fill_color=LIGHT_BLUE, line_color=MID_BLUE, line_width=Pt(1))
add_text(slide, "Definition & Principle", 0.4, 1.35, 5.9, 0.4, font_size=14, bold=True, color=DARK_BLUE)
add_multiline_textbox(slide, [
    ("• SPEP is a laboratory technique that separates serum proteins by size and electrical charge in an electric field", False, DARK_GRAY, 14, 0),
    ("• Proteins migrate toward the anode (positive electrode) at different speeds depending on their charge and molecular weight", False, DARK_GRAY, 14, 0),
    ("• Result displayed as densitometric tracing (peaks) or gel electrophoresis bands", False, DARK_GRAY, 14, 0),
    ("• Identifies and quantifies 6 major protein fractions:", True, DARK_BLUE, 14, 0),
    ("   1. Prealbumin (transthyretin)", False, DARK_GRAY, 13, 0),
    ("   2. Albumin", False, DARK_GRAY, 13, 0),
    ("   3. Alpha-1 (α1) globulins", False, DARK_GRAY, 13, 0),
    ("   4. Alpha-2 (α2) globulins", False, DARK_GRAY, 13, 0),
    ("   5. Beta (β) globulins", False, DARK_GRAY, 13, 0),
    ("   6. Gamma (γ) globulins", False, DARK_GRAY, 13, 0),
], 0.35, 1.78, 6.0, 5.0)

# Right column
add_rect(slide, 6.7, 1.3, 6.3, 2.6, fill_color=LIGHT_GREEN, line_color=GREEN_ACC, line_width=Pt(1))
add_text(slide, "Clinical Indications", 0.1+6.7, 1.35, 6.1, 0.38, font_size=14, bold=True, color=TEAL)
add_multiline_textbox(slide, [
    ("• Suspected monoclonal gammopathy or myeloma", False, DARK_GRAY, 13, 0),
    ("• Evaluation of nephrotic syndrome", False, DARK_GRAY, 13, 0),
    ("• Screening for chronic liver disease / cirrhosis", False, DARK_GRAY, 13, 0),
    ("• Evaluation of chronic inflammatory states", False, DARK_GRAY, 13, 0),
    ("• Assessment of nutritional status / hypoalbuminemia", False, DARK_GRAY, 13, 0),
    ("• Alpha-1 antitrypsin deficiency workup", False, DARK_GRAY, 13, 0),
    ("• Investigation of immune deficiencies", False, DARK_GRAY, 13, 0),
], 6.8, 1.72, 6.1, 2.15)

add_rect(slide, 6.7, 4.1, 6.3, 2.9, fill_color=LIGHT_ORANGE, line_color=ORANGE_ACC, line_width=Pt(1))
add_text(slide, "Specimen & Method", 0.1+6.7, 4.15, 6.1, 0.38, font_size=14, bold=True, color=ORANGE_ACC)
add_multiline_textbox(slide, [
    ("• Specimen: Serum (NOT plasma — fibrinogen causes pseudo-band)", False, DARK_GRAY, 13, 0),
    ("• High-resolution agarose gel electrophoresis (most common)", False, DARK_GRAY, 13, 0),
    ("• Capillary zone electrophoresis (CZE) — increasingly used", False, DARK_GRAY, 13, 0),
    ("• Result reported as % and g/dL for each fraction", False, DARK_GRAY, 13, 0),
    ("• Total protein and albumin/globulin (A/G) ratio calculated", False, DARK_GRAY, 13, 0),
], 6.8, 4.55, 6.1, 2.35)

# ============================================================
# SLIDE 3: MAJOR SERUM PROTEINS TABLE
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "Major Serum Proteins — Electrophoretic Fractions",
              subtitle="Each fraction reflects specific proteins with distinct clinical significance")
add_footer(slide)

rows = [
    ("Fraction", "Key Protein(s)", "Function / Clinical Notes", True),
    ("Prealbumin\n(Transthyretin)", "Transthyretin, RBP", "Best marker of nutritional status; negative acute phase reactant; short half-life (2 days)", False),
    ("Albumin", "Albumin", "Most abundant protein; maintains oncotic pressure; binds drugs, hormones, fatty acids; half-life 17 days; negative acute phase reactant", False),
    ("α1 globulin", "α1-Antitrypsin (AAT)\nα1-Acid glycoprotein\nα1-Fetoprotein", "AAT = main component; protease inhibitor; acute phase reactant; decreased in AAT deficiency", False),
    ("α2 globulin", "Haptoglobin\nα2-Macroglobulin\nCeruloplasmin", "Haptoglobin binds free Hb (depleted in hemolysis); α2-Macroglobulin: NOT lost in nephrosis (large size) → elevated in nephrotic syndrome", False),
    ("β globulin\n(β1 & β2)", "Transferrin (β1)\nC3 complement (β2)\nLDL, IgA (β2)", "Transferrin: iron transport, ↑ in iron deficiency; C3 complement in β2; IgA paraprotein may migrate here", False),
    ("γ globulin", "IgG, IgA, IgM, IgD, IgE\nCRP, fibrinogen (if plasma)", "Site of immunoglobulins; M-spike seen here in myeloma (usually IgG); broad polyclonal rise in chronic infection", False),
]

col_widths = [1.9, 2.5, 7.4]
col_x = [0.25, 2.2, 4.75]
row_h = 0.82
start_y = 1.3

colors_bg = [DARK_BLUE, LIGHT_BLUE, LIGHT_GREEN, LIGHT_ORANGE, LIGHT_RED,
             RGBColor(0xF5, 0xEC, 0xFF), LIGHT_GRAY]
text_colors_hdr = WHITE

for ri, (c0, c1, c2, is_header) in enumerate(rows):
    y = start_y + ri * row_h
    bg = DARK_BLUE if is_header else colors_bg[ri]
    tc = WHITE if is_header else DARK_GRAY
    for ci, (cx, cw, ct) in enumerate(zip(col_x, col_widths, [c0, c1, c2])):
        add_rect(slide, cx, y, cw, row_h - 0.04, fill_color=bg,
                 line_color=MID_BLUE, line_width=Pt(0.5))
        add_multiline_textbox(slide, [
            (ct, is_header, tc if is_header else (DARK_BLUE if ci == 0 else DARK_GRAY),
             13 if not is_header else 14, 0)
        ], cx + 0.05, y + 0.05, cw - 0.1, row_h - 0.14)

# ============================================================
# SLIDE 4: NORMAL SPEP PATTERN
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "Normal SPEP Pattern",
              subtitle="Understanding the baseline — what to expect in a healthy individual")
add_footer(slide)

# Left: image
add_image_from_url(slide,
    "https://cdn.orris.care/cdss_images/765119bd78e9873c8d751f719b5a823eddefcfe0e36efd07b0902eb28257ddec.png",
    0.3, 1.3, 5.8)

# Right: description
add_rect(slide, 6.4, 1.3, 6.6, 5.9, fill_color=LIGHT_BLUE, line_color=MID_BLUE, line_width=Pt(1.2))
add_text(slide, "Features of Normal SPEP", 6.55, 1.35, 6.35, 0.42, font_size=15, bold=True, color=DARK_BLUE)
add_multiline_textbox(slide, [
    ("PREALBUMIN", True, DARK_BLUE, 13, 0),
    ("  Nearly invisible / very faint band", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 10, 0),
    ("ALBUMIN", True, DARK_BLUE, 13, 0),
    ("  Largest, tallest peak — fastest migrating band", False, DARK_GRAY, 13, 0),
    ("  ~52-66% of total protein | 3.5-5.0 g/dL", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 10, 0),
    ("α1 BAND", True, DARK_BLUE, 13, 0),
    ("  Small, sharp peak just after albumin", False, DARK_GRAY, 13, 0),
    ("  ~3.9-5.8% | 0.2-0.4 g/dL", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 10, 0),
    ("α2 BAND", True, DARK_BLUE, 13, 0),
    ("  Somewhat broader peak", False, DARK_GRAY, 13, 0),
    ("  ~7.5-13.4% | 0.5-0.9 g/dL", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 10, 0),
    ("β BAND (bi-nodal)", True, DARK_BLUE, 13, 0),
    ("  Bi-nodal (β1 + β2); moderate height", False, DARK_GRAY, 13, 0),
    ("  ~8.5-13.7% | 0.6-1.0 g/dL", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 10, 0),
    ("γ BAND", True, DARK_BLUE, 13, 0),
    ("  Broad, diffuse, low-level plateau", False, DARK_GRAY, 13, 0),
    ("  ~8.8-19.2% | 0.6-1.4 g/dL", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 10, 0),
    ("A/G Ratio: Normal = 1.2-2.5", True, TEAL, 14, 0),
], 6.55, 1.8, 6.3, 5.25)

# ============================================================
# SLIDE 5: HOW TO READ SPEP REPORT
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "How to Read an SPEP Report — Step-by-Step",
              subtitle="A systematic approach to interpreting every SPEP result")
add_footer(slide)

steps = [
    ("STEP 1", "Check Total Protein", "Normal: 6.0-8.0 g/dL. Low = malnutrition / protein loss. High = may suggest paraprotein.", DARK_BLUE, LIGHT_BLUE),
    ("STEP 2", "Assess Albumin Band", "Largest band. Reduced in liver disease, nephrotic syndrome, malnutrition, acute illness. Half-life: 17 days.", MID_BLUE, RGBColor(0xEB, 0xF5, 0xFB)),
    ("STEP 3", "Calculate A/G Ratio", "A/G = Albumin / (Total Protein - Albumin). Low ratio (<1.2) → globulin excess or albumin loss. Reversed A/G = important flag.", TEAL, LIGHT_GREEN),
    ("STEP 4", "Evaluate α1 & α2 Bands", "↑ α1 + α2 = acute phase response (infection, inflammation). ↑ α2 alone with ↓ albumin = nephrotic syndrome. ↓ α1 = AAT deficiency.", ORANGE_ACC, LIGHT_ORANGE),
    ("STEP 5", "Examine β Band", "β-γ bridging (no gap between β and γ) = cirrhosis hallmark. IgA paraprotein migrates to β. Iron deficiency → ↑ transferrin (↑ β1).", RED_ACC, LIGHT_RED),
    ("STEP 6", "Inspect γ Band carefully", "Look for: (a) Discrete spike = M protein (monoclonal), (b) Broad ↑ = polyclonal, (c) ↓ γ = immunodeficiency / light chain myeloma.", DARK_BLUE, LIGHT_BLUE),
]

for i, (step, title, desc, title_color, bg_color) in enumerate(steps):
    col = i % 3
    row = i // 3
    x = 0.25 + col * 4.33
    y = 1.3 + row * 2.85
    add_rect(slide, x, y, 4.1, 2.65, fill_color=bg_color, line_color=title_color, line_width=Pt(1.5))
    add_rect(slide, x, y, 4.1, 0.42, fill_color=title_color)
    add_text(slide, f"{step}: {title}", x+0.1, y+0.05, 3.9, 0.35,
             font_size=13, bold=True, color=WHITE)
    add_multiline_textbox(slide, [
        (desc, False, DARK_GRAY, 13, 0)
    ], x+0.1, y+0.48, 3.9, 2.1)

# ============================================================
# SLIDE 6: ACUTE PHASE RESPONSE PATTERN
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "Abnormal Pattern 1: Acute Phase Response",
              subtitle="Elevated α1 & α2 bands — seen in acute inflammation, infection, trauma, malignancy")
add_footer(slide)

add_image_from_url(slide,
    "https://cdn.orris.care/cdss_images/9c99a74d689c2dcc213cf063c777ce894e4b1a103bfe834a24c4213f3a87f3bc.png",
    0.3, 1.3, 5.5)

add_rect(slide, 6.1, 1.3, 6.9, 5.85, fill_color=LIGHT_ORANGE, line_color=ORANGE_ACC, line_width=Pt(1.2))
add_text(slide, "Acute Inflammation Pattern — Key Features", 6.25, 1.35, 6.6, 0.42,
         font_size=14, bold=True, color=ORANGE_ACC)
add_multiline_textbox(slide, [
    ("TYPICAL LAB VALUES (example):", True, DARK_BLUE, 13, 0),
    ("  Albumin: 38.1% (↓) | 2.5 g/dL", False, DARK_GRAY, 13, 0),
    ("  α1: 9.9% (↑↑) | 0.6 g/dL (ref: 0.2-0.4)", False, RED_ACC, 13, 0),
    ("  α2: 25.4% (↑↑) | 1.7 g/dL (ref: 0.5-0.9)", False, RED_ACC, 13, 0),
    ("  β: 11.6% — Normal", False, DARK_GRAY, 13, 0),
    ("  γ: 15.0% — Normal to mildly ↑", False, DARK_GRAY, 13, 0),
    ("  A/G Ratio: 0.62 (reversed / low)", False, RED_ACC, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("MECHANISM:", True, DARK_BLUE, 13, 0),
    ("  Liver produces acute phase reactants", False, DARK_GRAY, 13, 0),
    ("  ↑ α1-antitrypsin, α1-acid glycoprotein → ↑ α1", False, DARK_GRAY, 13, 0),
    ("  ↑ Haptoglobin, α2-macroglobulin, ceruloplasmin → ↑ α2", False, DARK_GRAY, 13, 0),
    ("  Albumin is negative acute phase reactant (↓)", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("CAUSES:", True, DARK_BLUE, 13, 0),
    ("  Infection, sepsis, surgery, trauma, MI, burns", False, DARK_GRAY, 13, 0),
    ("  Autoimmune disease, malignancy", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("NOTE: Prolonged inflammation → polyclonal ↑ γ", True, ORANGE_ACC, 13, 0),
], 6.25, 1.82, 6.6, 5.3)

# ============================================================
# SLIDE 7: NEPHROTIC SYNDROME PATTERN
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "Abnormal Pattern 2: Nephrotic Syndrome",
              subtitle="Massive loss of small proteins → selective hypoalbuminemia with elevated α2")
add_footer(slide)

add_rect(slide, 0.3, 1.3, 12.7, 5.9, fill_color=WHITE)
# Left info box
add_rect(slide, 0.3, 1.3, 6.0, 5.9, fill_color=LIGHT_RED, line_color=RED_ACC, line_width=Pt(1.2))
add_text(slide, "Nephrotic Syndrome Pattern", 0.45, 1.35, 5.7, 0.42, font_size=15, bold=True, color=RED_ACC)
add_multiline_textbox(slide, [
    ("HALLMARK FINDINGS:", True, DARK_BLUE, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("↓↓ Albumin", True, RED_ACC, 14, 0),
    ("  Massive urinary loss of small proteins", False, DARK_GRAY, 13, 0),
    ("  Albumin < 3.0 g/dL common", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("↑↑ α2 band (MOST CHARACTERISTIC)", True, RED_ACC, 14, 0),
    ("  α2-macroglobulin is LARGE (720 kDa) — NOT lost in urine", False, DARK_GRAY, 13, 0),
    ("  Compensatory hepatic synthesis of α2-macroglobulin", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("↓ All other fractions (lost in urine):", True, DARK_BLUE, 13, 0),
    ("  α1 globulins, transferrin (β), IgG (γ) all reduced", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("VISUAL PATTERN:", True, DARK_BLUE, 13, 0),
    ("  Small albumin peak + Tall α2 peak + Flat everything else", False, DARK_GRAY, 13, 0),
    ("  A/G ratio markedly reversed (very low)", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("ASSOCIATED: Hyperlipidemia (VLDL/LDL ↑)", True, ORANGE_ACC, 13, 0),
    ("  ↑ Lipoproteins in β band due to compensatory hepatic synthesis", False, DARK_GRAY, 13, 0),
], 0.45, 1.82, 5.7, 5.3)

# Right: summary table
add_rect(slide, 6.6, 1.3, 6.4, 5.9, fill_color=LIGHT_BLUE, line_color=MID_BLUE, line_width=Pt(1.2))
add_text(slide, "Fraction-by-Fraction Summary", 6.75, 1.35, 6.1, 0.42, font_size=15, bold=True, color=DARK_BLUE)

fractions_ns = [
    ("Fraction", "Direction", "Reason", True),
    ("Albumin", "↓↓↓ Markedly Low", "Lost in urine (small size, 66 kDa)", False),
    ("α1 globulin", "↓ Reduced", "Small proteins lost in urine", False),
    ("α2 globulin", "↑↑↑ Markedly HIGH", "α2-Macroglobulin too large to be lost (720 kDa)", False),
    ("β globulin", "↓ / Normal", "Transferrin lost; LDL may ↑", False),
    ("γ globulin", "↓ Reduced", "IgG lost in urine", False),
    ("Total Protein", "↓ Reduced", "Net protein loss", False),
    ("A/G Ratio", "< 1 (Reversed)", "Albumin loss predominates", False),
]
row_h2 = 0.63
for ri, (c0, c1, c2, is_hdr) in enumerate(fractions_ns):
    ry = 1.82 + ri * row_h2
    bg = DARK_BLUE if is_hdr else (LIGHT_BLUE if ri % 2 == 0 else WHITE)
    tc = WHITE if is_hdr else DARK_GRAY
    tc1 = WHITE if is_hdr else (RED_ACC if "↓" in c1 or "↑" in c1 else DARK_GRAY)
    for ci, (cx, cw, ct, ftc) in enumerate(zip([6.65, 8.55, 9.9], [1.85, 1.3, 3.0], [c0, c1, c2], [tc, tc1, tc])):
        add_rect(slide, cx, ry, cw-0.05, row_h2-0.04, fill_color=bg,
                 line_color=MID_BLUE, line_width=Pt(0.5))
        add_multiline_textbox(slide, [
            (ct, is_hdr, ftc, 12 if not is_hdr else 12, 0)
        ], cx+0.05, ry+0.05, cw-0.15, row_h2-0.12)

# ============================================================
# SLIDE 8: CIRRHOSIS / LIVER DISEASE PATTERN
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "Abnormal Pattern 3: Cirrhosis / Chronic Liver Disease",
              subtitle="β-γ bridging — the hallmark of cirrhosis on SPEP")
add_footer(slide)

# Left: image
add_rect(slide, 0.3, 1.3, 5.8, 5.9, fill_color=LIGHT_GRAY, line_color=MID_BLUE, line_width=Pt(1))
add_text(slide, "Cirrhosis SPEP Pattern (Schematic)", 0.45, 1.35, 5.5, 0.42,
         font_size=14, bold=True, color=DARK_BLUE)
add_multiline_textbox(slide, [
    ("β-γ BRIDGE:", True, RED_ACC, 22, 0),
    ("The gap between β and γ peaks disappears.", False, DARK_GRAY, 14, 0),
    ("This is the HALLMARK of cirrhosis.", True, RED_ACC, 14, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("On densitometry tracing, β and γ merge", False, DARK_GRAY, 14, 0),
    ("into a continuous elevation — no valley", False, DARK_GRAY, 14, 0),
    ("between them.", False, DARK_GRAY, 14, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("Primarily due to: ↑ serum IgA", True, DARK_BLUE, 14, 0),
    ("IgA migrates in β-γ interface region,", False, DARK_GRAY, 14, 0),
    ("filling the trough and causing bridging.", False, DARK_GRAY, 14, 0),
], 0.45, 1.82, 5.6, 5.3)

# Right: features
add_rect(slide, 6.4, 1.3, 6.6, 5.9, fill_color=LIGHT_ORANGE, line_color=ORANGE_ACC, line_width=Pt(1.2))
add_text(slide, "Key SPEP Features in Cirrhosis", 6.55, 1.35, 6.35, 0.42,
         font_size=15, bold=True, color=ORANGE_ACC)
add_multiline_textbox(slide, [
    ("1. β-γ BRIDGING (HALLMARK)", True, RED_ACC, 14, 0),
    ("   Absence of distinct valley between β and γ", False, DARK_GRAY, 13, 0),
    ("   Due to ↑ serum IgA (produced by gut plasma cells)", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("2. HYPOALBUMINEMIA", True, DARK_BLUE, 14, 0),
    ("   ↓ Hepatic albumin synthesis", False, DARK_GRAY, 13, 0),
    ("   Reflects degree of hepatic synthetic failure", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("3. BLUNTED α1 & α2 BANDS", True, DARK_BLUE, 14, 0),
    ("   ↓ Hepatic synthesis of acute phase proteins", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("4. POLYCLONAL ↑ γ (broad)", True, DARK_BLUE, 14, 0),
    ("   Chronic immune stimulation from portosystemic shunting", False, DARK_GRAY, 13, 0),
    ("   Antigens bypass liver → systemic B-cell activation", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("5. REVERSED A/G RATIO", True, DARK_BLUE, 14, 0),
    ("   A/G < 1.0 common in advanced cirrhosis", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("REMEMBER: Plasma (not serum) may show fibrinogen band", True, TEAL, 13, 0),
    ("   in β region — potential pseudo-M spike source", False, DARK_GRAY, 13, 0),
], 6.55, 1.82, 6.35, 5.3)

# ============================================================
# SLIDE 9: MONOCLONAL GAMMOPATHY / M-SPIKE
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "Abnormal Pattern 4: Monoclonal Gammopathy (M-Spike)",
              subtitle="Most important SPEP finding — discrete spike = clonal plasma cell disorder until proven otherwise")
add_footer(slide)

# Textbook image
add_image_from_url(slide,
    "https://cdn.orris.care/cdss_images/33f3a80e7caa2460589e39464d7261581e1fc22a422d8a345ed83590cdc36dc0.png",
    0.3, 1.3, 4.8)

# Right main
add_rect(slide, 5.4, 1.3, 7.6, 5.9, fill_color=LIGHT_RED, line_color=RED_ACC, line_width=Pt(1.2))
add_text(slide, "Monoclonal Gammopathy — Key Points", 5.55, 1.35, 7.35, 0.42,
         font_size=15, bold=True, color=RED_ACC)
add_multiline_textbox(slide, [
    ("DEFINITION:", True, DARK_BLUE, 13, 0),
    ("  Homogeneous (clonal) immunoglobulin produced by a single plasma cell clone", False, DARK_GRAY, 13, 0),
    ("  = Paraprotein / M protein", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("SPEP APPEARANCE:", True, DARK_BLUE, 13, 0),
    ("  Prominent, discrete, narrow, DARK band on gel", False, DARK_GRAY, 13, 0),
    ("  Sharp spike on densitometry tracing (M spike)", False, DARK_GRAY, 13, 0),
    ("  Usually in γ region; can be in β or α2", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("MIGRATION BY ISOTYPE:", True, DARK_BLUE, 13, 0),
    ("  IgG → Usually γ region (most common)", False, DARK_GRAY, 13, 0),
    ("  IgM → β-γ interface", False, DARK_GRAY, 13, 0),
    ("  IgA → β region (can be mistaken for β peak)", False, DARK_GRAY, 13, 0),
    ("  Light chain only → γ or β; often ONLY hypogammaglobulinemia on SPEP!", False, RED_ACC, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("M PROTEIN COMPOSITION:", True, DARK_BLUE, 13, 0),
    ("  Usually: 2 heavy chains + 2 light chains", False, DARK_GRAY, 13, 0),
    ("  Sometimes: light chain only (Bence Jones protein)", False, DARK_GRAY, 13, 0),
    ("  Rarely: heavy chain only", False, DARK_GRAY, 13, 0),
    ("  Biclonal: 3-4% of cases", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("CAUSES:", True, DARK_BLUE, 13, 0),
    ("  Multiple Myeloma, MGUS, Waldenström macroglobulinemia", False, DARK_GRAY, 13, 0),
    ("  Lymphoma (esp. lymphoplasmacytic / CLL/SLL)", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("NEXT STEP: Immunofixation electrophoresis (IFE)", True, TEAL, 13, 0),
    ("  to characterize heavy chain + light chain type", False, DARK_GRAY, 13, 0),
], 5.55, 1.82, 7.35, 5.3)

# ============================================================
# SLIDE 10: M SPIKE vs POLYCLONAL + IFE
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "M-Spike: Monoclonal vs Polyclonal Gammopathy",
              subtitle="Critical distinction — monoclonal = malignant potential; polyclonal = reactive/benign")
add_footer(slide)

# Monoclonal box
add_rect(slide, 0.3, 1.3, 6.0, 5.9, fill_color=LIGHT_RED, line_color=RED_ACC, line_width=Pt(2))
add_rect(slide, 0.3, 1.3, 6.0, 0.42, fill_color=RED_ACC)
add_text(slide, "MONOCLONAL (M-Spike)", 0.45, 1.33, 5.7, 0.38, font_size=15, bold=True, color=WHITE)
add_multiline_textbox(slide, [
    ("APPEARANCE ON SPEP:", True, DARK_BLUE, 13, 0),
    ("  Tall, narrow, sharp, discrete spike", False, DARK_GRAY, 13, 0),
    ("  Looks like a 'church steeple'", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("REPRESENTS:", True, DARK_BLUE, 13, 0),
    ("  Single clone of plasma cells producing identical Ig", False, DARK_GRAY, 13, 0),
    ("  Pathological — requires further workup", False, RED_ACC, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("DISEASES:", True, DARK_BLUE, 13, 0),
    ("  • Multiple myeloma", False, DARK_GRAY, 13, 0),
    ("  • MGUS (Monoclonal Gammopathy of Undetermined Significance)", False, DARK_GRAY, 13, 0),
    ("  • Waldenström macroglobulinemia (IgM)", False, DARK_GRAY, 13, 0),
    ("  • Primary amyloidosis (AL amyloid)", False, DARK_GRAY, 13, 0),
    ("  • Lymphoma / CLL / SLL", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("WORKUP:", True, DARK_BLUE, 13, 0),
    ("  1. Immunofixation electrophoresis (IFE) — characterize Ig type", False, DARK_GRAY, 13, 0),
    ("  2. 24-hour urine protein electrophoresis (UPEP)", False, DARK_GRAY, 13, 0),
    ("  3. Serum free light chains (κ/λ ratio)", False, DARK_GRAY, 13, 0),
    ("  4. Bone marrow biopsy if myeloma suspected", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("⚠ 10% of myeloma → NO M-spike (light chain only)", True, RED_ACC, 13, 0),
    ("   Only hypogammaglobulinemia seen on SPEP!", False, RED_ACC, 13, 0),
], 0.45, 1.78, 5.7, 5.35)

# Polyclonal box
add_rect(slide, 6.7, 1.3, 6.3, 5.9, fill_color=LIGHT_GREEN, line_color=GREEN_ACC, line_width=Pt(2))
add_rect(slide, 6.7, 1.3, 6.3, 0.42, fill_color=GREEN_ACC)
add_text(slide, "POLYCLONAL (Broad γ elevation)", 6.85, 1.33, 6.0, 0.38, font_size=15, bold=True, color=WHITE)
add_multiline_textbox(slide, [
    ("APPEARANCE ON SPEP:", True, DARK_BLUE, 13, 0),
    ("  Broad, diffuse, wide elevation in γ zone", False, DARK_GRAY, 13, 0),
    ("  No single narrow spike", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("REPRESENTS:", True, DARK_BLUE, 13, 0),
    ("  Multiple clones producing varied immunoglobulins", False, DARK_GRAY, 13, 0),
    ("  Reactive / benign — body's immune response", False, TEAL, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("DISEASES:", True, DARK_BLUE, 13, 0),
    ("  • Chronic infections (HIV, TB, hepatitis, malaria)", False, DARK_GRAY, 13, 0),
    ("  • Autoimmune diseases (SLE, RA, Sjögren)", False, DARK_GRAY, 13, 0),
    ("  • Chronic liver disease / cirrhosis", False, DARK_GRAY, 13, 0),
    ("  • Sarcoidosis", False, DARK_GRAY, 13, 0),
    ("  • Prolonged inflammation", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("KEY DISTINCTION FROM MONOCLONAL:", True, DARK_BLUE, 13, 0),
    ("  • Broad base vs. narrow spike", False, DARK_GRAY, 13, 0),
    ("  • IFE: multiple heavy + light chains vs. single clone", False, DARK_GRAY, 13, 0),
    ("  • Usually benign / reactive cause", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("✓ IFE not required unless doubt about monoclonal component", True, TEAL, 13, 0),
], 6.85, 1.78, 6.0, 5.35)

# ============================================================
# SLIDE 11: α1-ANTITRYPSIN DEFICIENCY + PSEUDO M-SPIKE
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "Other Abnormal Patterns: AAT Deficiency & Pseudo M-Spikes",
              subtitle="Pattern recognition pitfalls — knowing when the M-spike is NOT a paraprotein")
add_footer(slide)

add_image_from_url(slide,
    "https://cdn.orris.care/cdss_images/78dde153893d992acec78bf0d3e23e7bd23427da83d45793078fe33ee8ca8ea2.png",
    0.3, 1.3, 5.2)

add_rect(slide, 5.8, 1.3, 7.2, 2.7, fill_color=LIGHT_ORANGE, line_color=ORANGE_ACC, line_width=Pt(1.2))
add_text(slide, "α1-Antitrypsin (AAT) Deficiency", 5.95, 1.35, 6.95, 0.42, font_size=14, bold=True, color=ORANGE_ACC)
add_multiline_textbox(slide, [
    ("• Nearly absent α1 band on SPEP (AAT = major component of α1)", False, DARK_GRAY, 13, 0),
    ("• NOT sensitive or specific alone — confirmatory testing needed", False, DARK_GRAY, 13, 0),
    ("• AAT is an acute phase reactant — may appear normal in inflammation!", False, RED_ACC, 13, 0),
    ("• Confirm with quantitative AAT level + phenotyping (PiZZ = severe deficiency)", False, DARK_GRAY, 13, 0),
    ("• Associated: emphysema (panacinar), liver cirrhosis", False, DARK_GRAY, 13, 0),
], 5.95, 1.82, 6.9, 2.1)

add_rect(slide, 5.8, 4.2, 7.2, 2.95, fill_color=LIGHT_RED, line_color=RED_ACC, line_width=Pt(1.2))
add_text(slide, "⚠ Pseudo M-Spikes (False Paraproteins)", 5.95, 4.25, 6.95, 0.42, font_size=14, bold=True, color=RED_ACC)
add_multiline_textbox(slide, [
    ("These can MIMIC a monoclonal spike on SPEP:", True, DARK_BLUE, 13, 0),
    ("  1. Fibrinogen — from incompletely clotted sample (use serum, NOT plasma)", False, DARK_GRAY, 13, 0),
    ("  2. Hemoglobin — from hemolyzed specimen", False, DARK_GRAY, 13, 0),
    ("  3. Elevated CRP — migrates in γ region", False, DARK_GRAY, 13, 0),
    ("  4. Elevated transferrin — β region", False, DARK_GRAY, 13, 0),
    ("  5. Certain antibiotics (e.g., penicillin)", False, DARK_GRAY, 13, 0),
    ("  6. Radiocontrast agents", False, DARK_GRAY, 13, 0),
    ("  7. Very high tumor markers", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("Confirm all spikes with IFE before diagnosing paraproteinemia!", True, RED_ACC, 13, 0),
], 5.95, 4.7, 6.9, 2.4)

# ============================================================
# SLIDE 12: HYPOGAMMAGLOBULINEMIA
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "Abnormal Pattern 5: Hypogammaglobulinemia",
              subtitle="Reduced or absent γ band — primary or secondary immune deficiency")
add_footer(slide)

add_rect(slide, 0.3, 1.3, 12.7, 5.9, fill_color=WHITE)

cols_data = [
    ("Primary Hypogammaglobulinemia\n(Immune Deficiency Disorders)", [
        ("X-linked agammaglobulinemia (Bruton's):", True, DARK_BLUE, 13),
        ("  No B cells; absent all Ig fractions", False, DARK_GRAY, 13),
        ("Common Variable Immunodeficiency (CVID):", True, DARK_BLUE, 13),
        ("  Low IgG ± IgA/IgM; recurrent infections", False, DARK_GRAY, 13),
        ("Selective IgA deficiency:", True, DARK_BLUE, 13),
        ("  Most common primary immunodeficiency", False, DARK_GRAY, 13),
        ("  IgA absent; IgG/IgM normal", False, DARK_GRAY, 13),
        ("Hyper-IgM syndrome:", True, DARK_BLUE, 13),
        ("  ↑ IgM; absent IgG, IgA", False, DARK_GRAY, 13),
    ], LIGHT_GREEN, GREEN_ACC),
    ("Secondary Hypogammaglobulinemia\n(Acquired Causes)", [
        ("Protein-losing states:", True, DARK_BLUE, 13),
        ("  Nephrotic syndrome, protein-losing enteropathy", False, DARK_GRAY, 13),
        ("Immunosuppression:", True, DARK_BLUE, 13),
        ("  Corticosteroids, chemotherapy, rituximab", False, DARK_GRAY, 13),
        ("Hematological malignancies:", True, DARK_BLUE, 13),
        ("  CLL, light chain myeloma (M-spike absent!)", False, RED_ACC, 13),
        ("  10% of myeloma → only hypogammaglobulinemia", False, RED_ACC, 13),
        ("Splenectomy, HIV/AIDS", True, DARK_BLUE, 13),
        ("  Secondary immune suppression", False, DARK_GRAY, 13),
    ], LIGHT_ORANGE, ORANGE_ACC),
    ("SPEP Appearance &\nNext Steps", [
        ("SPEP shows:", True, DARK_BLUE, 13),
        ("  Flat / nearly absent γ region", False, DARK_GRAY, 13),
        ("  All other bands may be normal", False, DARK_GRAY, 13),
        ("", False, DARK_GRAY, 8),
        ("Key pearl: Light chain myeloma", True, RED_ACC, 13),
        ("  SPEP shows ONLY hypogammaglobulinemia", False, RED_ACC, 13),
        ("  Light chains (Bence Jones protein) in URINE", False, DARK_GRAY, 13),
        ("  MUST check UPEP + serum free light chains!", True, RED_ACC, 13),
        ("", False, DARK_GRAY, 8),
        ("Always follow up with:", True, DARK_BLUE, 13),
        ("  Serum IgG, IgA, IgM quantitation", False, DARK_GRAY, 13),
        ("  Serum free light chains", False, DARK_GRAY, 13),
    ], LIGHT_RED, RED_ACC),
]
for ci, (title, lines, bg, lc) in enumerate(cols_data):
    cx = 0.35 + ci * 4.3
    add_rect(slide, cx, 1.3, 4.1, 5.9, fill_color=bg, line_color=lc, line_width=Pt(1.2))
    add_rect(slide, cx, 1.3, 4.1, 0.52, fill_color=lc)
    add_text(slide, title, cx+0.1, 1.32, 3.9, 0.48, font_size=13, bold=True, color=WHITE)
    add_multiline_textbox(slide, [
        (t, b, c, s, 0) for t,b,c,s in lines
    ], cx+0.12, 1.86, 3.85, 5.28)

# ============================================================
# SLIDE 13: URINE PROTEIN ELECTROPHORESIS (UPEP)
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "Urine Protein Electrophoresis (UPEP)",
              subtitle="Complements SPEP — essential for detecting light chain (Bence Jones) proteinuria")
add_footer(slide)

add_image_from_url(slide,
    "https://cdn.orris.care/cdss_images/5e1b3b4a5838553f80767fae0ac000ce93806a5744e54e41732139a269eb339c.png",
    0.3, 1.3, 5.5)

add_rect(slide, 6.1, 1.3, 6.9, 5.9, fill_color=LIGHT_BLUE, line_color=MID_BLUE, line_width=Pt(1.2))
add_text(slide, "UPEP — Patterns & Interpretation", 6.25, 1.35, 6.6, 0.42, font_size=15, bold=True, color=DARK_BLUE)
add_multiline_textbox(slide, [
    ("PATTERN 1: Normal Urine", True, TEAL, 13, 0),
    ("  Very little protein — mainly Tamm-Horsfall mucoprotein", False, DARK_GRAY, 13, 0),
    ("  No significant bands", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("PATTERN 2a: Glomerular Proteinuria", True, DARK_BLUE, 13, 0),
    ("  Large proteins pass through damaged glomerular filter", False, DARK_GRAY, 13, 0),
    ("  Albumin-predominant band in urine", False, DARK_GRAY, 13, 0),
    ("  Seen in: nephrotic syndrome, glomerulonephritis", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("PATTERN 2b: Tubular Proteinuria", True, DARK_BLUE, 13, 0),
    ("  Small proteins not reabsorbed by damaged tubules", False, DARK_GRAY, 13, 0),
    ("  Pre-albumin, α1, β2-microglobulin bands", False, DARK_GRAY, 13, 0),
    ("  Seen in: Fanconi syndrome, toxic nephropathy", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("PATTERN 2c: Overflow Proteinuria", True, RED_ACC, 13, 0),
    ("  Overproduction overwhelms tubular reabsorption", False, DARK_GRAY, 13, 0),
    ("  BENCE JONES PROTEIN (free light chains)", True, RED_ACC, 13, 0),
    ("  Sharp spike — may be κ or λ light chains", False, DARK_GRAY, 13, 0),
    ("  SPEP may be NORMAL or show only hypogammaglobulinemia!", False, RED_ACC, 13, 0),
    ("  Diagnose by IFE of urine", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("KEY POINT:", True, DARK_BLUE, 14, 0),
    ("  Always order UPEP + IFE alongside SPEP", False, DARK_GRAY, 13, 0),
    ("  when myeloma / paraprotein is suspected!", False, DARK_GRAY, 13, 0),
], 6.25, 1.82, 6.6, 5.3)

# ============================================================
# SLIDE 14: COMPLETE COMPARISON TABLE
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "SPEP Abnormal Patterns — At a Glance Summary Table",
              subtitle="Quick-reference comparison of all major SPEP patterns")
add_footer(slide)

table_data = [
    ("Pattern", "Albumin", "α1", "α2", "β", "γ", "Key Clue", True),
    ("Normal", "↑↑ (large)", "Small peak", "Broad", "Bi-nodal", "Broad low", "A/G 1.2–2.5", False),
    ("Acute Inflammation", "↓ mild", "↑↑", "↑↑", "Normal", "↑ poly (late)", "CRP ↑; α1+α2 both up", False),
    ("Nephrotic Syndrome", "↓↓↓", "↓", "↑↑↑", "↓/norm", "↓ (IgG lost)", "α2-macroglobulin spared", False),
    ("Cirrhosis", "↓", "↓", "↓", "Bridge →γ", "↑ broad poly", "β-γ bridging; IgA ↑", False),
    ("AAT Deficiency", "Normal", "↓↓ (absent)", "Normal", "Normal", "Normal", "α1 nearly absent", False),
    ("Monoclonal Gammopathy", "↓ (sometimes)", "Norm", "Norm", "Norm/M-spike", "M-SPIKE ↑↑", "Sharp narrow spike; IFE+", False),
    ("Polyclonal Gammopathy", "↓ (chronic dz)", "Norm/↑", "Norm/↑", "Normal", "↑↑ BROAD", "Wide γ elevation; reactive", False),
    ("Hypogammaglobulinemia", "Normal", "Normal", "Normal", "Normal", "↓↓ flat", "IgG/IgA/IgM all ↓; check light chains", False),
    ("Iron Deficiency", "Normal", "Normal", "Normal", "↑ (transferrin)", "Normal", "Isolated β1 ↑; check Fe studies", False),
]

col_widths_t = [2.3, 1.2, 0.8, 0.9, 1.4, 1.5, 2.0, 2.8]
col_x_t = [0.15]
for cw in col_widths_t[:-1]:
    col_x_t.append(col_x_t[-1] + cw + 0.02)

row_h_t = 0.53
start_y_t = 1.28

alt_colors = [LIGHT_BLUE, WHITE]

for ri, row_data in enumerate(table_data):
    *cells, is_hdr = row_data
    y = start_y_t + ri * row_h_t
    bg = DARK_BLUE if is_hdr else alt_colors[ri % 2]
    for ci, (ct, cx, cw) in enumerate(zip(cells, col_x_t, col_widths_t)):
        cell_bg = bg
        tc = WHITE if is_hdr else DARK_GRAY
        if not is_hdr:
            if "↑↑↑" in ct or "↓↓↓" in ct or "M-SPIKE" in ct:
                tc = RED_ACC
            elif "↓" in ct and ct not in ("Normal", "Norm"):
                tc = RED_ACC
            elif "↑" in ct and ci > 0:
                tc = TEAL
        add_rect(slide, cx, y, cw-0.02, row_h_t-0.03, fill_color=cell_bg,
                 line_color=MID_BLUE, line_width=Pt(0.3))
        add_multiline_textbox(slide, [
            (ct, is_hdr, tc, 11 if not is_hdr else 12, 0)
        ], cx+0.04, y+0.04, cw-0.1, row_h_t-0.1)

# ============================================================
# SLIDE 15: IMMUNOFIXATION ELECTROPHORESIS (IFE)
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "Immunofixation Electrophoresis (IFE)",
              subtitle="Gold standard for confirming and characterizing an M protein detected on SPEP")
add_footer(slide)

# IgG image
add_image_from_url(slide,
    "https://cdn.orris.care/cdss_images/607cee6948ede4518033703db584873d1830b7122e0dde6a40f33224ebba81b5.png",
    0.3, 1.3, 5.5)

add_rect(slide, 6.1, 1.3, 6.9, 5.9, fill_color=LIGHT_BLUE, line_color=MID_BLUE, line_width=Pt(1.2))
add_text(slide, "IFE — Principles & Interpretation", 6.25, 1.35, 6.65, 0.42,
         font_size=15, bold=True, color=DARK_BLUE)
add_multiline_textbox(slide, [
    ("PRINCIPLE:", True, DARK_BLUE, 13, 0),
    ("  After electrophoresis, separate antisera applied to lanes:", False, DARK_GRAY, 13, 0),
    ("  Anti-IgG, Anti-IgA, Anti-IgM, Anti-κ, Anti-λ", False, DARK_GRAY, 13, 0),
    ("  Precipitin reaction identifies the M protein type", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("HOW TO READ IFE:", True, DARK_BLUE, 13, 0),
    ("  A band in ONE heavy chain lane (e.g., IgG)", False, DARK_GRAY, 13, 0),
    ("  AND ONE light chain lane (e.g., κ or λ)", False, DARK_GRAY, 13, 0),
    ("  = Monoclonal IgG κ (or IgG λ)", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("MIGRATION PATTERNS BY ISOTYPE:", True, DARK_BLUE, 13, 0),
    ("  IgG κ/λ → γ region (most common, ~70%)", False, DARK_GRAY, 13, 0),
    ("  IgA κ/λ → β region (appears as β peak on SPEP)", False, DARK_GRAY, 13, 0),
    ("  IgM κ/λ → β-γ interface (Waldenström)", False, DARK_GRAY, 13, 0),
    ("  Light chain only → κ or λ in any region", False, RED_ACC, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("BICLONAL GAMMOPATHY:", True, DARK_BLUE, 13, 0),
    ("  Two separate M proteins (3-4% of cases)", False, DARK_GRAY, 13, 0),
    ("  Apparent IgA biclonality may be IgA dimer", False, DARK_GRAY, 13, 0),
    ("  → pretreat with β-mercaptoethanol to distinguish", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("IFE vs SPEP sensitivity:", True, DARK_BLUE, 13, 0),
    ("  IFE detects M proteins < 0.2 g/dL (SPEP misses these)", False, DARK_GRAY, 13, 0),
    ("  IFE is mandatory for M protein characterization", False, DARK_GRAY, 13, 0),
], 6.25, 1.82, 6.65, 5.3)

# ============================================================
# SLIDE 16: MGUS vs MYELOMA DIFFERENTIATION
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=WHITE)
add_title_bar(slide, "MGUS vs Multiple Myeloma — Clinical Differentiation",
              subtitle="Both show M-spike on SPEP — key lab & clinical features distinguish them")
add_footer(slide)

add_rect(slide, 0.3, 1.3, 6.0, 5.9, fill_color=LIGHT_GREEN, line_color=GREEN_ACC, line_width=Pt(2))
add_rect(slide, 0.3, 1.3, 6.0, 0.42, fill_color=GREEN_ACC)
add_text(slide, "MGUS (Monoclonal Gammopathy of Undetermined Significance)", 0.45, 1.33, 5.7, 0.38, font_size=12, bold=True, color=WHITE)
add_multiline_textbox(slide, [
    ("SPEP / Lab Criteria:", True, DARK_BLUE, 13, 0),
    ("  • M protein < 3 g/dL", False, DARK_GRAY, 13, 0),
    ("  • Bone marrow plasma cells < 10%", False, DARK_GRAY, 13, 0),
    ("  • No end-organ damage (CRAB absent)", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("CRAB Criteria (absent in MGUS):", True, DARK_BLUE, 13, 0),
    ("  C = hyperCalcemia", False, DARK_GRAY, 13, 0),
    ("  R = Renal impairment", False, DARK_GRAY, 13, 0),
    ("  A = Anemia", False, DARK_GRAY, 13, 0),
    ("  B = Bone lesions", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("Risk of progression to myeloma:", True, DARK_BLUE, 13, 0),
    ("  ~1% per year", False, DARK_GRAY, 13, 0),
    ("  Requires regular monitoring (SPEP every 6-12 months)", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("MOST COMMON cause of M-spike in general population", True, TEAL, 13, 0),
    ("  Prevalence ~3% in persons >50 years old", False, DARK_GRAY, 13, 0),
], 0.45, 1.78, 5.7, 5.35)

add_rect(slide, 6.7, 1.3, 6.3, 5.9, fill_color=LIGHT_RED, line_color=RED_ACC, line_width=Pt(2))
add_rect(slide, 6.7, 1.3, 6.3, 0.42, fill_color=RED_ACC)
add_text(slide, "Multiple Myeloma", 6.85, 1.33, 6.0, 0.38, font_size=15, bold=True, color=WHITE)
add_multiline_textbox(slide, [
    ("SPEP / Lab Criteria:", True, DARK_BLUE, 13, 0),
    ("  • M protein ≥ 3 g/dL  OR", False, RED_ACC, 13, 0),
    ("  • Bone marrow plasma cells ≥ 10%  PLUS", False, RED_ACC, 13, 0),
    ("  • End-organ damage (CRAB) OR biomarkers:", False, RED_ACC, 13, 0),
    ("    - Plasma cells ≥ 60%", False, DARK_GRAY, 13, 0),
    ("    - Free light chain ratio ≥ 100", False, DARK_GRAY, 13, 0),
    ("    - >1 focal MRI lesion", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("SPEP Findings in Myeloma:", True, DARK_BLUE, 13, 0),
    ("  • Large M-spike (usually IgG > IgA > IgD/IgE)", False, DARK_GRAY, 13, 0),
    ("  • ↓ normal Ig (immune paresis)", False, DARK_GRAY, 13, 0),
    ("  • Hypogammaglobulinemia only in 10%", False, RED_ACC, 13, 0),
    ("    (light chain myeloma — no serum M-spike!)", False, RED_ACC, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("Other SPEP findings:", True, DARK_BLUE, 13, 0),
    ("  • Anemia pattern (normochromic normocytic)", False, DARK_GRAY, 13, 0),
    ("  • Possible high ESR (rouleaux)", False, DARK_GRAY, 13, 0),
    ("", False, DARK_GRAY, 8, 0),
    ("Always correlate SPEP with:", True, DARK_BLUE, 13, 0),
    ("  IFE, UPEP + IFE, serum free light chains", False, DARK_GRAY, 13, 0),
    ("  CBC, creatinine, calcium, LDH, β2-microglobulin", False, DARK_GRAY, 13, 0),
], 6.85, 1.78, 6.0, 5.35)

# ============================================================
# SLIDE 17: SUMMARY / KEY TAKEAWAYS
# ============================================================
slide = prs.slides.add_slide(blank)
add_rect(slide, 0, 0, 13.333, 7.5, fill_color=DARK_BLUE)
add_rect(slide, 0, 1.0, 13.333, 0.06, fill_color=YELLOW_ACC)
add_rect(slide, 0, 6.85, 13.333, 0.06, fill_color=YELLOW_ACC)

add_text(slide, "KEY TAKEAWAYS — SPEP Interpretation", 0.4, 0.22, 12.5, 0.75,
         font_size=28, bold=True, color=WHITE, align=PP_ALIGN.CENTER)

takeaways = [
    ("1", "Albumin = largest peak. Any reduction = significant (liver, kidney, nutrition).", YELLOW_ACC),
    ("2", "α1 ↓ → think AAT deficiency; α1+α2 ↑ → think acute phase response.", RGBColor(0x7D, 0xBF, 0xFF)),
    ("3", "α2 ↑↑ with ↓ albumin (other fractions ↓) = NEPHROTIC SYNDROME pattern.", RGBColor(0xFF, 0x99, 0x66)),
    ("4", "β-γ bridging = CIRRHOSIS hallmark (IgA fills the trough).", RGBColor(0x99, 0xFF, 0xCC)),
    ("5", "M-spike = monoclonal protein → always confirm with IFE. Check UPEP too.", RGBColor(0xFF, 0x77, 0x77)),
    ("6", "10% of myeloma has NO M-spike — only hypogammaglobulinemia. Order free light chains!", YELLOW_ACC),
    ("7", "Pseudo M-spikes: fibrinogen, hemoglobin, CRP, transferrin, antibiotics, contrast.", RGBColor(0xCC, 0xFF, 0xCC)),
    ("8", "Always read: Total protein → Albumin → A/G ratio → α1/α2 → β → γ (systematic approach)", RGBColor(0xAE, 0xCC, 0xEE)),
]
for i, (num, text, col) in enumerate(takeaways):
    row = i // 2
    col_n = i % 2
    x = 0.3 + col_n * 6.5
    y = 1.2 + row * 1.38
    add_rect(slide, x, y, 6.1, 1.25, fill_color=RGBColor(0x22, 0x44, 0x6E),
             line_color=col, line_width=Pt(1.5))
    add_rect(slide, x, y, 0.5, 1.25, fill_color=col)
    add_text(slide, num, x+0.05, y+0.35, 0.4, 0.55, font_size=18, bold=True,
             color=DARK_BLUE, align=PP_ALIGN.CENTER)
    add_multiline_textbox(slide, [
        (text, False, WHITE, 13, 0)
    ], x+0.6, y+0.18, 5.4, 0.95)

add_text(slide, "Source: Quick Compendium of Clinical Pathology, 5th Ed. | Orris Medical Library",
         0.3, 7.05, 12.5, 0.35, font_size=10, color=RGBColor(0x88, 0xAA, 0xCC), align=PP_ALIGN.CENTER)

# ---- SAVE ----
out_path = "/tmp/workspace/spep-ppt/SPEP_Complete_Guide.pptx"
prs.save(out_path)
print(f"Saved: {out_path}")
Running Command

cd /tmp/workspace/spep-ppt && python build_spep.py 2>&1

Finding Files

**/*.py in /tmp/skills

Editing File

~/spep-ppt/build_spep.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/spep-ppt/build_spep.py'
Editing File

~/spep-ppt/build_spep.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/spep-ppt/build_spep.py'
Running Command

cd /tmp/workspace/spep-ppt && python build_spep.py 2>&1

Running Command

ls -lh /tmp/workspace/spep-ppt/SPEP_Complete_Guide.pptx

Your credits are exhausted. You can purchase a top-up or subscribe to a plan to continue using Orris. If you're already subscribed, your daily credits will reset tomorrow.

Plz do it

Your credits are exhausted. You can purchase a top-up or subscribe to a plan to continue using Orris. If you're already subscribed, your daily credits will reset tomorrow.

Please if not than elaborate here

Your credits are exhausted. You can purchase a top-up or subscribe to a plan to continue using Orris. If you're already subscribed, your daily credits will reset tomorrow.
This is a shared conversation. Sign in to Orris to start your own chat.