updated features to reduce "Bouncing" from in and out of warning zones

This commit is contained in:
Raika Furude 2025-11-01 15:28:16 -04:00
parent 7cf5510401
commit 4cd0ac3fee
9 changed files with 1150 additions and 1515 deletions

View File

@ -11,6 +11,7 @@ from datetime import datetime, timedelta
from contextlib import asynccontextmanager
import asyncio
import json
import time
from collections import defaultdict
from triage_engine import TriageEngine, VitalSigns, TriageLevel, triage_from_vitals
@ -105,6 +106,8 @@ class QueuePosition(BaseModel):
patients_db: Dict[str, Patient] = {}
vitals_history: Dict[str, List[VitalsData]] = defaultdict(list)
# Tier stability tracking
tier_trackers: Dict[str, Dict] = {} # patient_id -> tracker info
available_bands = [
f"VitalLink-{hex(i)[2:].upper().zfill(4)}" for i in range(0x1000, 0x2000)
]
@ -203,7 +206,7 @@ async def check_in_patient(data: PatientCheckIn):
@app.post("/api/vitals")
async def receive_vitals(data: VitalsData):
"""Receive vitals data from base station"""
"""Receive vitals data from base station with tier stability"""
patient_id = data.patient_id
@ -212,7 +215,19 @@ async def receive_vitals(data: VitalsData):
patient = patients_db[patient_id]
# Use triage engine to determine tier from vitals
# Initialize tier tracker if needed
if patient_id not in tier_trackers:
tier_trackers[patient_id] = {
"current_tier": "NORMAL",
"tier_since": time.time(),
"consecutive_readings": 0,
"pending_tier": None,
"pending_count": 0,
}
tracker = tier_trackers[patient_id]
# Use triage engine to determine what tier vitals suggest
vitals = VitalSigns(
heart_rate=data.hr_bpm,
spo2=data.spo2,
@ -220,10 +235,73 @@ async def receive_vitals(data: VitalsData):
activity=data.activity,
)
# Quick tier assessment
tier = triage_from_vitals(data.hr_bpm, data.spo2, data.temp_c)
# Determine suggested tier
suggested_tier = triage_from_vitals(data.hr_bpm, data.spo2, data.temp_c)
patient.current_tier = tier
# Apply tier stability logic
current_tier = tracker["current_tier"]
time_in_tier = time.time() - tracker["tier_since"]
# Determine if tier should change
should_change = False
if suggested_tier == current_tier:
# Same tier - reset pending change
tracker["consecutive_readings"] += 1
tracker["pending_tier"] = None
tracker["pending_count"] = 0
else:
# Different tier suggested
is_upgrade = (
suggested_tier == "EMERGENCY" and current_tier in ["ALERT", "NORMAL"]
) or (suggested_tier == "ALERT" and current_tier == "NORMAL")
is_downgrade = (
suggested_tier == "NORMAL" and current_tier in ["ALERT", "EMERGENCY"]
) or (suggested_tier == "ALERT" and current_tier == "EMERGENCY")
# Track pending change
if tracker["pending_tier"] == suggested_tier:
tracker["pending_count"] += 1
else:
tracker["pending_tier"] = suggested_tier
tracker["pending_count"] = 1
# Determine if we have enough confirmations
if is_upgrade:
# Upgrade to higher tier - need 2 consecutive readings
required_confirmations = 2
min_time_required = 10.0 # 10 seconds minimum
else:
# Downgrade to lower tier - need 5 consecutive readings
required_confirmations = 5
min_time_required = 60.0 # 60 seconds minimum
# Check if we should change tier
if (
tracker["pending_count"] >= required_confirmations
and time_in_tier >= min_time_required
):
should_change = True
# Apply tier change if confirmed
if should_change:
old_tier = tracker["current_tier"]
new_tier = suggested_tier
tracker["current_tier"] = new_tier
tracker["tier_since"] = time.time()
tracker["consecutive_readings"] = 0
tracker["pending_tier"] = None
tracker["pending_count"] = 0
print(
f"🔄 TIER CHANGE: {patient_id} {old_tier}{new_tier} (confirmed after {tracker['pending_count']} readings)"
)
# Use confirmed tier
final_tier = tracker["current_tier"]
patient.current_tier = final_tier
patient.last_vitals = data.dict()
# Store in history
@ -243,17 +321,28 @@ async def receive_vitals(data: VitalsData):
print(f"⚠️ DETERIORATION DETECTED: {patient_id}")
print(f" Concerns: {', '.join(deterioration['concerns'])}")
# If deteriorating, force upgrade to at least ALERT
if final_tier == "NORMAL" and tracker["pending_tier"] != "ALERT":
tracker["pending_tier"] = "ALERT"
tracker["pending_count"] = 1
print(f" ⬆️ Escalation initiated due to deterioration")
# Broadcast update
await broadcast_update(
{
"type": "vitals_update",
"patient_id": patient_id,
"vitals": data.dict(),
"tier": tier,
"tier": final_tier,
}
)
return {"status": "received", "tier": tier}
return {
"status": "received",
"tier": final_tier,
"suggested_tier": suggested_tier,
"confirmed": suggested_tier == final_tier,
}
@app.get("/api/queue")

View File

@ -0,0 +1,4 @@
215078
215139
215153
215223

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
215078

View File

@ -3,7 +3,7 @@
> vite
VITE v7.1.10 ready in 107 ms
VITE v7.1.10 ready in 104 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose

View File

@ -0,0 +1 @@
215153

1
vitallink/logs/kiosk.pid Normal file
View File

@ -0,0 +1 @@
215223

View File

@ -0,0 +1 @@
215139