SChodavarpu commited on
Commit
4e2eb4c
·
verified ·
1 Parent(s): 9c8c3a4

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +233 -0
app.py ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math import numpy as np import pandas as pd import gradio as gr
2
+
3
+ ------------------------------
4
+
5
+ Utility helpers
6
+
7
+ ------------------------------
8
+
9
+ def usd(x: float) -> str: try: return "$" + f"{x:,.0f}" except Exception: return "$0"
10
+
11
+ def usd2(x: float) -> str: try: return "$" + f"{x:,.2f}" except Exception: return "$0.00"
12
+
13
+ def pct(x: float) -> str: return f"{x*100:.1f}%"
14
+
15
+ ------------------------------
16
+
17
+ Core calculator
18
+
19
+ ------------------------------
20
+
21
+ def compute_roi( scans_per_month: int, # Clinical (detection) base_ppr: float, # baseline positive pickup rate (as fraction) ai_ppr: float, # with-AI positive pickup rate (as fraction) base_audit_rate: float, ai_audit_rate: float, # Operational (time) base_read_seconds: float, read_reduction_pct: float, # as fraction radiologist_hourly_cost: float, # Financial (per-scan cost) base_cost_per_scan: float, cost_reduction_pct: float, # Financial (follow-ups) followup_price: float, followup_uplift_pct: float, # as fraction of scans # Recalls / false positives base_recall_rate: float, ai_recall_rate: float, recall_cost_per_case: float, # Early detection value early_detect_uplift_per_1000: float, # extra cancers detected per 1000 treatment_cost_delta_early_vs_late: float, # savings per earlier case # Program costs ai_subscription_monthly: float, integration_overhead_monthly: float, cloud_compute_monthly: float, ): # --- Clinical metrics --- errors_reduced = max(0, scans_per_month * (base_ppr - ai_ppr)) # if AI lowers miss rate via higher pickup, set accordingly discrepant_flags = max(0, scans_per_month * (ai_audit_rate - base_audit_rate)) earlier_detections = max(0.0, scans_per_month * (early_detect_uplift_per_1000 / 1000.0)) recalls_avoided = max(0, scans_per_month * (base_recall_rate - ai_recall_rate))
22
+
23
+ # --- Operational metrics ---
24
+ hours_saved = scans_per_month * (base_read_seconds * read_reduction_pct) / 3600.0
25
+ workload_reduction_pct = read_reduction_pct
26
+ fte_saved = hours_saved / 160.0 # rough FTE-month heuristic
27
+ capacity_increase_pct = (1.0 / max(1e-6, (1.0 - read_reduction_pct)) - 1.0) # approximate capacity headroom
28
+
29
+ # --- Financial metrics ---
30
+ value_time_saved = hours_saved * radiologist_hourly_cost
31
+
32
+ baseline_monthly_cost = scans_per_month * base_cost_per_scan
33
+ new_monthly_cost = baseline_monthly_cost * (1.0 - cost_reduction_pct)
34
+ per_scan_cost_savings = baseline_monthly_cost - new_monthly_cost
35
+
36
+ addl_followups = scans_per_month * followup_uplift_pct
37
+ addl_followup_revenue = addl_followups * followup_price
38
+
39
+ recall_cost_savings = recalls_avoided * recall_cost_per_case
40
+ early_detection_savings = earlier_detections * treatment_cost_delta_early_vs_late
41
+
42
+ total_monthly_benefit = (
43
+ value_time_saved
44
+ + per_scan_cost_savings
45
+ + addl_followup_revenue
46
+ + recall_cost_savings
47
+ + early_detection_savings
48
+ )
49
+
50
+ total_monthly_costs = ai_subscription_monthly + integration_overhead_monthly + cloud_compute_monthly
51
+ net_roi = total_monthly_benefit - total_monthly_costs
52
+ roi_pct = (net_roi / total_monthly_costs) if total_monthly_costs > 0 else np.nan
53
+
54
+ # One-line summary
55
+ clinical_bullet = (
56
+ f"~{int(round(recalls_avoided))} recalls avoided, "
57
+ f"{earlier_detections:.1f} earlier cancers detected, "
58
+ f"{int(round(errors_reduced))} fewer missed positives"
59
+ )
60
+ summary = (
61
+ f"For your practice with {scans_per_month:,} mammography scans/month, your net benefit is "
62
+ f"{usd(net_roi)} per month. Clinical impact: {clinical_bullet}."
63
+ )
64
+
65
+ # Build Markdown sections
66
+ financial_md = f"""
67
+
68
+ Financial (USD/month)
69
+
70
+ Metric Value
71
+
72
+ Value of radiologist time saved {usd(value_time_saved)}
73
+ Savings from per-scan radiologist cost {usd(per_scan_cost_savings)}
74
+ Additional follow-up revenue {usd(addl_followup_revenue)}
75
+ Savings from avoided recalls {usd(recall_cost_savings)}
76
+ Savings from earlier detection {usd(early_detection_savings)}
77
+ Total monthly benefit {usd(total_monthly_benefit)}
78
+ AI subscription {usd(ai_subscription_monthly)}
79
+ Integration / training / overhead {usd(integration_overhead_monthly)}
80
+ Cloud / compute {usd(cloud_compute_monthly)}
81
+ Total monthly costs {usd(total_monthly_costs)}
82
+ Net monthly ROI {usd(net_roi)}
83
+ ROI % {'' if math.isnan(roi_pct) else f'{roi_pct*100:.1f}%'}
84
+ """
85
+
86
+
87
+ clinical_md = f"""
88
+
89
+ Clinical (per month)
90
+
91
+ Metric Value
92
+
93
+ Fewer missed positives (Δ pickup) {int(round(errors_reduced))}
94
+ Discrepant cases flagged by AI (audit uplift) {int(round(discrepant_flags))}
95
+ Earlier cancers detected {earlier_detections:.1f}
96
+ Recalls avoided {int(round(recalls_avoided))}
97
+ """
98
+
99
+
100
+ operational_md = f"""
101
+
102
+ Operational
103
+
104
+ Metric Value
105
+
106
+ Hours of radiologist reading time saved / month {hours_saved:.1f}
107
+ Workload reduction {pct(workload_reduction_pct)}
108
+ Approx. FTE-month saved {fte_saved:.2f}
109
+ Effective reading capacity increase {pct(capacity_increase_pct)}
110
+ """
111
+
112
+
113
+ # CTA
114
+ cta_md = (
115
+ "**Want to see this live in your workflow?** "
116
+ "[Book a demo →](https://example.com/book-demo)"
117
+ )
118
+
119
+ return summary, financial_md, clinical_md, operational_md, cta_md
120
+
121
+ ------------------------------
122
+
123
+ UI Layout
124
+
125
+ ------------------------------
126
+
127
+ def build_ui(): with gr.Blocks(title="Mammography AI ROI Calculator", theme=gr.themes.Soft(), css=""" .gradio-container {max-width: 1200px !important} .section-head {font-weight: 700; margin-top: .5rem} .small-note {opacity: .70; font-size: 0.9em} """) as demo: gr.Markdown("""
128
+
129
+ Mammography AI ROI Calculator
130
+
131
+ A clean, defensible ROI model for breast imaging AI — with Financial, Clinical, and Operational impact, all in USD. """) with gr.Row(): with gr.Column(scale=1): gr.Markdown("## Inputs") scans_per_month = gr.Number(value=7500, label="Scans per month", precision=0)
132
+
133
+ with gr.Accordion("Clinical inputs", open=False):
134
+ base_ppr = gr.Slider(0, 1, value=0.10, step=0.001, label="Baseline positive pickup rate (fraction)")
135
+ ai_ppr = gr.Slider(0, 1, value=0.095, step=0.001, label="With-AI positive pickup rate (fraction)")
136
+ base_audit_rate = gr.Slider(0, 1, value=0.00, step=0.001, label="Baseline audit flag rate (fraction)")
137
+ ai_audit_rate = gr.Slider(0, 1, value=0.05, step=0.001, label="With-AI audit flag rate (fraction)")
138
+ base_recall_rate = gr.Slider(0, 1, value=0.028, step=0.001, label="Baseline recall rate (fraction)")
139
+ ai_recall_rate = gr.Slider(0, 1, value=0.025, step=0.001, label="With-AI recall rate (fraction)")
140
+ recall_cost_per_case = gr.Number(value=250.0, label="Cost per recall case (USD)")
141
+ early_detect_uplift_per_1000 = gr.Number(value=0.7, label="Earlier cancers detected (extra per 1000 scans)")
142
+ treatment_cost_delta_early_vs_late = gr.Number(value=15000.0, label="Treatment cost savings per earlier case (USD)")
143
+
144
+ with gr.Accordion("Operational inputs", open=False):
145
+ base_read_seconds = gr.Number(value=100, label="Baseline read time per scan (seconds)")
146
+ read_reduction_pct = gr.Slider(0, 0.8, value=0.15, step=0.005, label="Reading time reduction with AI (fraction)")
147
+ radiologist_hourly_cost = gr.Number(value=180, label="Radiologist hourly cost (USD)")
148
+
149
+ with gr.Accordion("Financial inputs", open=False):
150
+ base_cost_per_scan = gr.Number(value=15, label="Radiologist cost per scan (USD)")
151
+ cost_reduction_pct = gr.Slider(0, 0.8, value=0.15, step=0.005, label="Per-scan radiologist cost reduction (fraction)")
152
+ followup_price = gr.Number(value=200, label="Price per follow-up scan (USD)")
153
+ followup_uplift_pct = gr.Slider(0, 0.2, value=0.0095, step=0.0005, label="Follow-up uplift (fraction of scans)")
154
+
155
+ with gr.Accordion("Program costs", open=True):
156
+ ai_subscription_monthly = gr.Number(value=0, label="AI subscription (USD/month)")
157
+ integration_overhead_monthly = gr.Number(value=0, label="Integration / training / overhead (USD/month)")
158
+ cloud_compute_monthly = gr.Number(value=0, label="Cloud / compute (USD/month)")
159
+
160
+ calc_btn = gr.Button("Calculate ROI", variant="primary")
161
+
162
+ with gr.Column(scale=1):
163
+ summary = gr.Markdown("", elem_id="summary")
164
+ with gr.Tab("Financial"):
165
+ financial_md = gr.Markdown()
166
+ with gr.Tab("Clinical"):
167
+ clinical_md = gr.Markdown()
168
+ with gr.Tab("Operational"):
169
+ operational_md = gr.Markdown()
170
+ gr.Markdown("---")
171
+ cta_md = gr.Markdown()
172
+
173
+ calc_btn.click(
174
+ fn=compute_roi,
175
+ inputs=[
176
+ scans_per_month,
177
+ base_ppr,
178
+ ai_ppr,
179
+ base_audit_rate,
180
+ ai_audit_rate,
181
+ base_read_seconds,
182
+ read_reduction_pct,
183
+ radiologist_hourly_cost,
184
+ base_cost_per_scan,
185
+ cost_reduction_pct,
186
+ followup_price,
187
+ followup_uplift_pct,
188
+ base_recall_rate,
189
+ ai_recall_rate,
190
+ recall_cost_per_case,
191
+ early_detect_uplift_per_1000,
192
+ treatment_cost_delta_early_vs_late,
193
+ ai_subscription_monthly,
194
+ integration_overhead_monthly,
195
+ cloud_compute_monthly,
196
+ ],
197
+ outputs=[summary, financial_md, clinical_md, operational_md, cta_md],
198
+ )
199
+
200
+ # Auto-run with defaults
201
+ demo.load(
202
+ fn=compute_roi,
203
+ inputs=[
204
+ scans_per_month,
205
+ base_ppr,
206
+ ai_ppr,
207
+ base_audit_rate,
208
+ ai_audit_rate,
209
+ base_read_seconds,
210
+ read_reduction_pct,
211
+ radiologist_hourly_cost,
212
+ base_cost_per_scan,
213
+ cost_reduction_pct,
214
+ followup_price,
215
+ followup_uplift_pct,
216
+ base_recall_rate,
217
+ ai_recall_rate,
218
+ recall_cost_per_case,
219
+ early_detect_uplift_per_1000,
220
+ treatment_cost_delta_early_vs_late,
221
+ ai_subscription_monthly,
222
+ integration_overhead_monthly,
223
+ cloud_compute_monthly,
224
+ ],
225
+ outputs=[summary, financial_md, clinical_md, operational_md, cta_md],
226
+ )
227
+
228
+ return demo
229
+
230
+ def main(): return build_ui()
231
+
232
+ if name == "main": app = build_ui() app.launch()
233
+