polyguard-openenv / app /simulator /patient_generator.py
TheJackBright's picture
Deploy PolyGuard OpenEnv Space
877add7 verified
"""Synthetic patient generation."""
from __future__ import annotations
import random
from app.common.enums import Difficulty, DoseBucket
from app.common.types import LabSummary, Medication, PatientProfile
_DRUG_POOL = [
("warfarin_like", "anticoagulant"),
("benzodiazepine_like", "sedative"),
("metformin_like", "glucose_lowering"),
("statin_like", "lipid_lowering"),
("ace_inhibitor_like", "antihypertensive"),
("nsaid_like", "analgesic"),
("opioid_like", "analgesic"),
("ssri_like", "antidepressant"),
("ppi_like", "gastro"),
("beta_blocker_like", "antihypertensive"),
]
def generate_patient_profile(seed: int, difficulty: Difficulty, patient_id: str | None = None) -> PatientProfile:
random.seed(seed)
med_count = {Difficulty.EASY: 5, Difficulty.MEDIUM: 8, Difficulty.HARD: 10}[difficulty]
selected = random.sample(_DRUG_POOL, k=med_count)
medications = [
Medication(
drug=drug,
class_name=cls,
dose_bucket=random.choice([DoseBucket.LOW, DoseBucket.MEDIUM, DoseBucket.HIGH]),
indication=f"indication_{idx}",
requires_taper=drug in {"benzodiazepine_like", "opioid_like"},
)
for idx, (drug, cls) in enumerate(selected)
]
return PatientProfile(
patient_id=patient_id or f"patient_{seed}",
age=random.randint(55, 90),
sex=random.choice(["F", "M"]),
comorbidities=random.sample(
["htn", "dm2", "afib", "ckd", "copd", "depression", "fall_risk"], k=3
),
medications=medications,
labs=LabSummary(
egfr=round(random.uniform(20, 95), 1),
ast=round(random.uniform(10, 120), 1),
alt=round(random.uniform(10, 120), 1),
inr=round(random.uniform(1.0, 4.0), 2),
glucose=round(random.uniform(70, 280), 1),
),
vitals={
"sbp": random.randint(100, 180),
"dbp": random.randint(60, 105),
"hr": random.randint(50, 120),
"egfr_trend": round(random.uniform(-8.0, 3.0), 2),
"inr_trend": round(random.uniform(-0.5, 0.7), 2),
"glucose_trend": round(random.uniform(-35.0, 45.0), 2),
},
specialist_conflicts=[
"duplicate_analgesic_strategy",
"cardio_vs_pain_med_conflict",
]
if difficulty != Difficulty.EASY
else [],
prior_ade_history=["fall_event", "sedation_event"] if difficulty == Difficulty.HARD else [],
frailty_score=round(random.uniform(0.1, 0.9), 2),
adherence_estimate=round(random.uniform(0.4, 0.95), 2),
latent_confounders={
"metabolism_variability": round(random.uniform(0.1, 0.9), 3),
"social_support_risk": round(random.uniform(0.0, 1.0), 3),
"polyprovider_fragmentation": round(random.uniform(0.1, 0.95), 3),
},
monitoring_gaps=["no_recent_inr", "missing_liver_panel"] if difficulty == Difficulty.HARD else ["missing_followup_bp"],
)