import gradio as gr import pandas as pd import numpy as np import requests import folium from folium.plugins import AntPath from geopy.geocoders import Nominatim from geopy.extra.rate_limiter import RateLimiter from ortools.constraint_solver import pywrapcp, routing_enums_pb2 import os from openai import OpenAI from datetime import datetime import base64 # --------------------------------------- # CONSTANTS & BRANDING # --------------------------------------- PRIMARY_COLOR = "#0F2C59" # Procelevate Blue VEHICLE_MILEAGE = { "Truck (32 ft)": 2.5, "Mini-Truck / Tata Ace": 12, "Bike Delivery": 45, "Car / SUV": 12 } # GPT Client OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") client = OpenAI(api_key=OPENAI_API_KEY) # --------------------------------------- # GEOCODING # --------------------------------------- geolocator = Nominatim(user_agent="procelevate_route_app") geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1) def get_coordinates(address): try: loc = geocode(address) if loc: return (loc.latitude, loc.longitude) except: return None return None # --------------------------------------- # OSRM Distance + Time Fetcher # --------------------------------------- def osrm_query(coord1, coord2): url = f"http://router.project-osrm.org/route/v1/driving/{coord1[1]},{coord1[0]};{coord2[1]},{coord2[0]}?overview=false" r = requests.get(url).json() if "routes" in r: return r["routes"][0]["distance"], r["routes"][0]["duration"] return None, None def build_matrices(coords): n = len(coords) dist = np.zeros((n,n)) time = np.zeros((n,n)) for i in range(n): for j in range(n): if i == j: continue d, t = osrm_query(coords[i], coords[j]) if not d: return None, None dist[i][j] = d time[i][j] = t return dist, time # --------------------------------------- # OR-TOOLS Optimization # --------------------------------------- def optimize_route(distance_matrix): n = len(distance_matrix) manager = pywrapcp.RoutingIndexManager(n, 1, 0) routing = pywrapcp.RoutingModel(manager) def distance_callback(from_i, to_i): return int(distance_matrix[manager.IndexToNode(from_i)][manager.IndexToNode(to_i)]) transit_idx = routing.RegisterTransitCallback(distance_callback) routing.SetArcCostEvaluatorOfAllVehicles(transit_idx) params = pywrapcp.DefaultRoutingSearchParameters() params.first_solution_strategy = routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC sol = routing.SolveWithParameters(params) if not sol: return None index = routing.Start(0) order = [] while not routing.IsEnd(index): order.append(manager.IndexToNode(index)) index = sol.Value(routing.NextVar(index)) return order # --------------------------------------- # Fuel, Cost, Toll Calculations # --------------------------------------- def calculate_kpis(distance_km, mileage, fuel_price, toll_estimate=0): fuel_needed = distance_km / mileage fuel_cost = fuel_needed * fuel_price total_cost = fuel_cost + toll_estimate return fuel_needed, fuel_cost, total_cost # --------------------------------------- # Folium Map # --------------------------------------- def make_map(coords, addresses, order): m = folium.Map(location=coords[order[0]], zoom_start=12) path = [] for i, idx in enumerate(order): folium.Marker( coords[idx], tooltip=f"{i+1}. {addresses[idx]}", icon=folium.Icon(color="blue") ).add_to(m) path.append(coords[idx]) AntPath(path, color="blue", weight=4).add_to(m) return m._repr_html_() # --------------------------------------- # AI Explanation via GPT # --------------------------------------- def generate_ai_explanation(opt_km, naive_km, fuel_saved, cost_saved, time_saved): prompt = f""" You are an AI logistics expert. Explain clearly why the optimized route is better. Optimized distance: {opt_km:.2f} km Naive distance: {naive_km:.2f} km Fuel saved: {fuel_saved:.2f} litres Cost saved: ₹{cost_saved:.2f} Time saved: {time_saved:.2f} minutes Write a short, professional explanation suitable for a supply-chain manager at CEVA Logistics. """ response = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}] ) return response.choices[0].message.content # --------------------------------------- # HTML REPORT GENERATOR # --------------------------------------- def generate_report_html(summary_text, ai_text, map_html): html = f"""

Procelevate AI Route Optimization Report

Generated: {datetime.now().strftime('%Y-%m-%d %H:%M')}

Summary

{summary_text}

AI Explanation

{ai_text}

Route Map

{map_html} """ return html # --------------------------------------- # PART 3 — FULL ENTERPRISE DASHBOARD UI # --------------------------------------- def run_route_engine(start, end, stops_text, vehicle_type, fuel_price): stops = [s.strip() for s in stops_text.split("\n") if s.strip()] # Build address list addresses = [start] + stops + [end] addresses = [a for a in addresses if a.strip()] if len(addresses) < 2: return ["❌ Please enter valid addresses."] + [None]*5 # Geocode all addresses coords = [] for a in addresses: c = get_coordinates(a) if not c: return [f"❌ Failed to locate address: {a}"] + [None]*5 coords.append(c) # Build OSRM matrices dist_m, time_m = build_matrices(coords) if dist_m is None: return ["❌ OSRM routing failed. Try different locations."] + [None]*5 # Convert meters → km, seconds → minutes dist_km = dist_m / 1000 time_min = time_m / 60 # Optimized route opt_order = optimize_route(dist_m) if opt_order is None: return ["❌ Optimization failed."] + [None]*5 # Naive + reverse orders naive_order = list(range(len(addresses))) rev_order = list(reversed(naive_order)) def compute_totals(order): total_km = 0 total_min = 0 for i in range(len(order)-1): total_km += dist_km[order[i]][order[i+1]] total_min += time_min[order[i]][order[i+1]] return total_km, total_min opt_km, opt_min = compute_totals(opt_order) naive_km, naive_min = compute_totals(naive_order) rev_km, rev_min = compute_totals(rev_order) mileage = VEHICLE_MILEAGE[vehicle_type] # KPI calculations opt_fuel, opt_fuel_cost, opt_total_cost = calculate_kpis(opt_km, mileage, fuel_price) naive_fuel, naive_fuel_cost, naive_total_cost = calculate_kpis(naive_km, mileage, fuel_price) rev_fuel, rev_fuel_cost, rev_total_cost = calculate_kpis(rev_km, mileage, fuel_price) # Savings fuel_saved = naive_fuel - opt_fuel cost_saved = naive_total_cost - opt_total_cost time_saved = naive_min - opt_min # AI Explanation ai_text = generate_ai_explanation(opt_km, naive_km, fuel_saved, cost_saved, time_saved) # Optimized route map map_html = make_map(coords, addresses, opt_order) # Summary panel text summary_text = f""" Optimized Distance: {opt_km:.2f} km
Optimized Time: {opt_min:.2f} minutes
Fuel Needed: {opt_fuel:.2f} L
Total Cost: ₹{opt_total_cost:.2f}
Efficiency Gain vs Naive: {((naive_km-opt_km)/naive_km)*100:.2f}%
""" # Comparison table comp_df = pd.DataFrame({ "Route Type": ["Optimized", "Naive", "Reverse"], "Distance (km)": [opt_km, naive_km, rev_km], "Time (min)": [opt_min, naive_min, rev_min], "Fuel (L)": [opt_fuel, naive_fuel, rev_fuel], "Cost (₹)": [opt_total_cost, naive_total_cost, rev_total_cost] }) # Data tables dist_df = pd.DataFrame(dist_km, columns=addresses, index=addresses) time_df = pd.DataFrame(time_min, columns=addresses, index=addresses) # Downloadable report report_html = generate_report_html(summary_text, ai_text, map_html) b64 = base64.b64encode(report_html.encode()).decode() download_link = f'Download Report' return ( summary_text, # TAB 1 map_html, # TAB 2 comp_df, # TAB 3 ai_text, # TAB 4 dist_df, # TAB 5A time_df, # TAB 5B download_link # TAB 6 ) # --------------------------------------- # GRADIO UI LAYOUT — TABS + BRANDING # --------------------------------------- with gr.Blocks() as demo: gr.HTML(f""" """) gr.Markdown(f"

Procelevate AI Route Optimization Suite

") # ------------------------- # Address Inputs # ------------------------- with gr.Row(): start = gr.Textbox(label="From", placeholder="Starting point (e.g., Bangalore Airport)") end = gr.Textbox(label="To", placeholder="Final destination (e.g., Whitefield)") stops_text = gr.Textbox( label="Stops (one per line, optional)", lines=4, placeholder="Example:\nMG Road\nBTM Layout\nElectronic City" ) # ------------------------- # Vehicle + Fuel Inputs # ------------------------- vehicle_type = gr.Dropdown( list(VEHICLE_MILEAGE.keys()), label="Vehicle Type", value="Truck (32 ft)" ) fuel_price = gr.Number( label="Fuel Price (₹ per litre)", value=91 ) # ------------------------- # Submit Button # ------------------------- submit_btn = gr.Button("Optimize Route", variant="primary") # TAB STRUCTURE with gr.Tabs(): with gr.Tab("Overview"): overview_out = gr.HTML() with gr.Tab("Optimized Route"): map_out = gr.HTML() with gr.Tab("Route Comparison"): comp_out = gr.Dataframe() with gr.Tab("AI Explanation"): ai_out = gr.Markdown() with gr.Tab("Data Tables"): dist_out = gr.Dataframe(label="Distance (km)") time_out = gr.Dataframe(label="Time (min)") with gr.Tab("Download Report"): report_out = gr.HTML() # CONNECT BUTTON submit_btn.click( fn=run_route_engine, inputs=[start, end, stops_text, vehicle_type, fuel_price], outputs=[overview_out, map_out, comp_out, ai_out, dist_out, time_out, report_out] ) demo.launch( server_name="0.0.0.0", server_port=7860, ssr_mode=False )