attachment
attachment

Explain me ecg changes in images with pdf

Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Loading Image
Reading File
Reading File
Running Command

ls /home/daytona/workspace/ 2>/dev/null && echo "---exists---" || mkdir -p /home/daytona/workspace/ecg-report

Running Command

mkdir -p /home/daytona/workspace/ecg-report && curl -s -o /home/daytona/workspace/ecg-report/patient_ecg.jpg "https://d361swluvexzqs.cloudfront.net/chats-attachments/20260608_213336-1780974618521-vwdq6p.jpg" && echo "Downloaded"

Writing File

~/ecg-report/generate_ecg_pdf.py

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    Image, HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.pdfgen import canvas
import os

OUTPUT = "/home/daytona/workspace/ecg-report/ECG_Changes_Analysis.pdf"
ECG_IMG = "/home/daytona/workspace/ecg-report/patient_ecg.jpg"

# ── Custom page with header/footer ────────────────────────────────────────────
def header_footer(canvas_obj, doc):
    canvas_obj.saveState()
    w, h = A4
    # Header bar
    canvas_obj.setFillColor(colors.HexColor("#1a3d6b"))
    canvas_obj.rect(0, h - 2*cm, w, 2*cm, fill=1, stroke=0)
    canvas_obj.setFillColor(colors.white)
    canvas_obj.setFont("Helvetica-Bold", 14)
    canvas_obj.drawString(1.5*cm, h - 1.3*cm, "ECG ANALYSIS REPORT")
    canvas_obj.setFont("Helvetica", 9)
    canvas_obj.drawRightString(w - 1.5*cm, h - 1.3*cm, "Patient: Goutam Giloi  |  Date: 05/06/26")
    # Footer
    canvas_obj.setFillColor(colors.HexColor("#1a3d6b"))
    canvas_obj.rect(0, 0, w, 1.2*cm, fill=1, stroke=0)
    canvas_obj.setFillColor(colors.white)
    canvas_obj.setFont("Helvetica", 8)
    canvas_obj.drawString(1.5*cm, 0.45*cm, "Educational reference — Not a substitute for clinical judgment")
    canvas_obj.drawRightString(w - 1.5*cm, 0.45*cm, f"Page {doc.page}")
    canvas_obj.restoreState()

# ── Styles ─────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

title_style = ParagraphStyle(
    "Title2", parent=styles["Title"],
    fontSize=18, textColor=colors.HexColor("#1a3d6b"),
    spaceAfter=4, alignment=TA_CENTER
)
h1 = ParagraphStyle("H1", parent=styles["Heading1"],
    fontSize=13, textColor=colors.HexColor("#1a3d6b"),
    spaceBefore=14, spaceAfter=4,
    borderPad=4, leading=16
)
h2 = ParagraphStyle("H2", parent=styles["Heading2"],
    fontSize=11, textColor=colors.HexColor("#c0392b"),
    spaceBefore=10, spaceAfter=3
)
body = ParagraphStyle("Body", parent=styles["Normal"],
    fontSize=9.5, leading=14, alignment=TA_JUSTIFY,
    spaceAfter=6
)
bullet = ParagraphStyle("Bullet", parent=styles["Normal"],
    fontSize=9.5, leading=14, leftIndent=16,
    bulletIndent=6, spaceAfter=3
)
caption = ParagraphStyle("Caption", parent=styles["Normal"],
    fontSize=8.5, textColor=colors.HexColor("#555555"),
    alignment=TA_CENTER, spaceAfter=6, fontName="Helvetica-Oblique"
)
warn_style = ParagraphStyle("Warn", parent=styles["Normal"],
    fontSize=9.5, leading=14, backColor=colors.HexColor("#fff3cd"),
    textColor=colors.HexColor("#856404"), leftIndent=8, rightIndent=8,
    borderPad=6, spaceAfter=8
)

def section_bar(text):
    """Returns a styled section header table."""
    data = [[Paragraph(text, ParagraphStyle("SH", fontSize=11,
             textColor=colors.white, fontName="Helvetica-Bold", leading=14))]]
    t = Table(data, colWidths=[17*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#1a3d6b")),
        ("TOPPADDING", (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING", (0,0), (-1,-1), 10),
    ]))
    return t

# ── Build story ────────────────────────────────────────────────────────────────
story = []
story.append(Spacer(1, 0.3*cm))

# --- Patient ECG Image ---
story.append(section_bar("PATIENT ECG — SUBMITTED TRACING"))
story.append(Spacer(1, 0.3*cm))
if os.path.exists(ECG_IMG):
    img = Image(ECG_IMG, width=16*cm, height=10*cm, kind="proportional")
    story.append(img)
story.append(Paragraph(
    "Patient ECG recorded at Midnapore Multispeciality Hospital. 10 mm/mV, 25 mm/s. "
    "Date 05/06/26, Time 10:20 AM. Patient: Goutam Giloi.",
    caption
))
story.append(Spacer(1, 0.4*cm))

# ── 1. ECG BASICS ─────────────────────────────────────────────────────────────
story.append(section_bar("1. ECG BASICS & SYSTEMATIC READING"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
    "A 12-lead ECG records the heart's electrical activity from 12 different angles. "
    "Standard paper speed is 25 mm/s; 1 small box = 40 ms (0.04 s), "
    "1 large box = 200 ms (0.2 s). Amplitude: 1 mm = 0.1 mV at standard 10 mm/mV gain.",
    body
))

basics_data = [
    ["Component", "Normal Duration / Amplitude", "Significance"],
    ["P wave", "80–120 ms; ≤2.5 mm tall", "Atrial depolarisation"],
    ["PR interval", "120–200 ms", "AV nodal conduction"],
    ["QRS complex", "< 120 ms", "Ventricular depolarisation"],
    ["ST segment", "Isoelectric (±1 mm)", "Early ventricular repolarisation"],
    ["T wave", "Positive in I, II, V4-V6", "Ventricular repolarisation"],
    ["QT interval", "< 440 ms (men), < 460 ms (women)", "Total ventricular action potential"],
    ["QTc", "Corrected for HR (Bazett formula)", "Risk of arrhythmia if prolonged"],
]
t = Table(basics_data, colWidths=[4.5*cm, 6*cm, 6.5*cm])
t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#1a3d6b")),
    ("TEXTCOLOR", (0,0), (-1,0), colors.white),
    ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
    ("FONTSIZE", (0,0), (-1,-1), 9),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.HexColor("#f0f4f8"), colors.white]),
    ("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#b0bec5")),
    ("TOPPADDING", (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING", (0,0), (-1,-1), 6),
    ("ALIGN", (0,0), (-1,-1), "LEFT"),
    ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(t)
story.append(Spacer(1, 0.4*cm))

# ── 2. ANALYSIS OF SUBMITTED ECG ──────────────────────────────────────────────
story.append(section_bar("2. ANALYSIS OF SUBMITTED ECG"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
    "The submitted tracing (Goutam Giloi, 05/06/26) is a standard 12-lead ECG recorded "
    "at 25 mm/s, 10 mm/mV. The following observations can be made from visual inspection:",
    body
))

findings = [
    ("<b>Rhythm:</b>", "Regular narrow QRS complexes are visible throughout. The rhythm appears to be sinus in origin with P waves preceding each QRS. Rate appears in the range of 70–90 bpm (estimated)."),
    ("<b>QRS Axis:</b>", "The dominant deflections in limb leads suggest a normal or leftward axis. Detailed axis calculation requires precise lead I and aVF amplitudes."),
    ("<b>QRS Morphology:</b>", "QRS complexes appear narrow (< 120 ms), arguing against bundle branch block. Tall R waves are noted in left precordial leads (V4-V6 region)."),
    ("<b>ST Segment:</b>", "No obvious gross ST elevation in multiple leads. Careful lead-by-lead inspection is required for subtle changes. Some baseline wobble noted."),
    ("<b>T waves:</b>", "T waves appear upright in most leads visible. Possible flattening in inferior or lateral leads — clinical correlation needed."),
    ("<b>Precordial leads:</b>", "R-wave progression visible across chest leads. No obvious Q waves suggestive of old infarction identified on gross inspection."),
    ("<b>Voltage:</b>", "Tall precordial voltages may suggest LVH — formal Sokolov-Lyon or Cornell criteria should be applied (see Section 4)."),
]
for label, text in findings:
    story.append(Paragraph(f"{label} {text}", bullet))
story.append(Spacer(1, 0.3*cm))

story.append(Paragraph(
    "⚠  <b>Note:</b> This is a visual interpretation guide. Definitive clinical ECG reading must be "
    "performed by a qualified cardiologist with access to the original tracing and patient history.",
    warn_style
))
story.append(Spacer(1, 0.4*cm))

# ── 3. COMMON ECG CHANGES ─────────────────────────────────────────────────────
story.append(section_bar("3. COMMON PATHOLOGICAL ECG CHANGES"))
story.append(Spacer(1, 0.2*cm))

ecg_changes = [
    ["ECG Change", "Description", "Common Cause(s)"],
    ["ST Elevation (STE)", ">1 mm in ≥2 contiguous limb leads or >2 mm in precordial leads above J-point",
     "STEMI, pericarditis, Brugada, early repolarisation, LVH strain, vasospasm"],
    ["ST Depression", ">0.5 mm below baseline in ≥2 contiguous leads",
     "NSTEMI/UA, LVH strain, digoxin effect, subendocardial ischemia"],
    ["T-wave Inversion", "T wave negative where normally positive",
     "Ischemia, ARVD, PE (V1-V4), LVH strain, hypertrophic cardiomyopathy"],
    ["Pathological Q waves", "≥0.04 s wide and ≥25% of R wave height in ≥2 contiguous leads",
     "Previous MI (transmural), LBBB, WPW"],
    ["Tall peaked P waves", ">2.5 mm in II, III, aVF",
     "Right atrial enlargement, pulmonary hypertension, COPD"],
    ["Broad notched P waves", ">0.12 s, bifid P in lead II",
     "Left atrial enlargement, mitral stenosis"],
    ["Prolonged QTc", ">440 ms (men), >460 ms (women)",
     "Drugs (quinolones, antipsychotics), hypokalaemia, hypomagnesaemia, congenital LQTS"],
    ["Delta wave / Short PR", "Slurred QRS upstroke, PR < 120 ms",
     "Wolff-Parkinson-White syndrome (pre-excitation)"],
    ["LBBB", "QRS ≥120 ms; broad notched R in I, aVL, V5-V6; absence of septal Q",
     "IHD, cardiomyopathy, hypertension, conduction disease"],
    ["RBBB", "QRS ≥120 ms; rSR' in V1; wide S in I, V5-V6",
     "RV strain, PE, ASD, ischaemia, normal variant (incomplete RBBB)"],
]
t2 = Table(ecg_changes, colWidths=[4*cm, 7*cm, 6*cm])
t2.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#c0392b")),
    ("TEXTCOLOR", (0,0), (-1,0), colors.white),
    ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
    ("FONTSIZE", (0,0), (-1,-1), 8.5),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.HexColor("#fdf5f5"), colors.white]),
    ("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#e0b0b0")),
    ("TOPPADDING", (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING", (0,0), (-1,-1), 6),
    ("ALIGN", (0,0), (-1,-1), "LEFT"),
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("WORDWRAP", (0,0), (-1,-1), True),
]))
story.append(t2)
story.append(Spacer(1, 0.4*cm))

# ── 4. LVH CRITERIA ───────────────────────────────────────────────────────────
story.append(section_bar("4. LEFT VENTRICULAR HYPERTROPHY (LVH) CRITERIA"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
    "LVH is relevant when tall precordial voltages are seen (as may be present in this tracing). "
    "LVH increases amplitude of forces directed left and posteriorly, with characteristic "
    "repolarisation changes (ST depression + T-wave inversion in lateral leads = 'strain pattern').",
    body
))

lvh_data = [
    ["Criterion", "Formula / Threshold", "Sensitivity / Notes"],
    ["Sokolov-Lyon", "SV1 + RV5 (or RV6) > 35 mm", "~50% sensitivity, higher specificity"],
    ["Cornell (men)", "RaVL + SV3 > 28 mm", "Better in obese patients"],
    ["Cornell (women)", "RaVL + SV3 > 20 mm", "Gender-adjusted threshold"],
    ["Lewis index", "RI + SIII - RIII - SI > 16 mm", "Less commonly used"],
    ["RaVL alone", "> 28 mm (men), > 20 mm (women)", "Simple limb-lead criterion"],
    ["Strain pattern", "ST depression + T-wave inversion in I, aVL, V5-V6", "Indicates pressure overload"],
]
t3 = Table(lvh_data, colWidths=[4.5*cm, 6.5*cm, 6*cm])
t3.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#1a6b3d")),
    ("TEXTCOLOR", (0,0), (-1,0), colors.white),
    ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
    ("FONTSIZE", (0,0), (-1,-1), 9),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.HexColor("#f0faf4"), colors.white]),
    ("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#a0c8b0")),
    ("TOPPADDING", (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING", (0,0), (-1,-1), 6),
    ("ALIGN", (0,0), (-1,-1), "LEFT"),
    ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(t3)
story.append(Spacer(1, 0.4*cm))

# ── 5. MI ECG EVOLUTION ───────────────────────────────────────────────────────
story.append(section_bar("5. ECG EVOLUTION IN MYOCARDIAL INFARCTION"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
    "The ECG evolves in a predictable sequence during MI. Recognising which stage has been reached "
    "guides reperfusion decisions (Braunwald's Heart Disease, 22nd ed):",
    body
))

mi_phases = [
    ["Phase", "Timeframe", "ECG Features"],
    ["Hyperacute / Early", "Minutes to ~1 hour", "Tall, peaked (hyperacute) T waves; subtle STE at J-point"],
    ["Acute", "Hours to ~24 hours", "STE ≥ 1 mm in ≥2 contiguous leads; reciprocal ST depression opposite wall"],
    ["Evolving", "24–72 hours", "STE persists; Q waves develop; T-wave inversion begins"],
    ["Subacute", "Days to weeks", "STE diminishes; deep T-wave inversion; Q waves present"],
    ["Chronic / Old", "Weeks to years", "Q waves persist; T waves normalise; ST returns to baseline"],
    ["Posterior MI", "Any phase", "ST depression + tall R + upright T in V1-V3 (mirror image)"],
]
t4 = Table(mi_phases, colWidths=[3.5*cm, 4*cm, 9.5*cm])
t4.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#7b2d8b")),
    ("TEXTCOLOR", (0,0), (-1,0), colors.white),
    ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
    ("FONTSIZE", (0,0), (-1,-1), 9),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.HexColor("#faf0fc"), colors.white]),
    ("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#c8a0d0")),
    ("TOPPADDING", (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING", (0,0), (-1,-1), 6),
    ("ALIGN", (0,0), (-1,-1), "LEFT"),
    ("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(t4)
story.append(Spacer(1, 0.4*cm))

# ── 6. LOCALISATION TABLE ─────────────────────────────────────────────────────
story.append(section_bar("6. ECG LOCALISATION OF MI TERRITORY"))
story.append(Spacer(1, 0.2*cm))

loc_data = [
    ["Territory", "ECG Leads Affected", "Artery (typically)"],
    ["Anterior", "V1, V2, V3, V4", "LAD (proximal)"],
    ["Anteroseptal", "V1, V2, V3", "LAD (septal branches)"],
    ["Lateral", "I, aVL, V5, V6", "LCx or diagonal branch"],
    ["Inferior", "II, III, aVF", "RCA (80%) or LCx (20%)"],
    ["Posterior", "V1-V3 (reciprocal)", "RCA or LCx"],
    ["Right ventricular", "V3R, V4R (right-sided leads)", "RCA (proximal)"],
    ["Anterolateral", "V1-V6, I, aVL", "LAD or LCx"],
]
t5 = Table(loc_data, colWidths=[4.5*cm, 6*cm, 6.5*cm])
t5.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#c0392b")),
    ("TEXTCOLOR", (0,0), (-1,0), colors.white),
    ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
    ("FONTSIZE", (0,0), (-1,-1), 9),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.HexColor("#fff5f5"), colors.white]),
    ("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#e0b0b0")),
    ("TOPPADDING", (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING", (0,0), (-1,-1), 6),
    ("ALIGN", (0,0), (-1,-1), "LEFT"),
    ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(t5)
story.append(Spacer(1, 0.4*cm))

# ── 7. DIFFERENTIAL DIAGNOSIS ─────────────────────────────────────────────────
story.append(section_bar("7. DIFFERENTIAL DIAGNOSIS OF ST ELEVATION"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
    "ST elevation has a broad differential beyond STEMI. The Washington Manual of Medical Therapeutics "
    "lists the following important mimics (Table 4-16):",
    body
))

diff_data = [
    ["Cardiac Etiologies", "Non-Cardiac / Other"],
    ["STEMI (acute MI)", "Pulmonary embolism (S1Q3T3 pattern)"],
    ["Pericarditis (diffuse saddle-shaped STE)", "Hyperkalemia (peaked T, then STE)"],
    ["Myocarditis", "Normal variant / early repolarisation"],
    ["LV aneurysm (persistent STE after old MI)", "Brugada syndrome (V1-V3)"],
    ["Aortic dissection with coronary involvement", ""],
    ["Hypertrophic cardiomyopathy", ""],
    ["Coronary vasospasm (Prinzmetal angina)", ""],
    ["LV hypertrophy with strain", ""],
]
t6 = Table(diff_data, colWidths=[8.5*cm, 8.5*cm])
t6.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#2c5f8a")),
    ("TEXTCOLOR", (0,0), (-1,0), colors.white),
    ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
    ("FONTSIZE", (0,0), (-1,-1), 9),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.HexColor("#f0f7ff"), colors.white]),
    ("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#a0c0e0")),
    ("TOPPADDING", (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING", (0,0), (-1,-1), 6),
    ("ALIGN", (0,0), (-1,-1), "LEFT"),
    ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(t6)
story.append(Spacer(1, 0.4*cm))

# ── 8. PATHOLOGICAL Q WAVES ───────────────────────────────────────────────────
story.append(section_bar("8. PATHOLOGICAL Q WAVES — CRITERIA"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
    "Pathological Q waves indicate transmural infarction. Criteria (Washington Manual, 2023):",
    body
))
for pt in [
    "In leads <b>V2 and V3</b>: Q wave ≥ 0.02 s OR QS complex in both V2 and V3.",
    "In <b>all other leads</b> (except V1, III, aVR): Q wave ≥ 0.03 s AND ≥ 0.1 mV deep in ≥2 contiguous leads.",
    "Isolated Q in V1 or lead III is <b>normal</b>.",
    "<b>Posterior MI marker:</b> R wave ≥ 0.04 s in V1-V2 with R/S ≥ 1 and positive T wave (absence of RVH/RBBB).",
    "Q waves alone without symptoms do not mandate reperfusion — compare to prior ECG for chronicity.",
]:
    story.append(Paragraph(f"• {pt}", bullet))
story.append(Spacer(1, 0.4*cm))

# ── 9. SGARBOSSA CRITERIA ─────────────────────────────────────────────────────
story.append(section_bar("9. SGARBOSSA CRITERIA — STEMI IN LBBB / PACED RHYTHM"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
    "When LBBB or RV paced rhythm is present, standard STE criteria cannot be applied. "
    "Sgarbossa criteria (GUSTO trial) identify STEMI:",
    body
))
sgb = [
    ["Criterion", "Points", "Interpretation"],
    ["STE > 1 mm concordant with QRS (same direction)", "5", "Highly specific for STEMI"],
    ["ST depression > 1 mm in V1-V3", "3", "Reciprocal change suggesting STEMI"],
    ["STE > 5 mm discordant with QRS (opposite direction)", "2", "Less specific alone"],
    ["Score ≥ 3 points", "—", "High likelihood of STEMI; proceed to cath lab"],
]
t7 = Table(sgb, colWidths=[8*cm, 2.5*cm, 6.5*cm])
t7.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#7b4e2d")),
    ("TEXTCOLOR", (0,0), (-1,0), colors.white),
    ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
    ("FONTSIZE", (0,0), (-1,-1), 9),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.HexColor("#faf5f0"), colors.white]),
    ("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#d0b090")),
    ("TOPPADDING", (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING", (0,0), (-1,-1), 6),
    ("ALIGN", (0,0), (-1,-1), "LEFT"),
    ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(t7)
story.append(Spacer(1, 0.4*cm))

# ── 10. REFERENCES ─────────────────────────────────────────────────────────────
story.append(section_bar("10. REFERENCES"))
story.append(Spacer(1, 0.2*cm))
for ref in [
    "1. Zipes DP et al. <i>Braunwald's Heart Disease: A Textbook of Cardiovascular Medicine</i>, 12th ed. Elsevier (2022). ISBN 9780323722193.",
    "2. Longo DL et al. <i>Harrison's Principles of Internal Medicine</i>, 22nd ed. McGraw-Hill (2025). ISBN 9781265977061.",
    "3. Kollef MH et al. <i>The Washington Manual of Medical Therapeutics</i>. Wolters Kluwer (2023). ISBN 9781975190620.",
    "4. Tintinalli JE et al. <i>Tintinalli's Emergency Medicine</i>. McGraw-Hill (2020). ISBN 9781260019933.",
    "5. Marx JA et al. <i>Rosen's Emergency Medicine</i>, 10th ed. Elsevier (2023). ISBN 9780323757898.",
    "6. Sgarbossa EB et al. Electrocardiographic diagnosis of evolving acute myocardial infarction in the presence of left bundle-branch block. <i>N Engl J Med</i>. 1996;334(8):481-487.",
]:
    story.append(Paragraph(ref, body))
story.append(Spacer(1, 0.2*cm))

story.append(HRFlowable(width="100%", thickness=1, color=colors.HexColor("#1a3d6b")))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
    "<b>Disclaimer:</b> This report is generated for educational purposes only. "
    "ECG interpretation in a clinical context must be performed by a licensed cardiologist or physician. "
    "Do not make clinical decisions based solely on this document.",
    ParagraphStyle("Disc", parent=styles["Normal"], fontSize=8,
                   textColor=colors.HexColor("#888888"), alignment=TA_CENTER)
))

# ── Build PDF ──────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    topMargin=2.5*cm, bottomMargin=1.8*cm,
    leftMargin=1.5*cm, rightMargin=1.5*cm,
    title="ECG Analysis Report — Goutam Giloi",
    author="Orris Medical AI",
    subject="12-Lead ECG Interpretation"
)
doc.build(story, onFirstPage=header_footer, onLaterPages=header_footer)
print(f"PDF created: {OUTPUT}")
Running Command

cd /home/daytona/workspace/ecg-report && python generate_ecg_pdf.py

The PDF has been generated. Here is the full breakdown:

ECG Analysis — Goutam Giloi (05/06/26, Midnapore Hospital)

Visual Observations from Your Tracing

Looking at the submitted 12-lead ECG (10 mm/mV, 25 mm/s):
FeatureObservation
RhythmRegular narrow QRS complexes; P waves precede each QRS → likely sinus rhythm
RateEstimated ~70-90 bpm (R-R interval ~3-4 large boxes)
QRS widthNarrow (<120 ms) - no bundle branch block pattern visible
Precordial voltagesTall R waves in left precordial leads - possible LVH by voltage criteria
ST segmentNo gross ST elevation across leads; requires careful measurement
T wavesUpright in most visible leads; possible flattening in some inferior leads
Q wavesNo obvious pathological Q waves on gross inspection
P wavesPresent before each QRS; morphology needs closer measurement

Key ECG Changes You Should Know

ST Elevation - > 1 mm in ≥2 contiguous limb leads (or >2 mm precordial) = STEMI until proven otherwise. Mimics include pericarditis (diffuse, saddle-shaped), LVH strain, Brugada, early repolarisation, PE.
ST Depression - Subendocardial ischemia, NSTEMI, digoxin effect, LVH strain pattern in lateral leads.
Pathological Q waves - ≥0.03 s wide AND ≥0.1 mV deep in ≥2 contiguous leads = old transmural infarction. In V2-V3, even ≥0.02 s qualifies. (Washington Manual, 2023)
LVH Criteria (relevant if tall voltages confirmed):
  • Sokolov-Lyon: SV1 + RV5/RV6 > 35 mm
  • Cornell (men): RaVL + SV3 > 28 mm
  • Strain pattern: ST depression + T-wave inversion in I, aVL, V5-V6 (Harrison's, 22nd ed, 2025)
MI Localisation by leads:
  • Inferior: II, III, aVF → RCA
  • Anterior: V1-V4 → LAD
  • Lateral: I, aVL, V5-V6 → LCx
  • Posterior: Reciprocal changes in V1-V3

Download your full PDF report (with patient ECG image, all tables, references, and differential diagnosis):

ECG Changes Analysis

PDF Document · PDF


Important: This analysis is educational. A qualified cardiologist must perform the formal clinical ECG interpretation, especially before any treatment decision.

Ecg changes analysis report pdf

Running Command

ls -lh /home/daytona/workspace/ecg-report/

Your PDF is ready and waiting. Here it is:

ECG Changes Analysis

PDF Document · PDF

The report (3.2 MB) includes:
  1. Your patient's ECG image (Goutam Giloi, 05/06/26, Midnapore Hospital)
  2. Visual analysis of the submitted tracing - rhythm, QRS, ST segment, T waves, voltage
  3. ECG basics table - normal durations and amplitudes for all components
  4. Common pathological ECG changes - ST elevation, ST depression, T-wave inversion, Q waves, LBBB, RBBB, delta waves, prolonged QTc
  5. LVH voltage criteria - Sokolov-Lyon, Cornell, strain pattern
  6. MI ECG evolution - hyperacute through chronic phases
  7. MI localisation table - which leads correspond to which artery
  8. Differential diagnosis of ST elevation - STEMI vs mimics
  9. Pathological Q wave criteria
  10. Sgarbossa criteria for STEMI in LBBB/paced rhythm
  11. References - Braunwald's, Harrison's, Washington Manual, Rosen's EM
This is a shared conversation. Sign in to Orris to start your own chat.