Make a short notes on the stages of labour from dutta textbook for 10m consisting of 4 page information

| Stage | Definition | Duration (approx.) |
|---|---|---|
| First | Onset of labour → Full cervical dilatation (10 cm) | 11 hrs (nullipara), 7 hrs (multipara) |
| Second | Full dilatation → Delivery of infant | 54 min (nullipara), 20 min (multipara) |
| Third | Delivery of infant → Delivery of placenta | < 10 min (up to 30 min) |
| Fourth | 1st hour after placental delivery | 1 hour |
| Approach | Description |
|---|---|
| Active management (recommended) | Uterotonic (oxytocin 10 IU IM/IV) + controlled cord traction + uterine massage. Reduces PPH risk and shortens 3rd stage. |
| Expectant/physiological | Allow placenta to separate spontaneously; intervene only if bleeding occurs |
Caution: Never administer oxytocin before placental delivery — risk of trapping placental fragments or missing an undetected twin.
| Feature | 1st Stage | 2nd Stage | 3rd Stage | 4th Stage |
|---|---|---|---|---|
| From | Onset of labour | Full dilatation | Delivery of baby | Delivery of placenta |
| To | Full dilatation (10 cm) | Delivery of baby | Delivery of placenta | 1 hour post-delivery |
| Duration (nullipara) | ~11 hours | ~54 min | < 30 min | 1 hour |
| Duration (multipara) | ~7 hours | ~20 min | < 10 min | 1 hour |
| Key events | Cervical effacement + dilatation | Cardinal movements, delivery of head | Placental separation | Haemostasis, repair |
| Main risk | Dystocia, fetal distress | Cord prolapse, PPH, lacerations | PPH, retained placenta | PPH, uterine atony |
Make it pdf
ls -la /home/daytona/workspace/ 2>/dev/null || mkdir -p /home/daytona/workspace
~/stages_of_labour/generate_pdf.py
import json, subprocess, base64, os
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, Image, KeepTogether
)
from reportlab.platypus import PageBreak
from io import BytesIO
OUTPUT = "/home/daytona/workspace/stages_of_labour/Stages_of_Labour_Notes.pdf"
os.makedirs(os.path.dirname(OUTPUT), exist_ok=True)
# ── Download the labour curve image ──────────────────────────────────────────
IMG_URL = "https://cdn.orris.care/cdss_images/66a6d66cd968e50b593bad38abe1a2941126aecce9f8b4e846dde71beefb25c7.png"
result = json.loads(subprocess.check_output([
"node", "/home/daytona/skills/shared/scripts/fetch_images.js", IMG_URL
]))
img_path = None
if result and result[0].get("base64"):
raw = base64.b64decode(result[0]["base64"].split(",")[1])
img_path = "/home/daytona/workspace/stages_of_labour/labour_curve.png"
with open(img_path, "wb") as f:
f.write(raw)
print(f"Image saved: {img_path}")
else:
print("Image download failed, continuing without it")
# ── Colour palette ────────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1B3A6B")
TEAL = colors.HexColor("#0E7490")
LIGHT_BLUE = colors.HexColor("#E0F2FE")
AMBER = colors.HexColor("#FEF3C7")
GREEN_BG = colors.HexColor("#DCFCE7")
RED_BG = colors.HexColor("#FEE2E2")
GREY_BG = colors.HexColor("#F1F5F9")
WHITE = colors.white
BLACK = colors.black
BORDER = colors.HexColor("#CBD5E1")
# ── Styles ────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
title_style = S("MyTitle",
fontSize=20, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_CENTER,
spaceAfter=4, leading=24)
subtitle_style = S("MySubtitle",
fontSize=10, fontName="Helvetica",
textColor=colors.HexColor("#CBD5E1"), alignment=TA_CENTER,
spaceAfter=2)
h1_style = S("H1",
fontSize=13, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_LEFT,
spaceBefore=10, spaceAfter=4, leading=16,
leftIndent=6)
h2_style = S("H2",
fontSize=11, fontName="Helvetica-Bold",
textColor=NAVY, spaceBefore=8, spaceAfter=3, leading=14)
h3_style = S("H3",
fontSize=10, fontName="Helvetica-Bold",
textColor=TEAL, spaceBefore=5, spaceAfter=2, leading=13)
body_style = S("Body",
fontSize=9, fontName="Helvetica",
textColor=BLACK, spaceAfter=3, leading=13, alignment=TA_JUSTIFY)
bullet_style = S("Bullet",
fontSize=9, fontName="Helvetica",
textColor=BLACK, spaceAfter=2, leading=13,
leftIndent=14, bulletIndent=4)
small_style = S("Small",
fontSize=7.5, fontName="Helvetica-Oblique",
textColor=colors.HexColor("#475569"), spaceAfter=3, leading=10, alignment=TA_CENTER)
bold_body = S("BoldBody",
fontSize=9, fontName="Helvetica-Bold",
textColor=NAVY, spaceAfter=2, leading=13)
def section_header(text, color=NAVY):
"""Returns a coloured section-header table."""
t = Table([[Paragraph(text, h1_style)]], colWidths=[17.5*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("ROUNDEDCORNERS", [4]),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
def info_box(text, bg=LIGHT_BLUE, border=TEAL):
t = Table([[Paragraph(text, body_style)]], colWidths=[17.5*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 1, border),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
return t
def bullet(text):
return Paragraph(f"• {text}", bullet_style)
def sp(n=4):
return Spacer(1, n)
# ── Build story ───────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=1.5*cm, bottomMargin=1.8*cm,
title="Stages of Labour — Short Notes",
author="Orris Medical Notes"
)
story = []
# ===== TITLE BANNER =====
title_data = [[
Paragraph("STAGES OF LABOUR", title_style),
Paragraph("Short Notes | 10 Marks | Obstetrics", subtitle_style),
]]
# stack vertically
title_tbl = Table([
[Paragraph("STAGES OF LABOUR", title_style)],
[Paragraph("Short Notes | 10 Marks | Obstetrics (Dutta-based)", subtitle_style)],
], colWidths=[17.5*cm])
title_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
story.append(title_tbl)
story.append(sp(8))
# ===== DEFINITION =====
story.append(section_header("DEFINITION OF LABOUR"))
story.append(sp(4))
story.append(info_box(
"<b>Labour</b> is defined as the onset of <b>regular, painful uterine contractions</b> "
"that produce progressive <b>cervical effacement and dilatation</b>, ultimately leading "
"to delivery of the fetus and placenta."
))
story.append(sp(6))
# ===== OVERVIEW TABLE =====
story.append(Paragraph("Overview — Four Stages of Labour", h2_style))
story.append(sp(3))
ov_header = ["Stage", "Definition", "Duration\n(Nullipara)", "Duration\n(Multipara)"]
ov_data = [
ov_header,
["1st Stage\n(Cervical)", "Onset of labour →\nFull dilatation (10 cm)", "~11 hours", "~7 hours"],
["2nd Stage\n(Expulsive)", "Full dilatation →\nDelivery of infant", "~54 minutes", "~20 minutes"],
["3rd Stage\n(Placental)", "Delivery of infant →\nDelivery of placenta", "< 30 minutes", "< 10 minutes"],
["4th Stage\n(Recovery)", "Delivery of placenta →\n1 hour post-delivery", "1 hour", "1 hour"],
]
ov_tbl = Table(ov_data, colWidths=[3.5*cm, 5.5*cm, 4.2*cm, 4.3*cm])
ov_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROWBACKGROUNDS", (0,1), (-1,-1), [GREY_BG, WHITE]),
("BOX", (0,0), (-1,-1), 1, BORDER),
("INNERGRID", (0,0), (-1,-1), 0.5, BORDER),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), NAVY),
]))
story.append(ov_tbl)
story.append(sp(8))
# ===== LABOUR CURVE IMAGE =====
if img_path:
story.append(Paragraph("Friedman's Labour Curve — Stages of Labour", h2_style))
story.append(sp(3))
img = Image(img_path, width=16*cm, height=7*cm)
story.append(img)
story.append(Paragraph(
"Fig: Stages of labour showing cervical dilation curve — Latent phase, Active phase (Stage 1), "
"fetal expulsion (Stage 2), placental delivery (Stage 3), and recovery (Stage 4). "
"[Rosen's Emergency Medicine]",
small_style))
story.append(sp(8))
# ─────────────────────────────────────────────────────────────────────────────
# PAGE 2 — FIRST STAGE
# ─────────────────────────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("FIRST STAGE OF LABOUR — The Cervical Stage", TEAL))
story.append(sp(5))
story.append(info_box(
"<b>Definition:</b> From onset of regular uterine contractions to <b>complete dilatation "
"of the cervix (10 cm)</b>. Friedman's analysis describes a sigmoid (S-shaped) cervicogram."
))
story.append(sp(6))
# Phases side by side
latent_data = [
[Paragraph("<b>LATENT PHASE</b>", S("lh", fontSize=9, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_CENTER))],
[Paragraph("Onset of contractions → active phase begins", body_style)],
[Paragraph("• Cervix: 0–3 cm dilatation + effacement", bullet_style)],
[Paragraph("• Contractions: infrequent, irregular, mild", bullet_style)],
[Paragraph("• Duration: <b>6.4 hrs</b> (nullipara) | <b>4.8 hrs</b> (multipara)", bullet_style)],
[Paragraph("• Prolonged: >20 hrs (nullipara), >14 hrs (multipara)", bullet_style)],
]
active_data = [
[Paragraph("<b>ACTIVE PHASE</b>", S("ah", fontSize=9, fontName="Helvetica-Bold",
textColor=WHITE, alignment=TA_CENTER))],
[Paragraph("3–4 cm dilatation → 10 cm (full dilatation)", body_style)],
[Paragraph("• Rate: ≥1.2 cm/hr (nullipara) | ≥1.5 cm/hr (multipara)", bullet_style)],
[Paragraph("• Contractions: regular, strong, painful", bullet_style)],
[Paragraph("• Descent of fetal head accelerates", bullet_style)],
[Paragraph("• Duration: <b>4.6 hrs</b> (nullipara) | <b>2.4 hrs</b> (multipara)", bullet_style)],
]
latent_tbl = Table(latent_data, colWidths=[8.4*cm])
latent_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), TEAL),
("BACKGROUND", (0,1), (0,-1), LIGHT_BLUE),
("BOX", (0,0), (-1,-1), 1, TEAL),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),6),
]))
active_tbl = Table(active_data, colWidths=[8.4*cm])
active_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), colors.HexColor("#0F766E")),
("BACKGROUND", (0,1), (0,-1), GREEN_BG),
("BOX", (0,0), (-1,-1), 1, colors.HexColor("#0F766E")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),6),
]))
phases_tbl = Table([[latent_tbl, active_tbl]], colWidths=[8.65*cm, 8.65*cm])
phases_tbl.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING",(0,0),(-1,-1),0),
("RIGHTPADDING",(0,0),(-1,-1),0),
("TOPPADDING",(0,0),(-1,-1),0),
("BOTTOMPADDING",(0,0),(-1,-1),0),
("INNERGRID",(0,0),(-1,-1),0,WHITE),
]))
story.append(phases_tbl)
story.append(sp(6))
# Abnormalities
story.append(Paragraph("Abnormalities of First Stage (Friedman's Criteria)", h3_style))
abn_data = [
["Abnormality", "Nullipara", "Multipara"],
["Prolonged latent phase", "> 20 hours", "> 14 hours"],
["Protracted active phase", "< 1.2 cm/hr", "< 1.5 cm/hr"],
["Arrest of active phase", "No progress for ≥2 hours", "No progress for ≥2 hours"],
["Secondary arrest of dilatation", "No dilatation in active phase ≥2 hr", "Same"],
]
abn_tbl = Table(abn_data, colWidths=[6.5*cm, 5.5*cm, 5.5*cm])
abn_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#7C3AED")),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [RED_BG, WHITE]),
("BOX", (0,0), (-1,-1), 1, BORDER),
("INNERGRID", (0,0), (-1,-1), 0.5, BORDER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
]))
story.append(abn_tbl)
story.append(sp(6))
# Pelvic Assessment
story.append(Paragraph("Pelvic Assessment During First Stage", h3_style))
pa_data = [
["Parameter", "Description"],
["Effacement", "Thinning of cervix: 0% (thick) → 100% (paper thin)"],
["Dilatation", "Diameter of cervical os: 0–10 cm"],
["Station", "Relationship of presenting part to ischial spines (−3 to +3)"],
["Position", "Most common: Occiput Anterior (OA)"],
["Presentation","Vertex in 95% of labours"],
]
pa_tbl = Table(pa_data, colWidths=[4*cm, 13.5*cm])
pa_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (0,0), (0,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [GREY_BG, WHITE]),
("BOX", (0,0), (-1,-1), 1, BORDER),
("INNERGRID", (0,0), (-1,-1), 0.5, BORDER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), TEAL),
]))
story.append(pa_tbl)
# ─────────────────────────────────────────────────────────────────────────────
# PAGE 3 — SECOND & THIRD STAGE
# ─────────────────────────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("SECOND STAGE OF LABOUR — The Expulsive Stage", colors.HexColor("#B45309")))
story.append(sp(5))
story.append(info_box(
"<b>Definition:</b> From <b>complete cervical dilatation (10 cm)</b> to <b>delivery of the infant</b>. "
"Characterised by an involuntary urge to bear down and push with each uterine contraction.",
bg=AMBER, border=colors.HexColor("#B45309")
))
story.append(sp(5))
# Duration box
dur_data = [
[Paragraph("<b>Duration</b>", S("dh", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE, alignment=TA_CENTER))],
[Paragraph("Nulliparous: median <b>50–54 minutes</b> (upper limit 2 hours)", bullet_style)],
[Paragraph("Multiparous: median <b>20 minutes</b> (upper limit 1 hour)", bullet_style)],
[Paragraph("Prolonged 2nd stage → ↑ risk of PPH, infection, severe lacerations, fetal hypoxia", bullet_style)],
]
dur_tbl = Table(dur_data, colWidths=[17.5*cm])
dur_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), colors.HexColor("#B45309")),
("BACKGROUND", (0,1), (0,-1), AMBER),
("BOX", (0,0), (-1,-1), 1, colors.HexColor("#B45309")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),8),
]))
story.append(dur_tbl)
story.append(sp(6))
story.append(Paragraph("Cardinal Movements of Labour (Mechanism of Normal Delivery)", h3_style))
cm_data = [
["Step", "Movement", "Description"],
["1", "Engagement", "Biparietal diameter enters pelvic brim"],
["2", "Descent", "Progressive downward movement through birth canal"],
["3", "Flexion", "Chin on chest; suboccipitobregmatic diameter presented"],
["4", "Internal Rotation", "Occiput rotates anteriorly to OA position under symphysis"],
["5", "Extension", "Head delivered by extension under pubic arch"],
["6", "External Rotation", "Restitution — head aligns with fetal shoulders"],
["7", "Expulsion", "Delivery of anterior shoulder, posterior shoulder, then body"],
]
cm_tbl = Table(cm_data, colWidths=[1.2*cm, 4.2*cm, 12.1*cm])
cm_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#B45309")),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (0,0), (1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [AMBER, WHITE]),
("BOX", (0,0), (-1,-1), 1, BORDER),
("INNERGRID", (0,0), (-1,-1), 0.5, BORDER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("FONTNAME", (0,1), (1,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (1,-1), colors.HexColor("#92400E")),
]))
story.append(cm_tbl)
story.append(sp(5))
story.append(Paragraph("Episiotomy", h3_style))
story.append(info_box(
"NOT recommended routinely. Indicated only for <b>shoulder dystocia</b> or <b>breech delivery</b>. "
"<b>Mediolateral incision preferred</b> over midline to reduce rectal involvement and perineal tears. "
"Perform when introitus opens to 3–4 cm diameter during a contraction.",
bg=GREY_BG, border=BORDER
))
story.append(sp(10))
# THIRD STAGE
story.append(section_header("THIRD STAGE OF LABOUR — The Placental Stage", colors.HexColor("#166534")))
story.append(sp(5))
story.append(info_box(
"<b>Definition:</b> From <b>delivery of the infant</b> to <b>complete delivery of the placenta</b> "
"and membranes. Normal duration: <b><10 minutes</b>. Retained placenta: >30 minutes.",
bg=GREEN_BG, border=colors.HexColor("#166534")
))
story.append(sp(5))
story.append(Paragraph("Signs of Placental Separation", h3_style))
signs = [
("1", "Uterus becomes firm, globular and rises in the abdomen (Schroeder's sign)"),
("2", "Sudden gush of blood — retroplacental clot expulsion"),
("3", "Apparent lengthening of the umbilical cord (5–10 cm)"),
("4", "Uterus becomes mobile at suprapubic area"),
]
signs_data = [["Sign", "Description"]] + signs
signs_tbl = Table(signs_data, colWidths=[1.5*cm, 16*cm])
signs_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#166534")),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (0,0), (0,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [GREEN_BG, WHITE]),
("BOX", (0,0), (-1,-1), 1, BORDER),
("INNERGRID", (0,0), (-1,-1), 0.5, BORDER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), colors.HexColor("#166534")),
]))
story.append(signs_tbl)
story.append(sp(5))
story.append(Paragraph("Management — Active vs Expectant", h3_style))
mgmt_data = [
["Approach", "Steps", "Benefit"],
["Active Management\n(Recommended)",
"1. Oxytocin 10 IU IM/IV\n2. Controlled cord traction\n3. Uterine massage",
"Reduces PPH risk;\nShortens 3rd stage"],
["Expectant/Physiological",
"Allow spontaneous separation;\nIntervene if haemorrhage",
"Avoids drugs; longer wait"],
]
mgmt_tbl = Table(mgmt_data, colWidths=[4*cm, 8.5*cm, 5*cm])
mgmt_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#166534")),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [GREEN_BG, WHITE]),
("BOX", (0,0), (-1,-1), 1, BORDER),
("INNERGRID", (0,0), (-1,-1), 0.5, BORDER),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
]))
story.append(mgmt_tbl)
story.append(sp(4))
story.append(info_box(
"<b>CAUTION:</b> Never give oxytocin BEFORE placental delivery — risk of trapping placental fragments "
"or missing an undetected twin. Retained placenta (>30 min) → risk of PPH 6x higher.",
bg=RED_BG, border=colors.HexColor("#DC2626")
))
# ─────────────────────────────────────────────────────────────────────────────
# PAGE 4 — FOURTH STAGE + SUMMARY + KEY NUMBERS
# ─────────────────────────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("FOURTH STAGE OF LABOUR — The Recovery Stage", colors.HexColor("#7C3AED")))
story.append(sp(5))
story.append(info_box(
"<b>Definition:</b> The <b>first hour after delivery of the placenta</b> (described by Pritchard and MacDonald). "
"This is the most critical period — risk of <b>Primary PPH</b> is highest during this hour. "
"Uterine atony is the commonest cause.",
bg=colors.HexColor("#EDE9FE"), border=colors.HexColor("#7C3AED")
))
story.append(sp(5))
story.append(Paragraph("Management During Fourth Stage", h3_style))
fourth_steps = [
("Inspect", "Cervix, vagina, vaginal walls, and perineum for lacerations → repair promptly"),
("Oxytocin infusion", "Promote uterine contraction and control haemorrhage"),
("Uterine tone check", "Frequent palpation; transabdominal massage if uterus relaxes"),
("Vital signs monitoring", "BP, pulse, temperature, respiratory rate every 15 minutes"),
("Bladder care", "Encourage voiding; catheterise if unable (full bladder displaces uterus → PPH)"),
("Blood loss assessment", "Normal: ≤500 mL. PPH = ≥500 mL blood loss"),
]
fourth_data = [["Action", "Details"]] + list(fourth_steps)
fourth_tbl = Table(fourth_data, colWidths=[4.5*cm, 13*cm])
fourth_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#7C3AED")),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (0,0), (0,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [colors.HexColor("#EDE9FE"), WHITE]),
("BOX", (0,0), (-1,-1), 1, BORDER),
("INNERGRID", (0,0), (-1,-1), 0.5, BORDER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), colors.HexColor("#7C3AED")),
]))
story.append(fourth_tbl)
story.append(sp(8))
# MASTER SUMMARY TABLE
story.append(section_header("MASTER SUMMARY — All Four Stages", colors.HexColor("#1E3A5F")))
story.append(sp(5))
sum_data = [
["Feature", "1st Stage", "2nd Stage", "3rd Stage", "4th Stage"],
["From",
"Onset of labour",
"Full dilatation",
"Delivery of baby",
"Delivery of placenta"],
["To",
"Full dilatation\n(10 cm)",
"Delivery of baby",
"Delivery of\nplacenta",
"1 hour\npost-delivery"],
["Duration\n(Nullipara)",
"~11 hours",
"~54 minutes",
"< 30 min",
"1 hour"],
["Duration\n(Multipara)",
"~7 hours",
"~20 minutes",
"< 10 min",
"1 hour"],
["Key events",
"Effacement +\nDilatation",
"Cardinal\nmovements,\nDelivery of head",
"Placental\nseparation",
"Haemostasis,\nRepair"],
["Main risk",
"Dystocia,\nFetal distress",
"PPH, cord\nprolapse,\nlacerations",
"PPH, retained\nplacenta",
"PPH,\nUterine atony"],
]
sum_tbl = Table(sum_data, colWidths=[3.2*cm, 3.5*cm, 3.5*cm, 3.5*cm, 3.8*cm])
sum_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [LIGHT_BLUE, WHITE]),
("BOX", (0,0), (-1,-1), 1.5, NAVY),
("INNERGRID", (0,0), (-1,-1), 0.5, BORDER),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0), (-1,-1), 5),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), NAVY),
# Highlight risk row
("BACKGROUND", (0,6), (-1,6), RED_BG),
]))
story.append(sum_tbl)
story.append(sp(8))
# KEY NUMBERS BOX
story.append(Paragraph("Key Numbers to Remember", h2_style))
story.append(sp(3))
kn_data = [
["Parameter", "Value"],
["Full cervical dilatation", "10 cm"],
["Active phase begins at", "3–4 cm"],
["Normal dilatation rate (Nullipara)", "≥ 1.2 cm/hr"],
["Normal dilatation rate (Multipara)", "≥ 1.5 cm/hr"],
["Prolonged latent phase (Nullipara)", "> 20 hours"],
["Prolonged latent phase (Multipara)", "> 14 hours"],
["Arrest of active phase", "No change ≥ 2 hours"],
["Prolonged 2nd stage (Nullipara, no epidural)", "> 2 hours"],
["Prolonged 2nd stage (Multipara)", "> 1 hour"],
["Retained placenta", "> 30 minutes"],
["Normal blood loss (vaginal delivery)", "≤ 500 mL"],
["Primary PPH threshold", "≥ 500 mL"],
]
kn_tbl = Table(kn_data, colWidths=[11*cm, 6.5*cm])
kn_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (1,1), (1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROWBACKGROUNDS",(0,1),(-1,-1), [LIGHT_BLUE, WHITE]),
("BOX", (0,0), (-1,-1), 1, TEAL),
("INNERGRID", (0,0), (-1,-1), 0.5, BORDER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
("FONTNAME", (1,1), (1,-1), "Helvetica-Bold"),
("TEXTCOLOR", (1,1), (1,-1), NAVY),
]))
story.append(kn_tbl)
story.append(sp(5))
# Footer note
story.append(HRFlowable(width="100%", thickness=0.5, color=BORDER))
story.append(sp(3))
story.append(Paragraph(
"Sources: Creasy & Resnik's Maternal-Fetal Medicine (7e); Rosen's Emergency Medicine; "
"Tintinalli's Emergency Medicine. Content aligned with DC Dutta's Textbook of Obstetrics framework.",
small_style))
# ── Build ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT}")