immu4989's picture
mcp: app.py
5cf1e07 verified
Raw
History Blame Contribute Delete
6.15 kB
"""Interactive demo for the Shipping and Logistics Use Cases repo.
Three of the twelve use cases, wired to live controls: score a shipment for
delivery-commit risk (with a per-shipment SHAP breakdown), read its ETA as a
quantile interval with a keepable promise, and watch the intervention budget
allocate itself. Everything runs on synthetic data trained in-process; there is
no private data behind this Space.
"""
from __future__ import annotations
import gradio as gr
import logic
REPO = "https://github.com/immu4989/Logistics_UseCases"
INTRO = f"""
# 🚚 Shipping & Logistics ML β€” live demo
Three use cases from [the open-source repo]({REPO}), driven by the controls below.
Build a shipment and score it two ways, then see how a fixed intervention budget
should actually be spent. All models are trained in-process on documented synthetic
generators β€” no real customer data, and every number here reproduces the repo's tests.
"""
SHIP_INTRO = """
### Build a shipment
Set the operational conditions on the left, then score it. The **miss-risk** model and
the **ETA** model both read the same shipment, using only information known at induction
time (no cheating with in-transit scans).
"""
BUDGET_INTRO = """
### Spend an intervention budget
A risk score is not a decision. Given a day of 20,000 shipments and a fixed daily budget,
which ones do you reroute, upgrade, or leave alone? Move the budget and compare the
policies. **Expected-value greedy** weighs each shipment's risk against the cost of a
missed delivery for *that* customer; **top-K** just flags the scariest scores.
"""
ABOUT = f"""
### About this demo
Part of **[Shipping and Logistics Use Cases]({REPO})**, twelve self-contained,
end-to-end machine-learning projects for parcel and freight operations. Each ships with
a documented synthetic generator, audited cleaning, an honest operational baseline,
evaluation in dollars and days, and explainability grounded by tests.
- **Miss risk** comes from `delivery-commit-prediction` (XGBoost + SHAP).
- **ETA** comes from `eta-regression` (XGBoost quantile models, monotone-rearranged).
- **Budget** comes from `intervention-optimization` (expected-value allocation,
counterfactually evaluated).
The full repo also covers volume forecasting, route optimization, dynamic pricing,
predictive maintenance, address resolution, returns prediction, capacity planning,
network anomaly detection, and exception triage β€” several validated on real public
datasets (Olist, UCI AI4I, CVRPLIB). The models here are trained small for a fast
demo; the repo's reported numbers come from full runs.
"""
# Force dark mode on load: the plots are styled for a dark canvas, so we pin the
# theme rather than follow the visitor's system preference. One redirect on first
# load stamps ?__theme=dark, then the guard makes it a no-op.
FORCE_DARK = """
() => {
const u = new URL(window.location.href);
if (u.searchParams.get('__theme') !== 'dark') {
u.searchParams.set('__theme', 'dark');
window.location.replace(u.href);
}
}
"""
def build() -> gr.Blocks:
with gr.Blocks(
title="Shipping & Logistics ML demo", theme=gr.themes.Soft(), js=FORCE_DARK
) as demo:
gr.Markdown(INTRO)
with gr.Tab("Score a shipment"):
gr.Markdown(SHIP_INTRO)
with gr.Row():
with gr.Column(scale=1):
distance = gr.Slider(5, 3000, value=1800, step=5, label="Lane distance (miles)")
service = gr.Dropdown(
["overnight", "two_day", "ground"], value="ground", label="Service level"
)
origin_cong = gr.Slider(0, 1, value=0.7, step=0.05, label="Origin hub congestion")
dest_cong = gr.Slider(0, 1, value=0.6, step=0.05, label="Destination hub congestion")
weather = gr.Slider(0, 3, value=2, step=1, label="Destination weather (0 clear – 3 severe)")
cutoff = gr.Slider(
-120, 120, value=20, step=5, label="Pickup vs facility cutoff (min; + is late)"
)
dest_type = gr.Dropdown(
["residential", "commercial"], value="residential", label="Destination type"
)
with gr.Row():
peak = gr.Checkbox(value=True, label="Peak season")
rural = gr.Checkbox(value=True, label="Rural destination")
score_btn = gr.Button("Score this shipment", variant="primary")
with gr.Column(scale=2):
with gr.Tab("Will it miss the promise?"):
risk_label = gr.Markdown()
risk_plot = gr.Plot()
with gr.Tab("When will it arrive?"):
eta_label = gr.Markdown()
eta_plot = gr.Plot()
inputs = [distance, service, origin_cong, dest_cong, weather, cutoff, peak, rural, dest_type]
score_btn.click(logic.score_commit, inputs=inputs, outputs=[risk_label, risk_plot])
score_btn.click(logic.predict_eta, inputs=inputs, outputs=[eta_label, eta_plot])
with gr.Tab("Spend the budget"):
gr.Markdown(BUDGET_INTRO)
budget = gr.Slider(1000, 20000, value=6000, step=500, label="Daily intervention budget ($)")
run_btn = gr.Button("Allocate the budget", variant="primary")
budget_takeaway = gr.Markdown()
budget_plot = gr.Plot()
budget_table = gr.Dataframe(wrap=True)
run_btn.click(
logic.run_budget, inputs=budget, outputs=[budget_takeaway, budget_plot, budget_table]
)
with gr.Tab("About"):
gr.Markdown(ABOUT)
return demo
if __name__ == "__main__":
logic.warmup()
# mcp_server exposes the three callbacks as MCP tools (schemas generated
# from logic.py's signatures/docstrings), so agents can call the models at
# <space-url>/gradio_api/mcp/ in addition to humans using the UI.
build().launch(mcp_server=True)