Mujhe hinglish me ecg padhni sikhao all disease with image pdf bna dena
mkdir -p /home/daytona/workspace/ecg-hinglish && ls /home/daytona/workspace/ecg-…
~/ecg-hinglish/create_ecg_pdf.py
#!/usr/bin/env python3
"""
ECG Padhna Sikhao - Comprehensive Hinglish ECG Guide PDF
With images from medical textbooks
"""
import requests
import os
from io import BytesIO
from PIL import Image as PILImage
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm, cm
from reportlab.lib.colors import (
HexColor, white, black, red, blue, darkblue,
Color, lightgrey, darkred
)
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
OUTPUT_PATH = "/home/daytona/workspace/ecg-hinglish/ECG_Padhna_Sikhao_Hinglish.pdf"
# Colors
COLOR_TITLE_BG = HexColor("#C0392B") # Deep red (heart color)
COLOR_SECTION_BG = HexColor("#2C3E50") # Dark blue
COLOR_SUBSECTION_BG = HexColor("#E74C3C") # Red
COLOR_HIGHLIGHT = HexColor("#F39C12") # Orange
COLOR_BOX_BG = HexColor("#FADBD8") # Light pink
COLOR_GREEN_BOX = HexColor("#D5F5E3") # Light green
COLOR_BLUE_BOX = HexColor("#D6EAF8") # Light blue
COLOR_YELLOW_BOX = HexColor("#FDEBD0") # Light orange
COLOR_TEXT = HexColor("#1A1A1A")
styles = getSampleStyleSheet()
# Custom styles
title_style = ParagraphStyle(
'CustomTitle',
parent=styles['Title'],
fontSize=28,
textColor=white,
alignment=TA_CENTER,
spaceAfter=6,
fontName='Helvetica-Bold'
)
subtitle_style = ParagraphStyle(
'SubTitle',
parent=styles['Normal'],
fontSize=14,
textColor=HexColor("#FDEBD0"),
alignment=TA_CENTER,
spaceAfter=4,
fontName='Helvetica'
)
section_style = ParagraphStyle(
'SectionHead',
parent=styles['Heading1'],
fontSize=18,
textColor=white,
fontName='Helvetica-Bold',
spaceBefore=12,
spaceAfter=6,
leftIndent=0,
)
subsection_style = ParagraphStyle(
'SubsectionHead',
parent=styles['Heading2'],
fontSize=14,
textColor=HexColor("#C0392B"),
fontName='Helvetica-Bold',
spaceBefore=10,
spaceAfter=4,
)
body_style = ParagraphStyle(
'BodyText',
parent=styles['Normal'],
fontSize=11,
textColor=COLOR_TEXT,
fontName='Helvetica',
spaceAfter=6,
leading=16,
alignment=TA_JUSTIFY,
)
bullet_style = ParagraphStyle(
'BulletText',
parent=styles['Normal'],
fontSize=11,
textColor=COLOR_TEXT,
fontName='Helvetica',
spaceAfter=4,
leading=15,
leftIndent=15,
bulletIndent=5,
)
caption_style = ParagraphStyle(
'Caption',
parent=styles['Normal'],
fontSize=9,
textColor=HexColor("#555555"),
fontName='Helvetica-Oblique',
alignment=TA_CENTER,
spaceAfter=8,
leading=12,
)
important_style = ParagraphStyle(
'Important',
parent=styles['Normal'],
fontSize=11,
textColor=HexColor("#7B241C"),
fontName='Helvetica-Bold',
spaceAfter=4,
leading=16,
)
def fetch_image(url, max_width=140*mm, max_height=80*mm):
"""Download image from URL and return ReportLab Image object."""
try:
r = requests.get(url, timeout=15)
r.raise_for_status()
img_data = BytesIO(r.content)
pil_img = PILImage.open(img_data)
orig_w, orig_h = pil_img.size
# Scale to fit
ratio = min(max_width / orig_w, max_height / orig_h)
new_w = orig_w * ratio
new_h = orig_h * ratio
img_data.seek(0)
return Image(img_data, width=new_w, height=new_h)
except Exception as e:
print(f"Image fetch failed for {url}: {e}")
return None
def make_section_header(text):
"""Create a colored section header block."""
data = [[Paragraph(text, section_style)]]
t = Table(data, colWidths=[170*mm])
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), COLOR_SECTION_BG),
('TOPPADDING', (0,0), (-1,-1), 8),
('BOTTOMPADDING', (0,0), (-1,-1), 8),
('LEFTPADDING', (0,0), (-1,-1), 12),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('ROUNDEDCORNERS', [5, 5, 5, 5]),
]))
return t
def make_info_box(title, content_lines, bg_color=COLOR_BLUE_BOX, title_color=HexColor("#1A5276")):
"""Create a colored info box."""
items = [Paragraph(f"<b>{title}</b>", ParagraphStyle('BoxTitle', parent=styles['Normal'],
fontSize=12, textColor=title_color, fontName='Helvetica-Bold', spaceAfter=4))]
for line in content_lines:
items.append(Paragraph(f"• {line}", bullet_style))
data = [[item] for item in items]
# Use a single cell table with all items
cell_content = [Paragraph(f"<b>{title}</b>", ParagraphStyle('BoxTitle', parent=styles['Normal'],
fontSize=12, textColor=title_color, fontName='Helvetica-Bold', spaceAfter=6, leading=16))]
for line in content_lines:
cell_content.append(Paragraph(f"• {line}", bullet_style))
from reportlab.platypus import KeepInFrame
t = Table([[cell_content]], colWidths=[165*mm])
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), bg_color),
('TOPPADDING', (0,0), (-1,-1), 10),
('BOTTOMPADDING', (0,0), (-1,-1), 10),
('LEFTPADDING', (0,0), (-1,-1), 12),
('RIGHTPADDING', (0,0), (-1,-1), 12),
('BOX', (0,0), (-1,-1), 1, title_color),
('ROUNDEDCORNERS', [5, 5, 5, 5]),
]))
return t
def make_disease_table(headers, rows):
"""Create a styled table for disease info."""
data = [headers] + rows
col_count = len(headers)
col_width = 165*mm / col_count
t = Table(data, colWidths=[col_width]*col_count, repeatRows=1)
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), COLOR_SECTION_BG),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 11),
('ALIGN', (0,0), (-1,-1), 'LEFT'),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,1), (-1,-1), 10),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#EBF5FB")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
]))
return t
def build_pdf():
doc = SimpleDocTemplate(
OUTPUT_PATH,
pagesize=A4,
rightMargin=20*mm,
leftMargin=20*mm,
topMargin=20*mm,
bottomMargin=20*mm,
title="ECG Padhna Sikhao - Hinglish Guide",
author="Orris Medical AI"
)
story = []
page_w = A4[0] - 40*mm # usable width
# ═══════════════════════════════════════════════════════════
# COVER PAGE
# ═══════════════════════════════════════════════════════════
cover_data = [[
Paragraph("❤️ ECG Padhna Sikhao", title_style),
Paragraph("Complete Hinglish Guide with Images", subtitle_style),
Paragraph("━━━━━━━━━━━━━━━━━━━━━━━━━", ParagraphStyle('Sep', parent=styles['Normal'],
fontSize=12, textColor=HexColor("#E8DAEF"), alignment=TA_CENTER)),
Paragraph("Dil ki Bimariyon ka ECG Diagnosis", subtitle_style),
Paragraph("Harrison's • Braunwald's • Goldman-Cecil • Guyton & Hall", ParagraphStyle('Sources',
parent=styles['Normal'], fontSize=10, textColor=HexColor("#D0D3D4"),
alignment=TA_CENTER, spaceAfter=4)),
]]
cover_table = Table([[
[
Paragraph("❤ ECG PADHNA SIKHAO", title_style),
Spacer(1, 4),
Paragraph("Complete Hinglish Guide with Images", subtitle_style),
Spacer(1, 6),
Paragraph("──── Dil ki Bimariyon ka ECG Diagnosis ────", ParagraphStyle('Sep', parent=styles['Normal'],
fontSize=12, textColor=HexColor("#E8DAEF"), alignment=TA_CENTER)),
Spacer(1, 8),
Paragraph("Harrison's Principles | Braunwald's Heart Disease | Guyton & Hall", ParagraphStyle('Sources',
parent=styles['Normal'], fontSize=10, textColor=HexColor("#D0D3D4"), alignment=TA_CENTER)),
Spacer(1, 4),
Paragraph("Goldman-Cecil Medicine | Roberts & Hedges Emergency Medicine", ParagraphStyle('Sources2',
parent=styles['Normal'], fontSize=10, textColor=HexColor("#D0D3D4"), alignment=TA_CENTER)),
]
]], colWidths=[170*mm])
cover_table.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), COLOR_TITLE_BG),
('TOPPADDING', (0,0), (-1,-1), 30),
('BOTTOMPADDING', (0,0), (-1,-1), 30),
('LEFTPADDING', (0,0), (-1,-1), 20),
('RIGHTPADDING', (0,0), (-1,-1), 20),
]))
story.append(cover_table)
story.append(Spacer(1, 12))
# Quick intro
story.append(Paragraph(
"Yeh guide aapko ECG (Electrocardiogram) padhna sikhayegi - bilkul basic se lekar "
"important bimariyon tak. Har topic Hinglish mein explain kiya gaya hai taaki aasan samajh aa sake. "
"Real textbook images ke saath har disease ka ECG pattern dikhaya gaya hai.",
body_style
))
story.append(Spacer(1, 8))
# Table of Contents
toc_data = [
[Paragraph("<b>Chapter</b>", ParagraphStyle('TH', parent=styles['Normal'], fontSize=11,
textColor=white, fontName='Helvetica-Bold')),
Paragraph("<b>Topic</b>", ParagraphStyle('TH', parent=styles['Normal'], fontSize=11,
textColor=white, fontName='Helvetica-Bold'))],
["1", "ECG Kya Hota Hai? (Basics)"],
["2", "ECG Lead Kya Hote Hain?"],
["3", "Normal ECG Waves - P, QRS, T"],
["4", "Intervals aur Duration"],
["5", "Axis Deviation"],
["6", "Myocardial Infarction (Heart Attack)"],
["7", "Arrhythmias (Irregular Heartbeat)"],
["8", "Heart Block"],
["9", "Hypertrophy (LVH / RVH)"],
["10", "Electrolyte Abnormalities"],
["11", "Pericarditis aur Other Conditions"],
["12", "Quick Reference Summary"],
]
toc_table = Table(toc_data, colWidths=[15*mm, 155*mm])
toc_table.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), COLOR_SECTION_BG),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,1), (-1,-1), 11),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#FDFEFE")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 8),
('ALIGN', (0,0), (0,-1), 'CENTER'),
('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'),
('TEXTCOLOR', (0,1), (0,-1), COLOR_SUBSECTION_BG),
]))
story.append(toc_table)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════
# CHAPTER 1: ECG KYA HOTA HAI
# ═══════════════════════════════════════════════════════════
story.append(make_section_header("Chapter 1: ECG Kya Hota Hai? (Basics)"))
story.append(Spacer(1, 8))
story.append(Paragraph("ECG ki Definition", subsection_style))
story.append(Paragraph(
"ECG (Electrocardiogram) ek aisa test hai jo <b>dil ki electrical activity</b> ko record karta hai. "
"Jab dil dhakdhakta hai, toh cells mein electrical impulse hota hai. "
"Skin pe electrodes (sticker jaise) lagakar is electricity ko record kiya jata hai - "
"yahi ECG paper pe lines ki tarah dikhta hai.",
body_style
))
story.append(make_info_box(
"ECG Kyun Karte Hain? (Indications)",
[
"Chest pain ya angina ka evaluation",
"Heart attack (Myocardial Infarction) diagnose karna",
"Irregular heartbeat (Arrhythmia) dhundhna",
"Heart ka size aur structure assess karna",
"Electrolyte abnormalities (K+, Ca2+) dekhna",
"Pacemaker function check karna",
"Drug toxicity evaluate karna (Digoxin, antiarrhythmics)"
],
COLOR_BLUE_BOX, HexColor("#1A5276")
))
story.append(Spacer(1, 8))
story.append(Paragraph("ECG Paper ko Samajhna", subsection_style))
story.append(Paragraph(
"ECG paper ek grid hota hai jisme:",
body_style
))
grid_data = [
[Paragraph("<b>Measurement</b>", important_style),
Paragraph("<b>Horizontal (Time)</b>", important_style),
Paragraph("<b>Vertical (Voltage)</b>", important_style)],
["Small box (1mm)", "0.04 second (40 ms)", "0.1 mV"],
["Large box (5mm)", "0.20 second (200 ms)", "0.5 mV"],
["Standard speed", "25 mm/second", "1 mV = 10 mm"],
]
g_table = Table(grid_data, colWidths=[55*mm, 55*mm, 55*mm])
g_table.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), COLOR_SUBSECTION_BG),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 10),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#FADBD8")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 8),
('ALIGN', (0,0), (-1,-1), 'CENTER'),
]))
story.append(g_table)
story.append(Spacer(1, 8))
story.append(Paragraph(
"<b>Heart Rate Calculate karna (Simple Method):</b><br/>"
"300 ko bade boxes se divide karo jo 2 R waves ke beech hain.<br/>"
"Example: Agar 2 R waves ke beech 4 bade boxes hain = 300/4 = 75 bpm (Normal!)",
body_style
))
story.append(Spacer(1, 6))
# Cardiac conduction image
story.append(Paragraph("Cardiac Conduction System (Dil ka Bijli System)", subsection_style))
story.append(Paragraph(
"Dil mein ek special electrical pathway hota hai jo heartbeat control karta hai:",
body_style
))
img = fetch_image(
"https://cdn.orris.care/cdss_images/f5e3a879ca5dbed1bd501f4ceb433f4c9e1149de357262283320008cbac3f3f0.png",
max_width=130*mm, max_height=90*mm
)
if img:
story.append(img)
story.append(Paragraph(
"Cardiac Conduction System: SA Node → AV Node → Bundle of His → Left/Right Bundle Branches → Purkinje Fibers\n"
"(Source: Harrison's Principles of Internal Medicine, 22nd Ed.)",
caption_style
))
story.append(make_info_box(
"Conduction System ka ECG se Relation",
[
"SA Node (Sinoatrial) → P wave banata hai (atrial depolarization)",
"AV Node → PR interval mein delay hota hai (0.12-0.20 sec)",
"Bundle of His + Bundle Branches → QRS complex banata hai",
"Purkinje Fibers → Rapid ventricular conduction",
"T wave → Ventricular repolarization (heart recover karta hai)"
],
COLOR_GREEN_BOX, HexColor("#1D6A39")
))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════
# CHAPTER 2: ECG LEADS
# ═══════════════════════════════════════════════════════════
story.append(make_section_header("Chapter 2: ECG Leads Kya Hote Hain?"))
story.append(Spacer(1, 8))
story.append(Paragraph(
"12-lead ECG mein <b>12 alag-alag angles</b> se dil ko dekha jata hai - "
"jaise 12 cameras ek hi cheez ko alag directions se dekh rahi hoon. "
"Har lead ek alag view deta hai.",
body_style
))
story.append(Paragraph("Limb Leads (6 leads)", subsection_style))
limb_data = [
[Paragraph("<b>Lead</b>", important_style),
Paragraph("<b>Kya Dekha Jata Hai</b>", important_style),
Paragraph("<b>Normal Direction</b>", important_style)],
["Lead I", "Left side of heart", "Positive (upright)"],
["Lead II", "Inferior wall (sabse useful)", "Positive - best for P waves"],
["Lead III", "Inferior-right", "Variable"],
["aVR", "Right side from above", "Negative (inverted - normal!)"],
["aVL", "Left lateral high", "Small positive/negative"],
["aVF", "Inferior wall (feet)", "Positive"],
]
lt = Table(limb_data, colWidths=[25*mm, 80*mm, 60*mm])
lt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#1A5276")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 10),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#D6EAF8")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 8),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
]))
story.append(lt)
story.append(Spacer(1, 8))
story.append(Paragraph("Precordial (Chest) Leads (V1-V6)", subsection_style))
prec_data = [
[Paragraph("<b>Lead</b>", important_style),
Paragraph("<b>Position</b>", important_style),
Paragraph("<b>Kya Dekha Jata Hai</b>", important_style)],
["V1", "4th ICS, Right sternal border", "Right ventricle, Septal"],
["V2", "4th ICS, Left sternal border", "Septal / Anterior"],
["V3", "V2 aur V4 ke beech", "Anterior wall"],
["V4", "5th ICS, Midclavicular line", "Anterior wall"],
["V5", "Anterior axillary line", "Lateral wall"],
["V6", "Midaxillary line", "Lateral wall"],
]
pt = Table(prec_data, colWidths=[20*mm, 70*mm, 75*mm])
pt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#117A65")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 10),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#D5F5E3")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 8),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
]))
story.append(pt)
story.append(Spacer(1, 8))
# Chest lead placement image
img2 = fetch_image(
"https://cdn.orris.care/cdss_images/0a05159c6486e4e7ef48c4eb4c818c6727aa974175b9a8ad2c9d5531b49c5e5f.png",
max_width=110*mm, max_height=80*mm
)
if img2:
story.append(img2)
story.append(Paragraph(
"Precordial Lead Placement (V1-V6) - Chest pe electrode positions\n"
"(Source: Harrison's Principles of Internal Medicine, 22nd Ed.)",
caption_style
))
story.append(make_info_box(
"Leads ke Groups - Kon sa Lead Kahan Dekha Jata Hai",
[
"INFERIOR wall (niche ka hissa): Leads II, III, aVF - RCA se blood supply",
"ANTERIOR wall (aage ka hissa): V1-V4 - LAD se blood supply",
"LATERAL wall (side ka hissa): I, aVL, V5, V6 - LCX se blood supply",
"SEPTAL: V1, V2",
"POSTERIOR wall: Reciprocal changes V1-V3 mein (tall R, ST depression)"
],
COLOR_YELLOW_BOX, HexColor("#784212")
))
# Hexaxial diagram
img3 = fetch_image(
"https://cdn.orris.care/cdss_images/e6aca8885a0321111d802711d351d683adeb91964ab8665633967ee4fa4fdaa0.png",
max_width=110*mm, max_height=90*mm
)
if img3:
story.append(img3)
story.append(Paragraph(
"Hexaxial Diagram - Frontal plane leads ka orientation\n"
"(Source: Harrison's Principles of Internal Medicine, 22nd Ed.)",
caption_style
))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════
# CHAPTER 3: NORMAL ECG WAVES
# ═══════════════════════════════════════════════════════════
story.append(make_section_header("Chapter 3: Normal ECG Waves - P, QRS, T, U"))
story.append(Spacer(1, 8))
# Basic ECG waveform image
img4 = fetch_image(
"https://cdn.orris.care/cdss_images/d10fea83a9eb1cedfe9f47e0134dbd583444784d9cb2fbb3a373acfe18d879c7.png",
max_width=140*mm, max_height=85*mm
)
if img4:
story.append(img4)
story.append(Paragraph(
"Normal ECG waveforms: P wave, QRS complex, ST segment, T wave, U wave ke saath intervals\n"
"(Source: Harrison's Principles of Internal Medicine, 22nd Ed.)",
caption_style
))
waves_data = [
[Paragraph("<b>Wave/Segment</b>", important_style),
Paragraph("<b>Kya Represent Karta Hai</b>", important_style),
Paragraph("<b>Normal Values</b>", important_style),
Paragraph("<b>Yaad Karne ka Trick</b>", important_style)],
["P Wave", "Atrial depolarization\n(Atria ka contract hona)",
"Duration: <0.12 sec\nAmplitude: <2.5mm\nPositive in II, negative in aVR",
'"P = Pump kiya Atria ne"'],
["PR Interval", "AV node se conduction time\n(signal ka wait karna)",
"0.12 - 0.20 sec (3-5 small boxes)",
'"PR = Please Relay karo thoda wait karke"'],
["QRS Complex", "Ventricular depolarization\n(Ventricles ka contract hona)",
"Duration: <0.10-0.11 sec\nQ wave: <0.04 sec, <25% R",
'"QRS = Quite Rapid Squeeze"'],
["ST Segment", "Ventricular plateau phase\n(before repolarization)",
"Isoelectric (flat)\n±1mm normal",
'"ST = Still Time (dil rest kar raha hai)"'],
["T Wave", "Ventricular repolarization\n(dil relax karna)",
"Upright in I, II, V3-V6\nInverted in aVR normal",
'"T = Time to Relax"'],
["QT Interval", "Total ventricular activity",
"Males: <450ms\nFemales: <460ms\nQTc = QT/√RR",
'"QT = Quit Time for ventricles"'],
["U Wave", "Late ventricular repolarization\n(Purkinje fibers)",
"Small, follows T wave\nPronounced in hypokalemia",
'"U = Unusual wave (hypokalemia mein bada)"'],
]
wt = Table(waves_data, colWidths=[28*mm, 45*mm, 50*mm, 42*mm])
wt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), COLOR_SECTION_BG),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#FADBD8")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(wt)
story.append(Spacer(1, 10))
# Ventricular depolarization phases image
img5 = fetch_image(
"https://cdn.orris.care/cdss_images/3c19bed4b7dc721d6ff1f4789647829faec7c81d9446dec3cbcae6679dff7575.png",
max_width=130*mm, max_height=85*mm
)
if img5:
story.append(img5)
story.append(Paragraph(
"Ventricular depolarization ke do major phases - Vector 1 (septal) aur Vector 2 (LV dominant)\n"
"(Source: Harrison's Principles of Internal Medicine, 22nd Ed.)",
caption_style
))
story.append(make_info_box(
"Normal ECG - Kya Normal Hai Yeh Yaad Rakho",
[
"Heart Rate: 60-100 beats/minute (tachy = >100, brady = <60)",
"P wave: Upright in lead II, inverted in aVR - HAMESHA",
"PR interval: 0.12-0.20 second (< 3 boxes = short, > 5 boxes = prolonged)",
"QRS: <0.12 second. Wider QRS = bundle branch block ya ectopic beat",
"T wave: Upright mein V3-V6, I, II - inverted hoga toh ischemia sochna",
"QTc: <450ms men, <460ms women - lamba hoga toh torsades risk",
"Normal sinus rhythm: P before every QRS, regular intervals"
],
COLOR_GREEN_BOX, HexColor("#1D6A39")
))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════
# CHAPTER 4: INTERVALS AUR AXIS
# ═══════════════════════════════════════════════════════════
story.append(make_section_header("Chapter 4: Intervals aur Electrical Axis"))
story.append(Spacer(1, 8))
story.append(Paragraph("PR Interval Abnormalities", subsection_style))
pr_data = [
[Paragraph("<b>Finding</b>", important_style),
Paragraph("<b>Value</b>", important_style),
Paragraph("<b>Matlab</b>", important_style)],
["Short PR (<0.12 sec)", "<3 small boxes", "WPW syndrome, LGL syndrome, AV junctional rhythm"],
["Normal PR", "0.12-0.20 sec", "Normal conduction"],
["Long PR (>0.20 sec)", ">5 small boxes", "1st degree AV block (common, usually benign)"],
]
story.append(Table(pr_data, colWidths=[50*mm, 35*mm, 80*mm], style=TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#6C3483")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 10),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#F5EEF8")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 8),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
])))
story.append(Spacer(1, 8))
story.append(Paragraph("QRS Axis (Electrical Axis)", subsection_style))
story.append(Paragraph(
"Electrical axis batata hai ki dil ki <b>electrical force kis direction mein ja rahi hai</b>. "
"Simplest method: Lead I aur aVF dekhna.",
body_style
))
axis_data = [
[Paragraph("<b>Lead I</b>", important_style),
Paragraph("<b>Lead aVF</b>", important_style),
Paragraph("<b>Axis</b>", important_style),
Paragraph("<b>Normal Hai?</b>", important_style),
Paragraph("<b>Cause</b>", important_style)],
["Positive (+)", "Positive (+)", "Normal (-30° to +90°)", "✓ YES", "Normal"],
["Positive (+)", "Negative (-)", "Left Axis Deviation (LAD)", "Depends (<-30° abnormal)", "LBBB, Left anterior fascicular block, Inferior MI"],
["Negative (-)", "Positive (+)", "Right Axis Deviation (RAD)", "Abnormal if >+110°", "RVH, RBBB, Lateral MI, PE"],
["Negative (-)", "Negative (-)", "Extreme/Indeterminate", "✗ Abnormal", "VT, severe disease"],
]
at = Table(axis_data, colWidths=[28*mm, 28*mm, 38*mm, 28*mm, 43*mm])
at.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#1A5276")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#D6EAF8")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
]))
story.append(at)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════
# CHAPTER 5: MYOCARDIAL INFARCTION
# ═══════════════════════════════════════════════════════════
story.append(make_section_header("Chapter 5: Myocardial Infarction (Heart Attack)"))
story.append(Spacer(1, 8))
story.append(Paragraph(
"MI (Heart Attack) tab hota hai jab <b>coronary artery block ho jaati hai</b> aur dil ke ek hisse ko "
"blood nahi milta. ECG mein 3 classic changes hote hain jinhein yaad rakhna zaroori hai.",
body_style
))
story.append(make_info_box(
"MI ke 3 Classic ECG Changes (Infarction Triad)",
[
"1. HYPERACUTE T WAVES → Pehle tall, peaked T waves aate hain (minutes mein)",
"2. ST ELEVATION (STEMI) → Convex 'tombstone' ST elevation - EMERGENCY!",
"3. Q WAVES → Pathological Q waves develop hote hain (hours to days mein) - permanent damage",
"STEMI = ST elevation MI = Emergency cardiac catheterization chahiye",
"NSTEMI = No ST elevation but troponin raised = subendocardial ischemia"
],
COLOR_BOX_BG, HexColor("#922B21")
))
story.append(Spacer(1, 8))
# ST elevation/depression image
img6 = fetch_image(
"https://cdn.orris.care/cdss_images/90b2a4e8d4bfd20d740aafeb6a9a46d5110b4355298ab357e1f13d6592fccdef.png",
max_width=130*mm, max_height=85*mm
)
# Try alternative URL
img6 = fetch_image(
"https://cdn.orris.care/cdss_images/90b2a4e8d4bfd20d740aafeb6a9a46d5110b4355298ab357e1f13d6592fccdef.png",
max_width=130*mm, max_height=85*mm
)
img6b = fetch_image(
"https://cdn.orris.care/cdss_images/90b2a4e8d8bfd20d740aafeb6a9a46d5110b4355298ab357e1f13d6592fccdef.png",
max_width=130*mm, max_height=80*mm
)
if img6b:
story.append(img6b)
story.append(Paragraph(
"ST Vector aur Ischemia: A) Subendocardial ischemia = ST depression; B) Transmural/Epicardial ischemia = ST elevation\n"
"(Source: Harrison's Principles of Internal Medicine, 22nd Ed.)",
caption_style
))
# Wellens T wave image
img7 = fetch_image(
"https://cdn.orris.care/cdss_images/f3e984a53a0a64a9ac96e6035acfa4f3e60f0b0b4f43f8a50327252b01f9f891.png",
max_width=130*mm, max_height=75*mm
)
if img7:
story.append(img7)
story.append(Paragraph(
"Wellens T wave sign: Deep T wave inversions V1-V4 = LAD artery ki high-grade stenosis ki warning!\n"
"(Source: Harrison's Principles of Internal Medicine, 22nd Ed.)",
caption_style
))
story.append(Paragraph("MI Location aur ECG Leads", subsection_style))
mi_loc_data = [
[Paragraph("<b>MI Location</b>", important_style),
Paragraph("<b>Leads mein Changes</b>", important_style),
Paragraph("<b>Coronary Artery</b>", important_style),
Paragraph("<b>Reciprocal Changes</b>", important_style)],
["Anterior", "V1-V4", "LAD (Left Anterior Descending)", "III, aVF mein ST depression"],
["Inferior", "II, III, aVF", "RCA (Right Coronary Artery)", "I, aVL mein ST depression"],
["Lateral", "I, aVL, V5, V6", "LCX (Left Circumflex)", "V1-V3 mein"],
["Posterior", "V1-V2 mein tall R + ST depression", "RCA/LCX", "V7-V9 mein ST elevation"],
["Septal", "V1, V2", "Septal branches of LAD", "V5, V6"],
["RV Infarct", "V3R-V4R mein ST elevation + inferior MI", "Proximal RCA", "---"],
]
mi_t = Table(mi_loc_data, colWidths=[30*mm, 42*mm, 50*mm, 43*mm])
mi_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), COLOR_SUBSECTION_BG),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#FADBD8")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
]))
story.append(mi_t)
story.append(Spacer(1, 8))
story.append(Paragraph("MI ke Stages (Time ke saath Changes)", subsection_style))
story.append(Paragraph(
"Heart attack mein ECG pe changes time ke saath evolve karte hain:",
body_style
))
mi_stages = [
[Paragraph("<b>Stage</b>", important_style),
Paragraph("<b>Time</b>", important_style),
Paragraph("<b>ECG Changes</b>", important_style),
Paragraph("<b>Meaning</b>", important_style)],
["Hyperacute", "Minutes", "Tall peaked T waves", "Fresh ischemia - reverse ho sakta hai"],
["Acute STEMI", "Hours", "ST elevation, Q waves start", "Active infarction - EMERGENCY!"],
["Evolving", "6-24 hours", "ST elevation persist, deep Q waves, T inversion starts", "Ongoing damage"],
["Subacute", "Days-weeks", "Q waves persist, ST normalizes, T inverted", "Established MI"],
["Old MI", "Months-years", "Q waves remain, T waves may normalize", "Scar tissue"],
]
ms_t = Table(mi_stages, colWidths=[30*mm, 30*mm, 60*mm, 45*mm])
ms_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#922B21")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#FADBD8")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
]))
story.append(ms_t)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════
# CHAPTER 6: ARRHYTHMIAS
# ═══════════════════════════════════════════════════════════
story.append(make_section_header("Chapter 6: Arrhythmias (Irregular Heartbeat)"))
story.append(Spacer(1, 8))
story.append(Paragraph(
"Arrhythmia matlab dil ki abnormal rhythm. Yeh ho sakti hai: Too fast (tachycardia), "
"too slow (bradycardia), ya irregular. ECG se exact type pata chalta hai.",
body_style
))
story.append(Paragraph("Bradyarrhythmias (Slow Rhythms - <60 bpm)", subsection_style))
brady_data = [
[Paragraph("<b>Condition</b>", important_style),
Paragraph("<b>ECG Pattern</b>", important_style),
Paragraph("<b>Cause</b>", important_style)],
["Sinus Bradycardia", "Normal P-QRS pattern, rate <60 bpm", "Athletes, vagal tone, hypothyroidism, beta-blockers"],
["1st Degree AV Block", "PR interval >0.20 sec, all P waves conduct", "Usually benign, AV nodal disease"],
["2nd Degree AV Block\n(Mobitz I / Wenckebach)", "PR gradually lengthens then P wave drops (non-conducted)\nCyclic pattern", "AV nodal disease, inferior MI, digitalis"],
["2nd Degree AV Block\n(Mobitz II)", "Fixed PR interval, sudden P wave non-conducted\nMore dangerous!", "His-Purkinje disease, anterior MI\nCan progress to complete block"],
["3rd Degree / Complete\nAV Block", "P waves aur QRS completely dissociated\nAtria ka rate > Ventricle ka rate\nEscape rhythm (wide QRS ~40 bpm)", "Serious - needs pacemaker\nHypothermia, MI, Lyme disease"],
["Sinus Node Dysfunction\n(Sick Sinus Syndrome)", "Sinus pauses, brady-tachy syndrome\nEscape rhythms", "Elderly, ischemia, post-surgical"],
]
brady_t = Table(brady_data, colWidths=[40*mm, 65*mm, 60*mm])
brady_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#1A5276")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#D6EAF8")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(brady_t)
story.append(Spacer(1, 8))
story.append(Paragraph("Supraventricular Tachycardias (SVT - Fast Rhythms Above Ventricles)", subsection_style))
svt_data = [
[Paragraph("<b>Arrhythmia</b>", important_style),
Paragraph("<b>Rate</b>", important_style),
Paragraph("<b>ECG Pattern</b>", important_style),
Paragraph("<b>Key Points</b>", important_style)],
["Sinus Tachycardia", "100-180", "Normal P wave, QRS normal, gradual onset/offset", "Fever, pain, anemia, PE, etc. ki wajah se"],
["AVNRT (Common SVT)", "150-250", "Narrow QRS, P wave in QRS ya just after\nSudden start/stop", "Most common SVT, young females\nVagal maneuvers se convert"],
["Atrial Flutter", "Atrial 300, Ventricular 150 (2:1 block)", "Saw-tooth flutter waves (F waves) in II, III, aVF\nRegular or irregularly regular", "Carotid massage se reveal flutter waves\nAnticoagulation needed"],
["Atrial Fibrillation (AF)", "Atrial >350, Ventricular 100-180", "IRREGULARLY IRREGULAR rhythm\nNo distinct P waves, fibrillatory baseline\nNarrow QRS (unless aberrant)", "Most common sustained arrhythmia\nStroke risk! Anticoagulate\nRate vs rhythm control"],
["WPW (Wolff-Parkinson-White)", "Variable", "Short PR (<0.12s)\nDelta wave (slurred QRS onset)\nWide QRS", "Accessory pathway\nCan cause rapid AF - DANGEROUS\nNo AV nodal blockers in AF!"],
]
svt_t = Table(svt_data, colWidths=[35*mm, 20*mm, 60*mm, 50*mm])
svt_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#6C3483")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#F5EEF8")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (0,0), (-1,-1), 5),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(svt_t)
story.append(Spacer(1, 8))
story.append(Paragraph("Ventricular Arrhythmias (Khatarnak - Life-threatening)", subsection_style))
vt_data = [
[Paragraph("<b>Arrhythmia</b>", important_style),
Paragraph("<b>ECG Pattern</b>", important_style),
Paragraph("<b>Emergency?</b>", important_style),
Paragraph("<b>Treatment</b>", important_style)],
["PVC (Premature Ventricular Contraction)", "Wide QRS (>0.12s), no P before it\nCompensatory pause after\nT wave opposite to QRS", "Usually benign\n(unless frequent/run)", "Treat if symptomatic\nBeta-blockers"],
["Ventricular Tachycardia (VT)", "Wide QRS tachycardia (>100 bpm)\nAV dissociation present\nCapture/fusion beats\nRegular", "⚠️ YES - EMERGENCY\n(if sustained)", "Stable: Amiodarone, lidocaine\nUnstable: Cardioversion\nPulseless VT: DEFIBRILLATION"],
["Ventricular Fibrillation (VF)", "Chaotic, irregular oscillations\nNo organised QRS\nFlatline appearance", "🚨 CARDIAC ARREST", "IMMEDIATE DEFIBRILLATION\nCPR\nAdrenaline"],
["Torsades de Pointes", "Polymorphic VT\nQRS twists around isoelectric line\n'Twisting of points'", "⚠️ Can → VF", "Stop QT-prolonging drugs\nIV Magnesium sulfate\nOverdrive pacing"],
]
vt_t = Table(vt_data, colWidths=[38*mm, 55*mm, 30*mm, 42*mm])
vt_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#922B21")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#FADBD8")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (0,0), (-1,-1), 5),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(vt_t)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════
# CHAPTER 7: BUNDLE BRANCH BLOCKS
# ═══════════════════════════════════════════════════════════
story.append(make_section_header("Chapter 7: Bundle Branch Blocks (Heart Block)"))
story.append(Spacer(1, 8))
story.append(Paragraph(
"Jab bundle branches mein conduction abnormal ho jati hai, toh QRS wide ho jaata hai (>0.12 sec). "
"LBBB aur RBBB mein alag ECG patterns hote hain.",
body_style
))
bbb_data = [
[Paragraph("<b>Feature</b>", important_style),
Paragraph("<b>RBBB (Right BBB)</b>", important_style),
Paragraph("<b>LBBB (Left BBB)</b>", important_style)],
["QRS Duration", ">0.12 sec (3 small boxes)", ">0.12 sec (3 small boxes)"],
["V1 appearance", "RSR' pattern ('Rabbit ears' / 'M' shape)\nrSR' in V1", "Broad monophasic S wave\nWide notched QS or QR in V1"],
["V6 appearance", "Wide S wave", "Broad notched R wave ('M' shape)"],
["Lead I", "Small S wave", "Broad monophasic R, no S"],
["T wave", "T opposite to terminal QRS", "T opposite to QRS (discordant - NORMAL for LBBB)"],
["Causes", "Normal variant, RVH, PE (acute cor pulmonale), anterior MI", "Hypertension, LVH, anterior MI, dilated cardiomyopathy, aortic stenosis"],
["Significance", "Usually benign unless new\nNew RBBB in PE = important sign", "LBBB makes MI diagnosis DIFFICULT\nNew LBBB = Possible STEMI equivalent!"],
["Memory Trick", "WiLLiaM MaRRoW\nRight = MaRRoW → M in V1, W in V6", "WiLLiaM MaRRoW\nLeft = WiLLiaM → W in V1, M in V6"],
]
bbb_t = Table(bbb_data, colWidths=[40*mm, 63*mm, 62*mm])
bbb_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), COLOR_SECTION_BG),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9.5),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#EBF5FB")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(bbb_t)
story.append(Spacer(1, 10))
story.append(make_info_box(
"WiLLiaM MaRRoW Trick - BBB Yaad Karne Ka Sabse Easy Tarika!",
[
"W-I-L-L-I-A-M = LEFT BBB (LBBB):",
" → V1 mein W shape (QS), V6 mein M shape (RR')",
"M-A-R-R-O-W = RIGHT BBB (RBBB):",
" → V1 mein M shape (RSR'), V6 mein W shape (rS)",
"Example: WiLL → Will dekho V1 mein W chahiye = LBBB",
"Example: MaRR → Mar dekho V1 mein M chahiye = RBBB"
],
COLOR_YELLOW_BOX, HexColor("#784212")
))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════
# CHAPTER 8: HYPERTROPHY
# ═══════════════════════════════════════════════════════════
story.append(make_section_header("Chapter 8: Cardiac Hypertrophy (LVH aur RVH)"))
story.append(Spacer(1, 8))
story.append(Paragraph(
"Jab dil ka koi chamber bada ho jaata hai (hypertrophy), toh ECG pe "
"higher voltage aur characteristic changes aate hain.",
body_style
))
story.append(Paragraph("Left Ventricular Hypertrophy (LVH)", subsection_style))
story.append(make_info_box(
"LVH ke ECG Criteria (Sokolow-Lyon most common)",
[
"S in V1 + R in V5 or V6 > 35mm (Sokolow-Lyon) - Most used!",
"R in aVL > 11mm",
"R in lead I > 13mm",
"R in I + S in III > 25mm",
"Cornell voltage: R in aVL + S in V3 > 28mm (men), >20mm (women)",
"Strain pattern: Downsloping ST depression + T wave inversion in V5-V6, I, aVL",
"Left axis deviation common",
"Causes: HTN (most common!), aortic stenosis, HCM, aortic regurgitation"
],
COLOR_BOX_BG, HexColor("#922B21")
))
story.append(Spacer(1, 8))
story.append(Paragraph("Right Ventricular Hypertrophy (RVH)", subsection_style))
story.append(make_info_box(
"RVH ke ECG Features",
[
"Right Axis Deviation (RAD) > +100° - must have!",
"R wave > S wave in V1 (dominant R in V1)",
"R/S ratio in V1 > 1",
"S wave persistence in V5, V6 (S1S2S3 pattern)",
"P pulmonale: Tall peaked P waves >2.5mm in II, III, aVF (right atrial enlargement)",
"ST depression + T wave inversion in V1-V3 (RV strain pattern)",
"Causes: Pulmonary HTN, COPD, pulmonary stenosis, mitral stenosis, PE (acute RVH)"
],
COLOR_BLUE_BOX, HexColor("#1A5276")
))
story.append(Spacer(1, 8))
story.append(Paragraph("Atrial Enlargement", subsection_style))
atrial_data = [
[Paragraph("<b>Finding</b>", important_style),
Paragraph("<b>Left Atrial Enlargement (P mitrale)</b>", important_style),
Paragraph("<b>Right Atrial Enlargement (P pulmonale)</b>", important_style)],
["P wave shape", "Bifid P wave ('M' shape)\nDuration >0.12 sec", "Tall, peaked P wave\nAmplitude >2.5mm"],
["Best seen in", "Lead II, V1 (deep negative component)", "Lead II, III, aVF"],
["V1 pattern", "Biphasic P: positive then deep negative (>1mm x 1mm)", "Tall peaked P wave"],
["Causes", "Mitral stenosis, LV failure, AF", "Pulmonary HTN, tricuspid stenosis, COPD"],
]
at_t = Table(atrial_data, colWidths=[35*mm, 65*mm, 65*mm])
at_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#117A65")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 10),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#D5F5E3")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(at_t)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════
# CHAPTER 9: ELECTROLYTES
# ═══════════════════════════════════════════════════════════
story.append(make_section_header("Chapter 9: Electrolyte Abnormalities"))
story.append(Spacer(1, 8))
story.append(Paragraph(
"Electrolyte imbalances dil ki electricity ko directly affect karti hain aur characteristic ECG changes deti hain. "
"Yeh changes jaan-levu (life-threatening) ho sakte hain.",
body_style
))
electro_data = [
[Paragraph("<b>Electrolyte</b>", important_style),
Paragraph("<b>Abnormality</b>", important_style),
Paragraph("<b>ECG Changes</b>", important_style),
Paragraph("<b>Emergency?</b>", important_style)],
["Potassium (K+)", "HYPOKALEMIA\n(Low K+, <3.5)",
"1. Flat/inverted T waves\n2. Prominent U waves (>T wave)\n3. ST depression\n4. Prolonged QU interval\n5. Severe: VF risk!",
"⚠️ Yes if <2.5"],
["Potassium (K+)", "HYPERKALEMIA\n(High K+, >5.5)",
"1. Peaked/tall T waves (FIRST sign - 'tented' T)\n2. PR prolongation\n3. P wave flattening/disappears\n4. Wide QRS (sine wave)\n5. VF/Asystole → DEATH",
"🚨 >6.5 = EMERGENCY\nECG is more important than lab"],
["Calcium (Ca2+)", "HYPOCALCEMIA\n(Low Ca2+)",
"1. Prolonged QT interval (ST lengthening)\n2. Prolonged ST segment\n3. T wave normal\n4. Risk of Torsades de Pointes",
"⚠️ Yes if symptomatic"],
["Calcium (Ca2+)", "HYPERCALCEMIA\n(High Ca2+)",
"1. Short QT interval\n2. Short ST segment\n3. J waves sometimes\n4. PR prolongation",
"Moderate risk"],
["Magnesium (Mg2+)", "HYPOMAGNESEMIA",
"Similar to hypokalemia:\n1. U waves prominent\n2. QT prolongation\n3. T wave flattening\n4. Torsades de Pointes",
"⚠️ Yes - Treat with\nIV Magnesium"],
["Sodium (Na+)", "HYPO/HYPERNATREMIA",
"Usually minimal direct ECG changes\nSevere hyponatremia: non-specific\nST-T changes",
"Usually indirect effects only"],
]
e_t = Table(electro_data, colWidths=[30*mm, 35*mm, 65*mm, 35*mm])
e_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#784212")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#FDEBD0")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(e_t)
story.append(Spacer(1, 10))
story.append(make_info_box(
"Hyperkalemia ECG Changes Yaad Karne Ka Trick (Mild to Severe)",
[
"T - Tall (Peaked) T waves (K+ >5.5)",
"E - ECG shows PR prolongation (K+ >6.0)",
"N - No P wave visible (K+ >7.0)",
"T - Terminal: Wide QRS, sine wave (K+ >7.5-8.0)",
"E - End stage: VF / Asystole (K+ >8-9)",
"TENTED T → P disappears → QRS widens → SINE WAVE → DEATH",
"Treatment: Calcium gluconate (stabilize membrane), Insulin+glucose, Sodium bicarbonate, Dialysis"
],
COLOR_YELLOW_BOX, HexColor("#922B21")
))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════
# CHAPTER 10: OTHER CONDITIONS
# ═══════════════════════════════════════════════════════════
story.append(make_section_header("Chapter 10: Other Important ECG Conditions"))
story.append(Spacer(1, 8))
story.append(Paragraph("Pericarditis", subsection_style))
story.append(make_info_box(
"Pericarditis ki ECG Features (4 Stages)",
[
"Stage 1 (Acute): Diffuse saddle-shaped (concave) ST elevation in MULTIPLE leads\n PR DEPRESSION (hallmark!) - most important sign\n No reciprocal changes (unlike MI)",
"Stage 2 (Days): ST normalizes, PR still depressed",
"Stage 3: T wave inversions (diffuse)",
"Stage 4 (Weeks): ECG normalizes",
"KEY: Pericarditis = DIFFUSE ST elevation + PR depression (not focal like MI)",
"aVR = ST DEPRESSION + PR ELEVATION (reciprocal - opposite to rest)"
],
COLOR_BOX_BG, HexColor("#7D6608")
))
story.append(Spacer(1, 8))
story.append(Paragraph("Pulmonary Embolism (PE)", subsection_style))
story.append(make_info_box(
"PE ke ECG Features (S1Q3T3)",
[
"SINUS TACHYCARDIA - sabse common ECG finding in PE",
"S1Q3T3 pattern (classic but uncommon):",
" S1: Large S wave in Lead I",
" Q3: Q wave in Lead III",
" T3: T wave inversion in Lead III",
"RBBB (complete ya incomplete) - right heart strain",
"Right axis deviation",
"P pulmonale (right atrial enlargement)",
"ST changes, T inversions in V1-V4",
"Remember: ECG normal nahi hota necessarily - just non-specific changes"
],
COLOR_BLUE_BOX, HexColor("#1A5276")
))
story.append(Spacer(1, 8))
story.append(Paragraph("Hypothermia", subsection_style))
story.append(make_info_box(
"Hypothermia ki Classic ECG Sign - Osborn (J) Wave",
[
"J wave (Osborn wave): Positive deflection at J point (junction of QRS and ST segment)",
"Best seen in V4-V6 and inferior leads",
"Size of J wave is inversely proportional to temperature (thanda = bada wave)",
"Associated: Bradycardia, prolonged PR/QRS/QT, shivering artifact",
"Arrhythmias: AF, VF common in severe hypothermia",
"Treatment: Rewarm slowly - VF can occur during rewarming"
],
COLOR_GREEN_BOX, HexColor("#1D6A39")
))
story.append(Spacer(1, 8))
story.append(Paragraph("Digoxin (Digitalis) Effect", subsection_style))
story.append(make_info_box(
"Digoxin ECG Effects",
[
"THERAPEUTIC level (normal effect): 'Salvador Dali moustache' = Scooped downsloping ST depression",
"Inverted T waves, short QT interval",
"PR prolongation (AV nodal slowing)",
"TOXICITY (dangerous level):",
" Bradyarrhythmias: Sinus bradycardia, AV blocks",
" Tachyarrhythmias: PVCs (most common), bigeminy, trigeminy",
" Bidirectional VT = CLASSIC digoxin toxicity sign",
" Paroxysmal atrial tachycardia with block = Digoxin toxicity until proven otherwise"
],
COLOR_YELLOW_BOX, HexColor("#784212")
))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════
# CHAPTER 11: QUICK REFERENCE SUMMARY
# ═══════════════════════════════════════════════════════════
story.append(make_section_header("Chapter 11: Quick Reference - ECG Padhne ka Step-by-Step Method"))
story.append(Spacer(1, 8))
story.append(Paragraph(
"Har ECG ko systematically padhna chahiye - kabhi bhi randomly mat dekho. "
"Yeh <b>7-step method</b> follow karo:",
body_style
))
steps_data = [
[Paragraph("<b>Step</b>", important_style),
Paragraph("<b>Kya Dekho</b>", important_style),
Paragraph("<b>Normal Values / Key Points</b>", important_style)],
["STEP 1\nRate", "Count heart rate", "300 / big boxes between R waves\nNormal: 60-100 bpm\nTachy: >100 | Brady: <60"],
["STEP 2\nRhythm", "Regular hai? P wave har QRS ke pehle hai?", "Regular = Normal sinus\nIrregular = AF, ectopics, AV blocks\nP aur QRS ka relation check karo"],
["STEP 3\nAxis", "Lead I aur aVF dekho", "+/+ = Normal\n+/- = LAD\n-/+ = RAD\n-/- = Extreme"],
["STEP 4\nP Wave", "Shape, size, PR interval", "P: <0.12s, <2.5mm, upright in II\nPR: 0.12-0.20 sec\nAbnormal P = Atrial pathology"],
["STEP 5\nQRS", "Width, morphology, Q waves", "Normal: <0.12 sec\nWide: BBB, VT, WPW, hyperkalemia\nPathological Q: ≥0.04s, ≥25% R (old MI)"],
["STEP 6\nST Segment + T Wave", "Elevation, depression, T shape", "ST flat at baseline\nElevation: MI (convex), pericarditis (concave)\nDepression: Ischemia, strain, digoxin\nT inversion: Ischemia, strain, BBB"],
["STEP 7\nQT Interval", "Measure QT, calculate QTc", "QTc = QT / √RR (in seconds)\nMen: <450ms | Women: <460ms\nLong QT: TdP risk"],
]
steps_t = Table(steps_data, colWidths=[20*mm, 55*mm, 90*mm])
steps_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), COLOR_SECTION_BG),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9.5),
('ROWBACKGROUNDS', (0,1), (-1,-1), [HexColor("#FEF9E7"), HexColor("#FDFEFE")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'),
('TEXTCOLOR', (0,1), (0,-1), HexColor("#C0392B")),
]))
story.append(steps_t)
story.append(Spacer(1, 10))
story.append(Paragraph("Common Scenarios - Jaldi Diagnose Karo!", subsection_style))
common_scenarios = [
[Paragraph("<b>Clinical Scenario</b>", important_style),
Paragraph("<b>ECG Finding</b>", important_style),
Paragraph("<b>Diagnosis</b>", important_style)],
["Chest pain, ST elevation", "Convex ST elevation, Q waves appearing", "STEMI - CALL CODE BLUE!"],
["Chest pain, no ST elevation but ST/T changes + troponin+", "ST depression, T inversion, no Q waves", "NSTEMI (Non-ST elevation MI)"],
["Palpitations, sudden onset, narrow QRS, rate 150-250", "Narrow complex tachycardia, P in QRS or just after", "SVT (AVNRT usually) - Vagal maneuver!"],
["Palpitations, totally irregular rhythm", "Irregularly irregular, no P waves, fibrillatory baseline", "Atrial Fibrillation - Anticoagulate!"],
["Syncope, rate 150, saw-tooth waves in II", "Regular tachycardia, flutter waves 300/min", "Atrial Flutter 2:1 block"],
["Pulseless, wide irregular ECG waves", "Chaotic undulations, no QRS", "Ventricular Fibrillation - SHOCK NOW!"],
["Renal failure patient, peaked T waves", "Tall tented T waves, widening QRS", "Hyperkalemia - EMERGENCY!"],
["Chest pain, pleuritic, diffuse concave ST elevation", "PR depression in multiple leads, ST saddle-shaped", "Pericarditis - Aspirin/NSAIDs"],
["Post-surgery, sinus tach, right axis, S1Q3T3", "Tachycardia, S1Q3T3, RBBB, right strain", "Pulmonary Embolism - CT-PA!"],
["Elderly, short PR, delta wave, wide QRS", "Delta wave, PR <0.12, wide QRS complex", "WPW syndrome - Avoid AV nodal drugs!"],
]
cs_t = Table(common_scenarios, colWidths=[52*mm, 60*mm, 53*mm])
cs_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#17202A")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9),
('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor("#FDFEFE")]),
('GRID', (0,0), (-1,-1), 0.5, HexColor("#BDC3C7")),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(cs_t)
story.append(Spacer(1, 10))
# Final summary box
final_box_data = [[
Paragraph("IMPORTANT EMERGENCY ECGs - Inhe Kabhi Mat Bhulo!",
ParagraphStyle('FinalTitle', parent=styles['Normal'],
fontSize=13, textColor=white, fontName='Helvetica-Bold',
spaceAfter=8, alignment=TA_CENTER)),
Paragraph("🚨 STEMI = Convex ST elevation + evolving Q waves → Cath lab immediately",
ParagraphStyle('FL', parent=styles['Normal'], fontSize=10, textColor=white,
fontName='Helvetica', spaceAfter=4, leading=14)),
Paragraph("🚨 VF = Chaotic rhythm, pulseless → DEFIBRILLATE immediately (200J biphasic)",
ParagraphStyle('FL', parent=styles['Normal'], fontSize=10, textColor=white,
fontName='Helvetica', spaceAfter=4, leading=14)),
Paragraph("🚨 Hyperkalemia Sine Wave = Wide QRS sine pattern → IV Calcium, Insulin, Dialysis",
ParagraphStyle('FL', parent=styles['Normal'], fontSize=10, textColor=white,
fontName='Helvetica', spaceAfter=4, leading=14)),
Paragraph("🚨 Complete Heart Block = P waves dissociated from slow wide QRS → Pacemaker",
ParagraphStyle('FL', parent=styles['Normal'], fontSize=10, textColor=white,
fontName='Helvetica', spaceAfter=4, leading=14)),
Paragraph("🚨 Torsades de Pointes = Polymorphic VT twisting → IV Magnesium sulfate",
ParagraphStyle('FL', parent=styles['Normal'], fontSize=10, textColor=white,
fontName='Helvetica', spaceAfter=4, leading=14)),
]]
final_table = Table(final_box_data, colWidths=[170*mm])
final_table.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), HexColor("#922B21")),
('TOPPADDING', (0,0), (-1,-1), 12),
('BOTTOMPADDING', (0,0), (-1,-1), 12),
('LEFTPADDING', (0,0), (-1,-1), 15),
('RIGHTPADDING', (0,0), (-1,-1), 15),
]))
story.append(final_table)
story.append(Spacer(1, 10))
# References
story.append(HRFlowable(width="100%", thickness=1, color=HexColor("#BDC3C7")))
story.append(Spacer(1, 6))
story.append(Paragraph(
"<b>References:</b> Harrison's Principles of Internal Medicine 22nd Ed. (2025) | "
"Braunwald's Heart Disease 12th Ed. | Goldman-Cecil Medicine | Guyton & Hall Medical Physiology | "
"Roberts & Hedges' Clinical Procedures in Emergency Medicine",
ParagraphStyle('Ref', parent=styles['Normal'], fontSize=8, textColor=HexColor("#7F8C8D"),
fontName='Helvetica', leading=12)
))
story.append(Paragraph(
"Prepared by Orris Medical AI | For educational purposes only. Clinical decisions should be made by qualified healthcare professionals.",
ParagraphStyle('Disclaimer', parent=styles['Normal'], fontSize=8, textColor=HexColor("#7F8C8D"),
fontName='Helvetica', leading=12, alignment=TA_CENTER, spaceBefore=4)
))
# Build PDF
print("Building PDF...")
doc.build(story)
print(f"PDF saved to: {OUTPUT_PATH}")
if __name__ == "__main__":
build_pdf()