CoolFace
Apppublic

Samvickid/pubmed-hr

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
generate_rich_data.py393 linesDownload Raw Back to root
1"""2Comprehensive Fake Data Generator — PubMed Center3Generates rich patient data: medications, procedures, labs, vitals, follow-ups.4All data links to existing 1006 patients and feeds into booking intelligence.5"""6import json, random, datetime, os, sys7from collections import defaultdict8 9random.seed(42)10 11BASE = os.path.dirname(os.path.abspath(__file__))12PATIENTS_FILE = os.path.join(BASE, "patients.json")13SUMMARIES_FILE = os.path.join(BASE, "booking_summary.json")14OUTPUT_FILE = os.path.join(BASE, "rich_patient_data.json")15 16# ── Load existing data ──17with open(PATIENTS_FILE) as f:18    patients = json.load(f)19 20with open(SUMMARIES_FILE) as f:21    summaries = json.load(f)22 23patient_lookup = {p["patient_number"]: p for p in patients}24summary_lookup = {s["patient_id"]: s for s in summaries.get("patient_summaries", [])}25 26print(f"Loaded {len(patients)} patients, {len(summary_lookup)} summaries")27 28# ── 40+ Real Medications ──29MEDICATIONS = [30    ("Metformin", "500mg", "850mg", "1000mg", "Diabetes, Type 2"),31    ("Aspirin", "81mg", "325mg", "", "Antiplatelet, CVD prevention"),32    ("Amlodipine", "5mg", "10mg", "", "Hypertension"),33    ("Lisinopril", "5mg", "10mg", "20mg", "Hypertension, Heart failure"),34    ("Atorvastatin", "10mg", "20mg", "40mg", "Hypercholesterolemia"),35    ("Metoprolol", "25mg", "50mg", "100mg", "Hypertension, Angina"),36    ("Insulin Glargine", "10U", "20U", "30U", "Diabetes, Type 1 & 2"),37    ("Levothyroxine", "25mcg", "50mcg", "100mcg", "Hypothyroidism"),38    ("Omeprazole", "20mg", "40mg", "", "GERD, Acid reflux"),39    ("Losartan", "25mg", "50mg", "100mg", "Hypertension"),40    ("Hydrochlorothiazide", "12.5mg", "25mg", "", "Hypertension"),41    ("Simvastatin", "10mg", "20mg", "40mg", "Hypercholesterolemia"),42    ("Warfarin", "2mg", "5mg", "7.5mg", "Atrial fibrillation, DVT"),43    ("Clopidogrel", "75mg", "", "", "Antiplatelet, post-stent"),44    ("Furosemide", "20mg", "40mg", "80mg", "Heart failure, Edema"),45    ("Prednisone", "5mg", "10mg", "20mg", "Inflammation, Asthma"),46    ("Albuterol Inhaler", "90mcg", "", "", "Asthma, COPD"),47    ("Gabapentin", "100mg", "300mg", "600mg", "Neuropathic pain"),48    ("Sertraline", "25mg", "50mg", "100mg", "Depression, Anxiety"),49    ("Pantoprazole", "20mg", "40mg", "", "GERD"),50    ("Digoxin", "0.125mg", "0.25mg", "", "Heart failure, AFib"),51    ("Spironolactone", "25mg", "50mg", "", "Heart failure"),52    ("Carvedilol", "3.125mg", "6.25mg", "25mg", "Heart failure"),53    ("Empagliflozin", "10mg", "25mg", "", "Diabetes, Heart failure"),54    ("Dapagliflozin", "5mg", "10mg", "", "Diabetes, Heart failure"),55    ("Semaglutide", "0.25mg", "0.5mg", "1mg", "Diabetes, Weight loss"),56    ("Fenofibrate", "48mg", "145mg", "", "Hypertriglyceridemia"),57    ("Allopurinol", "100mg", "300mg", "", "Gout"),58    ("Febuxostat", "40mg", "80mg", "", "Gout"),59    ("Vitamin D3", "1000IU", "2000IU", "5000IU", "Vitamin D deficiency"),60    ("Calcium Carbonate", "500mg", "1000mg", "", "Osteoporosis"),61    ("Alendronate", "70mg", "", "", "Osteoporosis"),62    ("Tramadol", "50mg", "100mg", "", "Moderate pain"),63    ("Acetaminophen", "500mg", "650mg", "1000mg", "Mild pain, Fever"),64    ("Ibuprofen", "200mg", "400mg", "600mg", "Inflammation, Pain"),65    ("Naproxen", "250mg", "500mg", "", "Arthritis, Pain"),66    ("Montelukast", "10mg", "", "", "Asthma, Allergies"),67    ("Cetirizine", "10mg", "", "", "Allergies"),68    ("Doxycycline", "100mg", "", "", "Antibiotic"),69    ("Amoxicillin", "250mg", "500mg", "", "Antibiotic"),70    ("Azithromycin", "250mg", "500mg", "", "Antibiotic"),71    ("Ciprofloxacin", "250mg", "500mg", "", "Antibiotic"),72    ("Fluoxetine", "10mg", "20mg", "40mg", "Depression, OCD"),73    ("Bupropion", "150mg", "300mg", "", "Depression, Smoking cessation"),74]75 76# ── Procedures ──77PROCEDURES = [78    ("Lab Work - Complete Blood Count", "CBC"),79    ("Lab Work - Basic Metabolic Panel", "BMP"),80    ("Lab Work - Lipid Panel", "Lipids"),81    ("Lab Work - HbA1c", "HbA1c"),82    ("Lab Work - Thyroid Panel", "TSH"),83    ("ECG / EKG", "ECG"),84    ("Chest X-Ray", "CXR"),85    ("Mammogram", "Mammo"),86    ("Colonoscopy", "Colon"),87    ("Bone Density Scan", "DEXA"),88    ("Stress Test", "Stress"),89    ("Echocardiogram", "Echo"),90    ("MRI - Brain", "MRI_Brain"),91    ("CT Scan - Abdomen", "CT_Abd"),92    ("Ultrasound - Abdomen", "US_Abd"),93    ("Holter Monitor", "Holter"),94    ("Pulmonary Function Test", "PFT"),95    ("Skin Biopsy", "Skin_Bx"),96    ("Joint Injection", "Joint_Inject"),97    ("Suture Removal", "Suture"),98    ("Wound Dressing", "Wound"),99    ("Vaccination - Influenza", "Flu_Vax"),100    ("Vaccination - COVID-19", "COVID_Vax"),101    ("Vaccination - Pneumococcal", "Pneumo_Vax"),102]103 104# ── Follow-up Reasons ──105FOLLOW_UP_REASONS = [106    "Post-operative follow-up — wound healing normal",107    "Lab results review — all within normal range",108    "Medication adjustment — dosage decreased due to side effects",109    "Blood pressure check — controlled on current regimen",110    "Glucose monitoring follow-up — HbA1c improving",111    "Post-discharge follow-up — recovering well at home",112    "Pain management review — pain controlled with current meds",113    "Physical therapy progress assessment",114    "Specialist referral follow-up — plan discussed with patient",115    "Vaccination follow-up — no adverse reactions",116    "Imaging results discussion — findings reviewed with patient",117    "Pre-operative clearance — cleared for surgery",118    "Post-procedure check — no complications",119    "Chronic disease management — treatment plan updated",120    "Medication refill — 3-month supply authorized",121    "Weight management follow-up — 5 lbs lost since last visit",122    "Smoking cessation follow-up — patient using nicotine patch",123    "Mental health follow-up — mood stable on current meds",124    "Cardiac rehab progress — tolerating increased activity",125    "Dietitian consult follow-up — dietary changes implemented",126]127 128# ── Vitals ──129def generate_vitals(age, gender):130    """Generate realistic vitals based on age and gender"""131    base_sbp = 110 + random.gauss(0, 10)132    base_dbp = 70 + random.gauss(0, 5)133    if age > 60:134        base_sbp += 10135    if age > 75:136        base_sbp += 5137    return {138        "blood_pressure_systolic": round(base_sbp + random.gauss(0, 5), 0),139        "blood_pressure_diastolic": round(base_dbp + random.gauss(0, 3), 0),140        "heart_rate": round(72 + random.gauss(0, 8), 0),141        "temperature": round(36.8 + random.gauss(0, 0.2), 1),142        "respiratory_rate": round(16 + random.gauss(0, 2), 0),143        "oxygen_saturation": round(97 + random.gauss(0, 1.5), 0),144        "weight_kg": round(70 + random.gauss(0, 15) + (5 if age > 50 else 0), 1),145        "height_cm": round(170 + random.gauss(0, 10), 1),146    }147 148def generate_labs(age, gender):149    """Generate realistic lab results"""150    return {151        "hemoglobin": round(14 + random.gauss(0, 1), 1),152        "wbc": round(7 + random.gauss(0, 2), 1),153        "platelets": round(250 + random.gauss(0, 50), 0),154        "glucose_fasting": round(95 + random.gauss(0, 15) + (20 if age > 55 else 0), 0),155        "hba1c": round(5.7 + random.gauss(0, 0.5), 1),156        "creatinine": round(0.9 + random.gauss(0, 0.2), 2),157        "egfr": round(90 - random.gauss(0, 10) - (age // 2) * 0.5, 0),158        "total_cholesterol": round(190 + random.gauss(0, 20), 0),159        "ldl": round(110 + random.gauss(0, 15), 0),160        "hdl": round(50 + random.gauss(0, 10) + (7 if gender == "F" else 0), 0),161        "triglycerides": round(130 + random.gauss(0, 25), 0),162        "potassium": round(4.2 + random.gauss(0, 0.3), 1),163        "sodium": round(140 + random.gauss(0, 3), 0),164        "alt": round(25 + random.gauss(0, 8), 0),165        "ast": round(22 + random.gauss(0, 7), 0),166        "vitamin_d": round(35 + random.gauss(0, 10), 0),167        "tsh": round(2.5 + random.gauss(0, 1), 1),168        "crp": round(3 + random.gauss(0, 2), 1)169    }170 171# ── Procedure Codes ──172PROCEDURE_CODES = {173    "CBC": "80050", "BMP": "80048", "Lipids": "80061", "HbA1c": "83036",174    "TSH": "84443", "ECG": "93005", "CXR": "71045", "Mammo": "77065",175    "Colon": "45378", "DEXA": "77080", "Stress": "93015", "Echo": "93306",176    "MRI_Brain": "70551", "CT_Abd": "74176", "US_Abd": "76700",177    "Holter": "93224", "PFT": "94010", "Skin_Bx": "11100",178    "Joint_Inject": "20610", "Suture": "12001", "Wound": "97602",179    "Flu_Vax": "90656", "COVID_Vax": "91300", "Pneumo_Vax": "90670"180}181 182# ── Helper ──183def random_date(start="2023-01-01", end="2026-06-17"):184    s = datetime.date.fromisoformat(start)185    e = datetime.date.fromisoformat(end)186    return s + datetime.timedelta(days=random.randint(0, (e - s).days))187 188def prev_date(days_ago):189    return (datetime.date.today() - datetime.timedelta(days=days_ago)).isoformat()190 191# ── Generate Rich Data ──192print("\nGenerating rich patient data...")193rich_data = {}194 195for i, patient in enumerate(patients):196    pid = patient["patient_number"]197    age = patient.get("age", 45)198    gender = patient.get("gender", random.choice(["M", "F"]))199    name = patient.get("name", f"Patient {pid}")200 201    # Get summary if exists202    summary = summary_lookup.get(pid)203    total_visits = summary.get("total_visits", random.randint(100, 1100)) if summary else random.randint(100, 1100)204    existing_meds = summary.get("medications", []) if summary else []205    existing_conditions = summary.get("conditions", []) if summary else []206 207    #── Medications (5-12 per patient with prescription details) ──208    num_meds = random.randint(5, 12)209 210    # Start with existing meds, then add more211    med_names_in_use = set()212    medications = []213 214    # Parse existing meds215    for em in existing_meds:216        # "Metformin 500mg" -> name, dose217        parts = em.split()218        if len(parts) >= 2 and num_meds > 0:219            try:220                dose = parts[-1]221                name_part = " ".join(parts[:-1])222                med = random.choice([m for m in MEDICATIONS if m[0] == name_part or m[0].split()[0] == name_part.split()[0]])223            except:224                med = random.choice(MEDICATIONS)225            med_names_in_use.add(med[0])226            start_dt = random_date("2022-01-01", "2024-06-01")227            medications.append({228                "name": f"{med[0]} {med[1]}",229                "generic_name": med[0],230                "dosage": med[1],231                "dosage_form": "Tablet" if "mg" in med[1] else "Injection",232                "frequency": random.choice(["Once daily", "Twice daily", "Three times daily", "As needed"]),233                "route": "Oral" if "Inhaler" not in med[0] else "Inhalation",234                "prescribed_by": random.choice(["Dr. Samuel Alobo", "Dr. Jane Doe", "Dr. James Chen", "Dr. Maria Santos"]),235                "start_date": start_dt.isoformat(),236                "end_date": None,237                "status": "active",238                "refills_remaining": random.randint(0, 11),239                "pharmacy": random.choice(["PubMed Center Pharmacy", "CVS Pharmacy", "Walgreens", "Rite Aid"]),240                "notes": random.choice(["Take with food", "Take in the morning", "Take before bed", "Monitor for dizziness"])241            })242            num_meds -= 1243 244    # Add more meds if we need more245    extra_meds = random.sample([m for m in MEDICATIONS if m[0] not in med_names_in_use], min(num_meds, len(MEDICATIONS) - len(med_names_in_use)))246    for med in extra_meds:247        start_dt = random_date("2022-01-01", "2025-06-01")248        dose = random.choice([d for d in [med[1], med[2], med[3]] if d])249        end_date = None250        status = "active"251        if random.random() < 0.2:  # 20% historical252            end_date = random_date(start_dt.isoformat(), "2026-05-01")253            status = "discontinued"254        medications.append({255            "name": f"{med[0]} {dose}",256            "generic_name": med[0],257            "dosage": dose,258            "dosage_form": "Tablet" if "mg" in dose else ("Injection" if "U" in dose else "Inhaler"),259            "frequency": random.choice(["Once daily", "Twice daily", "Three times daily", "As needed"]),260            "route": "Oral" if "Inhaler" not in med[0] else "Inhalation",261            "prescribed_by": random.choice(["Dr. Samuel Alobo", "Dr. Jane Doe", "Dr. James Chen", "Dr. Maria Santos",262                                            "Dr. Robert Mitchell", "Dr. Laura Chen", "Dr. Karen Walsh", "Dr. David Park"]),263            "start_date": start_dt.isoformat(),264            "end_date": end_date.isoformat() if end_date else None,265            "status": status,266            "refills_remaining": random.randint(0, 11) if status == "active" else 0,267            "pharmacy": random.choice(["PubMed Center Pharmacy", "CVS Pharmacy", "Walgreens", "Rite Aid", "Kaiser Pharmacy"]),268            "notes": random.choice(["Take with food", "Take in the morning", "Take before bed", "Monitor for dizziness",269                                    "Avoid grapefruit juice", "Take on empty stomach", "Do not crush"])270        })271 272    #── Procedures (each patient has 5-25 procedures across their visit history) ──273    num_procedures = random.randint(5, 25)274    procedures = []275    for _ in range(num_procedures):276        proc = random.choice(PROCEDURES)277        proc_date = random_date()278        proc_code = PROCEDURE_CODES.get(proc[1], "00000")279        procedures.append({280            "procedure_name": proc[0],281            "procedure_code": proc_code,282            "category": proc[1],283            "date": proc_date.isoformat(),284            "performed_by": random.choice(["Dr. Samuel Alobo", "Dr. Jane Doe", "Dr. James Chen", "Dr. Maria Santos",285                                           "Dr. Robert Mitchell", "Dr. Laura Chen", "Dr. Paul Okonkwo"]),286            "location": random.choice(["PubMed Center Main", "PubMed Center - East Wing", "PubMed Center - West Wing"]),287            "result": random.choice(["Normal", "Normal", "Normal", "Abnormal - requiring follow-up", "Normal", "Inconclusive"]),288            "notes": random.choice(["Procedure tolerated well", "Patient comfortable throughout", "No complications",289                                    "Mild discomfort reported", "Standard protocol followed"])290        })291 292    #── Lab Results (one per visit basically, sampled) ──293    num_labs = min(random.randint(3, 15), total_visits // 20 + 3)294    labs = []295    for _ in range(num_labs):296        lab_date = random_date()297        lab_data = generate_labs(age, gender)298        labs.append({299            "date": lab_date.isoformat(),300            "results": lab_data,301            "notes": random.choice(["Fasting sample", "Non-fasting", "Random draw", "Post-prandial"])302        })303 304    #── Vitals (sampled) ──305    num_vitals = min(random.randint(3, 20), total_visits // 30 + 2)306    vitals_list = []307    for _ in range(num_vitals):308        v_date = random_date()309        v = generate_vitals(age, gender)310        vitals_list.append({311            "date": v_date.isoformat(),312            "vitals": v313        })314 315    #── Follow-ups ──316    num_followups = random.randint(2, 10)317    followups = []318    for _ in range(num_followups):319        f_date = random_date("2023-06-01", "2026-06-17")320        completed = random.random() < 0.85321        followups.append({322            "scheduled_date": f_date.isoformat(),323            "completed": completed,324            "completed_date": f_date.isoformat() if completed else None,325            "reason": random.choice(FOLLOW_UP_REASONS),326            "provider": random.choice(["Dr. Samuel Alobo", "Dr. Jane Doe", "Dr. James Chen", "Dr. Maria Santos",327                                       "Dr. Robert Mitchell", "Nurse Practitioner Wilson"]),328            "outcome": random.choice(["Resolved", "Improving", "Stable", "Referred to specialist", "Medication adjusted"]) if completed else None,329            "notes": random.choice(["Patient advised to continue current plan", "Return in 3 months", "Schedule imaging",330                                    "Lab work ordered", "Referral placed"])331        })332 333    #── Allergies ──334    num_allergies = random.randint(0, 4)335    allergies_list = []336    allergy_options = ["Penicillin", "Sulfa", "Aspirin", "Ibuprofen", "Codeine", "Morphine",337                       "Latex", "Pollen", "Shellfish", "Peanuts", "Seasonal",338                       "ACE Inhibitors", "Statins", "Metformin", "Contrast Dye"]339    for _ in range(num_allergies):340        allergy = random.choice(allergy_options)341        allergies_list.append({342            "allergen": allergy,343            "reaction": random.choice(["Rash", "Hives", "Swelling", "Anaphylaxis", "Nausea", "Dizziness"]),344            "severity": random.choice(["Mild", "Moderate", "Severe"]),345            "recorded_date": random_date("2020-01-01", "2025-01-01").isoformat()346        })347 348    #── Insurance Info ──349    insurance_plans = ["Aetna PPO", "Blue Cross Blue Shield", "Cigna HMO", "United Healthcare",350                       "Medicare Part D", "Medicaid", "Humana Gold Plus", "Kaiser Permanente"]351    insurance = {352        "provider": random.choice(insurance_plans),353        "member_id": f"PMC-{random.randint(100000,999999)}",354        "group_number": f"GRP-{random.randint(100,999)}",355        "copay": random.choice([10, 15, 20, 25, 30, 40, 50]),356        "deductible_met": random.random() < 0.7,357        "effective_date": random_date("2022-01-01", "2025-01-01").isoformat()358    }359 360    #── Build rich patient record ──361    rich_data[pid] = {362        "patient_id": pid,363        "name": name,364        "age": age,365        "gender": gender,366        "medications": medications,367        "procedures": sorted(procedures, key=lambda x: x["date"]),368        "lab_results": sorted(labs, key=lambda x: x["date"]),369        "vitals_history": sorted(vitals_list, key=lambda x: x["date"]),370        "follow_ups": sorted(followups, key=lambda x: x["scheduled_date"]),371        "allergies": allergies_list,372        "insurance": insurance,373        "active_conditions": existing_conditions,374        "total_visits": total_visits,375        "updated_at": datetime.datetime.now().isoformat()376    }377 378    if (i+1) % 100 == 0:379        print(f"  Generated {i+1}/{len(patients)} patients...")380 381# ── Save ──382with open(OUTPUT_FILE, "w") as f:383    json.dump(rich_data, f, indent=2)384 385print(f"\n✅ Rich data saved to {OUTPUT_FILE}")386print(f"   Patients: {len(rich_data)}")387print(f"   Total medications: {sum(len(d['medications']) for d in rich_data.values())}")388print(f"   Total procedures: {sum(len(d['procedures']) for d in rich_data.values())}")389print(f"   Total lab_results: {sum(len(d['lab_results']) for d in rich_data.values())}")390print(f"   Total vitals records: {sum(len(d['vitals_history']) for d in rich_data.values())}")391print(f"   Total follow-ups: {sum(len(d['follow_ups']) for d in rich_data.values())}")392print(f"   File size: {os.path.getsize(OUTPUT_FILE) / 1024 / 1024:.1f} MB")393