Doctor clinical sheets of case asthma

Asking for Preferences

Realife feeling doctor sheets

Reading File
Reading File
Running Command

mkdir -p /tmp/workspace/asthma-clinical-sheet && ls /tmp/workspace/asthma-clinical-sheet/

Writing File

~/asthma-clinical-sheet/create_sheet.py

from docx import Document
from docx.shared import Pt, Inches, RGBColor, Cm
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
import copy

doc = Document()

# ── Page margins ──
section = doc.sections[0]
section.page_width  = Cm(21)
section.page_height = Cm(29.7)
section.top_margin    = Cm(1.5)
section.bottom_margin = Cm(1.5)
section.left_margin   = Cm(2.0)
section.right_margin  = Cm(2.0)

# ── Helper: set cell background ──
def set_cell_bg(cell, hex_color):
    tc   = cell._tc
    tcPr = tc.get_or_add_tcPr()
    shd  = OxmlElement('w:shd')
    shd.set(qn('w:val'),   'clear')
    shd.set(qn('w:color'), 'auto')
    shd.set(qn('w:fill'),  hex_color)
    tcPr.append(shd)

# ── Helper: set cell borders ──
def set_cell_border(cell, top=None, bottom=None, left=None, right=None):
    tc   = cell._tc
    tcPr = tc.get_or_add_tcPr()
    tcBorders = OxmlElement('w:tcBorders')
    for side, val in [('top', top), ('bottom', bottom), ('left', left), ('right', right)]:
        if val:
            el = OxmlElement(f'w:{side}')
            el.set(qn('w:val'),   val.get('val',   'single'))
            el.set(qn('w:sz'),    val.get('sz',    '4'))
            el.set(qn('w:space'), val.get('space', '0'))
            el.set(qn('w:color'), val.get('color', '000000'))
            tcBorders.append(el)
    tcPr.append(tcBorders)

# ── Helper: paragraph spacing ──
def para_space(p, before=0, after=0, line=None):
    pPr  = p._p.get_or_add_pPr()
    spng = OxmlElement('w:spacing')
    spng.set(qn('w:before'), str(before))
    spng.set(qn('w:after'),  str(after))
    if line:
        spng.set(qn('w:line'),     str(line))
        spng.set(qn('w:lineRule'), 'auto')
    pPr.append(spng)

def add_run(para, text, bold=False, italic=False, size=10, color=None, underline=False):
    run = para.add_run(text)
    run.bold      = bold
    run.italic    = italic
    run.underline = underline
    run.font.size = Pt(size)
    run.font.name = 'Arial'
    if color:
        run.font.color.rgb = RGBColor(*color)
    return run

# ══════════════════════════════════════════════
#  HOSPITAL HEADER
# ══════════════════════════════════════════════
hosp_table = doc.add_table(rows=1, cols=3)
hosp_table.style = 'Table Grid'
hosp_table.alignment = WD_TABLE_ALIGNMENT.CENTER

# Left cell – Hospital name
lc = hosp_table.cell(0, 0)
set_cell_bg(lc, '1A3A5C')
lc.width = Inches(2.8)
lp = lc.paragraphs[0]
lp.alignment = WD_ALIGN_PARAGRAPH.CENTER
add_run(lp, 'CITY GENERAL HOSPITAL', bold=True, size=13, color=(255,255,255))
lp.add_run('\n')
add_run(lp, 'Department of Respiratory Medicine', bold=False, size=8.5, color=(200,220,255))
para_space(lp, before=80, after=80)

# Centre cell – Red Cross / logo placeholder
cc = hosp_table.cell(0, 1)
set_cell_bg(cc, '1A3A5C')
cc.width = Inches(0.9)
cp = cc.paragraphs[0]
cp.alignment = WD_ALIGN_PARAGRAPH.CENTER
add_run(cp, '✚', bold=True, size=22, color=(220, 50, 50))
para_space(cp, before=60, after=60)

# Right cell – form title
rc = hosp_table.cell(0, 2)
set_cell_bg(rc, '0E2540')
rc.width = Inches(2.8)
rp = rc.paragraphs[0]
rp.alignment = WD_ALIGN_PARAGRAPH.CENTER
add_run(rp, 'ASTHMA CLINICAL CASE SHEET', bold=True, size=11, color=(255, 220, 50))
rp.add_run('\n')
add_run(rp, 'Form No: RES-AST-001  |  Rev: 3.0', size=7.5, color=(180, 200, 230))
para_space(rp, before=80, after=80)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  SECTION helper
# ══════════════════════════════════════════════
def section_heading(doc, title, icon=''):
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.LEFT
    para_space(p, before=60, after=40)
    add_run(p, f'  {icon}  {title}  ', bold=True, size=10, color=(255,255,255))
    # Blue bar background via paragraph shading
    pPr  = p._p.get_or_add_pPr()
    shd  = OxmlElement('w:shd')
    shd.set(qn('w:val'),   'clear')
    shd.set(qn('w:color'), 'auto')
    shd.set(qn('w:fill'),  '1A3A5C')
    pPr.append(shd)
    return p

def field_row(table, row_idx, label, value='', label_bg='EBF1F8', value_bg='FFFFFF'):
    r = table.rows[row_idx]
    lc_cell = r.cells[0]
    vc_cell = r.cells[1]
    set_cell_bg(lc_cell, label_bg)
    set_cell_bg(vc_cell, value_bg)
    lp = lc_cell.paragraphs[0]
    add_run(lp, label, bold=True, size=9, color=(30,60,100))
    para_space(lp, before=40, after=40)
    vp = vc_cell.paragraphs[0]
    add_run(vp, value, size=9)
    para_space(vp, before=40, after=40)

# ══════════════════════════════════════════════
#  1. PATIENT DEMOGRAPHICS
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 1 — PATIENT DEMOGRAPHICS', '👤')
dem = doc.add_table(rows=6, cols=4)
dem.style = 'Table Grid'
dem.alignment = WD_TABLE_ALIGNMENT.CENTER

labels = [
    ['Patient Name:', 'Ahmed Al-Rashidi', 'MR Number:', 'MR-2026-08847'],
    ['Date of Birth:', '14 / 03 / 1989', 'Age:', '37 years'],
    ['Gender:', 'Male   ☑       Female   ☐', 'Nationality:', 'Saudi Arabian'],
    ['Contact:', '+966 55 234 7890', 'Emergency Contact:', 'Fatima Al-Rashidi (wife)'],
    ['Address:', 'Villa 12, Al-Rawdah District, Riyadh', 'Occupation:', 'School Teacher'],
    ['Insurance:', 'Bupa Arabia — Policy #BP-94512', 'Attending Physician:', 'Dr. Khalid Al-Otaibi, MD'],
]

for ri, row in enumerate(labels):
    for ci in range(0, 4, 2):
        cell_l = dem.cell(ri, ci)
        cell_v = dem.cell(ri, ci+1)
        set_cell_bg(cell_l, 'D6E4F0')
        set_cell_bg(cell_v, 'FFFFFF')
        pl = cell_l.paragraphs[0]
        pv = cell_v.paragraphs[0]
        add_run(pl, row[ci],   bold=True, size=8.5, color=(20,50,100))
        add_run(pv, row[ci+1], size=8.5)
        para_space(pl, before=40, after=40)
        para_space(pv, before=40, after=40)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  2. VISIT INFORMATION
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 2 — VISIT INFORMATION', '📋')
vis = doc.add_table(rows=3, cols=4)
vis.style = 'Table Grid'
vis.alignment = WD_TABLE_ALIGNMENT.CENTER

vis_data = [
    ['Date of Visit:', '19 / 07 / 2026', 'Visit Type:', 'Acute Follow-Up'],
    ['Time:', '09:15 AM', 'Referred By:', 'Emergency Dept.'],
    ['Previous Visits:', '3 (last: 14/04/2026)', 'Allergies Documented:', 'Yes — see Allergy section'],
]
for ri, row in enumerate(vis_data):
    for ci in range(0, 4, 2):
        cl = vis.cell(ri, ci);  cv = vis.cell(ri, ci+1)
        set_cell_bg(cl, 'D6E4F0'); set_cell_bg(cv, 'FFFFFF')
        pl = cl.paragraphs[0];  pv = cv.paragraphs[0]
        add_run(pl, row[ci],   bold=True, size=8.5, color=(20,50,100))
        add_run(pv, row[ci+1], size=8.5)
        para_space(pl, before=40, after=40); para_space(pv, before=40, after=40)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  3. CHIEF COMPLAINT & HISTORY OF PRESENT ILLNESS
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 3 — CHIEF COMPLAINT & HISTORY OF PRESENT ILLNESS', '🩺')
cc_table = doc.add_table(rows=5, cols=2)
cc_table.style = 'Table Grid'
cc_table.alignment = WD_TABLE_ALIGNMENT.CENTER
cc_table.columns[0].width = Cm(4.5)
cc_table.columns[1].width = Cm(12)

cc_data = [
    ('Chief Complaint:', 'Progressive dyspnoea, wheezing, and chest tightness × 3 days'),
    ('Onset & Duration:', 'Gradual onset 3 days ago; worsening over past 24 hours'),
    ('Precipitating Factors:', 'Exposure to dust (classroom renovation) + recent URTI (5 days ago)'),
    ('Associated Symptoms:', 'Dry cough (worse at night), mild rhinorrhoea, no fever, no haemoptysis, no chest pain'),
    ('Relieving Factors:', 'Partial relief with salbutamol puffer (4 puffs used in last 12 h)'),
]
for ri, (lbl, val) in enumerate(cc_data):
    cl = cc_table.cell(ri, 0); cv = cc_table.cell(ri, 1)
    set_cell_bg(cl, 'D6E4F0'); set_cell_bg(cv, 'FFFFFF')
    pl = cl.paragraphs[0]; pv = cv.paragraphs[0]
    add_run(pl, lbl, bold=True, size=8.5, color=(20,50,100))
    add_run(pv, val, size=8.5)
    para_space(pl, before=40, after=40); para_space(pv, before=40, after=40)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  4. PAST MEDICAL & FAMILY HISTORY
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 4 — PAST MEDICAL, SURGICAL & FAMILY HISTORY', '📜')
hx_table = doc.add_table(rows=4, cols=2)
hx_table.style = 'Table Grid'
hx_table.columns[0].width = Cm(4.5)
hx_table.columns[1].width = Cm(12)

hx_data = [
    ('Past Medical Hx:', 'Bronchial asthma (diagnosed 2014) | Allergic rhinitis (2016) | No T2DM | No HTN'),
    ('Surgical Hx:', 'Appendicectomy (2008) — uneventful | No thoracic surgeries'),
    ('Family Hx:', 'Mother: asthma + eczema | Father: allergic rhinitis | No TB, no malignancy'),
    ('Social Hx:', 'Non-smoker | No alcohol | Lives with wife + 2 children | No pets | Teaches indoor classes'),
]
for ri, (lbl, val) in enumerate(hx_data):
    cl = hx_table.cell(ri, 0); cv = hx_table.cell(ri, 1)
    set_cell_bg(cl, 'D6E4F0'); set_cell_bg(cv, 'FFFFFF')
    pl = cl.paragraphs[0]; pv = cv.paragraphs[0]
    add_run(pl, lbl, bold=True, size=8.5, color=(20,50,100))
    add_run(pv, val, size=8.5)
    para_space(pl, before=40, after=40); para_space(pv, before=40, after=40)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  5. CURRENT MEDICATIONS & ALLERGIES
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 5 — CURRENT MEDICATIONS & ALLERGIES', '💊')
med_tbl = doc.add_table(rows=1, cols=5)
med_tbl.style = 'Table Grid'

headers = ['Drug Name', 'Dose', 'Route', 'Frequency', 'Duration']
for ci, h in enumerate(headers):
    cell = med_tbl.cell(0, ci)
    set_cell_bg(cell, '1A3A5C')
    p = cell.paragraphs[0]
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    add_run(p, h, bold=True, size=9, color=(255,255,255))
    para_space(p, before=40, after=40)

meds = [
    ['Budesonide / Formoterol (Symbicort 200/6)', '1 puff', 'Inhaled', 'BD', 'Ongoing'],
    ['Salbutamol (Ventolin) — Reliever', '100 mcg / puff', 'Inhaled', 'PRN', 'As needed'],
    ['Montelukast (Singulair)', '10 mg', 'Oral', 'Nocte', 'Ongoing'],
    ['Normal Saline nasal spray', '2 sprays each nostril', 'Intranasal', 'BD', 'PRN rhinitis'],
]
for med in meds:
    row = med_tbl.add_row()
    for ci, val in enumerate(med):
        cell = row.cells[ci]
        set_cell_bg(cell, 'FFFFFF')
        p = cell.paragraphs[0]
        add_run(p, val, size=8.5)
        para_space(p, before=30, after=30)

# Allergies
doc.add_paragraph()
alg_tbl = doc.add_table(rows=2, cols=4)
alg_tbl.style = 'Table Grid'
alg_headers = ['Allergen', 'Type', 'Reaction', 'Severity']
for ci, h in enumerate(alg_headers):
    cell = alg_tbl.cell(0, ci)
    set_cell_bg(cell, 'C0392B')
    p = cell.paragraphs[0]
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    add_run(p, h, bold=True, size=9, color=(255,255,255))
    para_space(p, before=40, after=40)

alg_data = ['Aspirin / NSAIDs', 'Drug', 'Bronchospasm, urticaria', '⚠ HIGH — Avoid']
for ci, val in enumerate(alg_data):
    cell = alg_tbl.cell(1, ci)
    set_cell_bg(cell, 'FDECEA')
    p = cell.paragraphs[0]
    add_run(p, val, size=8.5, bold=(ci==3), color=(180,0,0) if ci==3 else (0,0,0))
    para_space(p, before=30, after=30)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  6. PHYSICAL EXAMINATION
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 6 — PHYSICAL EXAMINATION', '🔬')

# Vitals
vitals_p = doc.add_paragraph()
add_run(vitals_p, 'VITAL SIGNS', bold=True, size=9, color=(20,50,100))
para_space(vitals_p, before=40, after=20)

vit_tbl = doc.add_table(rows=2, cols=7)
vit_tbl.style = 'Table Grid'
vit_headers = ['Temp (°C)', 'HR (bpm)', 'RR (/min)', 'BP (mmHg)', 'SpO₂ (%)', 'Peak Flow (L/min)', 'Weight (kg)']
vit_vals    = ['37.1', '102', '24', '124/78', '93% (room air)', '240  ← 60% predicted', '74']
for ci, h in enumerate(vit_headers):
    cell = vit_tbl.cell(0, ci); set_cell_bg(cell, '2471A3')
    p = cell.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    add_run(p, h, bold=True, size=8, color=(255,255,255)); para_space(p, before=30, after=30)
for ci, v in enumerate(vit_vals):
    cell = vit_tbl.cell(1, ci)
    color = 'FFD7D7' if ci in [1,2,4,5] else 'FFFFFF'
    set_cell_bg(cell, color)
    p = cell.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    is_abn = ci in [1,2,4,5]
    add_run(p, v, size=8.5, bold=is_abn, color=(180,0,0) if is_abn else (0,0,0))
    para_space(p, before=30, after=30)

doc.add_paragraph()

# Systems exam
sys_tbl = doc.add_table(rows=6, cols=2)
sys_tbl.style = 'Table Grid'
sys_tbl.columns[0].width = Cm(4)
sys_tbl.columns[1].width = Cm(12.5)

sys_data = [
    ('General:', 'Alert, conscious, oriented. In mild-moderate respiratory distress. Sitting upright. Using accessory muscles. Speaking in full sentences.'),
    ('Respiratory:', 'Chest: hyperinflated. Bilateral diffuse expiratory wheeze on auscultation. Prolonged expiratory phase. No crepitations. Percussion: resonant bilaterally. Trachea midline.'),
    ('Cardiovascular:', 'Regular rate and rhythm. S1 S2 heard. No murmurs. No JVP elevation. Capillary refill < 2 sec.'),
    ('Abdomen:', 'Soft, non-tender. No organomegaly. Bowel sounds normal.'),
    ('ENT / Head-Neck:', 'Nasal mucosa mildly congested. No nasal polyps. Pharynx mildly erythematous. Tonsils normal. No cervical lymphadenopathy.'),
    ('Skin:', 'No eczema, no urticaria. No cyanosis. No clubbing.'),
]
for ri, (lbl, val) in enumerate(sys_data):
    cl = sys_tbl.cell(ri, 0); cv = sys_tbl.cell(ri, 1)
    set_cell_bg(cl, 'D6E4F0'); set_cell_bg(cv, 'FFFFFF')
    pl = cl.paragraphs[0]; pv = cv.paragraphs[0]
    add_run(pl, lbl, bold=True, size=8.5, color=(20,50,100))
    add_run(pv, val, size=8.5)
    para_space(pl, before=40, after=40); para_space(pv, before=40, after=40)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  7. SEVERITY ASSESSMENT (GINA)
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 7 — ASTHMA SEVERITY ASSESSMENT (GINA 2024)', '⚠')

sev_tbl = doc.add_table(rows=2, cols=5)
sev_tbl.style = 'Table Grid'
sev_cols = ['Criterion', 'Mild', 'Moderate', 'Severe', 'Life-Threatening']
sev_colors = ['D6E4F0', 'D4EFDF', 'FCF3CF', 'FDECEA', 'F9EBEA']
for ci, (h, col) in enumerate(zip(sev_cols, sev_colors)):
    cell = sev_tbl.cell(0, ci); set_cell_bg(cell, '1A3A5C')
    p = cell.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    add_run(p, h, bold=True, size=8.5, color=(255,255,255)); para_space(p, before=30, after=30)

checks = ['GINA Parameters', '—', '✔ THIS PATIENT', '—', '—']
row_data = [
    'SpO₂ > 95% / 92-95% / <92% / <90%',
    'PEF > 80%',
    'PEF 60–80% predicted',
    'PEF <60%',
    'Pulsus paradoxus'
]
for ci, val in enumerate(checks):
    cell = sev_tbl.cell(1, ci)
    bg = 'FCF3CF' if ci == 2 else 'FFFFFF'
    set_cell_bg(cell, bg)
    p = cell.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    bold = ci == 2
    color = (180,0,0) if ci == 2 else (0,0,0)
    add_run(p, val, bold=bold, size=9, color=color)
    para_space(p, before=30, after=30)

verdict_p = doc.add_paragraph()
para_space(verdict_p, before=40, after=40)
add_run(verdict_p, '  ASSESSMENT: ', bold=True, size=10, color=(255,255,255))
add_run(verdict_p, '  MODERATE ACUTE ASTHMA EXACERBATION  ', bold=True, size=10, color=(180,0,0))
pPr = verdict_p._p.get_or_add_pPr()
shd = OxmlElement('w:shd'); shd.set(qn('w:val'),'clear'); shd.set(qn('w:color'),'auto'); shd.set(qn('w:fill'),'FFF9C4')
pPr.append(shd)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  8. INVESTIGATIONS
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 8 — INVESTIGATIONS ORDERED / RESULTS', '🔭')

inv_tbl = doc.add_table(rows=1, cols=4)
inv_tbl.style = 'Table Grid'
inv_headers = ['Investigation', 'Result', 'Normal Range', 'Interpretation']
for ci, h in enumerate(inv_headers):
    cell = inv_tbl.cell(0, ci); set_cell_bg(cell, '1A3A5C')
    p = cell.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    add_run(p, h, bold=True, size=9, color=(255,255,255)); para_space(p, before=30, after=30)

inv_data = [
    ['SpO₂ (pulse oximetry)', '93%', '95–100%', '⬇ Low — supplemental O₂ initiated'],
    ['Peak Expiratory Flow (PEF)', '240 L/min', '400 L/min predicted', '⬇ 60% of predicted — Moderate'],
    ['ABG (Arterial Blood Gas)', 'pH 7.44 | PaO₂ 72 | PaCO₂ 34', '7.35–7.45 | 80–100 | 35–45', 'Mild hypoxaemia; resp alkalosis'],
    ['CXR (Chest X-ray)', 'Hyperinflation; no consolidation; no pneumothorax', '—', 'Consistent with acute asthma'],
    ['FBC (Full Blood Count)', 'WBC 9.8 × 10⁹/L; Eos 0.6 (6%)', 'WBC 4–11 × 10⁹/L; Eos <5%', '⬆ Eosinophilia — allergic component'],
    ['Serum IgE', '480 IU/mL', '< 100 IU/mL', '⬆ Elevated — atopic asthma'],
    ['ECG', 'Sinus tachycardia — rate 102/min', 'Normal sinus rhythm', 'Tachycardia (response to hypoxia/SABA)'],
    ['Spirometry (pre-bronchodilator)', 'FEV₁ 62% predicted; FEV₁/FVC 0.64', '> 80% predicted; > 0.70', '⬇ Obstructive pattern'],
    ['Spirometry (post-bronchodilator)', 'FEV₁ 78% predicted; +16% change', '< 12% change = irreversible', '✔ Reversible obstruction confirmed'],
]
for row in inv_data:
    trow = inv_tbl.add_row()
    for ci, val in enumerate(row):
        cell = trow.cells[ci]
        abn = '⬇' in val or '⬆' in val
        set_cell_bg(cell, 'FFF5F5' if abn else 'FFFFFF')
        p = cell.paragraphs[0]
        col = (160,0,0) if abn else (0,0,0)
        add_run(p, val, size=8, color=col)
        para_space(p, before=25, after=25)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  9. DIAGNOSIS
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 9 — DIAGNOSIS', '✅')
dx_tbl = doc.add_table(rows=3, cols=2)
dx_tbl.style = 'Table Grid'
dx_tbl.columns[0].width = Cm(4)
dx_tbl.columns[1].width = Cm(12.5)
dx_data = [
    ('Primary Diagnosis:', 'Moderate acute exacerbation of bronchial asthma (ICD-10: J45.41)'),
    ('Secondary Diagnosis:', 'Allergic rhinitis (J30.1) | Viral-triggered exacerbation (URTI)'),
    ('Differential Diagnoses:', 'COPD exacerbation (less likely — age, non-smoker) | Vocal cord dysfunction | Pulmonary embolism (excluded by clinical picture)'),
]
for ri, (lbl, val) in enumerate(dx_data):
    cl = dx_tbl.cell(ri, 0); cv = dx_tbl.cell(ri, 1)
    set_cell_bg(cl, 'D6E4F0'); set_cell_bg(cv, 'FFFFFF')
    pl = cl.paragraphs[0]; pv = cv.paragraphs[0]
    add_run(pl, lbl, bold=True, size=8.5, color=(20,50,100))
    add_run(pv, val, size=8.5)
    para_space(pl, before=40, after=40); para_space(pv, before=40, after=40)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  10. TREATMENT PLAN
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 10 — MANAGEMENT & TREATMENT PLAN', '💉')

# Immediate management
imm_p = doc.add_paragraph()
add_run(imm_p, 'A. IMMEDIATE MANAGEMENT (Emergency Bay)', bold=True, size=9, color=(20,50,100))
para_space(imm_p, before=40, after=20)

imm_tbl = doc.add_table(rows=1, cols=4)
imm_tbl.style = 'Table Grid'
for ci, h in enumerate(['Intervention', 'Dose / Detail', 'Route', 'Time Given']):
    cell = imm_tbl.cell(0, ci); set_cell_bg(cell, '2E86C1')
    p = cell.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    add_run(p, h, bold=True, size=8.5, color=(255,255,255)); para_space(p, before=30, after=30)

imm_rows = [
    ['Oxygen therapy', '4 L/min via nasal cannula — target SpO₂ > 95%', 'Inhalation', '09:20 AM'],
    ['Salbutamol nebulisation', '5 mg in 3 mL normal saline — repeat × 3 q20min', 'Nebulised', '09:22 AM'],
    ['Ipratropium bromide', '500 mcg — mixed with salbutamol (first 3 doses)', 'Nebulised', '09:22 AM'],
    ['Prednisolone (oral)', '50 mg stat — then 40 mg OD × 5 days', 'Oral', '09:30 AM'],
    ['Magnesium sulphate IV', '2 g in 100 mL NS over 20 min (if poor response)', 'IV infusion', 'PRN / 10:00 AM'],
]
for row in imm_rows:
    trow = imm_tbl.add_row()
    for ci, val in enumerate(row):
        cell = trow.cells[ci]; set_cell_bg(cell, 'FFFFFF')
        p = cell.paragraphs[0]
        add_run(p, val, size=8.5); para_space(p, before=25, after=25)

doc.add_paragraph()

# Step-up therapy
stu_p = doc.add_paragraph()
add_run(stu_p, 'B. STEP-UP MAINTENANCE THERAPY (GINA Step 3 → Step 4)', bold=True, size=9, color=(20,50,100))
para_space(stu_p, before=40, after=20)

step_tbl = doc.add_table(rows=1, cols=4)
step_tbl.style = 'Table Grid'
for ci, h in enumerate(['Drug', 'Dose', 'Frequency', 'Notes']):
    cell = step_tbl.cell(0, ci); set_cell_bg(cell, '2E86C1')
    p = cell.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    add_run(p, h, bold=True, size=8.5, color=(255,255,255)); para_space(p, before=30, after=30)

step_rows = [
    ['Budesonide/Formoterol 400/12 (upgraded)', '1 puff BD', 'Twice daily', 'Step-up from 200/6 — reassess in 4 weeks'],
    ['Montelukast (continue)', '10 mg nocte', 'Once daily at night', 'Leukotriene receptor antagonist'],
    ['Salbutamol (reliever)', 'PRN (max 4 puffs/day)', 'As needed', 'If using > 2×/week → reassess control'],
    ['Chlorpheniramine (antihistamine)', '4 mg TDS PRN', 'PRN for rhinitis', 'Short-term for allergic symptoms'],
]
for row in step_rows:
    trow = step_tbl.add_row()
    for ci, val in enumerate(row):
        cell = trow.cells[ci]; set_cell_bg(cell, 'FFFFFF')
        p = cell.paragraphs[0]
        add_run(p, val, size=8.5); para_space(p, before=25, after=25)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  11. PATIENT EDUCATION & ACTION PLAN
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 11 — PATIENT EDUCATION & ASTHMA ACTION PLAN', '📚')

edu_tbl = doc.add_table(rows=4, cols=2)
edu_tbl.style = 'Table Grid'
edu_tbl.columns[0].width = Cm(4.5)
edu_tbl.columns[1].width = Cm(12)

edu_data = [
    ('GREEN Zone\n(PEF > 80%)', 'Continue regular preventer. Reliever only if needed. Maintain normal activities.'),
    ('YELLOW Zone\n(PEF 60–80%)', 'Increase reliever to 2–4 puffs q4h. Start prednisolone 40 mg/day. Contact clinic within 24h.'),
    ('RED Zone\n(PEF < 60%)', '4–8 puffs salbutamol immediately. Call family. Go to Emergency NOW. Do not drive alone.'),
    ('Education Given:', 'Inhaler technique demonstrated (spacer use). Avoidance of triggers. Importance of preventer compliance. Written action plan provided. Asthma diary issued.'),
]
edu_bg = ['D4EFDF','FCF3CF','FDECEA','E8F5E9']
for ri, ((lbl, val), bg) in enumerate(zip(edu_data, edu_bg)):
    cl = edu_tbl.cell(ri, 0); cv = edu_tbl.cell(ri, 1)
    set_cell_bg(cl, bg); set_cell_bg(cv, 'FFFFFF')
    pl = cl.paragraphs[0]; pv = cv.paragraphs[0]
    add_run(pl, lbl, bold=True, size=8.5, color=(20,50,100))
    add_run(pv, val, size=8.5)
    para_space(pl, before=50, after=50); para_space(pv, before=50, after=50)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  12. FOLLOW-UP & MONITORING
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 12 — FOLLOW-UP, MONITORING & DISPOSITION', '📅')
fup_tbl = doc.add_table(rows=4, cols=2)
fup_tbl.style = 'Table Grid'
fup_tbl.columns[0].width = Cm(4.5)
fup_tbl.columns[1].width = Cm(12)

fup_data = [
    ('Disposition:', 'Admit to Short Stay Unit (SSU) for 6–12 h observation — reassess at 2h and 4h post-nebulisation'),
    ('Discharge Criteria:', 'SpO₂ ≥ 95% on room air | PEF ≥ 70% predicted | Respiratory rate < 20/min | No accessory muscle use'),
    ('Follow-up:', 'Respiratory clinic in 1 week (26/07/2026). GP review in 48 h after discharge. Spirometry + FeNO test in 4 weeks.'),
    ('Referrals:', 'Allergy & Immunology referral for allergen skin testing. Consider biologics (dupilumab/mepolizumab) if Step 4 fails.'),
]
for ri, (lbl, val) in enumerate(fup_data):
    cl = fup_tbl.cell(ri, 0); cv = fup_tbl.cell(ri, 1)
    set_cell_bg(cl, 'D6E4F0'); set_cell_bg(cv, 'FFFFFF')
    pl = cl.paragraphs[0]; pv = cv.paragraphs[0]
    add_run(pl, lbl, bold=True, size=8.5, color=(20,50,100))
    add_run(pv, val, size=8.5)
    para_space(pl, before=40, after=40); para_space(pv, before=40, after=40)

doc.add_paragraph()

# ══════════════════════════════════════════════
#  13. PHYSICIAN SIGNATURE
# ══════════════════════════════════════════════
section_heading(doc, 'SECTION 13 — PHYSICIAN SIGN-OFF', '✍')
sig_tbl = doc.add_table(rows=2, cols=3)
sig_tbl.style = 'Table Grid'
sig_headers = ['Attending Physician', 'Resident / Intern', 'Nurse In-Charge']
for ci, h in enumerate(sig_headers):
    cell = sig_tbl.cell(0, ci); set_cell_bg(cell, 'D6E4F0')
    p = cell.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    add_run(p, h, bold=True, size=9, color=(20,50,100)); para_space(p, before=40, after=40)

sig_vals = [
    'Dr. Khalid Al-Otaibi, MD\nConsultant Pulmonologist\nSign: _______________\nDate: 19/07/2026',
    'Dr. Sara Mahmoud, MBBCh\nPGY-2 Internal Medicine\nSign: _______________\nDate: 19/07/2026',
    'Nurse Hana Al-Zahrani, RN\nRespiratory Ward\nSign: _______________\nDate: 19/07/2026',
]
for ci, val in enumerate(sig_vals):
    cell = sig_tbl.cell(1, ci); set_cell_bg(cell, 'FFFFFF')
    p = cell.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    add_run(p, val, size=8.5); para_space(p, before=60, after=60)

# ── Footer note ──
doc.add_paragraph()
ft = doc.add_paragraph()
ft.alignment = WD_ALIGN_PARAGRAPH.CENTER
add_run(ft, 'CONFIDENTIAL — For authorized medical personnel only  |  City General Hospital — Respiratory Medicine  |  Form RES-AST-001  |  GINA 2024 Guidelines', size=7, color=(120,120,120), italic=True)

# ── Save ──
out = '/tmp/workspace/asthma-clinical-sheet/Asthma_Clinical_Case_Sheet.docx'
doc.save(out)
print(f'Saved: {out}')
Running Command

python3 /tmp/workspace/asthma-clinical-sheet/create_sheet.py

Your realistic asthma clinical case sheet is ready. Download it here:

Asthma Clinical Case Sheet

Word Document · DOCX


Here is everything included in the sheet - 13 sections styled like a real hospital document:
SectionContents
HeaderHospital name, department, form number, red cross logo
1. Patient DemographicsName, MR#, DOB, gender, insurance, attending physician
2. Visit InformationDate, time, visit type, referral source
3. Chief Complaint & HPIDyspnoea, wheezing, precipitating factors, timeline
4. Past Medical / Family HxAsthma Dx 2014, allergic rhinitis, family atopy
5. Medications & AllergiesSymbicort, Ventolin, Montelukast + Aspirin allergy (red-flagged)
6. Physical ExaminationVital signs table (abnormals highlighted in red), full systems exam
7. Severity AssessmentGINA 2024 grid - classified as Moderate Acute Exacerbation
8. InvestigationsSpO₂, PEF, ABG, CXR, FBC, IgE, ECG, spirometry with results & interpretation
9. DiagnosisPrimary + secondary + differentials with ICD-10 codes
10. Treatment PlanImmediate ER management (O₂, nebulisers, steroids, MgSO₄) + step-up maintenance
11. Action PlanGreen / Yellow / Red zone instructions + patient education checklist
12. Follow-upDischarge criteria, clinic dates, specialist referrals
13. Sign-offAttending consultant, resident, and nurse signature blocks
The formatting uses a navy-blue hospital colour scheme with red alerts for abnormal values, exactly like a real clinical document.

Which app this application open

The file is a .docx (Word document). You can open it with any of these apps:

📱 On Mobile (Phone/Tablet)

AppPlatformFree?
Microsoft WordAndroid & iPhoneFree (basic)
WPS OfficeAndroid & iPhoneFree
Google DocsAndroid & iPhoneFree
OnlyOfficeAndroid & iPhoneFree

💻 On Computer (Desktop/Laptop)

AppPlatformFree?
Microsoft WordWindows & MacPaid (Office 365)
Google DocsAny browserFree
LibreOffice WriterWindows, Mac, LinuxFree
WPS OfficeWindows & MacFree
PagesMac / iPhoneFree

✅ Easiest & Fastest Option

Google Docs - completely free, no install needed:
  1. Go to docs.google.com
  2. Click the folder icon → Upload the .docx file
  3. It opens instantly in your browser

The .docx format is the most universal document format in the world - almost any office app on any device will open it correctly.
This is a shared conversation. Sign in to Orris to start your own chat.