Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# File: app.py
|
| 2 |
+
|
| 3 |
+
import gradio as gr
|
| 4 |
+
import pandas as pd
|
| 5 |
+
import io
|
| 6 |
+
import zipfile
|
| 7 |
+
import matplotlib.pyplot as plt
|
| 8 |
+
import seaborn as sns
|
| 9 |
+
from logic.care_gap_engine import evaluate_care_gaps
|
| 10 |
+
from logic.financial_model import estimate_financial_recovery
|
| 11 |
+
from logic.nlp_report import generate_patient_summary
|
| 12 |
+
from logic.exporter import export_to_docx_and_zip
|
| 13 |
+
|
| 14 |
+
CONFIG = {
|
| 15 |
+
"base_rate": 9500,
|
| 16 |
+
"care_gap_rules": {
|
| 17 |
+
"Breast Cancer Screening": {"gender": "F", "min_age": 50, "max_age": 74, "interval_days": 730},
|
| 18 |
+
"Colorectal Cancer Screening": {"min_age": 50, "max_age": 75, "interval_days": 365*10},
|
| 19 |
+
"Blood Pressure Control": {"bp_threshold": 140},
|
| 20 |
+
"Follow-Up Care": {},
|
| 21 |
+
"Readmission Risk": {}
|
| 22 |
+
},
|
| 23 |
+
"sdoh_modifiers": [
|
| 24 |
+
"Housing_Instability", "Food_Insecurity", "Transportation_Access", "Health_Literacy"
|
| 25 |
+
]
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
def run_analysis(file, tone, gap_filter, custom_prompt):
|
| 29 |
+
df = pd.read_csv(file.name)
|
| 30 |
+
df.fillna("", inplace=True)
|
| 31 |
+
|
| 32 |
+
care_gaps = evaluate_care_gaps(df, CONFIG)
|
| 33 |
+
financials = estimate_financial_recovery(care_gaps, df, CONFIG['base_rate'], CONFIG['sdoh_modifiers'])
|
| 34 |
+
merged = care_gaps.merge(financials, on="patient_id")
|
| 35 |
+
|
| 36 |
+
if gap_filter:
|
| 37 |
+
merged = merged[merged['care_gaps'].apply(lambda gaps: gap_filter in gaps)]
|
| 38 |
+
|
| 39 |
+
summaries = {}
|
| 40 |
+
for _, row in merged.iterrows():
|
| 41 |
+
summaries[row['patient_id']] = generate_patient_summary(row, tone, custom_prompt)
|
| 42 |
+
|
| 43 |
+
zip_bytes, file_names = export_to_docx_and_zip(merged, summaries)
|
| 44 |
+
|
| 45 |
+
# Risk score graph
|
| 46 |
+
plt.figure(figsize=(8, 4))
|
| 47 |
+
plt.hist(merged['risk_score'], bins=10)
|
| 48 |
+
plt.title("Risk Score Distribution")
|
| 49 |
+
plt.xlabel("Risk Score")
|
| 50 |
+
plt.ylabel("Number of Patients")
|
| 51 |
+
plt.tight_layout()
|
| 52 |
+
plt.savefig("risk_score_plot.png")
|
| 53 |
+
|
| 54 |
+
# Gap frequency bar chart
|
| 55 |
+
gap_freq = {}
|
| 56 |
+
for gaps in merged['care_gaps']:
|
| 57 |
+
for g in gaps:
|
| 58 |
+
gap_freq[g] = gap_freq.get(g, 0) + 1
|
| 59 |
+
gap_df = pd.DataFrame(list(gap_freq.items()), columns=["Gap", "Count"])
|
| 60 |
+
plt.figure(figsize=(10, 5))
|
| 61 |
+
sns.barplot(x="Count", y="Gap", data=gap_df.sort_values(by="Count", ascending=False))
|
| 62 |
+
plt.title("Care Gap Frequency")
|
| 63 |
+
plt.tight_layout()
|
| 64 |
+
plt.savefig("care_gap_freq.png")
|
| 65 |
+
|
| 66 |
+
# Top 10 revenue opportunities
|
| 67 |
+
top10 = merged.sort_values(by="projected_gain", ascending=False).head(10)
|
| 68 |
+
top10_chart_path = "top10_revenue.png"
|
| 69 |
+
plt.figure(figsize=(10, 5))
|
| 70 |
+
sns.barplot(x="projected_gain", y="patient_id", data=top10)
|
| 71 |
+
plt.title("Top 10 Patients by Projected Gain")
|
| 72 |
+
plt.xlabel("Projected Revenue Recovery ($)")
|
| 73 |
+
plt.ylabel("Patient ID")
|
| 74 |
+
plt.tight_layout()
|
| 75 |
+
plt.savefig(top10_chart_path)
|
| 76 |
+
|
| 77 |
+
return merged, zip_bytes, "risk_score_plot.png", "care_gap_freq.png", top10_chart_path
|
| 78 |
+
|
| 79 |
+
iface = gr.Interface(
|
| 80 |
+
fn=run_analysis,
|
| 81 |
+
inputs=[
|
| 82 |
+
gr.File(label="Upload Patient CSV"),
|
| 83 |
+
gr.Dropdown(choices=["clinical", "executive", "casual"], label="Report Tone", value="executive"),
|
| 84 |
+
gr.Textbox(label="Filter by Care Gap (e.g. 'Breast Cancer Screening')", value=""),
|
| 85 |
+
gr.Textbox(label="Custom Prompt Override (optional)", value="")
|
| 86 |
+
],
|
| 87 |
+
outputs=[
|
| 88 |
+
gr.Dataframe(label="Care Gap & Financial Report"),
|
| 89 |
+
gr.File(label="Download All Reports as ZIP"),
|
| 90 |
+
gr.Image(label="Risk Score Distribution"),
|
| 91 |
+
gr.Image(label="Care Gap Frequency"),
|
| 92 |
+
gr.Image(label="Top 10 Revenue Opportunities")
|
| 93 |
+
],
|
| 94 |
+
title="AI Medicare Advantage Analyzer",
|
| 95 |
+
description="Upload a patient dataset, evaluate CMS care gaps and SDOH risk, forecast financial recovery, and generate NLP summaries with LLMs."
|
| 96 |
+
)
|
| 97 |
+
|
| 98 |
+
if __name__ == "__main__":
|
| 99 |
+
iface.launch()
|