attachment
attachment

Please create a handbook pdf for calculation of of insulin dose in diabetes type 1 by looking at photos attached and from your own information what you have , please explain everything in very easy way as I am intern doctor in endocrinology department and explain all information with 5 examples of clinical patients with all mathematics calculation of insulin dose .

analyse_media
Reading File
Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Running Command

mkdir -p /tmp/workspace/insulin-handbook && ls /tmp/workspace/

Writing File

~/insulin-handbook/build_handbook.py

#!/usr/bin/env python3
"""
Insulin Dose Calculation Handbook for Type 1 Diabetes
For Intern Doctors in Endocrinology
"""

from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, PageBreak, KeepTogether
)
from reportlab.platypus.flowables import Flowable
import reportlab.rl_config

# ─── Color palette ────────────────────────────────────────────────────────────
BLUE_DARK   = colors.HexColor("#1A3C5E")
BLUE_MID    = colors.HexColor("#2E6DA4")
BLUE_LIGHT  = colors.HexColor("#D6E8F7")
TEAL        = colors.HexColor("#1A7A8A")
TEAL_LIGHT  = colors.HexColor("#D0EDF2")
GREEN_DARK  = colors.HexColor("#1A5E3A")
GREEN_LIGHT = colors.HexColor("#D4EDDA")
ORANGE      = colors.HexColor("#C0560A")
ORANGE_LIGHT= colors.HexColor("#FDEBD0")
RED_DARK    = colors.HexColor("#8B0000")
RED_LIGHT   = colors.HexColor("#FADADD")
YELLOW_LIGHT= colors.HexColor("#FFFDE7")
GREY_LIGHT  = colors.HexColor("#F5F5F5")
GREY_MID    = colors.HexColor("#CCCCCC")
WHITE       = colors.white
BLACK       = colors.black

W, H = A4

# ─── Style setup ──────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

def s(name, **kw):
    return ParagraphStyle(name, parent=styles["Normal"], **kw)

# Title styles
TITLE_STYLE = s("Title", fontSize=26, textColor=WHITE, alignment=TA_CENTER,
                fontName="Helvetica-Bold", spaceAfter=4, leading=30)
SUB_TITLE   = s("SubTitle", fontSize=13, textColor=BLUE_LIGHT, alignment=TA_CENTER,
                fontName="Helvetica-Oblique", spaceAfter=4)
AUTHOR_STYLE= s("Author", fontSize=11, textColor=YELLOW_LIGHT, alignment=TA_CENTER,
                fontName="Helvetica", spaceAfter=2)

# Section / heading
H1 = s("H1", fontSize=16, textColor=WHITE, fontName="Helvetica-Bold",
        spaceBefore=0, spaceAfter=4, leading=20)
H2 = s("H2", fontSize=13, textColor=BLUE_DARK, fontName="Helvetica-Bold",
        spaceBefore=8, spaceAfter=4, leading=16, leftIndent=0)
H3 = s("H3", fontSize=11, textColor=TEAL, fontName="Helvetica-Bold",
        spaceBefore=6, spaceAfter=3, leading=14)

# Body
BODY = s("Body", fontSize=10, textColor=BLACK, fontName="Helvetica",
         spaceBefore=2, spaceAfter=2, leading=14, alignment=TA_JUSTIFY)
BODY_BOLD = s("BodyBold", fontSize=10, textColor=BLACK, fontName="Helvetica-Bold",
              spaceBefore=2, spaceAfter=2, leading=14)
SMALL = s("Small", fontSize=9, textColor=colors.HexColor("#444444"),
          fontName="Helvetica", leading=12)
FORMULA = s("Formula", fontSize=11, textColor=BLUE_DARK, fontName="Helvetica-Bold",
            alignment=TA_CENTER, spaceBefore=4, spaceAfter=4, leading=16,
            backColor=BLUE_LIGHT, leftIndent=20, rightIndent=20, borderPad=6)
BULLET = s("Bullet", fontSize=10, textColor=BLACK, fontName="Helvetica",
           leftIndent=14, spaceBefore=1, spaceAfter=1, leading=14,
           bulletIndent=6, bulletFontName="Helvetica", bulletFontSize=10)
CASE_BODY = s("CaseBody", fontSize=10, textColor=BLACK, fontName="Helvetica",
              spaceBefore=2, spaceAfter=2, leading=14, leftIndent=10)
CALC_STEP = s("CalcStep", fontSize=10, textColor=GREEN_DARK, fontName="Helvetica",
              spaceBefore=2, spaceAfter=2, leading=14, leftIndent=10)
RESULT_STYLE= s("Result", fontSize=10, textColor=RED_DARK, fontName="Helvetica-Bold",
               spaceBefore=2, spaceAfter=2, leading=14, leftIndent=10)
NOTE_STYLE  = s("Note", fontSize=9, textColor=ORANGE, fontName="Helvetica-Oblique",
                spaceBefore=2, spaceAfter=2, leading=13, leftIndent=10)
TOC_STYLE   = s("TOC", fontSize=11, textColor=BLUE_DARK, fontName="Helvetica",
                spaceBefore=3, spaceAfter=3, leading=16, leftIndent=10)

# ─── Custom Flowables ─────────────────────────────────────────────────────────
class ColorBox(Flowable):
    """Colored header box for sections."""
    def __init__(self, text, style, bg_color, width=None, height=30, padding=8):
        super().__init__()
        self.text = text
        self.style = style
        self.bg_color = bg_color
        self.box_width = width
        self.box_height = height
        self.padding = padding

    def wrap(self, availWidth, availHeight):
        self.box_width = self.box_width or availWidth
        return self.box_width, self.box_height

    def draw(self):
        c = self.canv
        c.setFillColor(self.bg_color)
        c.roundRect(0, 0, self.box_width, self.box_height, 6, fill=1, stroke=0)
        p = Paragraph(self.text, self.style)
        p.wrapOn(c, self.box_width - 2*self.padding, self.box_height)
        p.drawOn(c, self.padding, self.padding // 2)


class TitlePage(Flowable):
    """Full cover page."""
    def wrap(self, availWidth, availHeight):
        return availWidth, availHeight

    def draw(self):
        c = self.canv
        w = W - 2*cm
        h = H - 2*cm

        # Background gradient (approx using rectangles)
        c.setFillColor(BLUE_DARK)
        c.rect(0, 0, w, h, fill=1, stroke=0)

        # Decorative stripe
        c.setFillColor(TEAL)
        c.rect(0, h*0.62, w, 5, fill=1, stroke=0)
        c.setFillColor(BLUE_MID)
        c.rect(0, h*0.62-7, w, 5, fill=1, stroke=0)

        # Title box
        c.setFillColor(colors.HexColor("#0D2A45"))
        c.roundRect(20, h*0.52, w-40, h*0.13, 8, fill=1, stroke=0)

        # Bottom bar
        c.setFillColor(TEAL)
        c.rect(0, 0, w, 50, fill=1, stroke=0)

        # Circle decoration
        c.setFillColor(colors.HexColor("#1A3C5E"))
        c.setStrokeColor(TEAL)
        c.setLineWidth(2)
        c.circle(w-50, h-50, 80, fill=1, stroke=1)
        c.setFillColor(BLUE_MID)
        c.circle(w-50, h-50, 60, fill=1, stroke=0)

        # Medical cross symbol
        c.setFillColor(WHITE)
        cx, cy = w-50, h-50
        c.rect(cx-5, cy-20, 10, 40, fill=1, stroke=0)
        c.rect(cx-20, cy-5, 40, 10, fill=1, stroke=0)


def build_title_page(story):
    story.append(Spacer(1, 2.5*cm))
    # Logo / emblem text
    story.append(Paragraph("⚕", s("Emblem", fontSize=48, textColor=TEAL,
                                   alignment=TA_CENTER, fontName="Helvetica-Bold")))
    story.append(Spacer(1, 0.4*cm))
    story.append(Paragraph(
        "INSULIN DOSE CALCULATION", 
        s("MT", fontSize=28, textColor=WHITE, alignment=TA_CENTER,
          fontName="Helvetica-Bold", leading=34)))
    story.append(Paragraph(
        "HANDBOOK FOR TYPE 1 DIABETES",
        s("MT2", fontSize=20, textColor=BLUE_LIGHT, alignment=TA_CENTER,
          fontName="Helvetica-Bold", leading=26)))
    story.append(Spacer(1, 0.5*cm))
    
    # Subtitle bar
    t = Table([[Paragraph("A Practical Guide for Intern Doctors in Endocrinology",
                          s("SB", fontSize=12, textColor=WHITE,
                            alignment=TA_CENTER, fontName="Helvetica-Oblique"))]],
              colWidths=[14*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), TEAL),
        ("ALIGN", (0,0), (-1,-1), "CENTER"),
        ("TOPPADDING", (0,0), (-1,-1), 8),
        ("BOTTOMPADDING", (0,0), (-1,-1), 8),
        ("ROUNDEDCORNERS", [6,6,6,6]),
    ]))
    story.append(t)
    story.append(Spacer(1, 1.5*cm))

    # Info box
    info = [
        ["Covers:", "Basal-Bolus Therapy   |   Correction Doses   |   Carb Ratios"],
        ["Includes:", "5 Complete Clinical Patient Examples with Full Math"],
        ["Level:", "Intern / Junior Resident in Endocrinology"],
        ["Date:", "August 2026"],
    ]
    tbl = Table(info, colWidths=[3*cm, 11.5*cm])
    tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#0D2A45")),
        ("TEXTCOLOR", (0,0), (0,-1), TEAL_LIGHT),
        ("TEXTCOLOR", (1,0), (1,-1), WHITE),
        ("FONTNAME", (0,0), (0,-1), "Helvetica-Bold"),
        ("FONTNAME", (1,0), (1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 10),
        ("TOPPADDING", (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING", (0,0), (-1,-1), 10),
        ("LINEBELOW", (0,0), (-1,-2), 0.5, colors.HexColor("#2A5080")),
    ]))
    story.append(tbl)
    story.append(Spacer(1, 2*cm))
    story.append(Paragraph(
        "Based on clinical guidelines and standard endocrinology practice",
        s("Disc", fontSize=9, textColor=GREY_MID, alignment=TA_CENTER,
          fontName="Helvetica-Oblique")))
    story.append(PageBreak())


def section_header(text, color=BLUE_DARK, icon=""):
    t = Table([[Paragraph(f"{icon}  {text}" if icon else text,
                          s("SH", fontSize=14, textColor=WHITE,
                            fontName="Helvetica-Bold", leading=18))]],
              colWidths=[16.5*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), color),
        ("TOPPADDING", (0,0), (-1,-1), 8),
        ("BOTTOMPADDING", (0,0), (-1,-1), 8),
        ("LEFTPADDING", (0,0), (-1,-1), 12),
        ("ROUNDEDCORNERS", [4,4,4,4]),
    ]))
    return t


def info_box(content_rows, header=None, bg=BLUE_LIGHT, hdr_bg=BLUE_DARK,
             col_widths=None):
    """General-purpose colored table box."""
    rows = []
    if header:
        rows.append([Paragraph(header, s("IH", fontSize=11, textColor=WHITE,
                                         fontName="Helvetica-Bold"))])
    for row in content_rows:
        if isinstance(row, str):
            rows.append([Paragraph(row, BODY)])
        else:
            rows.append([Paragraph(c, BODY) if isinstance(c, str) else c
                         for c in row])

    cw = col_widths or [16.5*cm]
    tbl = Table(rows, colWidths=cw)
    style_cmds = [
        ("BACKGROUND", (0,0), (-1,-1), bg),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 10),
        ("RIGHTPADDING", (0,0), (-1,-1), 10),
        ("GRID", (0,0), (-1,-1), 0.3, GREY_MID),
    ]
    if header:
        style_cmds += [
            ("BACKGROUND", (0,0), (-1,0), hdr_bg),
            ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ]
    tbl.setStyle(TableStyle(style_cmds))
    return tbl


def formula_box(text):
    t = Table([[Paragraph(text, s("FB", fontSize=11, textColor=BLUE_DARK,
                                   fontName="Helvetica-Bold", alignment=TA_CENTER,
                                   leading=16))]],
              colWidths=[16.5*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), BLUE_LIGHT),
        ("TOPPADDING", (0,0), (-1,-1), 10),
        ("BOTTOMPADDING", (0,0), (-1,-1), 10),
        ("LEFTPADDING", (0,0), (-1,-1), 15),
        ("BOX", (0,0), (-1,-1), 1.5, BLUE_MID),
        ("ROUNDEDCORNERS", [6,6,6,6]),
    ]))
    return t


def case_box(title, rows, bg=TEAL_LIGHT, hdr_bg=TEAL):
    """Clinical case box."""
    all_rows = [[Paragraph(title, s("CT", fontSize=12, textColor=WHITE,
                                     fontName="Helvetica-Bold"))]]
    for row in rows:
        if isinstance(row, str):
            all_rows.append([Paragraph(row, CASE_BODY)])
        else:
            all_rows.append(row)
    tbl = Table(all_rows, colWidths=[16.5*cm])
    tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), hdr_bg),
        ("BACKGROUND", (0,1), (-1,-1), bg),
        ("TOPPADDING", (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING", (0,0), (-1,-1), 12),
        ("BOX", (0,0), (-1,-1), 1, hdr_bg),
        ("LINEBELOW", (0,0), (-1,-2), 0.3, colors.HexColor("#B0D8DE")),
    ]))
    return tbl


def calc_table(steps, bg=GREEN_LIGHT, border=GREEN_DARK):
    rows = [[Paragraph("STEP", s("CH", fontSize=9, fontName="Helvetica-Bold",
                                  textColor=WHITE)),
             Paragraph("CALCULATION", s("CH", fontSize=9, fontName="Helvetica-Bold",
                                         textColor=WHITE)),
             Paragraph("RESULT", s("CH", fontSize=9, fontName="Helvetica-Bold",
                                    textColor=WHITE))]]
    for step in steps:
        rows.append([
            Paragraph(step[0], s("CS", fontSize=9, fontName="Helvetica-Bold",
                                   textColor=GREEN_DARK)),
            Paragraph(step[1], s("CC", fontSize=9, fontName="Helvetica")),
            Paragraph(step[2], s("CR", fontSize=9, fontName="Helvetica-Bold",
                                   textColor=RED_DARK)),
        ])
    tbl = Table(rows, colWidths=[2.8*cm, 9.5*cm, 4.2*cm])
    tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), GREEN_DARK),
        ("BACKGROUND", (0,1), (-1,-1), bg),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [bg, GREY_LIGHT]),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 6),
        ("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#A8D5B5")),
        ("BOX", (0,0), (-1,-1), 1, border),
    ]))
    return tbl


def result_summary_table(rows_data, hdr_bg=ORANGE, bg=ORANGE_LIGHT):
    rows = [[Paragraph("INSULIN TYPE", s("RSH", fontSize=10, fontName="Helvetica-Bold",
                                          textColor=WHITE)),
             Paragraph("DOSE", s("RSH", fontSize=10, fontName="Helvetica-Bold",
                                  textColor=WHITE)),
             Paragraph("TIMING", s("RSH", fontSize=10, fontName="Helvetica-Bold",
                                    textColor=WHITE)),
             Paragraph("SITE", s("RSH", fontSize=10, fontName="Helvetica-Bold",
                                  textColor=WHITE))]]
    for r in rows_data:
        rows.append([Paragraph(c, s("RSB", fontSize=10, fontName="Helvetica"))
                     for c in r])
    tbl = Table(rows, colWidths=[4*cm, 3*cm, 5*cm, 4.5*cm])
    tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), hdr_bg),
        ("BACKGROUND", (0,1), (-1,-1), bg),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [bg, YELLOW_LIGHT]),
        ("TOPPADDING", (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#E0A060")),
        ("BOX", (0,0), (-1,-1), 1, ORANGE),
    ]))
    return tbl

# ═══════════════════════════════════════════════════════════════════════════════
# BUILD DOCUMENT
# ═══════════════════════════════════════════════════════════════════════════════

def build():
    path = "/tmp/workspace/insulin-handbook/Insulin_Dose_Handbook_T1DM.pdf"
    doc = SimpleDocTemplate(
        path, pagesize=A4,
        leftMargin=1.8*cm, rightMargin=1.8*cm,
        topMargin=1.8*cm, bottomMargin=2*cm,
        title="Insulin Dose Calculation Handbook - Type 1 Diabetes",
        author="Endocrinology Education",
    )
    story = []

    # ── COVER PAGE ──────────────────────────────────────────────────────────
    build_title_page(story)

    # ── TABLE OF CONTENTS ───────────────────────────────────────────────────
    story.append(section_header("TABLE OF CONTENTS", BLUE_DARK))
    story.append(Spacer(1, 0.3*cm))
    toc_items = [
        ("1", "Understanding Type 1 Diabetes & Why We Need Insulin", "3"),
        ("2", "Types of Insulin at a Glance", "3"),
        ("3", "The Basal-Bolus Concept Explained Simply", "4"),
        ("4", "Step-by-Step Insulin Dose Calculation", "4"),
        ("5", "Key Formulas You Must Know", "5"),
        ("6", "Daily Dose Adjustment Factors", "6"),
        ("7", "Injection Technique & Devices", "6"),
        ("8", "The Honeymoon Phase", "7"),
        ("9", "Clinical Patient Examples (1-5)", "7"),
        ("10", "Quick Reference Card", "14"),
        ("11", "Common Mistakes & How to Avoid Them", "15"),
    ]
    for num, title, page in toc_items:
        row_data = [[
            Paragraph(f"<b>{num}.</b>", s("TN", fontSize=10, fontName="Helvetica-Bold",
                                            textColor=BLUE_DARK)),
            Paragraph(title, s("TT", fontSize=10, fontName="Helvetica",
                                textColor=BLACK)),
            Paragraph(f"<b>{page}</b>", s("TP", fontSize=10,
                                           fontName="Helvetica-Bold",
                                           textColor=BLUE_MID, alignment=TA_CENTER)),
        ]]
        t = Table(row_data, colWidths=[1*cm, 13.5*cm, 2*cm])
        t.setStyle(TableStyle([
            ("TOPPADDING", (0,0), (-1,-1), 4),
            ("BOTTOMPADDING", (0,0), (-1,-1), 4),
            ("LINEBELOW", (0,0), (-1,-1), 0.3, GREY_MID),
            ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
        ]))
        story.append(t)
    story.append(PageBreak())

    # ── SECTION 1: Understanding T1DM ───────────────────────────────────────
    story.append(section_header("1.  UNDERSTANDING TYPE 1 DIABETES & WHY WE NEED INSULIN",
                                BLUE_DARK))
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph(
        "In Type 1 Diabetes (T1DM), the immune system destroys the beta cells of the "
        "pancreas. These beta cells are the <b>only source of insulin</b> in the body. "
        "Without insulin, glucose cannot enter cells for energy, and blood glucose rises "
        "dangerously high.",
        BODY))
    story.append(Spacer(1, 0.2*cm))
    
    concept_rows = [
        ["Normal Pancreas", "Makes just the right amount of insulin 24 hours/day automatically"],
        ["T1DM Pancreas", "Makes ZERO insulin - patient must inject ALL insulin manually"],
        ["Our Goal", "Mimic the normal pancreas as closely as possible with injections"],
    ]
    t = Table(concept_rows, colWidths=[4*cm, 12.5*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (0,-1), BLUE_DARK),
        ("BACKGROUND", (1,0), (1,-1), BLUE_LIGHT),
        ("BACKGROUND", (1,2), (1,2), GREEN_LIGHT),
        ("TEXTCOLOR", (0,0), (0,-1), WHITE),
        ("FONTNAME", (0,0), (0,-1), "Helvetica-Bold"),
        ("FONTNAME", (1,0), (1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 10),
        ("TOPPADDING", (0,0), (-1,-1), 7),
        ("BOTTOMPADDING", (0,0), (-1,-1), 7),
        ("LEFTPADDING", (0,0), (-1,-1), 10),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph(
        "<b>Think of it this way:</b> A healthy pancreas works like an automatic water pump "
        "- it trickles water (insulin) all day and gives a big burst when you eat. "
        "In T1DM, the pump is broken, so <i>you</i> are the pump operator.",
        NOTE_STYLE))
    story.append(Spacer(1, 0.4*cm))

    # ── SECTION 2: Types of Insulin ─────────────────────────────────────────
    story.append(section_header("2.  TYPES OF INSULIN AT A GLANCE", BLUE_DARK))
    story.append(Spacer(1, 0.3*cm))

    insulin_table_data = [
        ["Category", "Examples", "Onset", "Peak", "Duration", "Used For"],
        ["Rapid-Acting\n(Ultra-short)", "Lispro (Humalog)\nAspart (NovoRapid)\nGlulisine (Apidra)",
         "5-15 min", "1-2 h", "3-5 h",
         "Bolus - with meals\n(given immediately\nbefore eating)"],
        ["Short-Acting\n(Regular)", "Regular insulin\n(Actrapid, Humulin R)",
         "30-60 min", "2-4 h", "6-8 h",
         "Bolus - 30 min\nbefore meals"],
        ["Intermediate\n(NPH)", "NPH (Insulatard\nHumulin N)",
         "1-3 h", "5-8 h", "12-16 h",
         "Background at night\nor daytime coverage"],
        ["Long-Acting\n(Basal)", "Glargine (Lantus)\nDetemir (Levemir)\nDegludec (Tresiba)",
         "1-2 h", "Flat\n(no peak)", "20-24 h\n(Degludec: 42 h)",
         "Basal - once or\ntwice daily"],
    ]
    t = Table(insulin_table_data, colWidths=[2.8*cm, 3.5*cm, 1.8*cm, 1.8*cm, 2.5*cm, 4.1*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), BLUE_DARK),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("FONTSIZE", (0,0), (-1,0), 9),
        ("FONTNAME", (0,1), (-1,-1), "Helvetica"),
        ("FONTSIZE", (0,1), (-1,-1), 9),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [BLUE_LIGHT, WHITE]),
        ("BACKGROUND", (0,-1), (-1,-1), GREEN_LIGHT),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 5),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
        ("VALIGN", (0,0), (-1,-1), "TOP"),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.3*cm))
    story.append(PageBreak())

    # ── SECTION 3: Basal-Bolus Concept ──────────────────────────────────────
    story.append(section_header("3.  THE BASAL-BOLUS CONCEPT EXPLAINED SIMPLY", TEAL))
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph(
        "The <b>Basal-Bolus regimen</b> is the gold standard for Type 1 DM. "
        "Think of it in two parts:",
        BODY))
    story.append(Spacer(1, 0.2*cm))

    bb_rows = [
        [Paragraph("<b>BASAL INSULIN\n(Background Dose)</b>",
                   s("BB1", fontSize=11, textColor=WHITE, fontName="Helvetica-Bold",
                     alignment=TA_CENTER)),
         Paragraph("<b>BOLUS INSULIN\n(Mealtime Dose)</b>",
                   s("BB2", fontSize=11, textColor=WHITE, fontName="Helvetica-Bold",
                     alignment=TA_CENTER))],
        [Paragraph(
            "- Long-acting insulin (e.g. Glargine/Detemir)\n"
            "- Given once or twice daily\n"
            "- Keeps blood sugar stable BETWEEN meals\n"
            "- Does NOT cover food\n"
            "- Mimics the tiny trickle of insulin the pancreas\n"
            "  normally releases all day\n"
            "- Amount: <b>~24-28 U/day (about 40-50% of TDD)</b>",
            s("BB1B", fontSize=10, fontName="Helvetica", leading=14)),
         Paragraph(
            "- Rapid-acting insulin (e.g. Aspart, Lispro)\n"
            "- Given at each meal (3x/day = breakfast, lunch, dinner)\n"
            "- Covers the carbohydrates in that meal\n"
            "- ALSO corrects high blood sugar\n"
            "- Mimics the big burst of insulin after eating\n"
            "  \n"
            "- Amount: <b>~20-30 U/day (about 50-60% of TDD)</b>",
            s("BB2B", fontSize=10, fontName="Helvetica", leading=14))],
    ]
    t = Table(bb_rows, colWidths=[8.25*cm, 8.25*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (0,0), TEAL),
        ("BACKGROUND", (1,0), (1,0), BLUE_DARK),
        ("BACKGROUND", (0,1), (0,1), TEAL_LIGHT),
        ("BACKGROUND", (1,1), (1,1), BLUE_LIGHT),
        ("TOPPADDING", (0,0), (-1,-1), 8),
        ("BOTTOMPADDING", (0,0), (-1,-1), 8),
        ("LEFTPADDING", (0,0), (-1,-1), 10),
        ("GRID", (0,0), (-1,-1), 1, WHITE),
        ("VALIGN", (0,0), (-1,-1), "TOP"),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.3*cm))
    story.append(formula_box(
        "TOTAL DAILY DOSE (TDD) = BASAL (40-50%) + BOLUS (50-60%)"))
    story.append(Spacer(1, 0.3*cm))

    # ── SECTION 4: Step-by-Step Calculation ─────────────────────────────────
    story.append(section_header("4.  STEP-BY-STEP INSULIN DOSE CALCULATION", TEAL))
    story.append(Spacer(1, 0.3*cm))

    # Step 1: TDD
    story.append(Paragraph("<b>STEP 1: Calculate the Total Daily Dose (TDD)</b>", H3))
    story.append(formula_box(
        "TDD = Body Weight (kg)  x  0.5 U/kg  (range: 0.4 - 0.8 U/kg)\n"
        "Usual adult range: 40 - 60 U/day"))
    story.append(Spacer(1, 0.15*cm))
    story.append(Paragraph(
        "Use <b>0.4 U/kg</b> for newly diagnosed, physically active, or lean patients. "
        "Use <b>0.6-0.8 U/kg</b> for established T1DM with moderate insulin resistance. "
        "In clinical practice, <b>0.5 U/kg</b> is the most common starting point.",
        BODY))

    # Step 2: Split basal/bolus
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph("<b>STEP 2: Split TDD into Basal and Bolus</b>", H3))
    split_table = [
        ["Component", "Proportion", "Calculation"],
        ["Basal (Long-acting)", "50% of TDD", "TDD x 0.5"],
        ["Total Bolus (all meals)", "50% of TDD", "TDD x 0.5"],
        ["Per Meal Bolus (equal split)", "~17% each", "Total Bolus ÷ 3"],
    ]
    t = Table(split_table, colWidths=[5.5*cm, 4*cm, 7*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), TEAL),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("FONTNAME", (0,1), (-1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 10),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [TEAL_LIGHT, WHITE]),
        ("TOPPADDING", (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
    ]))
    story.append(t)

    # Step 3: Correction factor
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph("<b>STEP 3: Calculate Insulin Sensitivity Factor (ISF) - "
                           "Correction Factor</b>", H3))
    story.append(formula_box(
        "ISF (mmol/L per unit) = 100 ÷ TDD\n"
        "This tells you: how much does 1 unit of insulin drop blood glucose (in mmol/L)?"))
    story.append(Spacer(1, 0.15*cm))
    story.append(Paragraph(
        "Example: TDD = 50 U  →  ISF = 100 ÷ 50 = <b>2.0 mmol/L per unit</b>. "
        "Meaning: each extra unit of rapid-acting insulin will lower blood sugar by ~2 mmol/L.",
        BODY))
    story.append(Paragraph(
        "Note from your notes: <b>1 U insulin lowers glucose by ~2.22 mmol/L</b> "
        "(this aligns with the 1800-rule for mg/dL, or the 100-rule for mmol/L).",
        NOTE_STYLE))

    # Step 4: Carb ratio
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph("<b>STEP 4: Calculate Insulin-to-Carbohydrate Ratio (ICR)</b>", H3))
    story.append(formula_box(
        "ICR = 500 ÷ TDD\n"
        "This tells you: how many grams of carbohydrate does 1 unit of insulin cover?"))
    story.append(Spacer(1, 0.15*cm))
    story.append(Paragraph(
        "Example: TDD = 50 U  →  ICR = 500 ÷ 50 = <b>10 g carbs per unit</b>. "
        "If the meal has 60 g of carbs, you need: 60 ÷ 10 = <b>6 units</b> of bolus.",
        BODY))
    story.append(Paragraph(
        "BREAD UNIT (BU) Approach from your notes: <b>1 BU = 12 g glucose = 50 kcal. "
        "1.4 U insulin needed per BU.</b>",
        NOTE_STYLE))

    # Step 5: Correction dose
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph("<b>STEP 5: Calculate Correction (Supplemental) Dose</b>", H3))
    story.append(formula_box(
        "Correction Dose = (Actual BG - Target BG) ÷ ISF\n"
        "Target BG is usually 5.5 - 6.0 mmol/L before meals"))
    story.append(Spacer(1, 0.15*cm))
    story.append(Paragraph(
        "Example: BG = 12 mmol/L, Target = 6 mmol/L, ISF = 2 mmol/L per unit.\n"
        "Correction = (12 - 6) ÷ 2 = <b>3 extra units</b>.",
        BODY))
    story.append(Spacer(1, 0.3*cm))
    story.append(PageBreak())

    # ── SECTION 5: Key Formulas ──────────────────────────────────────────────
    story.append(section_header("5.  KEY FORMULAS YOU MUST KNOW", ORANGE))
    story.append(Spacer(1, 0.3*cm))

    formulas = [
        ["FORMULA NAME", "FORMULA", "WHAT IT MEANS"],
        ["Total Daily Dose\n(Starting)", "Weight(kg) x 0.5",
         "Starting dose for new patient"],
        ["Basal Dose", "TDD x 0.5 (50%)",
         "Long-acting insulin/day"],
        ["Total Bolus", "TDD x 0.5 (50%)",
         "Split equally over 3 meals"],
        ["Per-Meal Bolus\n(Equal meals)", "Total Bolus ÷ 3",
         "Rapid-acting per meal"],
        ["Insulin-to-Carb\nRatio (ICR)", "500 ÷ TDD",
         "Grams of carbs per 1 unit"],
        ["Insulin Sensitivity\nFactor (ISF)", "100 ÷ TDD\n(mmol/L per unit)",
         "How much 1U lowers BG"],
        ["Correction Dose", "(Actual BG - Target BG) ÷ ISF",
         "Extra units to fix high BG"],
        ["Meal Bolus Total", "Carbs(g) ÷ ICR + Correction Dose",
         "Total rapid-acting at that meal"],
        ["Basal: 2/3 AM\n1/3 PM split", "AM dose = Basal x 2/3\nPM dose = Basal x 1/3",
         "When using NPH twice daily"],
        ["1 BU Rule", "1 BU = 12g carbs = 50 kcal\n→ 1.4 U insulin per BU",
         "Bread unit calculation"],
    ]
    t = Table(formulas, colWidths=[4.5*cm, 6*cm, 6*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), ORANGE),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("FONTSIZE", (0,0), (-1,0), 10),
        ("FONTNAME", (0,1), (-1,-1), "Helvetica"),
        ("FONTSIZE", (0,1), (-1,-1), 9),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [ORANGE_LIGHT, YELLOW_LIGHT]),
        ("TOPPADDING", (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#E8C080")),
        ("VALIGN", (0,0), (-1,-1), "TOP"),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.3*cm))
    story.append(PageBreak())

    # ── SECTION 6: Adjustment Factors ───────────────────────────────────────
    story.append(section_header("6.  DAILY DOSE ADJUSTMENT FACTORS", BLUE_DARK))
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph(
        "Insulin is never a fixed dose forever - it must be adjusted based on "
        "what is happening with the patient each day. The four main adjustment factors are:",
        BODY))
    story.append(Spacer(1, 0.2*cm))

    adj_data = [
        ["Factor", "Effect on Insulin Dose", "Practical Example"],
        ["1. Glycemic Profile\n(Blood glucose log)", "Adjust to keep BG in target range\n(4.4-7.8 mmol/L fasting)",
         "If BG consistently high before bed -> increase evening basal"],
        ["2. Carbohydrate Content\nper meal", "More carbs = more bolus needed\n(use ICR formula)",
         "Large meal (90g carbs) vs small (30g carbs): 3x more bolus for large"],
        ["3. Physical Activity\nLevel", "Exercise LOWERS insulin requirement\n(can reduce bolus by 20-50%)",
         "Patient goes jogging: reduce pre-exercise bolus; monitor for hypoglycemia"],
        ["4. Intercurrent Illness\n(Sick day rules)", "Illness usually RAISES insulin need\n(stress hormones are anti-insulin)",
         "Patient has flu with fever: increase basal dose; check BG every 2-4 hours"],
    ]
    t = Table(adj_data, colWidths=[3.5*cm, 6*cm, 7*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), BLUE_DARK),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("FONTNAME", (0,1), (-1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 9),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [BLUE_LIGHT, WHITE]),
        ("TOPPADDING", (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
        ("VALIGN", (0,0), (-1,-1), "TOP"),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.4*cm))

    # ── SECTION 7: Injection Technique ──────────────────────────────────────
    story.append(section_header("7.  INJECTION TECHNIQUE & DEVICES", TEAL))
    story.append(Spacer(1, 0.3*cm))

    inj_data = [
        ["INSULIN TYPE", "DEVICE", "INJECTION SITE", "DEPTH/ANGLE", "TIMING"],
        ["Rapid/Short-Acting\n(Bolus)", "Insulin pen\nor syringe",
         "Abdomen (SC)\n- fastest absorption", "45 degrees\n(90 if obese)",
         "Rapid-acting:\nimmediately before\nShort-acting:\n30 min before"],
        ["Intermediate/Long-Acting\n(Basal)", "Insulin pen\nor syringe",
         "Thigh or\nbuttock (SC)",
         "Deep SC, pinch skin\n45 degrees (90 if thick fat)",
         "Usually once daily\nat bedtime (or\ntwice for NPH)"],
    ]
    t = Table(inj_data, colWidths=[3.5*cm, 2.5*cm, 3.5*cm, 3.5*cm, 3.5*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), TEAL),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("FONTNAME", (0,1), (-1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 9),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [TEAL_LIGHT, WHITE]),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 6),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
        ("VALIGN", (0,0), (-1,-1), "TOP"),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.2*cm))
    story.append(info_box([
        "<b>Insulin Pens (100 U/mL; cartridges 1.5 or 3 mL):</b> Preferred for children, adolescents, "
        "pregnant women, visually impaired, and amputees.",
        "<b>Disposable Syringes (calibrated to insulin concentration):</b> Used for most other patients.",
        "<b>IMPORTANT - Rotation:</b> Always rotate injection sites within the same area daily to prevent "
        "lipodystrophy (fatty lumps under skin that cause erratic absorption).",
    ], bg=TEAL_LIGHT))
    story.append(Spacer(1, 0.4*cm))

    # ── SECTION 8: Honeymoon Phase ───────────────────────────────────────────
    story.append(section_header("8.  THE HONEYMOON PHASE (Partial Remission)", ORANGE))
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph(
        "In the <b>first weeks to months after diagnosis</b> of T1DM, the remaining "
        "beta cells may temporarily recover and produce some insulin on their own. "
        "This is called the <b>Honeymoon Period</b>.",
        BODY))
    story.append(Spacer(1, 0.15*cm))
    honey_rows = [
        "When: Typically within weeks to months of initial diagnosis",
        "What happens: Endogenous (own) insulin production temporarily recovers",
        "Result: Patient needs LESS injected insulin - dose must be reduced",
        "Duration: Usually a few weeks to a few months (rarely > 1 year)",
        "Warning: Do NOT stop insulin completely - continue low-dose insulin to preserve remaining beta cells",
        "Clinical sign: Unexplained hypoglycemia with same insulin dose = may be entering honeymoon",
    ]
    story.append(info_box(honey_rows, bg=ORANGE_LIGHT))
    story.append(PageBreak())

    # ═══════════════════════════════════════════════════════════════════════════
    # SECTION 9: CLINICAL PATIENT EXAMPLES
    # ═══════════════════════════════════════════════════════════════════════════
    story.append(section_header("9.  CLINICAL PATIENT EXAMPLES WITH FULL CALCULATIONS",
                                colors.HexColor("#5B2C6F")))
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph(
        "The following 5 patient cases will walk you through every step of insulin "
        "dose calculation. Each case is different to show you how to adapt the formulas "
        "to different clinical situations.",
        BODY))
    story.append(Spacer(1, 0.3*cm))

    # ── CASE 1 ───────────────────────────────────────────────────────────────
    story.append(section_header("PATIENT 1 - New Diagnosis, Lean Adult",
                                colors.HexColor("#1A5276")))
    story.append(Spacer(1, 0.2*cm))

    # Patient profile
    p1_profile = [
        ["PATIENT DETAILS", ""],
        ["Name / ID:", "Patient A (newly diagnosed T1DM)"],
        ["Age:", "22 years"],
        ["Weight:", "68 kg"],
        ["HbA1c:", "11.2% (very high at diagnosis)"],
        ["Blood glucose now:", "16.4 mmol/L (fasting)"],
        ["Target fasting BG:", "5.5 mmol/L"],
        ["Meals:", "3 regular meals; breakfast ~60g carbs, lunch ~75g carbs, dinner ~60g carbs"],
        ["Activity:", "Moderate (university student)"],
        ["Insulin type:", "Glargine (basal) + Aspart (bolus)"],
    ]
    t = Table(p1_profile, colWidths=[4*cm, 12.5*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#1A5276")),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("SPAN", (0,0), (-1,0)),
        ("BACKGROUND", (0,1), (0,-1), BLUE_LIGHT),
        ("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
        ("FONTNAME", (1,1), (1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 10),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.2*cm))

    # Calculation steps
    story.append(Paragraph("<b>Step-by-Step Calculation:</b>", H3))
    steps1 = [
        ("Step 1\nTotal Daily\nDose (TDD)",
         "TDD = Weight x 0.4 U/kg (new diagnosis = start low)\n= 68 x 0.4",
         "= 27.2 → Round to 28 U/day"),
        ("Step 2\nBasal Dose",
         "Basal = TDD x 50%\n= 28 x 0.5",
         "= 14 U Glargine/day"),
        ("Step 3\nTotal Bolus",
         "Total Bolus = TDD x 50%\n= 28 x 0.5",
         "= 14 U Aspart/day\n(for all 3 meals)"),
        ("Step 4\nPer Meal\nBolus",
         "Per meal = Total Bolus ÷ 3\n= 14 ÷ 3",
         "= ~4-5 U per meal\n(roughly equal)"),
        ("Step 5\nISF",
         "ISF = 100 ÷ TDD\n= 100 ÷ 28",
         "= 3.6 mmol/L per unit"),
        ("Step 6\nICR",
         "ICR = 500 ÷ TDD\n= 500 ÷ 28",
         "= 17.9 → ~1U per 18g carbs"),
        ("Step 7\nCorrection\nDose (now)",
         "BG = 16.4, Target = 5.5\nCorrection = (16.4 - 5.5) ÷ 3.6\n= 10.9 ÷ 3.6",
         "= ~3 U correction\n(add to breakfast bolus)"),
        ("Step 8\nBreakfast\nBolus (full)",
         "Carb bolus for breakfast (60g):\n= 60 ÷ 18 = 3.3 U\nPlus correction: + 3 U",
         "= ~6-7 U Aspart\nbefore breakfast"),
    ]
    story.append(calc_table(steps1))
    story.append(Spacer(1, 0.2*cm))

    story.append(Paragraph("<b>Final Prescription for Patient A:</b>", H3))
    p1_rx = [
        ["Glargine (Lantus)", "14 U", "At bedtime (10 PM)", "Thigh SC"],
        ["Aspart (NovoRapid) - Breakfast", "6-7 U", "Immediately before breakfast", "Abdomen SC"],
        ["Aspart (NovoRapid) - Lunch", "4-5 U", "Immediately before lunch", "Abdomen SC"],
        ["Aspart (NovoRapid) - Dinner", "4-5 U", "Immediately before dinner", "Abdomen SC"],
    ]
    story.append(result_summary_table(p1_rx))
    story.append(Spacer(1, 0.2*cm))
    story.append(Paragraph(
        "Monitor BG before each meal and at 2 AM for the first week. "
        "Adjust each dose by 1-2 U every 3 days based on glycemic log. "
        "Watch for honeymoon phase in coming weeks.",
        NOTE_STYLE))
    story.append(Spacer(1, 0.4*cm))

    # ── CASE 2 ───────────────────────────────────────────────────────────────
    story.append(section_header("PATIENT 2 - Established T1DM, Overweight",
                                colors.HexColor("#145A32")))
    story.append(Spacer(1, 0.2*cm))

    p2_profile = [
        ["PATIENT DETAILS", ""],
        ["Name / ID:", "Patient B (T1DM x 5 years)"],
        ["Age:", "35 years"],
        ["Weight:", "90 kg (BMI 29)"],
        ["HbA1c:", "9.1%"],
        ["Blood glucose now:", "8.5 mmol/L (pre-lunch)"],
        ["Target pre-meal BG:", "5.5 mmol/L"],
        ["Lunch meal:", "90 g carbohydrates planned"],
        ["Activity:", "Sedentary (office worker)"],
        ["Insulin type:", "Detemir (basal) + Lispro (bolus)"],
    ]
    t = Table(p2_profile, colWidths=[4*cm, 12.5*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#145A32")),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("SPAN", (0,0), (-1,0)),
        ("BACKGROUND", (0,1), (0,-1), GREEN_LIGHT),
        ("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
        ("FONTNAME", (1,1), (1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 10),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.2*cm))

    story.append(Paragraph("<b>Step-by-Step Calculation:</b>", H3))
    steps2 = [
        ("Step 1\nTDD",
         "TDD = Weight x 0.6 U/kg (overweight, insulin-resistant)\n= 90 x 0.6",
         "= 54 U/day"),
        ("Step 2\nBasal Dose",
         "Basal = TDD x 50%\n= 54 x 0.5",
         "= 27 U Detemir/day"),
        ("Step 3\nTotal Bolus",
         "Total Bolus = TDD x 50%\n= 54 x 0.5",
         "= 27 U Lispro/day"),
        ("Step 4\nISF",
         "ISF = 100 ÷ TDD\n= 100 ÷ 54",
         "= 1.85 mmol/L per unit\n(~1.9)"),
        ("Step 5\nICR",
         "ICR = 500 ÷ TDD\n= 500 ÷ 54",
         "= 9.3 → ~1U per 9g carbs"),
        ("Step 6\nCarb Bolus\nfor Lunch",
         "Lunch = 90g carbs ÷ ICR\n= 90 ÷ 9",
         "= 10 U for food"),
        ("Step 7\nCorrection",
         "BG = 8.5 mmol/L, Target = 5.5\nCorrection = (8.5 - 5.5) ÷ 1.85\n= 3 ÷ 1.85",
         "= 1.6 → round to 2 U"),
        ("Step 8\nTotal Lunch\nBolus",
         "Carb bolus + Correction\n= 10 + 2",
         "= 12 U Lispro\nbefore lunch"),
    ]
    story.append(calc_table(steps2, bg=GREEN_LIGHT, border=GREEN_DARK))
    story.append(Spacer(1, 0.2*cm))

    story.append(Paragraph("<b>Final Prescription for Patient B:</b>", H3))
    p2_rx = [
        ["Detemir (Levemir)", "27 U", "Bedtime (10 PM)", "Thigh SC"],
        ["Lispro (Humalog) - Breakfast", "9 U", "Immediately before breakfast", "Abdomen SC"],
        ["Lispro (Humalog) - Lunch", "12 U (with correction)", "Immediately before lunch", "Abdomen SC"],
        ["Lispro (Humalog) - Dinner", "9 U", "Immediately before dinner", "Abdomen SC"],
    ]
    story.append(result_summary_table(p2_rx))
    story.append(Spacer(1, 0.2*cm))
    story.append(Paragraph(
        "Because this patient is overweight and sedentary, insulin requirements are higher. "
        "Encourage weight management and physical activity - even moderate exercise can "
        "reduce insulin requirements by 20-30%.",
        NOTE_STYLE))
    story.append(PageBreak())

    # ── CASE 3 ───────────────────────────────────────────────────────────────
    story.append(section_header("PATIENT 3 - Child/Adolescent (10 years old)",
                                colors.HexColor("#6E2F8A")))
    story.append(Spacer(1, 0.2*cm))

    p3_profile = [
        ["PATIENT DETAILS", ""],
        ["Name / ID:", "Patient C (T1DM x 2 years)"],
        ["Age:", "10 years old"],
        ["Weight:", "32 kg"],
        ["HbA1c:", "8.4%"],
        ["Current fasting BG:", "9.2 mmol/L"],
        ["Target fasting BG:", "5.5 mmol/L"],
        ["Breakfast:", "45 g carbohydrates"],
        ["Insulin type:", "Glargine (basal) + Aspart (bolus) via insulin pen"],
    ]
    t = Table(p3_profile, colWidths=[4*cm, 12.5*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#6E2F8A")),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("SPAN", (0,0), (-1,0)),
        ("BACKGROUND", (0,1), (0,-1), colors.HexColor("#E8D5F5")),
        ("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
        ("FONTNAME", (1,1), (1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 10),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.2*cm))

    story.append(Paragraph(
        "<b>Note for children:</b> Use 0.5 U/kg for established T1DM in children. "
        "Children are more insulin-sensitive than adults and hypoglycemia is dangerous, "
        "so always start conservatively. Insulin pens are preferred for children.",
        NOTE_STYLE))
    story.append(Spacer(1, 0.15*cm))

    story.append(Paragraph("<b>Step-by-Step Calculation:</b>", H3))
    steps3 = [
        ("Step 1\nTDD",
         "TDD = Weight x 0.5 U/kg (established child T1DM)\n= 32 x 0.5",
         "= 16 U/day"),
        ("Step 2\nBasal",
         "Basal = TDD x 50%\n= 16 x 0.5",
         "= 8 U Glargine\nat bedtime"),
        ("Step 3\nTotal Bolus",
         "Total Bolus = TDD x 50%\n= 16 x 0.5",
         "= 8 U Aspart/day"),
        ("Step 4\nPer Meal Bolus",
         "Per meal = 8 ÷ 3",
         "= ~2-3 U per meal"),
        ("Step 5\nISF",
         "ISF = 100 ÷ TDD\n= 100 ÷ 16",
         "= 6.25 mmol/L per unit"),
        ("Step 6\nICR",
         "ICR = 500 ÷ TDD\n= 500 ÷ 16",
         "= 31.25 → ~1U per 31g carbs"),
        ("Step 7\nBreakfast Carb\nBolus",
         "Carb bolus for 45g breakfast:\n= 45 ÷ 31",
         "= 1.5 → round to 2 U"),
        ("Step 8\nCorrection",
         "BG = 9.2, Target = 5.5\nCorrection = (9.2 - 5.5) ÷ 6.25\n= 3.7 ÷ 6.25",
         "= 0.6 → round to 1 U"),
        ("Step 9\nTotal Breakfast\nBolus",
         "Carb bolus + Correction\n= 2 + 1",
         "= 3 U Aspart\nbefore breakfast"),
    ]
    story.append(calc_table(steps3, bg=colors.HexColor("#E8D5F5"),
                             border=colors.HexColor("#6E2F8A")))
    story.append(Spacer(1, 0.2*cm))
    story.append(Paragraph("<b>Final Prescription for Patient C:</b>", H3))
    p3_rx = [
        ["Glargine (Lantus)", "8 U", "Bedtime (10 PM)", "Thigh SC"],
        ["Aspart - Breakfast", "3 U", "Immediately before breakfast", "Abdomen SC"],
        ["Aspart - Lunch", "2-3 U", "Immediately before lunch", "Abdomen SC"],
        ["Aspart - Dinner", "2-3 U", "Immediately before dinner", "Abdomen SC"],
    ]
    story.append(result_summary_table(p3_rx,
                                       hdr_bg=colors.HexColor("#6E2F8A"),
                                       bg=colors.HexColor("#E8D5F5")))
    story.append(Spacer(1, 0.2*cm))
    story.append(Paragraph(
        "Always use insulin pens for children (accurate dosing, less pain). "
        "Check BG before every meal and at 2-3 AM. Parent/guardian education is essential. "
        "School nurse must be informed.",
        NOTE_STYLE))
    story.append(Spacer(1, 0.4*cm))

    # ── CASE 4 ───────────────────────────────────────────────────────────────
    story.append(section_header("PATIENT 4 - Active Patient with Pre-Exercise Adjustment",
                                colors.HexColor("#7D6608")))
    story.append(Spacer(1, 0.2*cm))

    p4_profile = [
        ["PATIENT DETAILS", ""],
        ["Name / ID:", "Patient D (T1DM x 8 years)"],
        ["Age:", "28 years"],
        ["Weight:", "75 kg"],
        ["HbA1c:", "7.2%"],
        ["Pre-dinner BG:", "7.0 mmol/L"],
        ["Target BG:", "6.0 mmol/L"],
        ["Dinner:", "60 g carbohydrates"],
        ["Evening plan:", "1-hour moderate cycling AFTER dinner"],
        ["Insulin type:", "Glargine (basal) + Lispro (bolus)"],
    ]
    t = Table(p4_profile, colWidths=[4*cm, 12.5*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#7D6608")),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("SPAN", (0,0), (-1,0)),
        ("BACKGROUND", (0,1), (0,-1), YELLOW_LIGHT),
        ("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
        ("FONTNAME", (1,1), (1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 10),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.2*cm))

    story.append(Paragraph("<b>Step-by-Step Calculation:</b>", H3))
    steps4 = [
        ("Step 1\nTDD",
         "TDD = 75 x 0.5 U/kg (well-controlled active patient)",
         "= 37.5 → 38 U/day"),
        ("Step 2\nBasal",
         "Basal = 38 x 50%",
         "= 19 U Glargine/day"),
        ("Step 3\nISF",
         "ISF = 100 ÷ 38",
         "= 2.6 mmol/L per unit"),
        ("Step 4\nICR",
         "ICR = 500 ÷ 38",
         "= 13.2 → 1U per 13g carbs"),
        ("Step 5\nStandard\nDinner Bolus",
         "Carb bolus: 60g ÷ 13 = 4.6 → 5 U\nCorrection: BG=7.0, Target=6.0\n(7.0-6.0) ÷ 2.6 = 0.4 → 0 U",
         "= 5 U standard"),
        ("Step 6\nExercise\nAdjustment",
         "Moderate exercise for 1 hour after dinner\nReduce bolus by ~30% to prevent\nexercise-induced hypoglycemia\n5 U x 0.7 (30% reduction)",
         "= 3.5 → 3-4 U\nadjusted dinner bolus"),
        ("Step 7\nAlso reduce\nBasal tonight",
         "If wearing insulin pump: reduce basal by 50%\nIf on injections: consider reducing\nevening basal by 20% (19 x 0.8)",
         "= ~15 U Glargine\nthis evening only"),
    ]
    story.append(calc_table(steps4, bg=YELLOW_LIGHT, border=colors.HexColor("#7D6608")))
    story.append(Spacer(1, 0.2*cm))
    story.append(Paragraph("<b>Final Prescription for Patient D (exercise day):</b>", H3))
    p4_rx = [
        ["Glargine (Lantus)", "15 U (reduced)", "Bedtime - exercise day only", "Thigh SC"],
        ["Lispro - Breakfast", "7 U", "Immediately before breakfast", "Abdomen SC"],
        ["Lispro - Lunch", "7 U", "Immediately before lunch", "Abdomen SC"],
        ["Lispro - Dinner", "3-4 U (REDUCED)", "Immediately before dinner", "Abdomen SC"],
    ]
    story.append(result_summary_table(p4_rx,
                                       hdr_bg=colors.HexColor("#7D6608"),
                                       bg=YELLOW_LIGHT))
    story.append(Spacer(1, 0.2*cm))
    story.append(Paragraph(
        "Always have fast-acting carbs (e.g. glucose tablets, juice) available during exercise. "
        "Check BG before, during (if > 1 hour), and after exercise. On non-exercise days, "
        "give the standard 5 U dinner bolus.",
        NOTE_STYLE))
    story.append(PageBreak())

    # ── CASE 5 ───────────────────────────────────────────────────────────────
    story.append(section_header("PATIENT 5 - Sick Day Management (Intercurrent Illness)",
                                colors.HexColor("#922B21")))
    story.append(Spacer(1, 0.2*cm))

    p5_profile = [
        ["PATIENT DETAILS", ""],
        ["Name / ID:", "Patient E (T1DM x 3 years)"],
        ["Age:", "19 years"],
        ["Weight:", "60 kg"],
        ["Usual HbA1c:", "7.8%"],
        ["Current situation:", "Flu with fever 38.5°C, vomiting, not eating normally"],
        ["Morning BG:", "18.5 mmol/L (very high due to illness)"],
        ["Urine/blood ketones:", "2+ (moderate) - not yet DKA"],
        ["Target BG:", "7.0-10.0 mmol/L (allow higher target during illness - safety)"],
        ["Usual TDD:", "30 U/day (60 x 0.5)"],
    ]
    t = Table(p5_profile, colWidths=[4*cm, 12.5*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#922B21")),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("SPAN", (0,0), (-1,0)),
        ("BACKGROUND", (0,1), (0,-1), RED_LIGHT),
        ("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
        ("FONTNAME", (1,1), (1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 10),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.2*cm))

    story.append(Paragraph(
        "<b>SICK DAY RULE:</b> During illness, stress hormones (cortisol, adrenaline, glucagon) "
        "are released which counteract insulin. Blood glucose rises even if the patient is not eating. "
        "<b>NEVER stop insulin during illness</b> - this is a common dangerous mistake.",
        NOTE_STYLE))
    story.append(Spacer(1, 0.15*cm))

    steps5 = [
        ("Step 1\nUsual TDD",
         "Usual TDD = 60 kg x 0.5 = 30 U/day\nBasal = 15 U Glargine\nBolus total = 15 U",
         "Normal day dose"),
        ("Step 2\nSick Day\nBasal",
         "INCREASE basal by 20% during illness\nNew basal = 15 x 1.2",
         "= 18 U Glargine\n(increased)"),
        ("Step 3\nISF for sick\ncorrection",
         "ISF = 100 ÷ TDD (use usual TDD)\n= 100 ÷ 30",
         "= 3.3 mmol/L per unit"),
        ("Step 4\nCorrection for\nBG = 18.5",
         "Target during illness = 8.0 mmol/L (higher target, safer)\nCorrection = (18.5 - 8.0) ÷ 3.3\n= 10.5 ÷ 3.3",
         "= 3.2 → 3 U\ncorrection bolus"),
        ("Step 5\nFood Bolus\n(if eating)",
         "Patient vomiting - eating only 20g carbs (crackers)\nICR = 500 ÷ 30 = 16.7 → 1U per 17g carbs\nCarb bolus = 20 ÷ 17",
         "= 1.2 → 1 U\nfor food"),
        ("Step 6\nTotal Bolus\nthis dose",
         "Correction + Food bolus\n= 3 + 1",
         "= 4 U Rapid-acting\nnow"),
        ("Step 7\nMonitoring\nPlan",
         "Check BG every 2-3 hours\nCheck ketones every 4-6 hours\nIf not improving in 4-6 hours → HOSPITAL",
         "Frequent monitoring\nmandatory"),
    ]
    story.append(calc_table(steps5, bg=RED_LIGHT, border=colors.HexColor("#922B21")))
    story.append(Spacer(1, 0.2*cm))
    story.append(Paragraph("<b>Final Prescription for Patient E (sick day):</b>", H3))
    p5_rx = [
        ["Glargine (Lantus)", "18 U (INCREASED)", "Morning (not bedtime - ill)", "Thigh SC"],
        ["Rapid-acting correction", "4 U now", "Given once for correction + food", "Abdomen SC"],
        ["Re-check BG in 2-3 hours", "Repeat correction if BG > 10", "Every 2-3 hours", "Abdomen SC"],
    ]
    story.append(result_summary_table(p5_rx,
                                       hdr_bg=colors.HexColor("#922B21"),
                                       bg=RED_LIGHT))
    story.append(Spacer(1, 0.2*cm))

    # Sick day rules box
    sick_rules = [
        "<b>SICK DAY RULES (memorize these):</b>",
        "1. NEVER stop insulin - illness raises blood glucose even without eating",
        "2. Increase basal insulin by 10-20% during fever/infection",
        "3. Check blood glucose every 2-4 hours (not just morning and night)",
        "4. Check for ketones every 4-6 hours if BG > 14 mmol/L",
        "5. Drink fluids (water, clear broth, sugar-free drinks)",
        "6. If you can't eat: give basal + correction only (skip food bolus)",
        "7. If vomiting and can't keep fluids down: GO TO HOSPITAL IMMEDIATELY",
        "8. If ketones are large (3+) or rising: GO TO HOSPITAL (risk of DKA)",
        "9. Contact your endocrinologist/diabetes team for guidance",
    ]
    story.append(info_box(sick_rules, bg=RED_LIGHT, hdr_bg=colors.HexColor("#922B21")))
    story.append(PageBreak())

    # ── SECTION 10: Quick Reference Card ────────────────────────────────────
    story.append(section_header("10.  QUICK REFERENCE CARD", colors.HexColor("#1C2833")))
    story.append(Spacer(1, 0.3*cm))

    qr_data = [
        ["SITUATION", "ACTION"],
        ["New T1DM patient", "Start with 0.4 U/kg/day total; 50% basal + 50% bolus"],
        ["Established T1DM", "0.5-0.7 U/kg/day based on control and weight"],
        ["Calculate Insulin:Carb ratio", "ICR = 500 ÷ TDD (grams of carb per 1 unit)"],
        ["Calculate Correction Factor", "ISF = 100 ÷ TDD (mmol/L drop per 1 unit)"],
        ["High BG before meal", "Add correction = (Actual BG - Target) ÷ ISF to meal bolus"],
        ["Before exercise", "Reduce bolus by 20-50% depending on exercise intensity"],
        ["During illness", "Increase basal by 20%, check BG every 2-4 hours, NEVER stop insulin"],
        ["Suspected honeymoon", "Reduce doses gradually; do not stop insulin completely"],
        ["Prevent lipodystrophy", "Rotate injection sites daily within same anatomical area"],
        ["NPH twice-daily split", "2/3 of basal dose in morning + 1/3 in evening"],
        ["1 Bread Unit (BU)", "= 12g glucose = 50 kcal = 1.4 U insulin needed"],
        ["1 U rapid-acting insulin", "Lowers BG by ~2.22 mmol/L (from your notes)"],
    ]
    t = Table(qr_data, colWidths=[6*cm, 10.5*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#1C2833")),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("FONTNAME", (0,1), (-1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 9.5),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [BLUE_LIGHT, WHITE]),
        ("TOPPADDING", (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
        ("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
        ("TEXTCOLOR", (0,1), (0,-1), BLUE_DARK),
    ]))
    story.append(t)
    story.append(PageBreak())

    # ── SECTION 11: Common Mistakes ──────────────────────────────────────────
    story.append(section_header("11.  COMMON MISTAKES & HOW TO AVOID THEM",
                                colors.HexColor("#922B21")))
    story.append(Spacer(1, 0.3*cm))

    mistakes = [
        ["MISTAKE", "WHY IT'S DANGEROUS", "CORRECT APPROACH"],
        ["Stopping insulin\nduring illness",
         "Stress hormones raise BG dangerously;\ncan trigger DKA rapidly",
         "Always continue insulin; increase basal\nif BG rising during illness"],
        ["Injecting short-acting\ninsulin without eating",
         "Severe hypoglycemia - no food to\ncover the insulin",
         "Only give bolus insulin when a meal\nis ready and about to be eaten"],
        ["Using same injection\nsite repeatedly",
         "Lipodystrophy: fatty lumps form;\nerratic insulin absorption",
         "Rotate daily within same area\n(e.g. upper-lower abdomen quadrants)"],
        ["Not adjusting for\nexercise",
         "Exercise-induced hypoglycemia;\ncan be severe and delayed (4-8 hours later)",
         "Reduce pre-exercise bolus 20-50%;\nhave glucose tablets available"],
        ["Forgetting correction\ndose before meals",
         "Pre-existing high BG is not treated;\npost-meal spike even worse",
         "Always check BG before meal;\nadd correction dose to meal bolus"],
        ["Starting TDD too high\nin new patients",
         "Risk of severe hypoglycemia;\npancreas may still make some insulin\n(honeymoon)",
         "Start at 0.4 U/kg for new T1DM;\ntitrate up slowly based on BG log"],
        ["Not rotating\nbasal insulin sites",
         "Variable absorption of long-acting insulin;\nunpredictable overnight control",
         "Rotate thigh/buttock sites daily;\ndocument injection location"],
    ]
    t = Table(mistakes, colWidths=[3.5*cm, 6*cm, 7*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#922B21")),
        ("TEXTCOLOR", (0,0), (-1,0), WHITE),
        ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
        ("FONTNAME", (0,1), (-1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 9),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [RED_LIGHT, YELLOW_LIGHT]),
        ("TOPPADDING", (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING", (0,0), (-1,-1), 6),
        ("GRID", (0,0), (-1,-1), 0.5, GREY_MID),
        ("VALIGN", (0,0), (-1,-1), "TOP"),
        ("TEXTCOLOR", (0,1), (0,-1), RED_DARK),
        ("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
    ]))
    story.append(t)
    story.append(Spacer(1, 0.5*cm))

    # Footer note
    story.append(HRFlowable(width="100%", thickness=1, color=BLUE_MID))
    story.append(Spacer(1, 0.2*cm))
    story.append(Paragraph(
        "<b>DISCLAIMER:</b> This handbook is for educational purposes for intern doctors "
        "in endocrinology. All insulin doses in clinical practice must be individualized "
        "and supervised by an experienced physician. Patient safety always comes first. "
        "Always double-check calculations and consult your senior before prescribing. "
        "Reference: Standard endocrinology guidelines and your provided course notes.",
        s("Disc2", fontSize=8.5, textColor=colors.HexColor("#666666"),
          fontName="Helvetica-Oblique", alignment=TA_CENTER, leading=12)))

    # ── BUILD ────────────────────────────────────────────────────────────────
    doc.build(story)
    print(f"PDF created: {path}")
    return path

if __name__ == "__main__":
    build()
Running Command

cd /tmp/workspace/insulin-handbook && python build_handbook.py 2>&1

Running Command

ls -lh /tmp/workspace/insulin-handbook/

Your handbook PDF is ready! Here is your download link:

Insulin Dose Handbook T1DM

PDF Document · PDF


Here is a summary of everything included in the handbook, written simply for you as an intern:

What Is Inside the Handbook (15 pages)

Sections 1-8: Theory (Easy Language)

SectionWhat You Learn
1Why T1DM patients need external insulin (broken beta cells)
2All insulin types: Rapid / Short / Intermediate / Long-acting with onset, peak, duration
3Basal-Bolus concept: Basal = background trickle, Bolus = mealtime burst
4Step-by-step calculation: TDD → Basal → Bolus → ISF → ICR → Correction dose
5All key formulas in one table (TDD, ISF, ICR, correction dose, BU rule)
64 daily adjustment factors: glycemic profile, carbs, exercise, illness
7Injection technique: where to inject, which angle, how to rotate sites
8Honeymoon phase explained simply

Section 9: The 5 Clinical Cases (Full Math)

PatientClinical ScenarioKey Teaching Point
Patient A22-year-old, 68 kg, newly diagnosed, BG = 16.4Start low (0.4 U/kg), add correction to breakfast
Patient B35-year-old, 90 kg, overweight, pre-lunch BG = 8.5, 90g carbsHigher dose (0.6 U/kg) + ICR for large meal
Patient C10-year-old child, 32 kg, BG = 9.2, 45g breakfastChildren need insulin pens; very high ISF
Patient D28-year-old athletic patient, cycling after dinnerReduce dinner bolus by 30%; reduce basal on exercise nights
Patient E19-year-old with flu, vomiting, BG = 18.5, ketones 2+Sick day rules: increase basal 20%, never stop insulin

Key Formulas to Memorize

  • TDD = Weight (kg) x 0.5 U/kg (range 0.4-0.8)
  • Basal = TDD x 50% (long-acting once/twice daily)
  • Bolus per meal = Total bolus ÷ 3 (adjusted by carbs)
  • ICR = 500 ÷ TDD (grams of carbs per 1 unit)
  • ISF = 100 ÷ TDD (mmol/L drop per 1 unit)
  • Correction dose = (Actual BG - Target BG) ÷ ISF
  • 1 Bread Unit = 12g carbs = 1.4 units insulin (from your notes)
  • 1 unit rapid insulin lowers BG by ~2.22 mmol/L (from your notes)
Good luck in your endocrinology rotation! Always verify your calculations with your senior registrar before prescribing.

Please create an audio explaining this above created handbook pdf ,the audio must explain me like a teacher to student with examples and always mention full name of abbreviations used

Running Command

python3 -c "import gtts; print('gTTS available')" 2>&1; python3 -c "import pyttsx3; print('pyttsx3 available')" 2>&1; python3 -c "from pydub import AudioSegment; print('pydub available')" 2>&1

Writing File

~/insulin-handbook/generate_audio.py

#!/usr/bin/env python3
"""
Generate teacher-to-student audio for the Insulin Dose Handbook (Type 1 Diabetes).
Uses gTTS (Google Text-to-Speech) to produce an MP3 file.
Long text is split into chunks to avoid gTTS request size limits.
"""

from gtts import gTTS
import os

# ─── Full audio script ────────────────────────────────────────────────────────
# Written in teacher-to-student conversational style.
# All abbreviations are always spoken in full.

SCRIPT = """
Welcome, Doctor.

I am your teacher today, and together we are going to go through everything you need to know
about calculating insulin doses in Type 1 Diabetes Mellitus.

By the end of this session, you will be confident enough to stand at the bedside of any
Type 1 Diabetes Mellitus patient and calculate their insulin dose — step by step.

Let us begin.

--- PART ONE: UNDERSTANDING TYPE 1 DIABETES MELLITUS AND WHY WE NEED INSULIN ---

First, let me ask you a simple question. Why does a patient with Type 1 Diabetes Mellitus
need insulin injections every single day?

The answer is this: In Type 1 Diabetes Mellitus, the patient's own immune system attacks and
destroys the beta cells of the pancreas. These beta cells are the only cells in the body
that produce insulin.

So when the beta cells are gone, the body makes ZERO insulin. None at all.

Now, why does that matter? Because insulin is the KEY that allows glucose — the sugar from
food — to enter body cells and be used for energy. Without insulin, the glucose stays stuck
in the bloodstream. It cannot get into the cells. Blood glucose rises to dangerous levels.

In a healthy person, the pancreas works like a smart, automatic pump. It releases a tiny,
steady trickle of insulin all day and all night to keep blood sugar stable between meals.
Then, when the person eats, the pancreas releases a large burst of insulin to handle the
glucose from food.

In Type 1 Diabetes Mellitus, this pump is completely broken. So WE become the pump operator.
WE must inject the right amount of insulin at the right time, every day.

Our goal is simple: to mimic what a healthy pancreas does, as closely as possible.

--- PART TWO: TYPES OF INSULIN ---

Now let us talk about the types of insulin we use.

There are four main categories, and you must know each one.

CATEGORY ONE: Rapid-Acting Insulin.
This is also called Ultra-Short-Acting Insulin.
Examples include Lispro — also sold as Humalog — Aspart — also sold as NovoRapid — and
Glulisine, sold as Apidra.

This insulin starts working in just five to fifteen minutes after injection.
It reaches its highest effect — what we call its PEAK — at one to two hours.
And it wears off after three to five hours.

We use this insulin AT mealtimes, immediately before the patient eats.

CATEGORY TWO: Short-Acting Insulin.
Also called Regular Insulin.
Examples include Regular Insulin, Actrapid, and Humulin R.

This one takes longer to start — thirty to sixty minutes — so we give it THIRTY MINUTES
before a meal.
It peaks at two to four hours and lasts six to eight hours.

CATEGORY THREE: Intermediate-Acting Insulin.
This is N P H insulin — which stands for Neutral Protamine Hagedorn.
Examples are Insulatard and Humulin N.

It starts working in one to three hours, peaks at five to eight hours, and lasts up to
sixteen hours.
We use this for overnight background coverage or daytime background in some regimens.

CATEGORY FOUR: Long-Acting Insulin.
Also called Basal Insulin.
Examples include Glargine — sold as Lantus — Detemir — sold as Levemir — and
Degludec — sold as Tresiba.

This is the most modern and preferred basal insulin.
It takes one to two hours to start, has NO peak — meaning it works smoothly and evenly
all day — and lasts twenty to twenty-four hours.
Degludec even lasts forty-two hours.

We give long-acting insulin once or twice daily to provide the background insulin coverage
between meals and overnight.

--- PART THREE: THE BASAL-BOLUS CONCEPT ---

Now here is the most important concept for Type 1 Diabetes Mellitus management.
It is called the BASAL-BOLUS REGIMEN, and it is the gold standard of care.

Let me explain it in the simplest possible way.

BASAL means the BACKGROUND dose.
Think of it as the baseline insulin level that keeps blood glucose stable BETWEEN meals.
No food is involved.
We use long-acting insulin — like Glargine — for this.
We give it once or twice daily.
The basal dose is usually about FORTY to FIFTY percent of the Total Daily Dose.
In numbers: approximately twenty-four to twenty-eight units per day for a typical adult.

BOLUS means the MEALTIME dose.
Think of it as the dose you give every time the patient eats.
It covers the glucose that comes from food.
We use rapid-acting insulin — like Aspart or Lispro — for this.
We give it before each meal, three times a day: breakfast, lunch, and dinner.
The total bolus insulin is usually about FIFTY to SIXTY percent of the Total Daily Dose.
In numbers: approximately twenty to thirty units per day total, split over three meals.

So the TOTAL equation is:

TOTAL DAILY DOSE equals BASAL dose PLUS BOLUS dose.

Easy, right? Let us move to the actual calculations now.

--- PART FOUR: STEP-BY-STEP INSULIN DOSE CALCULATION ---

I will teach you FIVE steps. Learn these five steps and you can calculate any insulin dose.

STEP ONE: Calculate the Total Daily Dose.

Total Daily Dose — abbreviated as T D D — is the total amount of insulin the patient needs
in one day, from all injections combined.

The formula is:
Total Daily Dose equals Body Weight in kilograms, multiplied by 0.5 units per kilogram.

The standard range is 0.4 to 0.8 units per kilogram per day.
For a newly diagnosed patient, start at the LOW end: 0.4 units per kilogram.
For an established patient with poor control or who is overweight, use 0.6 to 0.8
units per kilogram.
For most patients, 0.5 units per kilogram is the standard starting point.

The adult average is 40 to 60 units per day.

STEP TWO: Split the Total Daily Dose into Basal and Bolus.

Basal dose equals Total Daily Dose multiplied by 50 percent.
Total Bolus equals Total Daily Dose multiplied by 50 percent.

Then, split the Total Bolus equally over three meals:
Per meal bolus equals Total Bolus divided by 3.

STEP THREE: Calculate the Insulin Sensitivity Factor — also called the Correction Factor
or I S F, which stands for Insulin Sensitivity Factor.

The Insulin Sensitivity Factor tells you: how much does ONE unit of rapid-acting insulin
lower the blood glucose?

The formula is:
Insulin Sensitivity Factor equals 100 divided by Total Daily Dose.
The answer is in millimoles per litre per unit.

For example: if Total Daily Dose is 50 units,
Insulin Sensitivity Factor equals 100 divided by 50, which equals 2.0.
This means: every one unit of rapid-acting insulin will lower blood glucose by
approximately 2.0 millimoles per litre.

This matches what your notes say: one unit of insulin lowers glucose by approximately
2.22 millimoles per litre.

STEP FOUR: Calculate the Insulin-to-Carbohydrate Ratio — abbreviated as I C R.

The Insulin-to-Carbohydrate Ratio tells you: for every gram of carbohydrate the patient
eats, how many units of insulin are needed?

The formula is:
Insulin-to-Carbohydrate Ratio equals 500 divided by Total Daily Dose.
The answer is in grams of carbohydrate per one unit of insulin.

For example: if Total Daily Dose is 50 units,
Insulin-to-Carbohydrate Ratio equals 500 divided by 50, which equals 10.
This means: ONE unit of insulin covers TEN grams of carbohydrate.

So if the patient eats 60 grams of carbohydrate,
Carbohydrate Bolus equals 60 divided by 10, which equals 6 units.

Now let me also explain the BREAD UNIT method, because it is in your notes.
One Bread Unit — abbreviated B U — equals 12 grams of glucose, which is 50 kilocalories.
And 1.4 units of insulin are needed to cover one Bread Unit.
So if the patient eats 5 Bread Units — that is 60 grams of carbohydrate —
they need 5 multiplied by 1.4, which equals 7 units of insulin.

STEP FIVE: Calculate the Correction Dose.

The Correction Dose — also called Supplemental Dose — is the extra insulin you give
when blood glucose is ABOVE the target before a meal.

The formula is:
Correction Dose equals the Actual Blood Glucose minus the Target Blood Glucose,
divided by the Insulin Sensitivity Factor.

Target blood glucose before meals is usually 5.5 to 6.0 millimoles per litre.

For example: Blood glucose is 12 millimoles per litre.
Target is 6 millimoles per litre.
Insulin Sensitivity Factor is 2.0.
Correction Dose equals (12 minus 6) divided by 2.0, which equals 3 units.

So you add 3 units of correction to the regular meal bolus.

--- PART FIVE: KEY FORMULAS SUMMARY ---

Let me quickly review all formulas one more time so they are locked in your memory.

Formula 1:
Total Daily Dose equals Weight in kilograms multiplied by 0.5 units per kilogram.

Formula 2:
Basal dose equals Total Daily Dose multiplied by 50 percent.

Formula 3:
Per Meal Bolus equals (Total Daily Dose multiplied by 50 percent), divided by 3.

Formula 4:
Insulin-to-Carbohydrate Ratio equals 500 divided by Total Daily Dose.

Formula 5:
Insulin Sensitivity Factor equals 100 divided by Total Daily Dose.

Formula 6:
Correction Dose equals (Actual Blood Glucose minus Target Blood Glucose) divided by
Insulin Sensitivity Factor.

Formula 7:
Total Mealtime Dose equals Carbohydrate Bolus PLUS Correction Dose.

That last formula is the most practical one you will use at the bedside. Every mealtime,
you calculate the carbohydrate bolus for the food, add the correction dose for any
existing high blood glucose, and that is the total rapid-acting insulin to give.

--- PART SIX: DAILY DOSE ADJUSTMENT FACTORS ---

Now, insulin is NEVER a fixed dose forever. You must adjust it based on four factors.

FACTOR ONE: Glycemic Profile.
This means the pattern of blood glucose readings throughout the day.
If the patient's blood glucose is consistently high before bed, increase the evening
long-acting insulin.
If it is consistently high after breakfast, increase the breakfast rapid-acting dose.
Always look at the trend, not just one reading.

FACTOR TWO: Carbohydrate Content Per Meal.
A big meal with 90 grams of carbohydrate needs much more insulin than a small meal
with 30 grams.
Always ask the patient what they plan to eat, and calculate the bolus accordingly
using the Insulin-to-Carbohydrate Ratio.

FACTOR THREE: Physical Activity Level.
Exercise is a powerful insulin sensitizer — it makes insulin work much better.
During and after exercise, muscles take up glucose without needing as much insulin.
So if a patient exercises, you must REDUCE the bolus by 20 to 50 percent,
depending on how intense the exercise is.
If you do NOT reduce the dose, the patient may develop hypoglycemia — dangerously low
blood sugar — during or after the exercise.

FACTOR FOUR: Intercurrent Illness.
This means any infection, fever, surgery, or stress.
When a patient is sick, the body releases stress hormones — cortisol, adrenaline, and
glucagon — which are all counter-insulin hormones. They raise blood glucose.
So paradoxically, even if the patient is not eating, their blood glucose RISES during illness.
You must INCREASE the basal insulin by approximately 10 to 20 percent during illness.
And you must check blood glucose every two to four hours, not just twice a day.

--- PART SEVEN: INJECTION TECHNIQUE AND DEVICES ---

Now let me quickly cover injection technique, because how you inject matters as much as
what you inject.

For RAPID-ACTING or SHORT-ACTING Insulin — the Bolus insulin —
Inject into the ABDOMEN — the belly.
The abdomen has the fastest absorption of any injection site.
Give Rapid-Acting insulin immediately before the meal.
Give Short-Acting insulin thirty minutes before the meal.
Use a forty-five degree angle. If the patient is obese with thick subcutaneous fat,
use a ninety degree angle.

For LONG-ACTING or INTERMEDIATE-ACTING Insulin — the Basal insulin —
Inject into the THIGH or BUTTOCK.
These sites have slower absorption, which is what we want for a long-acting depot.
Pinch the skin. Inject at forty-five degrees, or ninety degrees if thick fat.

ABOUT DEVICES:
Insulin Pens — which come with cartridges of 100 units per millilitre, in 1.5 or 3
millilitre sizes — are preferred for children, adolescents, pregnant women,
visually impaired patients, and amputees.
For most other patients, disposable plastic insulin syringes calibrated to the
insulin concentration are used.

VERY IMPORTANT: Rotate injection sites daily within the same area.
For example, rotate around different quadrants of the abdomen.
If you always inject in the same spot, fatty lumps called LIPODYSTROPHY develop under
the skin. These lumps cause erratic, unpredictable insulin absorption — sometimes the
insulin works, sometimes it doesn't — which makes blood glucose control very difficult.

--- PART EIGHT: THE HONEYMOON PHASE ---

Now let me explain something that catches many interns off guard.

After a patient is first diagnosed with Type 1 Diabetes Mellitus, they may enter what
is called the HONEYMOON PHASE, or Partial Remission Period.

Here is what happens. When the patient is diagnosed and we start insulin, the stress
on the remaining beta cells is reduced. Some of these beta cells — the ones that were
not yet completely destroyed — temporarily recover and start producing a little insulin
of their own again.

This means the patient suddenly needs LESS injected insulin than before.
If you are not aware of this, you will give too much insulin, and the patient will
develop dangerous hypoglycemia.

Clinical sign: the patient starts having unexplained low blood sugars with the same
insulin dose they were previously fine on.

What should you do?
REDUCE the insulin doses gradually.
But do NOT stop insulin completely — even during the honeymoon phase.
If you stop, the stress returns and the remaining beta cells may deteriorate faster.
The honeymoon phase typically lasts a few weeks to a few months.
Rarely, it can last up to one year.

--- PART NINE: CLINICAL PATIENT EXAMPLES ---

Now, Doctor, this is my favourite part — let us work through FIVE real patient cases together.

I will walk you through every single calculation, step by step, just as you would do it at
the bedside.

---

PATIENT CASE NUMBER ONE: New Diagnosis, Lean Adult.

Patient details:
22-year-old university student.
Weight: 68 kilograms.
Glycated Haemoglobin — Haemoglobin A1c — is 11.2 percent. That is very high.
Current blood glucose: 16.4 millimoles per litre.
Target fasting blood glucose: 5.5 millimoles per litre.
Breakfast planned: 60 grams of carbohydrate.
We will use Glargine as basal and Aspart as bolus.

STEP ONE: Total Daily Dose.
Because this is a NEW diagnosis, we start conservatively at 0.4 units per kilogram.
Total Daily Dose equals 68 multiplied by 0.4, which equals 27.2.
We round this to 28 units per day.

STEP TWO: Basal Dose.
Basal equals 28 multiplied by 50 percent, which equals 14 units.
Give 14 units of Glargine at bedtime.

STEP THREE: Total Bolus.
Total Bolus equals 28 multiplied by 50 percent, which equals 14 units.
Per meal: 14 divided by 3 equals approximately 4 to 5 units per meal.

STEP FOUR: Insulin Sensitivity Factor.
Insulin Sensitivity Factor equals 100 divided by 28, which equals 3.6 millimoles per litre per unit.

STEP FIVE: Insulin-to-Carbohydrate Ratio.
Insulin-to-Carbohydrate Ratio equals 500 divided by 28, which equals approximately 18.
That means one unit covers 18 grams of carbohydrate.

STEP SIX: Breakfast Carbohydrate Bolus.
Breakfast has 60 grams.
Carbohydrate Bolus equals 60 divided by 18, which equals 3.3, rounded to 3 units.

STEP SEVEN: Correction Dose for current high blood glucose of 16.4.
Correction equals (16.4 minus 5.5) divided by 3.6.
That is 10.9 divided by 3.6, which equals 3.0 units.

STEP EIGHT: Total Breakfast Bolus.
Carbohydrate Bolus plus Correction Dose equals 3 plus 3, which equals 6 units.

FINAL PRESCRIPTION:
Glargine: 14 units at bedtime, injected into the thigh.
Aspart at breakfast: 6 units, immediately before eating, injected into the abdomen.
Aspart at lunch: 4 to 5 units, adjusted for meal size.
Aspart at dinner: 4 to 5 units, adjusted for meal size.

Remember to warn this patient about the Honeymoon Phase that may begin soon.

---

PATIENT CASE NUMBER TWO: Established Type 1 Diabetes Mellitus, Overweight Patient.

Patient details:
35-year-old office worker.
Weight: 90 kilograms. Body Mass Index of 29. Slightly overweight.
Haemoglobin A1c: 9.1 percent. Poor control.
Pre-lunch blood glucose: 8.5 millimoles per litre.
Target: 5.5 millimoles per litre.
Lunch: 90 grams of carbohydrate — a large meal.
Insulin: Detemir as basal, Lispro as bolus.

STEP ONE: Total Daily Dose.
This patient is overweight and sedentary — insulin resistance is higher.
We use 0.6 units per kilogram.
Total Daily Dose equals 90 multiplied by 0.6, which equals 54 units per day.

STEP TWO: Basal.
27 units of Detemir at bedtime.

STEP THREE: Total Bolus.
27 units of Lispro per day, split over three meals.

STEP FOUR: Insulin Sensitivity Factor.
100 divided by 54 equals approximately 1.85 millimoles per litre per unit.

STEP FIVE: Insulin-to-Carbohydrate Ratio.
500 divided by 54 equals approximately 9.
One unit covers only 9 grams of carbohydrate. This patient needs more insulin per gram of
carbohydrate because of their insulin resistance.

STEP SIX: Lunch Carbohydrate Bolus.
90 grams divided by 9 equals 10 units.

STEP SEVEN: Correction for blood glucose of 8.5.
(8.5 minus 5.5) divided by 1.85 equals 3 divided by 1.85, which equals 1.6.
Round to 2 units correction.

STEP EIGHT: Total Lunch Bolus.
10 plus 2 equals 12 units of Lispro before lunch.

FINAL PRESCRIPTION:
Detemir: 27 units at bedtime, thigh injection.
Lispro at breakfast: 9 units.
Lispro at lunch: 12 units including correction.
Lispro at dinner: 9 units.

Note for you, Doctor: Counsel this patient about weight reduction and physical activity.
Even modest weight loss can reduce insulin requirements significantly.

---

PATIENT CASE NUMBER THREE: Paediatric Patient — A 10-Year-Old Child.

Patient details:
10-year-old child. Type 1 Diabetes Mellitus for 2 years.
Weight: 32 kilograms.
Haemoglobin A1c: 8.4 percent.
Fasting blood glucose: 9.2 millimoles per litre.
Target: 5.5 millimoles per litre.
Breakfast: 45 grams of carbohydrate.
Insulin: Glargine plus Aspart, using an insulin pen.

IMPORTANT NOTE for children: Use insulin pens — they are more accurate and less painful.
Children are more insulin-sensitive than adults, so always start conservatively.
Hypoglycemia in children is particularly dangerous because it can affect brain development.

STEP ONE: Total Daily Dose.
For an established child: 0.5 units per kilogram.
32 multiplied by 0.5 equals 16 units per day.
See how much lower this is compared to an adult? That is normal. Children need less insulin.

STEP TWO: Basal.
8 units of Glargine at bedtime.

STEP THREE: Total Bolus.
8 units, split over three meals — roughly 2 to 3 units per meal.

STEP FOUR: Insulin Sensitivity Factor.
100 divided by 16 equals 6.25 millimoles per litre per unit.
Notice how HIGH the Insulin Sensitivity Factor is in children? One unit drops blood glucose
by over 6 millimoles per litre! This is why hypoglycemia risk is so high in children —
even a small insulin error has a big blood glucose effect.

STEP FIVE: Insulin-to-Carbohydrate Ratio.
500 divided by 16 equals 31.25.
One unit covers about 31 grams of carbohydrate.

STEP SIX: Breakfast Carbohydrate Bolus.
45 grams divided by 31 equals 1.45, rounded to 2 units.

STEP SEVEN: Correction.
(9.2 minus 5.5) divided by 6.25 equals 3.7 divided by 6.25, which equals 0.6.
We round this up to 1 unit — being careful not to over-correct given the high
Insulin Sensitivity Factor.

STEP EIGHT: Total Breakfast Bolus.
2 plus 1 equals 3 units of Aspart before breakfast.

FINAL PRESCRIPTION:
Glargine: 8 units at bedtime, thigh injection.
Aspart at breakfast: 3 units.
Aspart at lunch: 2 to 3 units.
Aspart at dinner: 2 to 3 units.

Always educate the parents. The school nurse must know the child's diagnosis and what to do
if blood glucose drops. Always carry glucose tablets or fruit juice to treat hypoglycemia.

---

PATIENT CASE NUMBER FOUR: Active Patient — Pre-Exercise Dose Adjustment.

Patient details:
28-year-old. Type 1 Diabetes Mellitus for 8 years. Well-controlled.
Weight: 75 kilograms.
Haemoglobin A1c: 7.2 percent. Good control!
Pre-dinner blood glucose: 7.0 millimoles per litre.
Target: 6.0 millimoles per litre.
Dinner: 60 grams of carbohydrate.
Plans to go cycling for one hour after dinner.
Insulin: Glargine plus Lispro.

STEP ONE: Total Daily Dose.
75 multiplied by 0.5 equals 37.5, rounded to 38 units per day.

STEP TWO: Basal.
19 units of Glargine.

STEP THREE: Insulin Sensitivity Factor.
100 divided by 38 equals 2.6 millimoles per litre per unit.

STEP FOUR: Insulin-to-Carbohydrate Ratio.
500 divided by 38 equals 13.2.
One unit covers 13 grams of carbohydrate.

STEP FIVE: Standard Dinner Bolus without exercise.
Carbohydrate Bolus: 60 divided by 13 equals 4.6, rounded to 5 units.
Correction: (7.0 minus 6.0) divided by 2.6 equals 0.4 units.
That is less than 0.5, so we round down to zero correction.
Standard dinner bolus would be 5 units.

STEP SIX: Exercise Adjustment.
He is cycling for one hour — moderate-intensity aerobic exercise.
Exercise makes muscles take up glucose directly, without needing much insulin.
We need to REDUCE the dinner bolus by approximately 30 percent to prevent
exercise-induced hypoglycemia — which can happen during exercise AND several hours later.

Adjusted Dinner Bolus equals 5 multiplied by 0.7, which equals 3.5 units.
Round to 3 or 4 units.

STEP SEVEN: Basal Adjustment.
On exercise days, also consider reducing the evening basal slightly.
19 units multiplied by 0.8 equals approximately 15 units Glargine tonight.
On non-exercise days, give the full 19 units.

FINAL PRESCRIPTION for this exercise day:
Glargine: 15 units tonight only.
Lispro at dinner: 3 to 4 units before dinner.

Always have fast-acting carbohydrates — glucose tablets or fruit juice — available during
and after exercise.
Check blood glucose before, during if exercise is over one hour, and after.
The risk of delayed hypoglycemia is real — it can happen 4 to 8 hours after exercise,
even in the middle of the night.

---

PATIENT CASE NUMBER FIVE: Sick Day Management — Intercurrent Illness.

Patient details:
19-year-old student. Type 1 Diabetes Mellitus for 3 years.
Weight: 60 kilograms.
Usual Haemoglobin A1c: 7.8 percent.
Current situation: Influenza with fever of 38.5 degrees Celsius. Vomiting. Not eating much.
Morning blood glucose: 18.5 millimoles per litre. Very high.
Urine ketones: 2 plus. Moderate ketonuria.
This patient is at RISK of Diabetic Ketoacidosis — abbreviated D K A —
which is a life-threatening complication.
Usual Total Daily Dose: 30 units per day.

Let me first remind you of the most important sick day rule:
NEVER STOP INSULIN DURING ILLNESS.
I repeat: NEVER STOP INSULIN DURING ILLNESS.
Even if the patient is vomiting and not eating, even if their blood glucose seems normal —
NEVER STOP INSULIN. Illness raises blood glucose through stress hormones, and stopping
insulin can rapidly lead to Diabetic Ketoacidosis.

STEP ONE: Usual doses as reference.
Total Daily Dose: 60 multiplied by 0.5 equals 30 units.
Usual Basal: 15 units Glargine.
Usual Total Bolus: 15 units.

STEP TWO: Sick day Basal adjustment.
Increase basal by 20 percent.
New Basal equals 15 multiplied by 1.2, which equals 18 units.

STEP THREE: Insulin Sensitivity Factor.
100 divided by 30 equals 3.3 millimoles per litre per unit.

STEP FOUR: Correction Dose.
During illness, we set a slightly higher target — 8.0 millimoles per litre — because
the patient is vomiting and we don't want to overshoot into hypoglycemia.
Correction equals (18.5 minus 8.0) divided by 3.3.
That is 10.5 divided by 3.3, which equals 3.2.
Round to 3 units correction.

STEP FIVE: Food Bolus.
The patient is vomiting but can keep down a few crackers — about 20 grams of carbohydrate.
Insulin-to-Carbohydrate Ratio equals 500 divided by 30, which equals 16.7.
One unit covers about 17 grams.
Food bolus equals 20 divided by 17, which equals 1.2, rounded to 1 unit.

STEP SIX: Total Bolus now.
3 units correction plus 1 unit for food equals 4 units of rapid-acting insulin now.

MONITORING PLAN:
Check blood glucose every 2 to 3 hours.
Check ketones every 4 to 6 hours.
If blood glucose is not improving after 4 to 6 hours, or ketones are large (3 plus),
SEND THE PATIENT TO HOSPITAL immediately.

FINAL PRESCRIPTION for this sick day:
Glargine: 18 units (increased dose).
Rapid-acting insulin: 4 units now for correction plus the small amount of food.
Repeat blood glucose in 2 to 3 hours. Recalculate correction if still high.

SICK DAY RULES — memorize these, Doctor:

Number 1: NEVER stop insulin during illness.
Number 2: Increase basal insulin by 10 to 20 percent.
Number 3: Check blood glucose every 2 to 4 hours.
Number 4: Check ketones every 4 to 6 hours if blood glucose is above 14 millimoles per litre.
Number 5: Drink plenty of fluids.
Number 6: If not eating, skip the food bolus but still give basal plus correction.
Number 7: If vomiting and can't keep fluids down, go to hospital immediately.
Number 8: Large ketones (3 plus) means go to hospital — risk of Diabetic Ketoacidosis.

--- PART TEN: QUICK REFERENCE REVIEW ---

Let me now do a rapid-fire review of the most important numbers to remember.

Total Daily Dose starting point: 0.5 units per kilogram. Range: 0.4 to 0.8.
Adult average total: 40 to 60 units per day.
Basal: 50 percent of Total Daily Dose.
Bolus: 50 percent of Total Daily Dose, divided equally over three meals.
Insulin-to-Carbohydrate Ratio formula: 500 divided by Total Daily Dose.
Insulin Sensitivity Factor formula: 100 divided by Total Daily Dose.
One unit of rapid-acting insulin lowers blood glucose by approximately 2.22 millimoles
per litre in an average adult.
One Bread Unit equals 12 grams of carbohydrate, equals 50 kilocalories, and requires
1.4 units of insulin.
Target fasting blood glucose: 5.5 to 6.0 millimoles per litre.
Target Haemoglobin A1c in Type 1 Diabetes Mellitus: below 7 percent.
Basal split for N P H insulin (Neutral Protamine Hagedorn): give two-thirds in the morning
and one-third in the evening.

--- PART ELEVEN: COMMON MISTAKES TO AVOID ---

Let me finish with the most common mistakes interns make, and how to avoid them.

MISTAKE ONE: Stopping insulin during illness.
This is the MOST dangerous mistake.
Illness raises blood glucose. If you stop insulin, the patient can develop Diabetic Ketoacidosis
within hours.
ALWAYS continue insulin. INCREASE it if blood glucose is rising.

MISTAKE TWO: Injecting bolus insulin without confirming the patient will eat.
If you give rapid-acting insulin and the patient then vomits or refuses food,
severe hypoglycemia can occur.
Always confirm the patient has food in front of them before giving bolus insulin.
With rapid-acting insulin, inject immediately before eating. With short-acting, 30 minutes before.

MISTAKE THREE: Injecting always in the same spot.
Fatty lumps — lipodystrophy — develop.
These lumps absorb insulin unpredictably. Blood glucose control becomes chaotic.
Always rotate sites daily.

MISTAKE FOUR: Not adjusting for exercise.
If a patient exercises after a meal with a full meal bolus, hypoglycemia is almost guaranteed.
Reduce pre-exercise bolus by 20 to 50 percent. Have glucose tablets available.

MISTAKE FIVE: Forgetting the correction dose.
If a patient comes to a meal with an already-high blood glucose and you give only the carbohydrate
bolus, the blood glucose will remain high after the meal.
Always check blood glucose BEFORE every meal and add the correction dose.

MISTAKE SIX: Starting the Total Daily Dose too high in a newly diagnosed patient.
New patients may be in the early honeymoon phase where their pancreas still makes some insulin.
Start at 0.4 units per kilogram. Titrate up slowly. Check blood glucose frequently.

--- CONCLUSION ---

Well done, Doctor. You have now completed the full Insulin Dose Calculation Handbook for
Type 1 Diabetes Mellitus.

Let me give you one final summary to carry with you.

Every insulin prescription for a Type 1 Diabetes Mellitus patient needs just five numbers:

Number 1: Total Daily Dose. Start with weight times 0.5.
Number 2: Basal Dose. Total Daily Dose times 0.5. Give long-acting insulin once daily.
Number 3: Meal Bolus. Total Daily Dose times 0.5, divided by 3 per meal. Adjust for carbs.
Number 4: Insulin Sensitivity Factor. 100 divided by Total Daily Dose. Use for correction.
Number 5: Insulin-to-Carbohydrate Ratio. 500 divided by Total Daily Dose. Use for meal bolus.

And always remember the Three Golden Rules:

Rule 1: NEVER stop insulin in Type 1 Diabetes Mellitus — not during illness, not during fasting,
not during any situation.

Rule 2: Always ROTATE injection sites to prevent lipodystrophy.

Rule 3: Always ADJUST doses based on glycemic profile, food, exercise, and illness.

You are now ready to manage insulin in Type 1 Diabetes Mellitus with confidence.
Good luck in your endocrinology rotation, Doctor. You've got this!

End of lecture.
"""

# ─── Split into manageable chunks for gTTS ───────────────────────────────────
def split_text(text, max_chars=4900):
    """Split script at sentence boundaries to stay under gTTS character limits."""
    sentences = text.replace("\n---\n", "\n.\n").split(". ")
    chunks = []
    current = ""
    for sent in sentences:
        candidate = current + sent + ". "
        if len(candidate) > max_chars:
            if current.strip():
                chunks.append(current.strip())
            current = sent + ". "
        else:
            current = candidate
    if current.strip():
        chunks.append(current.strip())
    return chunks


def build_audio():
    out_dir = "/tmp/workspace/insulin-handbook"
    os.makedirs(out_dir, exist_ok=True)
    
    chunks = split_text(SCRIPT)
    print(f"Total chunks to synthesize: {len(chunks)}")
    
    part_files = []
    for i, chunk in enumerate(chunks):
        part_path = os.path.join(out_dir, f"part_{i:03d}.mp3")
        print(f"  Synthesizing chunk {i+1}/{len(chunks)} ({len(chunk)} chars)...")
        tts = gTTS(text=chunk, lang="en", slow=False)
        tts.save(part_path)
        part_files.append(part_path)
    
    print("Merging audio parts...")
    # Merge with pydub (reads MP3 byte streams directly)
    from pydub import AudioSegment
    combined = AudioSegment.empty()
    pause = AudioSegment.silent(duration=600)  # 0.6 sec pause between chunks
    for pf in part_files:
        seg = AudioSegment.from_mp3(pf)
        combined += seg + pause
    
    final_path = os.path.join(out_dir, "Insulin_Handbook_Audio_Lecture.mp3")
    combined.export(final_path, format="mp3", bitrate="128k")
    print(f"\nFinal audio saved: {final_path}")
    
    # Clean up part files
    for pf in part_files:
        os.remove(pf)
    
    size_mb = os.path.getsize(final_path) / (1024 * 1024)
    print(f"File size: {size_mb:.1f} MB")
    return final_path


if __name__ == "__main__":
    build_audio()
Running Command

cd /tmp/workspace/insulin-handbook && python generate_audio.py 2>&1

Running Command

python3 -c " import subprocess, sys # Try piper TTS (offline, fast) result = subprocess.run(['which', 'piper'], capture_output=True) print('piper:', result.stdout.decode().strip()) # Try espeak result2 = subprocess.run(['which', 'espeak'], capture_output=True) print('espeak:', result2.stdout.decode().strip()) result3 = subprocess.run(['which', 'espeak-ng'], capture_output=True) print('espeak-ng:', result3.stdout.decode().strip()) # Try festival result4 = subprocess.run(['which', 'festival'], capture_output=True) print('festival:', result4.stdout.decode().strip()) # Check python TTS libs try: import TTS; print('TTS (Coqui) available') except: print('Coqui TTS: not available') try: import edge_tts; print('edge_tts available') except: print('edge_tts: not available') try: import kokoro; print('kokoro available') except: print('kokoro: not available') "

Running Command

# Try installing edge-tts (uses Microsoft Azure TTS - different endpoint from Google) pip install --user edge-tts --quiet 2>&1 | tail -3 python3 -c "import edge_tts; print('edge_tts installed successfully')" 2>&1

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.