updated features to reduce "Bouncing" from in and out of warning zones
This commit is contained in:
parent
7cf5510401
commit
4cd0ac3fee
Binary file not shown.
@ -11,6 +11,7 @@ from datetime import datetime, timedelta
|
|||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from triage_engine import TriageEngine, VitalSigns, TriageLevel, triage_from_vitals
|
from triage_engine import TriageEngine, VitalSigns, TriageLevel, triage_from_vitals
|
||||||
|
|
||||||
@ -105,6 +106,8 @@ class QueuePosition(BaseModel):
|
|||||||
|
|
||||||
patients_db: Dict[str, Patient] = {}
|
patients_db: Dict[str, Patient] = {}
|
||||||
vitals_history: Dict[str, List[VitalsData]] = defaultdict(list)
|
vitals_history: Dict[str, List[VitalsData]] = defaultdict(list)
|
||||||
|
# Tier stability tracking
|
||||||
|
tier_trackers: Dict[str, Dict] = {} # patient_id -> tracker info
|
||||||
available_bands = [
|
available_bands = [
|
||||||
f"VitalLink-{hex(i)[2:].upper().zfill(4)}" for i in range(0x1000, 0x2000)
|
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")
|
@app.post("/api/vitals")
|
||||||
async def receive_vitals(data: VitalsData):
|
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
|
patient_id = data.patient_id
|
||||||
|
|
||||||
@ -212,7 +215,19 @@ async def receive_vitals(data: VitalsData):
|
|||||||
|
|
||||||
patient = patients_db[patient_id]
|
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(
|
vitals = VitalSigns(
|
||||||
heart_rate=data.hr_bpm,
|
heart_rate=data.hr_bpm,
|
||||||
spo2=data.spo2,
|
spo2=data.spo2,
|
||||||
@ -220,10 +235,73 @@ async def receive_vitals(data: VitalsData):
|
|||||||
activity=data.activity,
|
activity=data.activity,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Quick tier assessment
|
# Determine suggested tier
|
||||||
tier = triage_from_vitals(data.hr_bpm, data.spo2, data.temp_c)
|
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()
|
patient.last_vitals = data.dict()
|
||||||
|
|
||||||
# Store in history
|
# Store in history
|
||||||
@ -243,17 +321,28 @@ async def receive_vitals(data: VitalsData):
|
|||||||
print(f"⚠️ DETERIORATION DETECTED: {patient_id}")
|
print(f"⚠️ DETERIORATION DETECTED: {patient_id}")
|
||||||
print(f" Concerns: {', '.join(deterioration['concerns'])}")
|
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
|
# Broadcast update
|
||||||
await broadcast_update(
|
await broadcast_update(
|
||||||
{
|
{
|
||||||
"type": "vitals_update",
|
"type": "vitals_update",
|
||||||
"patient_id": patient_id,
|
"patient_id": patient_id,
|
||||||
"vitals": data.dict(),
|
"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")
|
@app.get("/api/queue")
|
||||||
|
|||||||
4
vitallink/logs/all_pids.txt
Normal file
4
vitallink/logs/all_pids.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
215078
|
||||||
|
215139
|
||||||
|
215153
|
||||||
|
215223
|
||||||
File diff suppressed because it is too large
Load Diff
1
vitallink/logs/backend.pid
Normal file
1
vitallink/logs/backend.pid
Normal file
@ -0,0 +1 @@
|
|||||||
|
215078
|
||||||
@ -3,7 +3,7 @@
|
|||||||
> vite
|
> vite
|
||||||
|
|
||||||
|
|
||||||
VITE v7.1.10 ready in 107 ms
|
VITE v7.1.10 ready in 104 ms
|
||||||
|
|
||||||
➜ Local: http://localhost:5173/
|
➜ Local: http://localhost:5173/
|
||||||
➜ Network: use --host to expose
|
➜ Network: use --host to expose
|
||||||
|
|||||||
1
vitallink/logs/dashboard.pid
Normal file
1
vitallink/logs/dashboard.pid
Normal file
@ -0,0 +1 @@
|
|||||||
|
215153
|
||||||
1
vitallink/logs/kiosk.pid
Normal file
1
vitallink/logs/kiosk.pid
Normal file
@ -0,0 +1 @@
|
|||||||
|
215223
|
||||||
1
vitallink/logs/wristbands.pid
Normal file
1
vitallink/logs/wristbands.pid
Normal file
@ -0,0 +1 @@
|
|||||||
|
215139
|
||||||
Loading…
x
Reference in New Issue
Block a user