Take imges from it and inform to it
cd /home/daytona/workspace && mkdir -p physiology-charts/images && python3 << 'EOF' from pypdf import PdfReader import pdfplumber import os pdf_path = "/home/daytona/workspace/attachments/fb1a1c96-ffb6-41a7-bec6-6d440b713515/physiology practical charts.pdf" # Get basic info reader = PdfReader(pdf_path) print(f"Total pages: {len(reader.pages)}") print(f"Metadata: {reader.metadata}") # Extract text from all pages with pdfplumber.open(pdf_path) as pdf: for i, page in enumerate(pdf.pages): text = page.extract_text() print(f"\n=== PAGE {i+1} ===") print(text if text else "[No text found]") EOF
python3 << 'EOF' from pdf2image import convert_from_path import os pdf_path = "/home/daytona/workspace/attachments/fb1a1c96-ffb6-41a7-bec6-6d440b713515/physiology practical charts.pdf" out_dir = "/home/daytona/workspace/physiology-charts/images" os.makedirs(out_dir, exist_ok=True) # Convert first 10 pages to images to start pages = convert_from_path(pdf_path, dpi=150, first_page=1, last_page=10) for i, page in enumerate(pages, start=1): path = f"{out_dir}/page_{i:03d}.jpg" page.save(path, "JPEG", quality=85) print(f"Saved: {path}") print(f"\nTotal converted: {len(pages)} pages") EOF
python3 << 'EOF' import pytesseract from PIL import Image import os images_dir = "/home/daytona/workspace/physiology-charts/images" # OCR on pages 1-10 for i in range(1, 11): img_path = f"{images_dir}/page_{i:03d}.jpg" img = Image.open(img_path) text = pytesseract.image_to_string(img) print(f"\n{'='*50}") print(f"PAGE {i}") print('='*50) print(text.strip() if text.strip() else "[No text detected]") EOF
python3 << 'EOF' from pdf2image import convert_from_path import pytesseract from PIL import Image import os pdf_path = "/home/daytona/workspace/attachments/fb1a1c96-ffb6-41a7-bec6-6d440b713515/physiology practical charts.pdf" out_dir = "/home/daytona/workspace/physiology-charts/images" os.makedirs(out_dir, exist_ok=True) # Convert pages 11-123 pages = convert_from_path(pdf_path, dpi=150, first_page=11, last_page=123) for i, page in enumerate(pages, start=11): path = f"{out_dir}/page_{i:03d}.jpg" page.save(path, "JPEG", quality=85) print(f"Converted pages 11-123") # Now OCR all pages results = {} for i in range(1, 124): img_path = f"{out_dir}/page_{i:03d}.jpg" if os.path.exists(img_path): img = Image.open(img_path) text = pytesseract.image_to_string(img).strip() results[i] = text # Save full OCR output with open("/home/daytona/workspace/physiology-charts/ocr_full.txt", "w") as f: for pg, text in results.items(): f.write(f"\n{'='*60}\nPAGE {pg}\n{'='*60}\n") f.write(text if text else "[Image/chart - no text]\n") print("OCR complete. Summary of pages with text:") for pg, text in results.items(): preview = text[:80].replace('\n',' ') if text else "[no text]" print(f" Page {pg}: {preview}") EOF
python3 << 'EOF' from pdf2image import convert_from_path import pytesseract from PIL import Image import os pdf_path = "/home/daytona/workspace/attachments/fb1a1c96-ffb6-41a7-bec6-6d440b713515/physiology practical charts.pdf" out_dir = "/home/daytona/workspace/physiology-charts/images" os.makedirs(out_dir, exist_ok=True) all_text = {} # Process 10 pages at a time (pages 11-50) for batch_start in range(11, 51, 10): batch_end = min(batch_start + 9, 50) pages = convert_from_path(pdf_path, dpi=120, first_page=batch_start, last_page=batch_end) for i, page in enumerate(pages, start=batch_start): path = f"{out_dir}/page_{i:03d}.jpg" page.save(path, "JPEG", quality=80) text = pytesseract.image_to_string(Image.open(path)).strip() all_text[i] = text print(f"Processed pages {batch_start}-{batch_end}") # Save with open("/home/daytona/workspace/physiology-charts/ocr_11_50.txt", "w") as f: for pg in sorted(all_text.keys()): f.write(f"\n{'='*50}\nPAGE {pg}\n{'='*50}\n") f.write(all_text[pg] if all_text[pg] else "[Image/chart]\n") print("Done pages 11-50") EOF
python3 << 'EOF' from pdf2image import convert_from_path import pytesseract from PIL import Image import os pdf_path = "/home/daytona/workspace/attachments/fb1a1c96-ffb6-41a7-bec6-6d440b713515/physiology practical charts.pdf" out_dir = "/home/daytona/workspace/physiology-charts/images" all_text = {} # Process pages 51-123 for batch_start in range(51, 124, 10): batch_end = min(batch_start + 9, 123) pages = convert_from_path(pdf_path, dpi=120, first_page=batch_start, last_page=batch_end) for i, page in enumerate(pages, start=batch_start): path = f"{out_dir}/page_{i:03d}.jpg" page.save(path, "JPEG", quality=80) text = pytesseract.image_to_string(Image.open(path)).strip() all_text[i] = text print(f"Processed pages {batch_start}-{batch_end}") with open("/home/daytona/workspace/physiology-charts/ocr_51_123.txt", "w") as f: for pg in sorted(all_text.keys()): f.write(f"\n{'='*50}\nPAGE {pg}\n{'='*50}\n") f.write(all_text[pg] if all_text[pg] else "[Image/chart]\n") print("Done pages 51-123") EOF
| Station | Task 1 (15 marks) | Task 2 (5 marks) |
|---|---|---|
| Cardiovascular | Examine cardiovascular system & report findings | Elicit triceps jerk |
| Respiratory | Examine respiratory system & report findings | Elicit biceps jerk / knee jerk |
| Motor System | Perform motor system examination | Elicit ankle jerk |
| Sensory System | Perform sensory system examination | Elicit supinator jerk |
| General Exam | General examination + radial pulse | Elicit triceps/knee jerk |
| Cranial Nerves | Examine cranial nerves I-VI | Elicit plantar reflex |
| Muscle Tone/Power | Assess lower limb muscles (tone & power) | Elicit biceps jerk |
| Task 1 (15 marks) | Task 2 (5 marks) |
|---|---|
| Enumerate total leukocyte count (TLC) | Estimate bleeding time |
| Enumerate total erythrocyte count | Determine blood group |
| Enumerate differential leukocyte count (DLC) | Estimate bleeding time |
| Estimate hemoglobin concentration | Estimate bleeding time |
| Task 1 (10 marks) | Task 2 (10 marks) |
|---|---|
| Blood pressure in lying & standing postures | Electrocardiography (ECG) |
| Pulse rate, BP & mean arterial pressure (sitting) | ECG / Spirometry / Perimetry / Mosso's Ergography |
| Blood pressure changes in standing posture | ECG / Spirometry |
| Blood pressure changes in moderate physical exercise | ECG / Mosso's Ergography |



| System | Topics |
|---|---|
| Cardiovascular | ECG, blood pressure, cardiac muscle properties, extrasystole, cardiac output (Fick), Stannius ligatures, action potential |
| Hematology | TLC, DLC, RBC count, Hb estimation, bleeding time, blood grouping, MCH/MCV/MCHC/color index, absolute eosinophil count |
| Respiratory | Spirometry, dyspneic index, MVV, obstructive vs restrictive disease |
| Renal | GFR, TmG, glomerular filtration pressures, podocytes |
| Neurology/Clinical | Motor exam, sensory exam, cranial nerves I-VI, tendon reflexes (biceps/triceps/knee/ankle/supinator/plantar), muscle tone & power |
| Special Senses/Others | Perimetry, Mosso's ergography |
file
File ·
page 056
Image · JPG
page 010
Image · JPG
page 022
Image · JPG
It is not downloadable
ls -la /home/daytona/workspace/physiology-charts/images/ | head -20 && echo "---" && ls /home/daytona/workspace/physiology-charts/
cd /home/daytona/workspace && zip -r physiology-charts/physiology_charts_images.zip physiology-charts/images/ && ls -lh physiology-charts/physiology_charts_images.zip
# Try copying to a fresh directory first then zip mkdir -p /home/daytona/workspace/physio_export cp /home/daytona/workspace/physiology-charts/images/*.jpg /home/daytona/workspace/physio_export/ ls /home/daytona/workspace/physio_export/ | wc -l
# Try converting just the original PDF pages to a multi-page PDF with images embedded # Re-convert selected key pages at lower DPI and create a single PDF python3 -c " from pdf2image import convert_from_path from PIL import Image import os pdf_path = '/home/daytona/workspace/attachments/fb1a1c96-ffb6-41a7-bec6-6d440b713515/physiology practical charts.pdf' out = '/home/daytona/workspace/physiology-charts/pages_1_10.pdf' pages = convert_from_path(pdf_path, dpi=100, first_page=1, last_page=10) imgs = [p.convert('RGB') for p in pages] imgs[0].save(out, save_all=True, append_images=imgs[1:]) print('Done:', out, os.path.getsize(out)) "
python3 -c " from pdf2image import convert_from_path from PIL import Image import os pdf_path = '/home/daytona/workspace/attachments/fb1a1c96-ffb6-41a7-bec6-6d440b713515/physiology practical charts.pdf' out_dir = '/home/daytona/workspace/physiology-charts' # Pages 11-40 pages = convert_from_path(pdf_path, dpi=100, first_page=11, last_page=40) imgs = [p.convert('RGB') for p in pages] out = out_dir + '/pages_11_40.pdf' imgs[0].save(out, save_all=True, append_images=imgs[1:]) print('Done:', out, os.path.getsize(out)) "
python3 -c " from pdf2image import convert_from_path from PIL import Image import os pdf_path = '/home/daytona/workspace/attachments/fb1a1c96-ffb6-41a7-bec6-6d440b713515/physiology practical charts.pdf' out_dir = '/home/daytona/workspace/physiology-charts' # Pages 41-80 pages = convert_from_path(pdf_path, dpi=100, first_page=41, last_page=80) imgs = [p.convert('RGB') for p in pages] out = out_dir + '/pages_41_80.pdf' imgs[0].save(out, save_all=True, append_images=imgs[1:]) print('Done:', out, os.path.getsize(out)) "
python3 -c " from pdf2image import convert_from_path from PIL import Image import os pdf_path = '/home/daytona/workspace/attachments/fb1a1c96-ffb6-41a7-bec6-6d440b713515/physiology practical charts.pdf' out_dir = '/home/daytona/workspace/physiology-charts' # Pages 81-123 pages = convert_from_path(pdf_path, dpi=100, first_page=81, last_page=123) imgs = [p.convert('RGB') for p in pages] out = out_dir + '/pages_81_123.pdf' imgs[0].save(out, save_all=True, append_images=imgs[1:]) print('Done:', out, os.path.getsize(out)) "
python3 -c " from pypdf import PdfWriter, PdfReader import os out_dir = '/home/daytona/workspace/physiology-charts' parts = [ out_dir + '/pages_1_10.pdf', out_dir + '/pages_11_40.pdf', out_dir + '/pages_41_80.pdf', out_dir + '/pages_81_123.pdf', ] writer = PdfWriter() for f in parts: reader = PdfReader(f) for page in reader.pages: writer.add_page(page) final = out_dir + '/Physiology_Practical_Charts_ALL_PAGES.pdf' with open(final, 'wb') as out: writer.write(out) size_mb = os.path.getsize(final) / (1024*1024) print(f'Final PDF: {final}') print(f'Total pages: {len(writer.pages)}') print(f'File size: {size_mb:.1f} MB') "
Physiology Practical Charts ALL PAGES
PDF Document · PDF
Create a study guide summarizing key physiology concepts from the charts
~/physiology-charts/create_study_guide.js
const {
Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
HeadingLevel, AlignmentType, BorderStyle, WidthType, ShadingType,
PageNumber, Header, Footer, NumberFormat, TableOfContents,
LevelFormat, convertInchesToTwip
} = require('docx');
const fs = require('fs');
// ─── COLOUR PALETTE ───────────────────────────────────────────────
const DARK_BLUE = "1B3A6B";
const MID_BLUE = "2E6DA4";
const LIGHT_BLUE = "D6E8F7";
const ACCENT_RED = "C0392B";
const ACCENT_GOLD = "D4A017";
const WHITE = "FFFFFF";
const LIGHT_GREY = "F2F2F2";
const DARK_TEXT = "2C2C2C";
const MED_GREY = "666666";
// ─── HELPERS ──────────────────────────────────────────────────────
function h1(text) {
return new Paragraph({
heading: HeadingLevel.HEADING_1,
spacing: { before: 360, after: 160 },
border: { bottom: { style: BorderStyle.THICK, size: 6, color: MID_BLUE } },
children: [new TextRun({ text, bold: true, size: 32, color: DARK_BLUE, font: "Calibri" })]
});
}
function h2(text) {
return new Paragraph({
heading: HeadingLevel.HEADING_2,
spacing: { before: 280, after: 120 },
children: [new TextRun({ text, bold: true, size: 26, color: MID_BLUE, font: "Calibri" })]
});
}
function h3(text) {
return new Paragraph({
heading: HeadingLevel.HEADING_3,
spacing: { before: 200, after: 80 },
children: [new TextRun({ text, bold: true, size: 22, color: DARK_BLUE, font: "Calibri" })]
});
}
function body(text, opts = {}) {
return new Paragraph({
spacing: { after: 100 },
children: [new TextRun({ text, size: 20, font: "Calibri", color: DARK_TEXT, ...opts })]
});
}
function bullet(text, bold_prefix = null) {
const runs = [];
if (bold_prefix) {
runs.push(new TextRun({ text: bold_prefix + " ", bold: true, size: 20, font: "Calibri", color: DARK_BLUE }));
}
runs.push(new TextRun({ text, size: 20, font: "Calibri", color: DARK_TEXT }));
return new Paragraph({ bullet: { level: 0 }, spacing: { after: 80 }, children: runs });
}
function subbullet(text) {
return new Paragraph({
bullet: { level: 1 }, spacing: { after: 60 },
children: [new TextRun({ text, size: 19, font: "Calibri", color: MED_GREY })]
});
}
function keyval(key, val) {
return new Paragraph({
spacing: { after: 90 },
children: [
new TextRun({ text: key + ": ", bold: true, size: 20, font: "Calibri", color: DARK_BLUE }),
new TextRun({ text: val, size: 20, font: "Calibri", color: DARK_TEXT })
]
});
}
function blankLine() {
return new Paragraph({ children: [new TextRun({ text: "" })] });
}
function highlightBox(label, text) {
return new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
new TableRow({ children: [
new TableCell({
shading: { fill: LIGHT_BLUE, type: ShadingType.CLEAR },
borders: { top: { style: BorderStyle.THICK, size: 8, color: MID_BLUE }, left: { style: BorderStyle.THICK, size: 8, color: MID_BLUE }, bottom: { style: BorderStyle.NONE }, right: { style: BorderStyle.NONE } },
margins: { top: 80, bottom: 80, left: 120, right: 120 },
children: [
new Paragraph({ children: [new TextRun({ text: label, bold: true, size: 20, color: DARK_BLUE, font: "Calibri" })] }),
new Paragraph({ children: [new TextRun({ text, size: 19, color: DARK_TEXT, font: "Calibri" })] })
]
})
]})
]
});
}
function makeTable(headers, rows, headerColor = DARK_BLUE) {
const headerRow = new TableRow({
tableHeader: true,
children: headers.map(h => new TableCell({
shading: { fill: headerColor, type: ShadingType.CLEAR },
margins: { top: 60, bottom: 60, left: 100, right: 100 },
children: [new Paragraph({ alignment: AlignmentType.CENTER, children: [new TextRun({ text: h, bold: true, size: 19, color: WHITE, font: "Calibri" })] })]
}))
});
const dataRows = rows.map(row => new TableRow({
children: row.map((cell, ci) => new TableCell({
shading: { fill: ci === 0 ? LIGHT_GREY : WHITE, type: ShadingType.CLEAR },
margins: { top: 60, bottom: 60, left: 100, right: 100 },
children: [new Paragraph({ children: [new TextRun({ text: cell, size: 18, font: "Calibri", color: DARK_TEXT, bold: ci === 0 })] })]
}))
}));
return new Table({ width: { size: 100, type: WidthType.PERCENTAGE }, rows: [headerRow, ...dataRows] });
}
function divider() {
return new Paragraph({ border: { bottom: { style: BorderStyle.SINGLE, size: 3, color: "CCCCCC" } }, children: [new TextRun("")] });
}
// ─── TITLE PAGE ───────────────────────────────────────────────────
const titlePage = [
blankLine(), blankLine(), blankLine(),
new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({ text: "PHYSIOLOGY PRACTICAL", bold: true, size: 56, color: DARK_BLUE, font: "Calibri" })]
}),
new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({ text: "STUDY GUIDE", bold: true, size: 56, color: MID_BLUE, font: "Calibri" })]
}),
blankLine(),
new Paragraph({
alignment: AlignmentType.CENTER,
border: { top: { style: BorderStyle.THICK, size: 6, color: ACCENT_GOLD }, bottom: { style: BorderStyle.THICK, size: 6, color: ACCENT_GOLD } },
spacing: { before: 80, after: 80 },
children: [new TextRun({ text: "Hematology | Cardiovascular | Respiratory | Renal | Neurology", size: 24, color: MED_GREY, font: "Calibri" })]
}),
blankLine(), blankLine(),
new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({ text: "Based on Physiology Practical Charts (123 pages)", size: 20, color: MED_GREY, font: "Calibri", italics: true })]
}),
new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({ text: "Prepared: July 2026", size: 20, color: MED_GREY, font: "Calibri" })]
}),
blankLine(), blankLine(), blankLine(),
new Paragraph({ pageBreakBefore: true, children: [new TextRun("")] })
];
// ─── SECTION 1 – HEMATOLOGY ───────────────────────────────────────
const hematology = [
h1("1. HEMATOLOGY"),
h2("1.1 Red Blood Cell Indices"),
body("Red cell indices are calculated values that describe the size and hemoglobin content of RBCs. They are essential for classifying anemias."),
blankLine(),
makeTable(
["Index", "Formula", "Normal Value", "Unit"],
[
["MCV (Mean Corpuscular Volume)", "PCV × 10 / RBC count", "80 – 100", "fL"],
["MCH (Mean Corpuscular Hemoglobin)", "Hb × 10 / RBC count", "27 – 32", "pg"],
["MCHC (Mean Corpuscular Hb Conc.)", "Hb × 100 / PCV", "32 – 36", "%"],
["Color Index", "(Hb% / 100) ÷ (RBC / 5)", "0.9 – 1.1", "—"],
]
),
blankLine(),
highlightBox("⚠ Key Fact – Why MCHC Cannot Exceed 38%",
"Hemoglobin concentration inside RBCs cannot physically exceed its solubility limit in water (~36–38%). Above this level, Hb would precipitate, destroying the cell. Hence MCHC > 38% is physiologically impossible. MCHC is the most reliable index because it is independent of RBC count."),
blankLine(),
h2("1.2 Sample Calculation – MCH & MCV"),
body("Given: Hb = 14.5 g/dL | RBC = 4.8 million/mm³ | PCV = 42%"),
keyval("MCV", "42 × 10 ÷ 4.8 = 87.5 fL (Normal)"),
keyval("MCH", "14.5 × 10 ÷ 4.8 = 30.2 pg (Normal)"),
keyval("MCHC", "14.5 × 100 ÷ 42 = 34.5% (Normal)"),
blankLine(),
h2("1.3 Classification of Anemia by Red Cell Indices"),
makeTable(
["Type", "MCV", "MCH", "MCHC", "Example"],
[
["Microcytic hypochromic", "Low", "Low", "Low", "Iron deficiency anemia"],
["Normocytic normochromic", "Normal", "Normal", "Normal", "Hemolytic anemia, aplastic"],
["Macrocytic normochromic", "High", "Normal/High", "Normal", "B12/Folate deficiency"],
["Microcytic normochromic", "Low", "Normal", "High/Normal", "Thalassemia trait"],
]
),
blankLine(),
h2("1.4 Leukocyte (WBC) Counts"),
h3("Total Leukocyte Count (TLC)"),
keyval("Normal TLC", "4,000 – 11,000 /mm³"),
bullet("Leukocytosis (>11,000): infection, inflammation, leukemia"),
bullet("Leukopenia (<4,000): viral infections, bone marrow suppression"),
blankLine(),
h3("Differential Leukocyte Count (DLC) – Normal Ranges"),
makeTable(
["Cell Type", "Normal %", "Absolute Count /mm³", "Primary Function"],
[
["Neutrophils", "40 – 75%", "2,000 – 7,500", "First-line bacterial defense, phagocytosis"],
["Lymphocytes", "20 – 45%", "1,000 – 4,800", "Adaptive immunity (T & B cells)"],
["Monocytes", "2 – 10%", "200 – 1,000", "Phagocytosis, antigen presentation"],
["Eosinophils", "1 – 6%", "40 – 400", "Allergy, anti-parasitic"],
["Basophils", "0 – 1%", "0 – 100", "Allergic response (IgE receptors)"],
]
),
blankLine(),
h3("Absolute Eosinophil Count – Sample Calculation"),
body("Given: TLC = 6,000/mm³ | Eosinophils = 15%"),
keyval("Absolute Eosinophil Count", "6,000 × 15/100 = 900/mm³ (Elevated – eosinophilia)"),
blankLine(),
makeTable(
["Condition", "Effect on Eosinophils"],
[
["Allergic diseases (asthma, hay fever)", "Eosinophilia ↑"],
["Parasitic infections", "Eosinophilia ↑"],
["Cushing's syndrome / steroid use", "Eosinopenia ↓"],
["Acute bacterial infections", "Eosinopenia ↓"],
]
),
blankLine(),
h2("1.5 Bleeding Time & Blood Grouping"),
keyval("Normal Bleeding Time (Ivy method)", "1 – 9 minutes"),
keyval("Prolonged bleeding time suggests", "Thrombocytopenia, platelet dysfunction, von Willebrand disease"),
blankLine(),
body("ABO Blood Group System:", { bold: true }),
makeTable(
["Blood Group", "Antigens on RBC", "Antibodies in Plasma", "Can Donate To", "Can Receive From"],
[
["A", "A", "Anti-B", "A, AB", "A, O"],
["B", "B", "Anti-A", "B, AB", "B, O"],
["AB (Universal recipient)", "A & B", "None", "AB only", "A, B, AB, O"],
["O (Universal donor)", "None", "Anti-A & Anti-B", "A, B, AB, O", "O only"],
]
),
blankLine(),
h2("1.6 Hemoglobin Estimation"),
keyval("Normal Hb (Male)", "13.5 – 17.5 g/dL"),
keyval("Normal Hb (Female)", "12.0 – 16.0 g/dL"),
bullet("Methods: Sahli's (acid hematin), Cyanmethemoglobin (reference), Lovibond comparator"),
blankLine(),
];
// ─── SECTION 2 – CARDIOVASCULAR ───────────────────────────────────
const cardiovascular = [
h1("2. CARDIOVASCULAR PHYSIOLOGY"),
h2("2.1 Properties of Cardiac Muscle"),
body("The kymograph chart (Early diastole / Late diastole) demonstrates three key properties:"),
keyval("a – Extrasystole", "Premature contraction occurring when the ventricle is stimulated during the relative refractory period (relaxation phase)."),
keyval("b – Compensatory Pause", "The pause following an extrasystole. The next regular impulse arrives during the extrasystole's refractory period, fails to evoke a response, causing a pause."),
keyval("c – Treppe / Staircase Phenomenon", "Progressive increase in contraction strength when stimuli are delivered at increasing frequency. Due to accumulation of Ca²⁺ in the sarcoplasm."),
blankLine(),
h3("Refractory Periods of Cardiac Muscle"),
makeTable(
["Period", "Duration", "Response to 2nd Stimulus", "Clinical Significance"],
[
["Absolute Refractory Period (ARP)", "250 msec", "No response – regardless of strength", "Cardiac muscle CANNOT be tetanized (unlike skeletal muscle)"],
["Relative Refractory Period (RRP)", "50 msec", "Responds only to supramaximal stimulus", "Extrasystole can occur here"],
]
),
blankLine(),
highlightBox("Key Point – Why Heart Cannot Tetanize",
"ARP of cardiac muscle (250 msec) is almost as long as the contraction itself (~300 msec). This prevents summation and tetany, ensuring the heart relaxes fully between beats to allow refilling."),
blankLine(),
h3("Factors Predisposing to Extrasystole"),
bullet("Excess caffeine, alcohol, or tobacco"),
bullet("Anxiety / sympathetic overdrive"),
bullet("Hyperthyroidism"),
bullet("Hypoxia"),
bullet("Electrolyte imbalance (esp. K⁺, Ca²⁺)"),
keyval("Normal", "2–4 extrasystoles/minute"),
keyval("Clinically significant", ">6/minute or in a diseased heart (e.g., myocardial infarction)"),
blankLine(),
h2("2.2 Cardiac Output – Fick's Principle"),
body("Fick's principle states that cardiac output (CO) = O₂ consumption per minute ÷ arteriovenous O₂ difference."),
blankLine(),
highlightBox("Formula",
"CO (mL/min) = O₂ consumption (mL/min) ÷ [Arterial O₂ content – Venous O₂ content (mL/100mL)] × 100"),
blankLine(),
h3("Sample Calculation (from charts):"),
body("Given: O₂ content of mixed venous blood = 14.8 mL/100mL | Arterial O₂ = 19.5 mL/100mL | HR = 70/min | O₂ consumption = 245 mL/min"),
keyval("A-V O₂ difference", "19.5 – 14.8 = 4.7 mL/100mL"),
keyval("Cardiac Output", "245 ÷ 4.7 × 100 = 5,213 mL/min ≈ 5.2 L/min (Normal)"),
keyval("Stroke Volume", "CO ÷ HR = 5,213 ÷ 70 = 74 mL (Normal: 60–80 mL)"),
blankLine(),
h3("Another Calculation Set (from page 100):"),
body("Given: Pulmonary artery O₂ = 14 mL/dL | Brachial artery O₂ = 19 mL/dL | O₂ consumption = 250 mL/min"),
keyval("Cardiac Output", "250 ÷ 5 × 100 = 5,000 mL/min = 5 L/min"),
blankLine(),
makeTable(
["Parameter", "Normal Value"],
[
["Cardiac Output (CO)", "4.5 – 5.5 L/min"],
["Stroke Volume (SV)", "60 – 80 mL/beat"],
["Heart Rate (HR)", "60 – 100 beats/min"],
["Cardiac Index", "2.5 – 3.5 L/min/m²"],
["Ejection Fraction", "55 – 70%"],
]
),
blankLine(),
h3("Factors Affecting Cardiac Output"),
bullet("Preload (Frank-Starling law)", "Increased venous return → increased CO"),
bullet("Afterload", "Increased aortic pressure → decreased CO"),
bullet("Contractility (inotropy)", "Catecholamines, digoxin → increased CO"),
bullet("Heart rate", "Tachycardia (up to a point) → increased CO"),
blankLine(),
h2("2.3 Blood Pressure"),
makeTable(
["Category", "Systolic (mmHg)", "Diastolic (mmHg)"],
[
["Normal", "< 120", "< 80"],
["Elevated", "120 – 129", "< 80"],
["Hypertension Stage 1", "130 – 139", "80 – 89"],
["Hypertension Stage 2", "≥ 140", "≥ 90"],
["Hypotension", "< 90", "< 60"],
]
),
blankLine(),
keyval("Mean Arterial Pressure (MAP)", "Diastolic + 1/3 (Pulse Pressure) OR (SBP + 2×DBP) ÷ 3"),
body("Postural hypotension = fall of ≥20 mmHg systolic or ≥10 mmHg diastolic on standing."),
blankLine(),
h2("2.4 Stannius Ligature Experiment"),
body("Demonstrates the pacemaker hierarchy of the frog heart:"),
makeTable(
["Ligature", "Position", "Effect on Heart", "Explains"],
[
["I (between SA & AV nodes)", "SA-AV junction", "Ventricle stops briefly, then restarts slowly", "Ventricle has inherent automaticity (40/min)"],
["II (AV junction only)", "AV groove", "Ventricle beats at 40/min; atria at 60+/min", "AV node pacemaker rate = 40–60/min"],
["Normalization", "—", "Regular rhythm resumes", "SA node dominates as fastest pacemaker"],
]
),
blankLine(),
h2("2.5 Electrocardiography (ECG)"),
makeTable(
["Wave/Interval", "Represents", "Normal Duration/Amplitude"],
[
["P wave", "Atrial depolarization", "< 0.12 sec, < 2.5 mm"],
["PR interval", "AV conduction time", "0.12 – 0.20 sec"],
["QRS complex", "Ventricular depolarization", "0.06 – 0.10 sec, 5–25 mm"],
["ST segment", "Plateau of ventricular AP", "Isoelectric (±1 mm)"],
["T wave", "Ventricular repolarization", "Upright in I, II, V4–V6"],
["QT interval", "Ventricular systole", "0.35 – 0.45 sec (rate corrected)"],
]
),
blankLine(),
];
// ─── SECTION 3 – RESPIRATORY ──────────────────────────────────────
const respiratory = [
h1("3. RESPIRATORY PHYSIOLOGY"),
h2("3.1 Dyspneic Index"),
body("The dyspneic index (DI) is the ratio of resting pulmonary ventilation to maximum voluntary ventilation, expressed as a percentage."),
highlightBox("Formula",
"Dyspneic Index (%) = (Resting Pulmonary Ventilation ÷ Maximum Voluntary Ventilation) × 100"),
blankLine(),
h3("Sample Calculation:"),
body("Given: Resting PV = 6 L/min | MVV = 100 L/min"),
keyval("Dyspneic Index", "6 ÷ 100 × 100 = 6% (Normal < 25%)"),
blankLine(),
makeTable(
["Term", "Definition", "Normal Value"],
[
["Resting Pulmonary Ventilation", "Tidal volume × respiratory rate at rest", "≈ 6 L/min (500 mL × 12/min)"],
["Maximum Voluntary Ventilation (MVV)", "Max air breathed in 12–15 sec, extrapolated to 1 min", "120 – 180 L/min (males)"],
["Dyspneic Index", "% of breathing reserve used at rest", "< 25% (normal)"],
]
),
blankLine(),
bullet("Obstructive disorders (asthma, COPD)", "MVV reduced → DI elevated"),
bullet("Restrictive disorders (fibrosis, kyphoscoliosis)", "MVV reduced due to reduced compliance"),
blankLine(),
h2("3.2 Physiological Dead Space (Bohr Equation)"),
body("Dead space is the portion of each breath that does not participate in gas exchange."),
highlightBox("Bohr Formula",
"VD = VT × (PaCO₂ – PECO₂) ÷ PaCO₂"),
blankLine(),
h3("Sample Calculation:"),
body("Given: Tidal Volume (VT) = 450 mL | Alveolar PCO₂ = 40 mmHg | Expired PCO₂ = 26 mmHg"),
keyval("Physiological Dead Space", "450 × (40 – 26) ÷ 40 = 450 × 0.35 = 157.5 mL"),
keyval("Alveolar Ventilation", "450 – 157.5 = 292.5 mL/breath"),
blankLine(),
makeTable(
["Type of Dead Space", "Definition", "Normal Volume"],
[
["Anatomical Dead Space", "Volume of conducting airways (nose to terminal bronchioles)", "150 mL (≈ 2 mL/kg body weight)"],
["Alveolar Dead Space", "Alveoli ventilated but not perfused", "Minimal in health"],
["Physiological Dead Space", "Anatomical + Alveolar (Bohr equation)", "≈ 150 mL (= anatomical in health)"],
]
),
blankLine(),
h3("Factors That Increase Dead Space:"),
bullet("Pulmonary embolism (↑ alveolar dead space)"),
bullet("Positive pressure ventilation"),
bullet("Sitting or standing posture (vs supine)"),
bullet("Emphysema – loss of alveolar walls"),
bullet("Increased tidal volume (more anatomical dead space ventilated)"),
blankLine(),
h2("3.3 Respiratory Quotient (RQ)"),
body("From page 98 data: Expired air volume = 30 L in 8 minutes | CO₂% in expired air = 4% | O₂ consumed in 6 min = 1,410 mL"),
highlightBox("Formula",
"RQ = CO₂ produced ÷ O₂ consumed"),
makeTable(
["Substrate", "RQ Value"],
[
["Carbohydrates", "1.0"],
["Fats", "0.7"],
["Proteins", "0.8"],
["Mixed diet (normal)", "0.85"],
]
),
blankLine(),
h2("3.4 Spirometry Parameters"),
makeTable(
["Parameter", "Definition", "Normal Value (Male)"],
[
["Tidal Volume (TV)", "Air in/out per normal breath", "500 mL"],
["Inspiratory Reserve Volume (IRV)", "Extra air inhaled above TV", "3,000 mL"],
["Expiratory Reserve Volume (ERV)", "Extra air exhaled beyond TV", "1,100 mL"],
["Residual Volume (RV)", "Air remaining after max expiration", "1,200 mL"],
["Vital Capacity (VC)", "IRV + TV + ERV", "4,600 mL"],
["Total Lung Capacity (TLC)", "VC + RV", "5,800 mL"],
["FEV₁/FVC ratio", "Obstructive vs restrictive differentiator", "> 80% (normal)"],
]
),
blankLine(),
];
// ─── SECTION 4 – RENAL ────────────────────────────────────────────
const renal = [
h1("4. RENAL PHYSIOLOGY"),
h2("4.1 Glomerular Filtration Rate (GFR)"),
body("GFR is the volume of plasma filtered by the glomeruli per minute. It is the best overall measure of kidney function."),
highlightBox("Clearance Formula (Inulin)",
"GFR = (U × V) ÷ P\n U = concentration of inulin in urine (mg/mL)\n V = urine flow rate (mL/min)\n P = plasma concentration of inulin (mg/mL)"),
blankLine(),
h3("Sample Calculation (Page 91):"),
body("Given: Plasma inulin = 0.24 mg/mL | Urine inulin = 34 mg/mL | Urine flow = 0.9 mL/min"),
keyval("GFR", "(34 × 0.9) ÷ 0.24 = 30.6 ÷ 0.24 = 127.5 mL/min (Normal)"),
blankLine(),
makeTable(
["Parameter", "Normal Value"],
[
["GFR (male)", "125 mL/min (180 L/day)"],
["GFR (female)", "110 mL/min"],
["Filtration Fraction", "GFR/RPF = 125/625 = 0.20 (20%)"],
]
),
blankLine(),
h3("Factors Affecting GFR:"),
bullet("Hydrostatic pressure in glomerular capillaries (↑ = ↑ GFR)"),
bullet("Oncotic (osmotic) pressure in glomerular capillaries (↑ = ↓ GFR)"),
bullet("Hydrostatic pressure in Bowman's capsule (↑ = ↓ GFR)"),
bullet("Renal blood flow (↑ = ↑ GFR)"),
bullet("Filtration surface area – podocyte function"),
blankLine(),
h2("4.2 Net Filtration Pressure (Starling Forces)"),
h3("Sample Calculation (Page 47):"),
body("Given: Hydrostatic pressure in glomerulus = 60 mmHg | Bowman's capsule HP = 15 mmHg | Plasma oncotic pressure = 30 mmHg | Filtrate oncotic pressure = 0 mmHg"),
keyval("Net Filtration Pressure", "(60 – 15 – 30 + 0) = +15 mmHg (Favours filtration)"),
blankLine(),
makeTable(
["Force", "Effect on Filtration", "Value (example)"],
[
["Glomerular hydrostatic pressure", "Promotes ↑", "60 mmHg"],
["Bowman's capsule hydrostatic pressure", "Opposes ↓", "15 mmHg"],
["Glomerular oncotic pressure", "Opposes ↓", "30 mmHg"],
["Filtrate oncotic pressure", "Promotes ↑", "~0 mmHg"],
]
),
blankLine(),
h2("4.3 Transport Maximum for Glucose (TmG)"),
body("TmG is the maximum rate at which glucose can be reabsorbed by the renal tubules per minute."),
highlightBox("Formula",
"TmG = (GFR × Plasma glucose) – (Urine glucose × Urine flow rate)\n [All values in consistent units: mg/min]"),
blankLine(),
h3("Sample Calculation (Page 25):"),
body("Given: Plasma glucose = 300 mg/dL = 3 mg/mL | GFR = 100 mL/min | Urine glucose = 10 mg/mL | Urine flow = 1 mL/min"),
keyval("Filtered load of glucose", "3 mg/mL × 100 mL/min = 300 mg/min"),
keyval("Excreted glucose", "10 mg/mL × 1 mL/min = 10 mg/min"),
keyval("TmG", "300 – 10 = 290 mg/min (Normal TmG = 320 mg/min)"),
blankLine(),
makeTable(
["Parameter", "Value"],
[
["Normal TmG", "320 mg/min (male), 300 mg/min (female)"],
["Renal threshold for glucose", "180 mg/dL plasma glucose"],
["Clinical significance", "Glucosuria in diabetes when plasma glucose > renal threshold"],
["Splay", "Difference between theoretical and actual glucose threshold due to nephron heterogeneity"],
]
),
blankLine(),
h2("4.4 Renal Clearance"),
keyval("Definition", "Volume of plasma completely cleared of a substance per minute"),
keyval("Formula", "C = (U × V) ÷ P"),
makeTable(
["Substance", "Clearance", "Significance"],
[
["Inulin", "= GFR (125 mL/min)", "Reference for GFR measurement"],
["Creatinine", "≈ 120–130 mL/min", "Clinical GFR estimate (slightly overestimates)"],
["PAH (para-aminohippuric acid)", "≈ 625 mL/min (= RPF)", "Measures effective renal plasma flow"],
["Glucose", "= 0 (completely reabsorbed)", "—"],
["Urea", "≈ 75 mL/min (partial reabsorption)", "—"],
]
),
blankLine(),
];
// ─── SECTION 5 – NEUROLOGY / CLINICAL ─────────────────────────────
const neurology = [
h1("5. NEUROLOGY & CLINICAL PHYSIOLOGY"),
h2("5.1 Deep Tendon Reflexes (DTRs)"),
makeTable(
["Reflex", "Nerve Root", "Peripheral Nerve", "Technique"],
[
["Biceps jerk", "C5, C6", "Musculocutaneous", "Tap biceps tendon at elbow"],
["Triceps jerk", "C7, C8", "Radial nerve", "Tap triceps tendon above olecranon"],
["Supinator (brachioradialis) jerk", "C5, C6", "Radial nerve", "Tap styloid process of radius"],
["Knee jerk (patellar)", "L3, L4", "Femoral nerve", "Tap patellar tendon below patella"],
["Ankle jerk (Achilles)", "S1, S2", "Sciatic/tibial nerve", "Tap Achilles tendon above heel"],
["Plantar reflex", "L5, S1, S2", "Tibial nerve", "Stroke lateral sole of foot"],
]
),
blankLine(),
makeTable(
["Grade", "Response"],
[
["0 (absent)", "No response even with reinforcement"],
["1+ (diminished)", "Present but reduced – LMN lesion suspect"],
["2+ (normal)", "Normal brisk response"],
["3+ (increased)", "Brisk, slightly increased"],
["4+ (hyperreflexia)", "Clonus, UMN lesion suspect"],
]
),
blankLine(),
highlightBox("Plantar Reflex (Babinski Sign)",
"Normal (adults): Downward (flexor) plantar response – all toes flex.\nAbnormal (Babinski +ve): Big toe extends upward + fan-out of other toes.\nBabinski +ve indicates UPPER MOTOR NEURON lesion (e.g., stroke, MS, spinal cord injury).\nNormal in infants up to 18 months."),
blankLine(),
h2("5.2 Motor System Examination"),
h3("Components:"),
bullet("Inspection", "Wasting, fasciculations, abnormal movements, posture"),
bullet("Tone", "Resistance to passive movement – compare both sides"),
subbullet("Hypotonia – LMN lesion, cerebellar disease"),
subbullet("Hypertonia (spasticity) – UMN lesion; (rigidity) – extrapyramidal"),
bullet("Power", "MRC Scale 0–5 for each muscle group"),
bullet("Reflexes", "DTRs + plantar reflex"),
bullet("Co-ordination", "Finger-nose, heel-shin, dysdiadochokinesis"),
blankLine(),
makeTable(
["MRC Grade", "Definition"],
[
["0", "No contraction"],
["1", "Flicker or trace of contraction"],
["2", "Movement with gravity eliminated"],
["3", "Movement against gravity but not resistance"],
["4", "Movement against resistance (mild–moderate)"],
["5", "Normal power"],
]
),
blankLine(),
h2("5.3 Sensory System Examination"),
makeTable(
["Modality", "Pathway", "Method of Testing"],
[
["Light touch", "Dorsal column + spinothalamic", "Cotton wool"],
["Pain (pinprick)", "Spinothalamic tract", "Pin / Neurotip"],
["Temperature", "Spinothalamic tract", "Hot/cold tubes"],
["Vibration sense", "Dorsal column (posterior)", "128 Hz tuning fork on bony prominences"],
["Proprioception (joint position)", "Dorsal column", "Move finger/toe up or down – patient identifies"],
["2-point discrimination", "Dorsal column (cortical)", "Calipers"],
]
),
blankLine(),
h2("5.4 Cranial Nerve Examination (I–XII)"),
makeTable(
["CN", "Name", "Function", "Test"],
[
["I", "Olfactory", "Smell", "Each nostril separately with aromatic substances"],
["II", "Optic", "Vision", "Visual acuity (Snellen), visual fields, fundoscopy"],
["III", "Oculomotor", "Eye movement (up/in/down), ptosis, pupil", "EOM, pupil size & reflexes"],
["IV", "Trochlear", "Downward/inward eye movement", "Superior oblique – downgaze"],
["V", "Trigeminal", "Face sensation, mastication", "Cotton/pin to three divisions; jaw jerk"],
["VI", "Abducens", "Lateral eye movement", "Lateral gaze – lateral rectus"],
["VII", "Facial", "Facial expression, taste (ant 2/3)", "Forehead wrinkle, eye close, smile, puff cheeks"],
["VIII", "Vestibulocochlear", "Hearing, balance", "Rinne, Weber; Romberg"],
["IX", "Glossopharyngeal", "Taste (post 1/3), gag", "Gag reflex, taste posterior tongue"],
["X", "Vagus", "Palate, pharynx, vocal cords", "Say 'Ahh', check palate rise"],
["XI", "Accessory", "Trapezius, SCM", "Shoulder shrug, head turn against resistance"],
["XII", "Hypoglossal", "Tongue movement", "Tongue protrusion – deviates to side of lesion in LMN"],
]
),
blankLine(),
h2("5.5 General Physical Examination"),
h3("Order of Examination:"),
bullet("General appearance: built, nourishment, pallor, jaundice, cyanosis, edema, clubbing, lymphadenopathy"),
bullet("Vital signs: pulse (rate, rhythm, character, volume), BP, RR, temperature"),
bullet("Radial pulse assessment:", "Rate, rhythm, volume, character, radio-radial delay, radio-femoral delay"),
blankLine(),
makeTable(
["Pulse Character", "Condition"],
[
["Collapsing (water-hammer)", "Aortic regurgitation"],
["Pulsus paradoxus (↓ >10 mmHg on inspiration)", "Cardiac tamponade, severe asthma"],
["Plateau (pulsus tardus et parvus)", "Aortic stenosis"],
["Pulsus alternans", "Left ventricular failure"],
["Pulsus bisferiens", "Combined AS + AR, HOCM"],
]
),
blankLine(),
];
// ─── SECTION 6 – SPECIAL TESTS ────────────────────────────────────
const specialTests = [
h1("6. SPECIAL TESTS & INSTRUMENTS"),
h2("6.1 Perimetry"),
body("Perimetry maps the visual field of each eye. It tests CN II (optic nerve) and the visual pathway."),
bullet("Confrontation method – gross screening at bedside"),
bullet("Goldman perimeter – kinetic perimetry (standard clinical)"),
bullet("Humphrey automated perimeter – static threshold perimetry"),
blankLine(),
makeTable(
["Visual Field Defect", "Site of Lesion"],
[
["Monocular blindness", "Optic nerve (pre-chiasm)"],
["Bitemporal hemianopia", "Optic chiasm (e.g., pituitary adenoma)"],
["Homonymous hemianopia", "Optic tract / radiation / cortex"],
["Quadrantanopia (pie in the sky)", "Temporal lobe (Meyer's loop)"],
]
),
blankLine(),
h2("6.2 Mosso's Ergography"),
body("An ergograph records the work done by a muscle (usually the middle finger flexors) over time, demonstrating:"),
bullet("Fatigue curve – progressive decrease in contraction height"),
bullet("Recovery – height restoration after rest"),
bullet("Factors affecting fatigue: blood flow, metabolic waste accumulation (lactic acid), depletion of ATP/CP"),
blankLine(),
h2("6.3 Spirometry"),
body("Spirometry measures lung volumes and capacities using a bell/wedge spirometer or electronic flow sensor."),
makeTable(
["Pattern", "FVC", "FEV₁", "FEV₁/FVC", "Example"],
[
["Normal", "Normal", "Normal", "> 80%", "—"],
["Obstructive", "Normal/↓", "↓↓", "< 70%", "Asthma, COPD"],
["Restrictive", "↓↓", "↓", "> 80%", "Fibrosis, obesity"],
]
),
blankLine(),
];
// ─── SECTION 7 – QUICK REVISION TABLES ────────────────────────────
const quickRevision = [
h1("7. QUICK REVISION – NORMAL VALUES REFERENCE"),
makeTable(
["Parameter", "Normal Value"],
[
["Hb (male)", "13.5 – 17.5 g/dL"],
["Hb (female)", "12.0 – 16.0 g/dL"],
["RBC (male)", "4.5 – 5.5 million/mm³"],
["RBC (female)", "3.8 – 5.0 million/mm³"],
["PCV/Hematocrit (male)", "40 – 54%"],
["PCV (female)", "37 – 47%"],
["TLC (WBC)", "4,000 – 11,000 /mm³"],
["Platelet count", "1.5 – 4.0 × 10⁵ /mm³"],
["Bleeding time", "1 – 9 minutes"],
["Clotting time", "5 – 11 minutes"],
["ESR (male, Westergren)", "0 – 15 mm/hr"],
["ESR (female)", "0 – 20 mm/hr"],
["MCV", "80 – 100 fL"],
["MCH", "27 – 32 pg"],
["MCHC", "32 – 36%"],
["Blood pH", "7.35 – 7.45"],
["PaO₂", "80 – 100 mmHg"],
["PaCO₂", "35 – 45 mmHg"],
["HCO₃⁻", "22 – 26 mEq/L"],
["O₂ saturation (arterial)", "95 – 100%"],
["GFR", "125 mL/min (male)"],
["Renal plasma flow", "625 mL/min"],
["Filtration fraction", "20%"],
["TmG", "320 mg/min"],
["Cardiac output", "4.5 – 5.5 L/min"],
["Stroke volume", "60 – 80 mL"],
["Blood pressure (normal)", "< 120/80 mmHg"],
["MAP", "70 – 105 mmHg"],
["Tidal volume", "500 mL"],
["Vital capacity", "4,600 mL (male)"],
["FEV₁/FVC", "> 80%"],
["MVV", "120 – 180 L/min"],
["Dyspneic index", "< 25%"],
["Anatomical dead space", "150 mL"],
]
),
blankLine(),
];
// ─── ASSEMBLE DOCUMENT ────────────────────────────────────────────
const doc = new Document({
creator: "Physiology Study Guide Generator",
title: "Physiology Practical Study Guide",
description: "Comprehensive study guide for physiology practical exams",
styles: {
default: {
document: {
run: { font: "Calibri", size: 20, color: DARK_TEXT }
}
}
},
numbering: {
config: [{
reference: "bullet-list",
levels: [
{ level: 0, format: LevelFormat.BULLET, text: "\u2022", alignment: AlignmentType.LEFT,
style: { paragraph: { indent: { left: convertInchesToTwip(0.3), hanging: convertInchesToTwip(0.2) } } } },
{ level: 1, format: LevelFormat.BULLET, text: "\u25CB", alignment: AlignmentType.LEFT,
style: { paragraph: { indent: { left: convertInchesToTwip(0.6), hanging: convertInchesToTwip(0.2) } } } }
]
}]
},
sections: [{
properties: {
page: {
margin: { top: 1080, bottom: 1080, left: 1080, right: 1080 }
}
},
headers: {
default: new Header({
children: [new Paragraph({
alignment: AlignmentType.RIGHT,
border: { bottom: { style: BorderStyle.SINGLE, size: 3, color: "CCCCCC" } },
children: [new TextRun({ text: "PHYSIOLOGY PRACTICAL STUDY GUIDE", size: 16, color: MED_GREY, font: "Calibri" })]
})]
})
},
footers: {
default: new Footer({
children: [new Paragraph({
alignment: AlignmentType.CENTER,
border: { top: { style: BorderStyle.SINGLE, size: 3, color: "CCCCCC" } },
children: [
new TextRun({ text: "Page ", size: 16, color: MED_GREY }),
new TextRun({ children: [PageNumber.CURRENT], size: 16, color: MED_GREY }),
new TextRun({ text: " of ", size: 16, color: MED_GREY }),
new TextRun({ children: [PageNumber.TOTAL_PAGES], size: 16, color: MED_GREY }),
]
})]
})
},
children: [
...titlePage,
...hematology,
new Paragraph({ pageBreakBefore: true, children: [new TextRun("")] }),
...cardiovascular,
new Paragraph({ pageBreakBefore: true, children: [new TextRun("")] }),
...respiratory,
new Paragraph({ pageBreakBefore: true, children: [new TextRun("")] }),
...renal,
new Paragraph({ pageBreakBefore: true, children: [new TextRun("")] }),
...neurology,
new Paragraph({ pageBreakBefore: true, children: [new TextRun("")] }),
...specialTests,
new Paragraph({ pageBreakBefore: true, children: [new TextRun("")] }),
...quickRevision,
]
}]
});
Packer.toBuffer(doc).then(buf => {
const out = "/home/daytona/workspace/physiology-charts/Physiology_Practical_Study_Guide.docx";
fs.writeFileSync(out, buf);
console.log("Created:", out);
console.log("Size:", (buf.length / 1024).toFixed(1) + " KB");
});
cd /home/daytona/workspace/physiology-charts && node create_study_guide.js
cd /home/daytona/workspace/physiology-charts && python /home/daytona/skills/docx/scripts/office/validate.py Physiology_Practical_Study_Guide.docx
# Validate by opening the docx as zip and checking document.xml exists python3 -c " import zipfile, os path = '/home/daytona/workspace/physiology-charts/Physiology_Practical_Study_Guide.docx' with zipfile.ZipFile(path) as z: names = z.namelist() print('Files:', names[:10]) doc_xml = z.read('word/document.xml') print('document.xml size:', len(doc_xml), 'bytes') print('Valid DOCX structure:', 'word/document.xml' in names) print('File size:', os.path.getsize(path), 'bytes') "
Physiology Practical Study Guide
Word Document · DOCX
Convert it into pdf format
python3 /home/daytona/skills/docx/scripts/office/soffice.py --headless --convert-to pdf /home/daytona/workspace/physiology-charts/Physiology_Practical_Study_Guide.docx --outdir /home/daytona/workspace/physiology-charts/
# Try outputting to /tmp first then copy python3 /home/daytona/skills/docx/scripts/office/soffice.py --headless --convert-to pdf /home/daytona/workspace/physiology-charts/Physiology_Practical_Study_Guide.docx --outdir /tmp/ && cp /tmp/Physiology_Practical_Study_Guide.pdf /home/daytona/workspace/physiology-charts/ && ls -lh /home/daytona/workspace/physiology-charts/Physiology_Practical_Study_Guide.pdf
Physiology Practical Study Guide
PDF Document · PDF