Add two points for every chat
python3 -c " import pdfplumber path = '/home/daytona/workspace/attachments/69be2…
python3 -c " import subprocess # Convert first 5 pages to images for inspection …
python3 -c " from PIL import Image import os base = '/home/daytona/workspace/at…
python3 -c " import subprocess, os from PIL import Image pdf_path = '/home/dayt…
python3 -c " import subprocess, os pdf_path = '/home/daytona/workspace/attachme…
python3 -c " import pytesseract from PIL import Image import os, json out_dir =…
ls /home/daytona/workspace/attachments/69be2471-250e-478e-b1fe-e0a452192666/ | g…
python3 << 'PYEOF' import pytesseract from PIL import Image import os, json, re …
python3 << 'PYEOF' import json with open('/home/daytona/workspace/physio_ocr.js…
python3 << 'PYEOF' import json with open('/home/daytona/workspace/physio_ocr.js…
~/add_bullets.py
"""
Add 2 bullet points to each text-based chart page in the physiology practical charts PDF.
Uses reportlab to create an overlay, then merges with pypdf.
"""
import io
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.lib.colors import HexColor, black, white
from reportlab.lib.units import cm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# ── bullet points for each page number (1-indexed) ──────────────────────────
BULLETS = {
# Clinical: Cardiovascular system + triceps jerk
1: [
"CVS exam: Inspect for cyanosis, edema, JVP; palpate apex beat (normal 5th ICS, MCL).",
"Triceps jerk (C7-C8): Strike triceps tendon with elbow flexed 90°; expect elbow extension."
],
# Hematology: TLC + bleeding time
2: [
"TLC normal: 4000-11000/mm³; Neutrophilia → bacterial infection; Lymphocytosis → viral.",
"Bleeding time (Ivy method): Normal 2-7 min; prolonged in thrombocytopenia & platelet dysfunction."
],
# Dyspneic index calculation
3: [
"Dyspneic index = (MVV - RPV) / MVV × 100; normal >70%; <40% indicates severe respiratory disability.",
"MVV (Max Voluntary Ventilation): maximum air breathed per minute; reflects respiratory muscle strength."
],
# MCH & MCV calculation
4: [
"MCH = (Hb g/dl × 10) / RBC count (millions); Normal: 27-32 pg. MCV = (PCV × 10) / RBC count; Normal: 80-100 fL.",
"MCHC cannot exceed 38% because haemoglobin cannot supersaturate the RBC beyond its capacity."
],
# Duplicate MCH/MCV page
7: [
"MCH = (Hb g/dl × 10) / RBC count (millions); Normal: 27-32 pg. MCV = (PCV × 10) / RBC count; Normal: 80-100 fL.",
"MCHC cannot exceed 38% because haemoglobin cannot supersaturate the RBC beyond its capacity."
],
# Clinical: Respiratory system + biceps jerk
11: [
"Respiratory exam: Inspect chest shape, rate; percuss for dullness (consolidation) or resonance (pneumothorax).",
"Biceps jerk (C5-C6): Strike biceps tendon with forearm supinated; expect forearm flexion."
],
# Human: BP lying/standing + ECG
12: [
"Postural BP drop >20 mmHg systolic or >10 mmHg diastolic on standing = orthostatic hypotension.",
"ECG normal values: PR 0.12-0.20s; QRS <0.12s; QTc <0.44s; normal axis -30° to +90°."
],
# Clinical: Motor system + ankle jerk
13: [
"Motor exam: Test tone (flaccid vs. spastic), power (MRC 0-5 scale), coordination (finger-nose test).",
"Ankle jerk (S1-S2): Strike Achilles tendon with foot dorsiflexed; absent in peripheral neuropathy."
],
# Hematology: TEC + blood group
14: [
"TEC (Total Erythrocyte Count) normal: Males 4.5-5.5 million/mm³; Females 3.8-4.8 million/mm³.",
"ABO blood grouping: Type & screen before transfusion; O-negative is universal donor for RBCs."
],
# Clinical: Sensory system + supinator jerk
20: [
"Sensory exam: Test pain (pin-prick), light touch, temperature, vibration, and proprioception systematically.",
"Supinator jerk (C5-C6): Strike brachioradialis tendon; expect forearm supination and slight flexion."
],
# Clinical: General exam + radial pulse + triceps jerk
21: [
"Radial pulse: Normal 60-100 bpm, regular rhythm; assess rate, rhythm, volume, character, and vessel wall.",
"Triceps jerk (C7-C8): Strike triceps tendon with elbow flexed 90°; expect elbow extension."
],
# Clinical: CN I-VI + plantar reflex
23: [
"CN I-VI: Test olfaction (I), visual acuity/fields (II), pupillary reflexes (III), corneal reflex (V), facial sensation (V).",
"Plantar reflex: Babinski sign (upgoing toe) = upper motor neuron lesion; flexor response = normal in adults."
],
# TmG calculation
25: [
"TmG (Tubular maximum for glucose) = (Urine glucose × Urine flow) + (Plasma glucose × GFR) ÷ 1000; Normal ~320 mg/min.",
"In diabetes mellitus, plasma glucose exceeds TmG threshold (~180 mg/dL), causing glycosuria."
],
# Hematology: TLC + clotting time
26: [
"TLC normal: 4000-11000/mm³; Neutrophilia → bacterial infection; Lymphocytosis → viral.",
"Clotting time (Lee-White method): Normal 5-11 min; prolonged in haemophilia A & B, anticoagulant therapy."
],
# Clinical: CN I-VI + biceps jerk
29: [
"CN I-VI: Test olfaction (I), visual acuity/fields (II), pupillary reflexes (III), corneal reflex (V), facial sensation (V).",
"Biceps jerk (C5-C6): Strike biceps tendon with forearm supinated; expect forearm flexion."
],
# Clinical: Proprioception, vibration, stereognosis + supinator jerk
32: [
"Posterior column sensations (vibration, proprioception, 2-point discrimination) travel via dorsal column-medial lemniscus.",
"Stereognosis: ability to identify objects by touch alone; lost in parietal lobe lesions (astereognosis)."
],
# Clinical: CVS + supinator jerk
34: [
"CVS exam: Inspect for cyanosis, edema, JVP; palpate apex beat (normal 5th ICS, MCL).",
"Supinator jerk (C5-C6): Strike brachioradialis tendon; expect forearm supination and slight flexion."
],
# Clinical: CN VII-XII + biceps jerk
35: [
"CN VII-XII: Facial movement (VII), hearing/balance (VIII), palate elevation (IX/X), SCM/trapezius (XI), tongue (XII).",
"Biceps jerk (C5-C6): Strike biceps tendon with forearm supinated; expect forearm flexion."
],
# Clinical: Posterior column + knee jerk
36: [
"Posterior column sensations (vibration, proprioception, 2-point discrimination) travel via dorsal column-medial lemniscus.",
"Knee jerk (L3-L4): Strike patellar tendon with knee flexed; absent in femoral neuropathy or tabes dorsalis."
],
# Clinical: CN I-VI + knee jerk
39: [
"CN I-VI: Test olfaction (I), visual acuity/fields (II), pupillary reflexes (III), corneal reflex (V), facial sensation (V).",
"Knee jerk (L3-L4): Strike patellar tendon with knee flexed; absent in femoral neuropathy or tabes dorsalis."
],
# Clinical: CN VII-XII + triceps jerk
42: [
"CN VII-XII: Facial movement (VII), hearing/balance (VIII), palate elevation (IX/X), SCM/trapezius (XI), tongue (XII).",
"Triceps jerk (C7-C8): Strike triceps tendon with elbow flexed 90°; expect elbow extension."
],
# Human: BP lying/standing + Mosso's ergography
43: [
"Postural BP drop >20 mmHg systolic or >10 mmHg diastolic on standing = orthostatic hypotension.",
"Mosso's ergograph measures muscle fatigue; the tracing shows decreasing amplitude with repeated contractions."
],
# Clinical: Fine touch, tactile localization, 2-point discrimination + plantar reflex
44: [
"Two-point discrimination: Fingertip normal ~2-3 mm; back ~40 mm; tests density of cutaneous receptors.",
"Plantar reflex: Babinski sign (upgoing toe) = upper motor neuron lesion; flexor response = normal in adults."
],
# Human: BP in exercise + ECG
45: [
"During moderate exercise: systolic BP rises (increased cardiac output), diastolic BP stays same or falls (vasodilation).",
"ECG normal values: PR 0.12-0.20s; QRS <0.12s; QTc <0.44s; normal axis -30° to +90°."
],
# Clinical: General exam + JVP + triceps jerk
46: [
"JVP (Jugular Venous Pressure): Normal <4 cm above sternal angle; elevated in right heart failure, cardiac tamponade.",
"Triceps jerk (C7-C8): Strike triceps tendon with elbow flexed 90°; expect elbow extension."
],
# Net effective filtration pressure (NEFP)
47: [
"NEFP = (Glomerular HP - Bowman's HP) - Plasma osmotic pressure; Normal NEFP = 60 - 15 - 32 = +13 mmHg.",
"Filtration occurs as long as NEFP is positive; reduced GFR in hypoalbuminaemia (low oncotic pressure)."
],
# Clinical: CVS + knee jerk
49: [
"CVS exam: Inspect for cyanosis, edema, JVP; palpate apex beat (normal 5th ICS, MCL).",
"Knee jerk (L3-L4): Strike patellar tendon with knee flexed; absent in femoral neuropathy or tabes dorsalis."
],
# Hematology: DLC + bleeding time
50: [
"DLC normal %: Neutrophils 50-70%, Lymphocytes 20-40%, Monocytes 2-8%, Eosinophils 1-4%, Basophils 0-1%.",
"Bleeding time (Ivy method): Normal 2-7 min; prolonged in thrombocytopenia & platelet dysfunction."
],
# Clinical: Lower limb muscle tone/power + biceps jerk
53: [
"Lower limb power (MRC scale 0-5): Test hip flexion (L1-L2), knee extension (L3-L4), ankle dorsiflexion (L4-L5).",
"Biceps jerk (C5-C6): Strike biceps tendon with forearm supinated; expect forearm flexion."
],
# Cardiac muscle properties chart
56: [
"Treppe/Staircase phenomenon: Gradual increase in contraction strength with repeated stimuli at constant intervals.",
"Extrasystole: Premature contraction followed by a compensatory pause; occurs during relative refractory period."
],
# Clinical: Respiratory + knee jerk
57: [
"Respiratory exam: Inspect chest shape, rate; percuss for dullness (consolidation) or resonance (pneumothorax).",
"Knee jerk (L3-L4): Strike patellar tendon with knee flexed; absent in femoral neuropathy or tabes dorsalis."
],
# Clinical: JVP + ankle jerk
59: [
"JVP (Jugular Venous Pressure): Normal <4 cm above sternal angle; elevated in right heart failure, cardiac tamponade.",
"Ankle jerk (S1-S2): Strike Achilles tendon with foot dorsiflexed; absent in peripheral neuropathy."
],
# Clinical: Respiratory + plantar reflex
62: [
"Respiratory exam: Inspect chest shape, rate; percuss for dullness (consolidation) or resonance (pneumothorax).",
"Plantar reflex: Babinski sign (upgoing toe) = upper motor neuron lesion; flexor response = normal in adults."
],
# Human: BP in exercise + perimetry
63: [
"During moderate exercise: systolic BP rises (increased cardiac output), diastolic BP stays same or falls (vasodilation).",
"Perimetry maps visual fields; normal field: temporal 90°, nasal 60°, superior 50°, inferior 70°."
],
# Clinical: CN VII-XII + knee jerk
64: [
"CN VII-XII: Facial movement (VII), hearing/balance (VIII), palate elevation (IX/X), SCM/trapezius (XI), tongue (XII).",
"Knee jerk (L3-L4): Strike patellar tendon with knee flexed; absent in femoral neuropathy or tabes dorsalis."
],
# Lung compliance calculation
65: [
"Lung compliance = ΔV / ΔP; Normal static compliance ~200 mL/cmH₂O; reduced in fibrosis, pulmonary oedema.",
"Decreased compliance → increased work of breathing; increased compliance (emphysema) → air trapping."
],
# Hematology: Hb + clotting time
66: [
"Hb estimation (Sahli's method): Dilute blood with HCl; compare with standard. Normal: Males 13-17 g/dL; Females 12-15 g/dL.",
"Clotting time (Lee-White method): Normal 5-11 min; prolonged in haemophilia A & B, anticoagulant therapy."
],
# Hematology: TEC + bleeding time
67: [
"TEC normal: Males 4.5-5.5 million/mm³; Females 3.8-4.8 million/mm³; reduced in anaemia.",
"Bleeding time (Ivy method): Normal 2-7 min; prolonged in thrombocytopenia & platelet dysfunction."
],
# Clinical: Upper limb muscle tone/power + triceps jerk
68: [
"Upper limb power (MRC scale 0-5): Test shoulder abduction (C5), elbow flexion (C5-C6), wrist extension (C6-C7).",
"Triceps jerk (C7-C8): Strike triceps tendon with elbow flexed 90°; expect elbow extension."
],
# Human: BP lying/standing + Mosso's ergography
69: [
"Postural BP drop >20 mmHg systolic or >10 mmHg diastolic on standing = orthostatic hypotension.",
"Mosso's ergograph measures muscle fatigue; the tracing shows decreasing amplitude with repeated contractions."
],
# RV and FRC calculation
70: [
"RV = TLC - (IRV + TV + ERV); FRC = RV + ERV. Normal RV ~1.2 L; FRC ~2.3 L.",
"RV importance: Prevents lung collapse at end-expiration; cannot be measured by spirometry (needs helium dilution/body plethysmography)."
],
# Human: BP in exercise + Mosso's ergography
73: [
"During moderate exercise: systolic BP rises (increased cardiac output), diastolic BP stays same or falls (vasodilation).",
"Mosso's ergograph measures muscle fatigue; the tracing shows decreasing amplitude with repeated contractions."
],
# Human: BP in exercise + ECG
75: [
"During moderate exercise: systolic BP rises (increased cardiac output), diastolic BP stays same or falls (vasodilation).",
"ECG normal values: PR 0.12-0.20s; QRS <0.12s; QTc <0.44s; normal axis -30° to +90°."
],
# Human: Pulse/BP/MAP sitting + Mosso's ergography
76: [
"MAP = Diastolic BP + 1/3 (Pulse Pressure); Normal MAP ~93 mmHg; drives tissue perfusion.",
"Mosso's ergograph measures muscle fatigue; the tracing shows decreasing amplitude with repeated contractions."
],
# Human: Pulse/BP/MAP sitting + perimetry
77: [
"MAP = Diastolic BP + 1/3 (Pulse Pressure); Normal MAP ~93 mmHg; drives tissue perfusion.",
"Perimetry maps visual fields; normal field: temporal 90°, nasal 60°, superior 50°, inferior 70°."
],
# Stroke volume & cardiac output (Fick's principle)
78: [
"Fick's principle: CO = O₂ consumption ÷ (arterial O₂ content - venous O₂ content); Normal CO ~5 L/min.",
"Stroke volume = CO / Heart rate; Normal ~70 mL; increased in trained athletes."
],
# Human: Pulse/BP/MAP sitting + ECG
80: [
"MAP = Diastolic BP + 1/3 (Pulse Pressure); Normal MAP ~93 mmHg; drives tissue perfusion.",
"ECG normal values: PR 0.12-0.20s; QRS <0.12s; QTc <0.44s; normal axis -30° to +90°."
],
# Human: Pulse/BP/MAP sitting + spirometry
81: [
"MAP = Diastolic BP + 1/3 (Pulse Pressure); Normal MAP ~93 mmHg; drives tissue perfusion.",
"Spirometry: FEV1/FVC <0.7 = obstructive; normal FEV1/FVC with reduced FVC = restrictive pattern."
],
# Absolute eosinophil count (AEC)
82: [
"AEC = (TLC × Eosinophil % from DLC) / 100; Normal AEC < 500/mm³; > 500 = eosinophilia.",
"Eosinophilia in asthma is driven by IL-5; elevated AEC also seen in parasitic infections and allergies."
],
# Human: BP lying/standing + spirometry
85: [
"Postural BP drop >20 mmHg systolic or >10 mmHg diastolic on standing = orthostatic hypotension.",
"Spirometry: FEV1/FVC <0.7 = obstructive; normal FEV1/FVC with reduced FVC = restrictive pattern."
],
# Clinical: General exam + radial pulse + knee jerk
86: [
"Radial pulse: Normal 60-100 bpm, regular rhythm; assess rate, rhythm, volume, character, and vessel wall.",
"Knee jerk (L3-L4): Strike patellar tendon with knee flexed; absent in femoral neuropathy or tabes dorsalis."
],
# Hematology: Hb + bleeding time
87: [
"Hb estimation (Sahli's method): Dilute blood with HCl; compare with standard. Normal: Males 13-17 g/dL; Females 12-15 g/dL.",
"Bleeding time (Ivy method): Normal 2-7 min; prolonged in thrombocytopenia & platelet dysfunction."
],
# Color index calculation
88: [
"Color index = (Patient Hb% / Normal Hb%) / (Patient RBC% / Normal RBC%); Normal = 1.0; <0.9 = hypochromic.",
"Hypochromic anaemia (CI <0.9): iron deficiency, thalassaemia. Hyperchromic (CI >1.0): pernicious anaemia."
],
# GFR calculation (Inulin clearance)
91: [
"GFR (Inulin clearance) = (U × V) / P; Normal GFR ~125 mL/min; reduced GFR indicates renal impairment.",
"Inulin is freely filtered, not secreted or reabsorbed — the gold standard marker for GFR measurement."
],
# Clinical: CN VII-XII + ankle jerk
94: [
"CN VII-XII: Facial movement (VII), hearing/balance (VIII), palate elevation (IX/X), SCM/trapezius (XI), tongue (XII).",
"Ankle jerk (S1-S2): Strike Achilles tendon with foot dorsiflexed; absent in peripheral neuropathy."
],
# Clinical: CN I-VI + triceps jerk
95: [
"CN I-VI: Test olfaction (I), visual acuity/fields (II), pupillary reflexes (III), corneal reflex (V), facial sensation (V).",
"Triceps jerk (C7-C8): Strike triceps tendon with elbow flexed 90°; expect elbow extension."
],
# Physiological dead space (Bohr equation)
96: [
"Dead space (Bohr): VD/VT = (PaCO₂ - PeCO₂) / PaCO₂; Normal dead space ~150 mL (anatomical) or up to 30% of VT.",
"Increased dead space (pulmonary embolism) raises minute ventilation requirement without improving gas exchange."
],
# Cardiac output by Fick's principle
100: [
"Fick's principle: CO = O₂ consumption ÷ (arterial O₂ content - venous O₂ content); Normal CO ~5 L/min.",
"Stroke volume = CO / Heart rate; Normal ~70 mL; increased in trained athletes."
],
# Chronaxie / nerve excitability chart
108: [
"Chronaxie: time needed to excite tissue at twice rheobase current; shorter chronaxie = more excitable nerve/muscle.",
"Rheobase: minimum current of infinite duration needed to excite tissue; measures excitability threshold."
],
# Nerve conduction velocity
109: [
"Nerve conduction velocity = Distance between two stimulation points / Difference in latent periods.",
"Normal motor conduction velocity: upper limb ~50-70 m/s; lower limb ~40-55 m/s; reduced in demyelination."
],
# Human: BP lying/standing + spirometry
111: [
"Postural BP drop >20 mmHg systolic or >10 mmHg diastolic on standing = orthostatic hypotension.",
"Spirometry: FEV1/FVC <0.7 = obstructive; normal FEV1/FVC with reduced FVC = restrictive pattern."
],
# AEC (duplicate)
113: [
"AEC = (TLC × Eosinophil % from DLC) / 100; Normal AEC < 500/mm³; > 500 = eosinophilia.",
"Eosinophilia in asthma is driven by IL-5; elevated AEC also seen in parasitic infections and allergies."
],
# Human: Pulse/BP/MAP + spirometry
114: [
"MAP = Diastolic BP + 1/3 (Pulse Pressure); Normal MAP ~93 mmHg; drives tissue perfusion.",
"Spirometry: FEV1/FVC <0.7 = obstructive; normal FEV1/FVC with reduced FVC = restrictive pattern."
],
# Human: Pulse/BP/MAP + ECG
115: [
"MAP = Diastolic BP + 1/3 (Pulse Pressure); Normal MAP ~93 mmHg; drives tissue perfusion.",
"ECG normal values: PR 0.12-0.20s; QRS <0.12s; QTc <0.44s; normal axis -30° to +90°."
],
# Stroke volume & cardiac output (duplicate)
117: [
"Fick's principle: CO = O₂ consumption ÷ (arterial O₂ content - venous O₂ content); Normal CO ~5 L/min.",
"Stroke volume = CO / Heart rate; Normal ~70 mL; increased in trained athletes."
],
# Human: Pulse/BP/MAP + perimetry
118: [
"MAP = Diastolic BP + 1/3 (Pulse Pressure); Normal MAP ~93 mmHg; drives tissue perfusion.",
"Perimetry maps visual fields; normal field: temporal 90°, nasal 60°, superior 50°, inferior 70°."
],
# Human: Pulse/BP/MAP + Mosso's ergography
119: [
"MAP = Diastolic BP + 1/3 (Pulse Pressure); Normal MAP ~93 mmHg; drives tissue perfusion.",
"Mosso's ergograph measures muscle fatigue; the tracing shows decreasing amplitude with repeated contractions."
],
# Human: BP in exercise + Mosso's ergography
120: [
"During moderate exercise: systolic BP rises (increased cardiac output), diastolic BP stays same or falls (vasodilation).",
"Mosso's ergograph measures muscle fatigue; the tracing shows decreasing amplitude with repeated contractions."
],
# Human: BP in exercise + ECG
121: [
"During moderate exercise: systolic BP rises (increased cardiac output), diastolic BP stays same or falls (vasodilation).",
"ECG normal values: PR 0.12-0.20s; QRS <0.12s; QTc <0.44s; normal axis -30° to +90°."
],
}
def make_overlay(page_width, page_height, bullet1, bullet2):
"""Create a PDF overlay with 2 bullet points at the bottom of the page."""
packet = io.BytesIO()
c = canvas.Canvas(packet, pagesize=(page_width, page_height))
# Draw a light blue background box at bottom
box_height = 80
margin = 20
padding = 8
c.setFillColor(HexColor('#EBF4FB'))
c.setStrokeColor(HexColor('#2980B9'))
c.setLineWidth(1)
c.roundRect(margin, margin, page_width - 2*margin, box_height, 5, fill=1, stroke=1)
# Title
c.setFillColor(HexColor('#1A5276'))
c.setFont("Helvetica-Bold", 7.5)
c.drawString(margin + padding, margin + box_height - padding - 8, "Key Points:")
# Bullet 1
c.setFillColor(HexColor('#1A5276'))
c.setFont("Helvetica-Bold", 7)
c.drawString(margin + padding, margin + box_height - padding - 22, "\u2022")
c.setFont("Helvetica", 7)
# Word-wrap bullet text
max_w = page_width - 2*margin - 2*padding - 12
_draw_wrapped(c, margin + padding + 10, margin + box_height - padding - 22, bullet1, 7, max_w)
# Bullet 2
c.setFillColor(HexColor('#1A5276'))
c.setFont("Helvetica-Bold", 7)
c.drawString(margin + padding, margin + box_height - padding - 50, "\u2022")
c.setFont("Helvetica", 7)
_draw_wrapped(c, margin + padding + 10, margin + box_height - padding - 50, bullet2, 7, max_w)
c.save()
packet.seek(0)
return PdfReader(packet).pages[0]
def _draw_wrapped(c, x, y, text, font_size, max_width):
"""Draw text with simple word-wrap on one line (truncate if too long)."""
from reportlab.pdfbase.pdfmetrics import stringWidth
c.setFont("Helvetica", font_size)
c.setFillColor(HexColor('#1A5276'))
words = text.split()
line = ""
for word in words:
test = (line + " " + word).strip()
if stringWidth(test, "Helvetica", font_size) <= max_width:
line = test
else:
break
# Draw single line (clipped)
c.drawString(x, y, line)
def main():
pdf_path = '/home/daytona/workspace/attachments/69be2471-250e-478e-b1fe-e0a452192666/physiology practical charts.pdf'
output_path = '/home/daytona/workspace/physiology_practical_charts_with_bullets.pdf'
reader = PdfReader(pdf_path)
writer = PdfWriter()
total = len(reader.pages)
added = 0
for i, page in enumerate(reader.pages):
page_num = i + 1
if page_num in BULLETS:
b1, b2 = BULLETS[page_num]
# Get page dimensions
box = page.mediabox
pw = float(box.width)
ph = float(box.height)
overlay_page = make_overlay(pw, ph, b1, b2)
page.merge_page(overlay_page)
added += 1
writer.add_page(page)
with open(output_path, 'wb') as f:
writer.write(f)
print(f"Done! Added bullet points to {added}/{total} pages.")
print(f"Output: {output_path}")
if __name__ == '__main__':
main()
python3 /home/daytona/workspace/add_bullets.py
python3 -c " import subprocess, os from PIL import Image # Convert first 2 text…