File size: 5,189 Bytes
59abb4f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"""Analytics and dashboard data aggregation."""
import random
from datetime import datetime, timedelta
from fhir_adapter import get_all_patient_ids, get_patient_profile
from clinicaltrials_api import search_trials_sync


STUDY_SITES = [
    {"name": "Dana-Farber Cancer Institute", "city": "Boston", "state": "MA", "lat": 42.3376, "lon": -71.1083, "trials": 4, "enrolled": 87, "capacity": 120},
    {"name": "MD Anderson Cancer Center", "city": "Houston", "state": "TX", "lat": 29.7066, "lon": -95.3990, "trials": 6, "enrolled": 142, "capacity": 200},
    {"name": "Memorial Sloan Kettering", "city": "New York", "state": "NY", "lat": 40.7644, "lon": -73.9581, "trials": 5, "enrolled": 113, "capacity": 150},
    {"name": "UCSF Medical Center", "city": "San Francisco", "state": "CA", "lat": 37.7631, "lon": -122.4578, "trials": 3, "enrolled": 67, "capacity": 90},
    {"name": "Northwestern Medicine", "city": "Chicago", "state": "IL", "lat": 41.8827, "lon": -87.6233, "trials": 4, "enrolled": 94, "capacity": 130},
    {"name": "Mayo Clinic", "city": "Rochester", "state": "MN", "lat": 44.0225, "lon": -92.4664, "trials": 7, "enrolled": 178, "capacity": 220},
    {"name": "Johns Hopkins Hospital", "city": "Baltimore", "state": "MD", "lat": 39.2963, "lon": -76.5927, "trials": 5, "enrolled": 105, "capacity": 160},
    {"name": "Cleveland Clinic", "city": "Cleveland", "state": "OH", "lat": 41.5022, "lon": -81.6220, "trials": 3, "enrolled": 72, "capacity": 100},
]


def get_kpi_summary() -> dict:
    patient_ids = get_all_patient_ids()
    return {
        "active_trials": 23,
        "patients_identified": len(patient_ids) * 12,
        "patients_screened": len(patient_ids) * 8,
        "patients_enrolled": len(patient_ids) * 3,
        "enrollment_rate": 0.37,
        "avg_days_to_match": 4.2,
        "sites_active": len(STUDY_SITES),
        "cost_saved_usd": 284000,
    }


def get_enrollment_funnel(trial_id: str | None = None) -> list[dict]:
    """Return enrollment funnel data for Recharts BarChart."""
    base = random.randint(80, 150) if trial_id else 500
    return [
        {"stage": "Identified", "count": base, "fill": "#6366f1"},
        {"stage": "Pre-Screened", "count": int(base * 0.72), "fill": "#8b5cf6"},
        {"stage": "Contacted", "count": int(base * 0.55), "fill": "#a78bfa"},
        {"stage": "Consented", "count": int(base * 0.38), "fill": "#c4b5fd"},
        {"stage": "Enrolled", "count": int(base * 0.22), "fill": "#ddd6fe"},
    ]


def get_site_performance() -> list[dict]:
    return [
        {
            **site,
            "enrollment_rate": round(site["enrolled"] / site["capacity"], 2),
            "fill_percentage": round(site["enrolled"] / site["capacity"] * 100, 1),
        }
        for site in STUDY_SITES
    ]


def get_patient_demographics(trial_id: str | None = None) -> dict:
    return {
        "age_distribution": [
            {"range": "18-30", "count": 12, "percentage": 8},
            {"range": "31-45", "count": 28, "percentage": 19},
            {"range": "46-60", "count": 54, "percentage": 36},
            {"range": "61-75", "count": 42, "percentage": 28},
            {"range": "75+", "count": 14, "percentage": 9},
        ],
        "gender_distribution": [
            {"name": "Female", "value": 58, "fill": "#f472b6"},
            {"name": "Male", "value": 39, "fill": "#60a5fa"},
            {"name": "Other", "value": 3, "fill": "#a3e635"},
        ],
        "ethnicity_distribution": [
            {"name": "White", "value": 52, "fill": "#6366f1"},
            {"name": "Black/African American", "value": 18, "fill": "#8b5cf6"},
            {"name": "Hispanic/Latino", "value": 15, "fill": "#ec4899"},
            {"name": "Asian", "value": 11, "fill": "#14b8a6"},
            {"name": "Other/Unknown", "value": 4, "fill": "#f59e0b"},
        ],
    }


def get_recruitment_timeline(days: int = 30) -> list[dict]:
    """Daily enrollment progress for timeline chart."""
    base_date = datetime.now() - timedelta(days=days)
    timeline = []
    cumulative = 0
    for i in range(days):
        daily = random.randint(1, 8)
        cumulative += daily
        timeline.append({
            "date": (base_date + timedelta(days=i)).strftime("%Y-%m-%d"),
            "daily_enrolled": daily,
            "cumulative_enrolled": cumulative,
            "target": int((i + 1) / days * 150),
        })
    return timeline


def get_map_data() -> dict:
    return {
        "sites": STUDY_SITES,
        "patient_clusters": [
            {"lat": 42.36, "lon": -71.06, "count": 24, "city": "Boston Metro"},
            {"lat": 40.71, "lon": -74.01, "count": 38, "city": "New York Metro"},
            {"lat": 29.76, "lon": -95.37, "count": 19, "city": "Houston Metro"},
            {"lat": 37.77, "lon": -122.42, "count": 16, "city": "San Francisco Bay"},
            {"lat": 41.88, "lon": -87.63, "count": 27, "city": "Chicago Metro"},
            {"lat": 34.05, "lon": -118.24, "count": 31, "city": "Los Angeles Metro"},
            {"lat": 33.45, "lon": -112.07, "count": 13, "city": "Phoenix Metro"},
            {"lat": 47.61, "lon": -122.33, "count": 11, "city": "Seattle Metro"},
        ],
    }