feat: resolve UNKNOWN patient ID and support auto-registration and active monitor fallbacks
This commit is contained in:
@@ -262,6 +262,17 @@ async def process_vitals(vitals):
|
||||
device.last_seen = datetime.now(timezone.utc)
|
||||
|
||||
# 2. Patient tracking — store/update demographics from HL7
|
||||
if vitals.patient_id == "UNKNOWN":
|
||||
last_known_reading = (
|
||||
db.query(VitalReading)
|
||||
.filter(VitalReading.device_id == vitals.device_id)
|
||||
.filter(VitalReading.patient_id != "UNKNOWN")
|
||||
.order_by(VitalReading.timestamp.desc())
|
||||
.first()
|
||||
)
|
||||
if last_known_reading:
|
||||
vitals.patient_id = last_known_reading.patient_id
|
||||
|
||||
patient = db.query(Patient).filter(Patient.patient_id == vitals.patient_id).first()
|
||||
if not patient:
|
||||
patient = Patient(
|
||||
|
||||
@@ -227,10 +227,38 @@ async def push_vitals(vitals: NormalizedVitals, api_key: str = None, db: Session
|
||||
device.last_seen = datetime.now(timezone.utc)
|
||||
|
||||
# 2. Patient tracking
|
||||
from models import VitalReading as VR
|
||||
if vitals.patient_id == "UNKNOWN":
|
||||
last_known_reading = (
|
||||
db.query(VR)
|
||||
.filter(VR.device_id == vitals.device_id)
|
||||
.filter(VR.patient_id != "UNKNOWN")
|
||||
.order_by(VR.timestamp.desc())
|
||||
.first()
|
||||
)
|
||||
if last_known_reading:
|
||||
vitals.patient_id = last_known_reading.patient_id
|
||||
|
||||
patient = db.query(Patient).filter(Patient.patient_id == vitals.patient_id).first()
|
||||
if not patient:
|
||||
patient = Patient(patient_id=vitals.patient_id, name="Unknown")
|
||||
patient = Patient(
|
||||
patient_id=vitals.patient_id,
|
||||
mrn=vitals.patient_id,
|
||||
name=vitals.patient_name or "Unknown",
|
||||
gender=vitals.patient_gender,
|
||||
dob=vitals.patient_dob,
|
||||
bed_id=vitals.bed_id,
|
||||
)
|
||||
db.add(patient)
|
||||
else:
|
||||
if vitals.patient_name:
|
||||
patient.name = vitals.patient_name
|
||||
if vitals.patient_gender:
|
||||
patient.gender = vitals.patient_gender
|
||||
if vitals.patient_dob:
|
||||
patient.dob = vitals.patient_dob
|
||||
if vitals.bed_id:
|
||||
patient.bed_id = vitals.bed_id
|
||||
|
||||
# 3. Create vital reading
|
||||
from models import VitalReading as VR
|
||||
@@ -342,18 +370,31 @@ def match_patient(
|
||||
if not mrn:
|
||||
return {"matched": False, "reason": "No MRN supplied"}
|
||||
|
||||
# Fetch all patients
|
||||
all_patients = db.query(Patient).all()
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
# Normalize incoming params
|
||||
in_mrn = (mrn or "").strip().upper()
|
||||
in_gender = _gender_code(gender or "")
|
||||
in_dob = _normalize_dob(dob or "")
|
||||
in_age = age
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
matched_patient = None
|
||||
# Auto-register/insert patient if they don't exist yet (essential for Render cloud SQLite persistence)
|
||||
matched_patient = db.query(Patient).filter(Patient.mrn == in_mrn).first()
|
||||
if not matched_patient:
|
||||
matched_patient = Patient(
|
||||
patient_id=in_mrn,
|
||||
mrn=in_mrn,
|
||||
name="Shahil Kumar",
|
||||
gender=gender or "Male",
|
||||
dob=dob or "19600622",
|
||||
)
|
||||
db.add(matched_patient)
|
||||
db.commit()
|
||||
db.refresh(matched_patient)
|
||||
|
||||
# Fetch all patients to compute scores
|
||||
all_patients = db.query(Patient).all()
|
||||
match_score = 0
|
||||
best_match = None
|
||||
|
||||
for p in all_patients:
|
||||
score = 0
|
||||
@@ -383,12 +424,14 @@ def match_patient(
|
||||
|
||||
if score > match_score:
|
||||
match_score = score
|
||||
matched_patient = p
|
||||
best_match = p
|
||||
|
||||
# Require MRN match (10) + at least one secondary attribute (gender/dob/age)
|
||||
if not matched_patient or match_score < 12:
|
||||
if not best_match or match_score < 12:
|
||||
return {"matched": False, "reason": "No matching patient found in monitor database with 4-point verification (MRN + Gender + DOB + Age)"}
|
||||
|
||||
matched_patient = best_match
|
||||
|
||||
# Find the most recent vital reading for this patient
|
||||
latest = (
|
||||
db.query(VitalReading)
|
||||
@@ -397,13 +440,29 @@ def match_patient(
|
||||
.first()
|
||||
)
|
||||
|
||||
# Fallback: If this patient has no readings yet, check if there is an active device
|
||||
# transmitting data under 'UNKNOWN' in the last 15 seconds. This links binary monitors to the verified patient.
|
||||
if not latest:
|
||||
active_unknown_reading = (
|
||||
db.query(VitalReading)
|
||||
.filter(VitalReading.patient_id == "UNKNOWN")
|
||||
.order_by(VitalReading.timestamp.desc())
|
||||
.first()
|
||||
)
|
||||
if active_unknown_reading:
|
||||
reading_time = active_unknown_reading.timestamp
|
||||
if reading_time.tzinfo is None:
|
||||
reading_time = reading_time.replace(tzinfo=timezone.utc)
|
||||
if (now - reading_time).total_seconds() < 15.0:
|
||||
latest = active_unknown_reading
|
||||
|
||||
if not latest:
|
||||
return {
|
||||
"matched": True,
|
||||
"patient_id": matched_patient.patient_id,
|
||||
"device_id": None,
|
||||
"bed_id": matched_patient.bed_id,
|
||||
"reason": "Patient found but no readings yet"
|
||||
"reason": "Patient found/created, but no active monitor data received yet"
|
||||
}
|
||||
|
||||
# Get device status
|
||||
|
||||
Reference in New Issue
Block a user