CTA / backend /analytics.py
TheQuantEd's picture
Initial deployment: ClinicalMatch AI v2.0 — FHIR R4 · MCP (9 tools) · A2A workflow · SHARP compliance · 100k synthetic patients · Neo4j graph · GraphRAG chatbot
59abb4f
"""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"},
],
}