Clinical scoring calculators: GCS, AVPU, APGAR, START, NEWS2, qSOFA, HEART
Project description
vitalscore
Clinical scoring calculators for Python.
vitalscore provides typed, validated implementations of the clinical scoring tools used in emergency medicine, critical care, and pre-hospital settings — all exposed as clean Python dataclasses with interpretation strings built in.
Scores included
| Score | Function | Description |
|---|---|---|
| GCS | score_gcs |
Glasgow Coma Scale (3–15) |
| AVPU | score_avpu |
Consciousness level: Alert / Voice / Pain / Unresponsive |
| APGAR | score_apgar |
Newborn assessment (0–10) |
| START | score_start |
Mass-casualty triage: Immediate / Delayed / Minor / Deceased |
| NEWS2 | score_news2 |
National Early Warning Score 2 (0–20) |
| qSOFA | score_qsofa |
Sepsis screening (0–3) |
| HEART | score_heart |
Chest pain risk stratification (0–10) |
Assessment models
| Model | Description |
|---|---|
CUPS |
Critical / Unstable / Potentially unstable / Stable |
OPQRST |
Symptom characterisation mnemonic |
SAMPLE |
Patient history mnemonic |
Installation
pip install vitalscore
Requires Python 3.10+. No external dependencies.
Quick start
from vitalscore import score_gcs, score_avpu, score_start, score_news2, score_qsofa, score_heart
from vitalscore import OPQRST, SAMPLE, CUPS, CUPSCategory
from vitalscore import batch_triage, TriagePatient
GCS — Glasgow Coma Scale
result = score_gcs(eye=2, verbal=1, motor=3)
result.total # 6
result.severity # "Severe TBI"
result.interpretation
# "Severe TBI (GCS 6) — critical, consider intubation and ICU"
print(result)
# GCS 6/15 [E2 V1 M3]
# Eye: 2 — Eye opening to pain
# Verbal: 1 — No verbal response
# Motor: 3 — Flexion to pain (decorticate)
# → Severe TBI (GCS 6) — critical, consider intubation and ICU
AVPU — Consciousness scale
result = score_avpu("P") # also accepts AVPULevel enum
result.is_critical # True
result.gcs_equivalent # "GCS ~8 (estimated)"
result.recommended_action
# "Immediate intervention; manage airway, IV access, call for help"
APGAR — Newborn score
result = score_apgar(appearance=2, pulse=2, grimace=1, activity=1, respiration=2)
result.total # 8
result.category # "Normal"
START — Mass-casualty triage
# Walking wounded → Minor (Green)
score_start(can_walk=True, respiratory_rate=18).priority
# <STARTPriority.MINOR: 'Minor'>
# Apnoeic → Deceased (Black)
score_start(can_walk=False, respiratory_rate=None).priority
# <STARTPriority.DECEASED: 'Deceased'>
# RR > 30 → Immediate (Red)
score_start(can_walk=False, respiratory_rate=35).priority
# <STARTPriority.IMMEDIATE: 'Immediate'>
# All OK → Delayed (Yellow)
score_start(
can_walk=False, respiratory_rate=20,
has_radial_pulse=True, follows_commands=True
).priority
# <STARTPriority.DELAYED: 'Delayed'>
NEWS2 — National Early Warning Score 2
result = score_news2(
respiratory_rate=22,
spo2=94.0,
on_oxygen=False,
systolic_bp=105,
heart_rate=98,
consciousness="A", # ACVPU: A / C / V / P / U
temperature=37.2,
)
result.total # 5
result.risk.value # "Medium"
result.interpretation
# "NEWS2 5 — MEDIUM risk. Urgent SpR/senior clinician review within 1 hour."
# For COPD patients (SpO₂ target 88–92%), use Scale 2:
result = score_news2(..., use_spo2_scale2=True)
qSOFA — Sepsis screening
result = score_qsofa(gcs=13, respiratory_rate=24, systolic_bp=95)
result.total # 3
result.sepsis_alert # True
result.interpretation
# "qSOFA 3/3 — SEPSIS ALERT. Urgent full SOFA assessment, blood cultures, lactate."
HEART — Chest pain risk
from vitalscore.scores.heart import HistoryScore, ECGScore, AgeScore, RiskFactorScore, TroponinScore
result = score_heart(
history=HistoryScore.HIGHLY_SUSPICIOUS,
ecg=ECGScore.SIGNIFICANT_ST_DEV,
age=AgeScore.AGE_65_UP,
risk_factors=RiskFactorScore.THREE_OR_MORE_OR_KNOWN_DISEASE,
troponin=TroponinScore.ABOVE_THREE,
)
# or pass plain integers 0–2 for each field
result.total # 10
result.risk_category # "High"
result.mace_probability # "~50–65%"
Assessment models
CUPS — Transport priority
from vitalscore import CUPS, CUPSCategory
c = CUPS(category=CUPSCategory.CRITICAL, chief_complaint="Unresponsive, no pulse")
c.transport_priority # 1
c.description # "Life-threatening condition. Immediate intervention required..."
# String input also accepted:
CUPS(category="Unstable")
OPQRST — Symptom characterisation
from vitalscore import OPQRST
pain = OPQRST(
onset="Sudden, during exertion",
quality="Crushing pressure",
radiation="Radiates to left arm and jaw",
severity=9, # 0–10 NRS
time="30 minutes",
associated="Diaphoresis, nausea",
)
print(pain.summary)
SAMPLE — Patient history
from vitalscore import SAMPLE
history = SAMPLE(
signs_symptoms="Crushing chest pain, diaphoresis",
allergies="Penicillin (anaphylaxis)",
medications="Aspirin 81 mg, Metformin 500 mg BD",
pertinent_history="HTN, T2DM, previous MI 2019",
last_oral_intake="6 hours ago",
events="Onset at rest, watching TV",
)
history.has_allergies # True
print(history)
Batch triage
Score a list of patients and receive them sorted from most to least critical.
from vitalscore import batch_triage, TriagePatient
from vitalscore.batch import format_triage_report
patients = [
TriagePatient("P1", can_walk=True, respiratory_rate=18),
TriagePatient("P2", can_walk=False, respiratory_rate=35),
TriagePatient("P3", can_walk=False, respiratory_rate=None), # apnoeic
TriagePatient("P4", can_walk=False, respiratory_rate=20,
has_radial_pulse=True, follows_commands=True),
]
sorted_pts = batch_triage(patients, method="start")
# → [P2 (Immediate), P4 (Delayed), P1 (Minor), P3 (Deceased)]
print(format_triage_report(sorted_pts))
For NEWS2 batch scoring, populate the NEWS2 fields (spo2, on_oxygen,
systolic_bp, heart_rate, consciousness, temperature) and pass method="news2".
Use method="both" to run both algorithms simultaneously.
CLI
Every score is accessible from the terminal:
# GCS
vitalscore gcs --eye 2 --verbal 1 --motor 3
# AVPU
vitalscore avpu --level P
# APGAR
vitalscore apgar --appearance 2 --pulse 2 --grimace 1 --activity 1 --respiration 2
# START triage
vitalscore start --no-walk --rr 35
vitalscore start --no-walk --rr 20 --pulse --follows-commands
# NEWS2
vitalscore news2 --rr 22 --spo2 94 --no-o2 --sbp 105 --hr 98 --acvpu A --temp 37.2
vitalscore news2 --rr 10 --spo2 89 --o2 --sbp 90 --hr 115 --acvpu V --temp 35.0 --scale2
# qSOFA
vitalscore qsofa --gcs 13 --rr 24 --sbp 95
# HEART
vitalscore heart --history 2 --ecg 1 --age 2 --risk 2 --troponin 1
Output is ANSI-coloured when run in a terminal (red for critical, yellow for urgent, green for low risk).
Input validation
All score_* functions raise a ValueError with a clear message if any input is out of range:
score_gcs(eye=0, verbal=5, motor=6)
# ValueError: Eye opening must be 1–4, got 0
score_news2(respiratory_rate=18, spo2=110.0, ...)
# ValueError: spo2 must be 50–100%, got 110.0
Project layout
vitalscore/
├── vitalscore/
│ ├── scores/ # gcs.py avpu.py apgar.py start.py
│ │ # news2.py qsofa.py heart.py
│ ├── models/ # assessment.py (CUPS, OPQRST, SAMPLE)
│ ├── batch.py # batch_triage, TriagePatient, format_triage_report
│ └── cli.py # vitalscore CLI entry point
└── tests/
└── test_scores.py # 80 unit tests
Contributing
Pull requests are welcome. Please run the test suite before submitting:
pip install -e ".[dev]"
pytest
Disclaimer
vitalscore is a software tool intended to support clinical decision-making, not replace it. Always defer to qualified medical professionals and local clinical guidelines. The authors accept no liability for patient outcomes.
License
MIT © London Chowdhury
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vitalscore-0.1.0.tar.gz.
File metadata
- Download URL: vitalscore-0.1.0.tar.gz
- Upload date:
- Size: 31.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59bf17d1d05f9dc6cacf8a1e4f7fb5289b5203a57852193196dd1ca3815add62
|
|
| MD5 |
66a7e5844695e853daf4354b220d167f
|
|
| BLAKE2b-256 |
e44db3dba3a04d3e50da8723a7b9ab4e0ffe0818d0ef00c77c57eea16a57c1e7
|
File details
Details for the file vitalscore-0.1.0-py3-none-any.whl.
File metadata
- Download URL: vitalscore-0.1.0-py3-none-any.whl
- Upload date:
- Size: 30.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28e8d272279c0b3c5e2f5bd823a2b02cfd71d7b00ee49dbed38dd85ed32025d9
|
|
| MD5 |
d6227402bc673d8aa00eca73f72f709f
|
|
| BLAKE2b-256 |
02667b4d772b42bd3bf41767baee81a9644260b5d01391c57520172df4f69397
|