| import json |
| import gradio as gr |
| import pandas as pd |
| from solver import ( |
| generate_random_instance, |
| solve_vrp, |
| plot_solution, |
| parse_uploaded_csv, |
| make_template_dataframe, |
| ) |
|
|
| TITLE = "Ride-Sharing Optimizer (Capacitated VRP) β Gradio Demo" |
| DESC = """ |
| This demo assigns **stops (riders)** to **drivers (vehicles)** with a simple, fast heuristic: |
| **Sweep clustering** β **Greedy routing** β **2-opt improvement**. |
| You can **generate a sample** dataset or **upload a CSV** with columns: |
| `id,x,y,demand,tw_start,tw_end,service`. |
| |
| - **Capacity** = max riders per vehicle (sum of `demand` per route). |
| - **Time windows** are *soft* (violations are reported in metrics). |
| - Distances are Euclidean on the X-Y plane for clarity. |
| |
| π‘ Tip: Start with the generator, then switch to your CSV. |
| """ |
|
|
| FOOTER = "Made with β€οΈ using Gradio. No native dependencies; runs quickly on Spaces." |
|
|
|
|
| |
| |
| |
| def run_generator(n_clients, n_vehicles, capacity, spread, demand_min, demand_max, seed): |
| df = generate_random_instance( |
| n_clients=n_clients, |
| n_vehicles=n_vehicles, |
| capacity=capacity, |
| spread=spread, |
| demand_min=demand_min, |
| demand_max=demand_max, |
| seed=seed, |
| ) |
| depot = (0.0, 0.0) |
| sol = solve_vrp(df, depot=depot, n_vehicles=n_vehicles, capacity=capacity, speed=1.0) |
|
|
| |
| img = plot_solution(df, sol, depot=depot) |
|
|
| route_table = sol["assignments_table"] |
| metrics = json.dumps(sol["metrics"], indent=2) |
|
|
| return img, route_table, metrics, df |
|
|
|
|
| def run_csv(file, n_vehicles, capacity): |
| if file is None: |
| raise gr.Error("Please upload a CSV first.") |
| try: |
| df = parse_uploaded_csv(file) |
| except Exception as e: |
| raise gr.Error(f"CSV parsing error: {e}") |
|
|
| depot = (0.0, 0.0) |
| sol = solve_vrp(df, depot=depot, n_vehicles=n_vehicles, capacity=capacity, speed=1.0) |
|
|
| img = plot_solution(df, sol, depot=depot) |
|
|
| route_table = sol["assignments_table"] |
| metrics = json.dumps(sol["metrics"], indent=2) |
| return img, route_table, metrics |
|
|
|
|
| def download_template(): |
| return make_template_dataframe() |
|
|
|
|
| |
| |
| |
| with gr.Blocks(title=TITLE) as demo: |
| gr.Markdown(f"# {TITLE}") |
| gr.Markdown(DESC) |
|
|
| with gr.Tab("π Generate sample"): |
| with gr.Row(): |
| with gr.Column(): |
| n_clients = gr.Slider(5, 200, value=30, step=1, label="Number of riders (clients)") |
| n_vehicles = gr.Slider(1, 20, value=4, step=1, label="Number of drivers (vehicles)") |
| capacity = gr.Slider(1, 50, value=10, step=1, label="Vehicle capacity (sum of demand)") |
| spread = gr.Slider(10, 200, value=50, step=1, label="Spatial spread (larger = wider map)") |
| demand_min = gr.Slider(1, 5, value=1, step=1, label="Min demand per stop") |
| demand_max = gr.Slider(1, 10, value=3, step=1, label="Max demand per stop") |
| seed = gr.Slider(0, 9999, value=42, step=1, label="Random seed") |
| run_btn = gr.Button("π Generate & Optimize", variant="primary") |
| with gr.Column(): |
| img = gr.Image(type="pil", label="Route Visualization", interactive=False) |
|
|
| with gr.Row(): |
| route_df = gr.Dataframe(label="Route assignments (per stop)", wrap=True) |
| metrics = gr.Code(label="Metrics (JSON)") |
| with gr.Accordion("Show generated dataset", open=False): |
| data_out = gr.Dataframe(label="Generated input data") |
|
|
| run_btn.click( |
| fn=run_generator, |
| inputs=[n_clients, n_vehicles, capacity, spread, demand_min, demand_max, seed], |
| outputs=[img, route_df, metrics, data_out], |
| ) |
|
|
| with gr.Tab("π Upload CSV"): |
| with gr.Row(): |
| with gr.Column(): |
| file = gr.File(label="Upload CSV (id,x,y,demand,tw_start,tw_end,service)") |
| dl_tmp = gr.Button("Get CSV Template") |
| n_vehicles2 = gr.Slider(1, 50, value=5, step=1, label="Number of drivers (vehicles)") |
| capacity2 = gr.Slider(1, 200, value=15, step=1, label="Vehicle capacity (sum of demand)") |
| run_btn2 = gr.Button("π Optimize uploaded data", variant="primary") |
| with gr.Column(): |
| img2 = gr.Image(type="pil", label="Route Visualization", interactive=False) |
|
|
| with gr.Row(): |
| route_df2 = gr.Dataframe(label="Route assignments (per stop)") |
| metrics2 = gr.Code(label="Metrics (JSON)") |
|
|
| run_btn2.click( |
| fn=run_csv, |
| inputs=[file, n_vehicles2, capacity2], |
| outputs=[img2, route_df2, metrics2], |
| ) |
|
|
| def _tmpl(): |
| return gr.File.update(value=None), download_template() |
|
|
| dl_tmp.click(fn=_tmpl, outputs=[file, route_df2], inputs=None) |
|
|
| gr.Markdown(f"---\n{FOOTER}") |
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|