# Repo layout (create these files in your Space) # ├─ app.py ← paste this whole file # ├─ requirements.txt ← at end of this file # └─ assets/msk/Gleamer bone view.png, assets/msk/overlay.png ← optional demo images import math from pathlib import Path import gradio as gr import matplotlib.pyplot as plt # ------------------------------ # Config: Gleamer Bone View scenario # ------------------------------ ASSETS = Path("assets") MSK_CFG = { "description": ( "Gleamer Bone View AI assists in detecting fractures on X-rays, speeding reporting, " "reducing missed diagnoses, and improving workflow efficiency." ), "sample_images": ["msk/Gleamer Bone View.png", "msk/overlay.png"], "roi_inputs": { "baseline_volume": 15000, "avg_rev_per_study": 6000, "mins_saved_per_study": 5, "cost_per_rad_hour": 5200, "baseline_repeats": 750, "cost_per_repeat": 6000, "repeat_reduction_pct": 10, "program_cost_annual": 1200000 }, "evidence": [ "Time savings in fracture detection reported in multi-center settings.", "Reduced missed fractures through AI-assisted reads.", "High agreement with subspecialty musculoskeletal radiologists in fracture detection." ], "methodology": ( "Gross benefit = Efficiency savings + Savings from reduced repeats.\n" "Efficiency savings = (Minutes saved per study / 60) × Volume × Cost/hour.\n" "Repeat savings = (Baseline repeats × Reduction% × Cost per repeat).\n" "ROI = (Gross benefit − Program cost) / Program cost.\n" "Payback (months) = Program cost / (Gross benefit / 12), if benefit > 0." ), } # ------------------------------ # ROI math # ------------------------------ def compute_roi(period, baseline_volume, avg_rev_per_study, mins_saved_per_study, cost_per_rad_hour, baseline_repeats, cost_per_repeat, repeat_reduction_pct, program_cost_annual): eff_savings_annual = (mins_saved_per_study / 60.0) * baseline_volume * cost_per_rad_hour repeats_avoided_annual = baseline_repeats * (repeat_reduction_pct / 100.0) repeat_savings_annual = repeats_avoided_annual * cost_per_repeat gross_benefit_annual = eff_savings_annual + repeat_savings_annual program_cost = program_cost_annual net_benefit_annual = gross_benefit_annual - program_cost roi_pct = (net_benefit_annual / program_cost * 100.0) if program_cost else 0.0 payback_months = (program_cost / (gross_benefit_annual / 12.0)) if gross_benefit_annual > 0 else math.inf hours_saved_annual = (mins_saved_per_study / 60.0) * baseline_volume fte_saved_eq = hours_saved_annual / 1920.0 factor = 1 if period == "Annual" else 1/12 metrics = { "Program cost": round(program_cost * factor, 2), "Efficiency savings": round(eff_savings_annual * factor, 2), "Repeat savings": round(repeat_savings_annual * factor, 2), "Gross benefit": round(gross_benefit_annual * factor, 2), "Net benefit": round(net_benefit_annual * factor, 2), "ROI % (annualized)": round(roi_pct, 1), "Payback (months)": (round(payback_months, 1) if payback_months != math.inf else float("inf")), "Hours saved / year": round(hours_saved_annual, 1), "FTE saved (≈1920h/yr)": round(fte_saved_eq, 2), "Avg revenue per study (input)": avg_rev_per_study, } return metrics def waterfall_plot(metrics: dict): fig = plt.figure() components = ["Efficiency savings", "Repeat savings", "Program cost"] deltas = [metrics[c] for c in components] deltas[2] = -abs(deltas[2]) running = 0 cumulative = [0] for d in deltas: running += d cumulative.append(running) for i in range(len(deltas)): y0, y1 = cumulative[i], cumulative[i+1] plt.plot([i, i], [y0, y1], linewidth=14) plt.axhline(0, linewidth=1) plt.title("Benefit/Cost Waterfall (selected period)") plt.xlabel("Components") plt.ylabel("Value") plt.xticks(range(len(components)), components, rotation=15) return fig def init(period): cfg = MSK_CFG desc = cfg["description"] gallery = [str(ASSETS / p) for p in cfg["sample_images"] if (ASSETS / p).exists()] inputs = cfg["roi_inputs"] metrics = compute_roi(period, **inputs) fig = waterfall_plot(metrics) readout = ( f"**Gleamer Bone View snapshot** — Net benefit: {metrics['Net benefit']:.0f}; " f"ROI (annualized): {metrics['ROI % (annualized)']}%; " f"Payback: {metrics['Payback (months)']} months.\n\n" f"Operational: {metrics['Hours saved / year']:.0f} hours saved (~{metrics['FTE saved (≈1920h/yr)']:.2f} FTE)." ) ev_md = "\n".join([f"- {e}" for e in cfg.get('evidence', [])]) or "_Add citations_" meth_md = cfg.get("methodology", "") defaults = list(inputs.values()) return desc, gallery, *defaults, metrics, fig, readout, ev_md, meth_md def recalc(period, baseline_volume, avg_rev_per_study, mins_saved_per_study, cost_per_rad_hour, baseline_repeats, cost_per_repeat, repeat_reduction_pct, program_cost_annual): metrics = compute_roi(period, baseline_volume, avg_rev_per_study, mins_saved_per_study, cost_per_rad_hour, baseline_repeats, cost_per_repeat, repeat_reduction_pct, program_cost_annual) fig = waterfall_plot(metrics) readout = ( f"**Gleamer Bone View snapshot** — Net benefit: {metrics['Net benefit']:.0f}; " f"ROI (annualized): {metrics['ROI % (annualized)']}%; " f"Payback: {metrics['Payback (months)']} months.\n\n" f"Operational: {metrics['Hours saved / year']:.0f} hours saved (~{metrics['FTE saved (≈1920h/yr)']:.2f} FTE)." ) return metrics, fig, readout with gr.Blocks(title="Gleamer Bone View ROI – Interactive", fill_height=True) as demo: gr.Markdown(""" # Gleamer Bone View ROI – Interactive **Clinician-first sandbox**: explore a sample fracture detection case, tweak workflow assumptions, and see financial, operational, and clinical impact instantly. """) period = gr.Radio(["Annual", "Monthly"], value="Annual", label="Time basis") with gr.Tabs(): with gr.Tab("Explore"): desc = gr.Markdown() gallery = gr.Gallery(label="Sample case", columns=3, height=320, show_label=True) with gr.Tab("ROI Simulator"): with gr.Row(): with gr.Column(scale=1, min_width=360): baseline_volume = gr.Slider(0, 100000, value=15000, step=50, label="Annual volume") avg_rev_per_study = gr.Slider(0, 50000, value=6000, step=50, label="Avg revenue per study (info)") mins_saved_per_study = gr.Slider(0, 60, value=5, step=1, label="Minutes saved per study") cost_per_rad_hour = gr.Slider(0, 20000, value=5200, step=50, label="Radiologist cost/hour") baseline_repeats = gr.Slider(0, 100000, value=750, step=10, label="Baseline repeats/year") cost_per_repeat = gr.Slider(0, 50000, value=6000, step=50, label="Cost per repeat") repeat_reduction_pct = gr.Slider(0, 100, value=10, step=1, label="Repeat reduction with AI (%)") program_cost_annual = gr.Slider(0, 10000000, value=1200000, step=10000, label="Program cost (annual)") with gr.Column(scale=1): metrics = gr.JSON(label="Outputs") chart = gr.Plot(label="Waterfall") readout = gr.Markdown(label="Executive readout") with gr.Tab("Evidence"): evidence_md = gr.Markdown() with gr.Tab("Methodology"): methodology_md = gr.Markdown() period.change(init, [period], [desc, gallery, baseline_volume, avg_rev_per_study, mins_saved_per_study, cost_per_rad_hour, baseline_repeats, cost_per_repeat, repeat_reduction_pct, program_cost_annual, metrics, chart, readout, evidence_md, methodology_md]) for comp in [baseline_volume, avg_rev_per_study, mins_saved_per_study, cost_per_rad_hour, baseline_repeats, cost_per_repeat, repeat_reduction_pct, program_cost_annual]: comp.change(recalc, [period, baseline_volume, avg_rev_per_study, mins_saved_per_study, cost_per_rad_hour, baseline_repeats, cost_per_repeat, repeat_reduction_pct, program_cost_annual], [metrics, chart, readout]) demo.load(init, [period], [desc, gallery, baseline_volume, avg_rev_per_study, mins_saved_per_study, cost_per_rad_hour, baseline_repeats, cost_per_repeat, repeat_reduction_pct, program_cost_annual, metrics, chart, readout, evidence_md, methodology_md]) if __name__ == "__main__": demo.launch() # ------------------------------ # requirements.txt # ------------------------------ # gradio>=4.44.0 # matplotlib