Skip to main content

Clinical scoring calculators: GCS, AVPU, APGAR, START, NEWS2, qSOFA, HEART

Project description

vitalscore

Clinical scoring calculators for Python.

PyPI version Python 3.10+ License: MIT

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vitalscore-0.1.0.tar.gz (31.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vitalscore-0.1.0-py3-none-any.whl (30.3 kB view details)

Uploaded Python 3

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

Hashes for vitalscore-0.1.0.tar.gz
Algorithm Hash digest
SHA256 59bf17d1d05f9dc6cacf8a1e4f7fb5289b5203a57852193196dd1ca3815add62
MD5 66a7e5844695e853daf4354b220d167f
BLAKE2b-256 e44db3dba3a04d3e50da8723a7b9ab4e0ffe0818d0ef00c77c57eea16a57c1e7

See more details on using hashes here.

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

Hashes for vitalscore-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 28e8d272279c0b3c5e2f5bd823a2b02cfd71d7b00ee49dbed38dd85ed32025d9
MD5 d6227402bc673d8aa00eca73f72f709f
BLAKE2b-256 02667b4d772b42bd3bf41767baee81a9644260b5d01391c57520172df4f69397

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page