diff --git a/ai-models/fare_estimation.py b/ai-models/fare_estimation.py index 162420b..c1ebedb 100644 --- a/ai-models/fare_estimation.py +++ b/ai-models/fare_estimation.py @@ -1,85 +1,192 @@ -import streamlit as st -import folium -from streamlit_folium import st_folium -import random - -# Sample metro stations with coordinates -stations = { - "Wardha Junction": [20.738, 78.601], - "Indira Chowk": [20.742, 78.623], - "Mahatma Nagar": [20.753, 78.634], - "Wardha Bazaar": [20.756, 78.61], - "IT Park": [20.77, 78.645] -} - -station_list = list(stations.keys()) - -# Fare calculation logic -def calculate_fare(start, end): - distance = abs(station_list.index(start) - station_list.index(end)) - if distance == 0: - return 0, 0, 0 - base_fare = 10 - extra_fare = 5 * (distance - 1) - total = base_fare + extra_fare - return total, base_fare, extra_fare - -# Travel time estimation -def estimate_time(start, end): - distance = abs(station_list.index(start) - station_list.index(end)) - return distance * 2 # assume 2 minutes per station - -# Crowd level generator -def crowd_level(): - levels = ["Low 🟒", "Moderate 🟑", "High πŸ”΄"] - return random.choice(levels) - -# Streamlit UI -st.set_page_config(page_title="WardhaMetroFlow - Fare Estimator", layout="wide") -st.title("πŸ’° Wardha Metro Fare Estimator") - -col1, col2 = st.columns(2) -with col1: - start_station = st.selectbox("Select Start Station", station_list) -with col2: - end_station = st.selectbox("Select Destination Station", station_list) - -if start_station and end_station: - total_fare, base_fare, extra_fare = calculate_fare(start_station, end_station) - time_estimate = estimate_time(start_station, end_station) - - # Display results - st.success(f"**Route:** {start_station} β†’ {end_station}") - st.info(f"🚌 Stations covered: {abs(station_list.index(start_station) - station_list.index(end_station)) + 1}") - st.success(f"πŸ’° Fare: β‚Ή{total_fare} (Base β‚Ή{base_fare} + Extra β‚Ή{extra_fare})") - st.warning(f"⏱ Estimated Travel Time: {time_estimate} minutes") - st.error(f"🚦 Current Crowd Level: {crowd_level()}") - - # Intermediate stations - idx_start = station_list.index(start_station) - idx_end = station_list.index(end_station) - if idx_start < idx_end: - route_stations = station_list[idx_start:idx_end+1] - else: - route_stations = station_list[idx_end:idx_start+1][::-1] - - st.markdown("### 🚏 Intermediate Stations on this Route:") - st.write(" β†’ ".join(route_stations)) - - # Show map - m = folium.Map(location=[20.75, 78.62], zoom_start=13, tiles="CartoDB Positron") - - # Add all stations - for station, coords in stations.items(): - color = "blue" - if station == start_station: - color = "green" - elif station == end_station: - color = "red" - folium.Marker(coords, tooltip=station, icon=folium.Icon(color=color, icon="train")).add_to(m) - - # Highlight route path - route_coords = [stations[s] for s in route_stations] - folium.PolyLine(route_coords, color="purple", weight=5).add_to(m) - - st_folium(m, width=750, height=500) +import streamlit as st +import folium +from streamlit_folium import st_folium +import pickle +import pandas as pd +from datetime import datetime + +# Sample metro stations with coordinates +stations = { + "Wardha Junction": [20.738, 78.601], + "Indira Chowk": [20.742, 78.623], + "Mahatma Nagar": [20.753, 78.634], + "Wardha Bazaar": [20.756, 78.61], + "IT Park": [20.77, 78.645] +} +station_list = list(stations.keys()) + +# Load ML model with caching +@st.cache_resource +def load_model(): + try: + with open('passenger_flow_model.pkl', 'rb') as f: + model = pickle.load(f) + return model + except FileNotFoundError: + return None + +# Fare calculation logic +def calculate_fare(start, end): + distance = abs(station_list.index(start) - station_list.index(end)) + if distance == 0: + return 0, 0, 0 + base_fare = 10 + extra_fare = 5 * (distance - 1) + total = base_fare + extra_fare + return total, base_fare, extra_fare + +# Travel time estimation +def estimate_time(start, end): + distance = abs(station_list.index(start) - station_list.index(end)) + return distance * 2 # assume 2 minutes per station + +# ML-based crowd prediction +def predict_crowd_level(model, station_name, hour, day_of_week): + """ + Predict crowd level using ML model + + Args: + model: Trained RandomForestRegressor + station_name: Name of the station + hour: Hour of day (0-23) + day_of_week: Day (0=Monday, 6=Sunday) + + Returns: + tuple: (crowd_label, passenger_count) + """ + if model is None: + # Fallback to time-based logic if model not available + if hour in range(7, 10) or hour in range(17, 20): # Peak hours + return "High πŸ”΄", 450 + elif hour in range(10, 17): # Moderate hours + return "Moderate 🟑", 250 + else: # Off-peak + return "Low 🟒", 100 + + try: + # Create feature dataframe matching model training format + # Adjust features based on your actual model training + station_idx = station_list.index(station_name) + + features = pd.DataFrame({ + 'hour': [hour], + 'day_of_week': [day_of_week], + 'station_id': [station_idx], + 'is_weekend': [1 if day_of_week >= 5 else 0], + 'is_peak_hour': [1 if hour in range(7, 10) or hour in range(17, 20) else 0] + }) + + # Predict passenger count + passenger_count = int(model.predict(features)[0]) + + # Convert to crowd level + if passenger_count < 150: + crowd_label = "Low 🟒" + elif passenger_count < 300: + crowd_label = "Moderate 🟑" + else: + crowd_label = "High πŸ”΄" + + return crowd_label, passenger_count + + except Exception as e: + st.error(f"Prediction error: {str(e)}") + return "Unknown βšͺ", 0 + +# Streamlit UI +st.set_page_config(page_title="WardhaMetroFlow - Fare Estimator", layout="wide") +st.title("πŸ’° Wardha Metro Fare Estimator") + +# Load model +model = load_model() +if model is None: + st.warning("⚠️ ML model not found. Using time-based crowd estimation as fallback.") + +# Time and day selection +st.sidebar.header("πŸ• Travel Time Settings") +current_hour = datetime.now().hour +selected_hour = st.sidebar.slider("Select Hour of Day", 0, 23, current_hour, + help="Choose travel time (24-hour format)") +days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] +current_day = datetime.now().weekday() +selected_day = st.sidebar.selectbox("Select Day of Week", days, index=current_day) +day_of_week = days.index(selected_day) + +# Display selected time +st.sidebar.info(f"πŸ“… {selected_day}, {selected_hour}:00") + +# Station selection +col1, col2 = st.columns(2) +with col1: + start_station = st.selectbox("Select Start Station", station_list) +with col2: + end_station = st.selectbox("Select Destination Station", station_list) + +if start_station and end_station: + total_fare, base_fare, extra_fare = calculate_fare(start_station, end_station) + time_estimate = estimate_time(start_station, end_station) + + # Get crowd predictions for both stations + start_crowd, start_passengers = predict_crowd_level(model, start_station, selected_hour, day_of_week) + end_crowd, end_passengers = predict_crowd_level(model, end_station, selected_hour, day_of_week) + + # Display results + st.success(f"**Route:** {start_station} β†’ {end_station}") + st.info(f"🚌 Stations covered: {abs(station_list.index(start_station) - station_list.index(end_station)) + 1}") + st.success(f"πŸ’° Fare: β‚Ή{total_fare} (Base β‚Ή{base_fare} + Extra β‚Ή{extra_fare})") + st.warning(f"⏱ Estimated Travel Time: {time_estimate} minutes") + + # Display crowd predictions with metrics + st.markdown("### 🚦 Real-Time Crowd Predictions") + col_crowd1, col_crowd2 = st.columns(2) + + with col_crowd1: + st.metric( + label=f"πŸš‰ {start_station}", + value=start_crowd, + delta=f"{start_passengers} passengers" + ) + + with col_crowd2: + st.metric( + label=f"πŸš‰ {end_station}", + value=end_crowd, + delta=f"{end_passengers} passengers" + ) + + # Intermediate stations + idx_start = station_list.index(start_station) + idx_end = station_list.index(end_station) + if idx_start < idx_end: + route_stations = station_list[idx_start:idx_end+1] + else: + route_stations = station_list[idx_end:idx_start+1][::-1] + + st.markdown("### 🚏 Intermediate Stations on this Route:") + st.write(" β†’ ".join(route_stations)) + + # Show map + m = folium.Map(location=[20.75, 78.62], zoom_start=13, tiles="CartoDB Positron") + + # Add all stations + for station, coords in stations.items(): + color = "blue" + if station == start_station: + color = "green" + elif station == end_station: + color = "red" + folium.Marker(coords, tooltip=station, icon=folium.Icon(color=color, icon="train")).add_to(m) + + # Highlight route path + route_coords = [stations[s] for s in route_stations] + folium.PolyLine(route_coords, color="purple", weight=5).add_to(m) + + st_folium(m, width=750, height=500) + +# Footer with info +st.markdown("---") +st.markdown("**πŸ“Š Powered by Machine Learning** | Predictions based on historical passenger flow data") +if model: + st.success("βœ… ML Model Active: Using RandomForestRegressor for accurate crowd predictions") +else: + st.info("ℹ️ Using time-based heuristics for crowd estimation") \ No newline at end of file diff --git a/ai-models/wardha_passenger_view.py b/ai-models/wardha_passenger_view.py index 0db2885..438cc5f 100644 --- a/ai-models/wardha_passenger_view.py +++ b/ai-models/wardha_passenger_view.py @@ -1,187 +1,226 @@ - - -import streamlit as st -import pandas as pd -import numpy as np -import networkx as nx -import folium -from streamlit_folium import st_folium -from folium.plugins import HeatMap, AntPath - -st.set_page_config(page_title="WardhaMetroFlow - Passenger Route Planner", layout="wide") - -# --- Sidebar Navigation --- -st.sidebar.title("πŸ“‚ Navigation") -page = st.sidebar.radio("Go to:", ["About", "Passenger Route Planner"]) - -# ========================= -# ABOUT PAGE -# ========================= -if page == "About": - st.title("ℹ️ About WardhaMetroFlow") - st.markdown(""" - ## πŸš‡ Welcome to WardhaMetroFlow - - **WardhaMetroFlow** is an AI-powered metro simulation designed for **Wardha city**, built to showcase how **smart transit systems** - can improve daily commuting and city transport management. - - ### 🌟 Key Features - 1. **Passenger View** - - Plan metro routes between any two stations - - Get **real-time congestion-aware suggestions** - - View **estimated travel time** - - Explore an **interactive metro map** with congestion heatmaps and station info - - Watch a **live simulation** of your route 🎬 - - 2. **Admin View** *(future scope)* - - Monitor traffic flow across the network - - Manage stations and track congestion - - Analyze predictive AI trends for future capacity planning - - 3. **Congestion Heatmap** - - Color-coded visualization of congestion across all stations - - Helps both passengers and admins make better decisions - - ### 🧭 How to Use This App - - Use the **sidebar navigation** to switch between sections. - - In **Passenger Route Planner**: - - Select a **Start Station** and **Destination Station** - - See the **optimal route** and estimated travel time - - Check congestion levels at each station along the way - - Explore the **interactive metro map** - - Run the **live simulation** to see how your journey progresses - - ### 🎯 Vision - WardhaMetroFlow envisions **smarter, AI-driven public transit systems** for emerging smart cities like Wardha. - It’s a step toward building efficient, reliable, and commuter-friendly metro systems. - - --- - """) - -# ========================= -# PASSENGER ROUTE PLANNER -# ========================= -elif page == "Passenger Route Planner": - st.title("πŸš† Passenger Route Planner") - st.markdown("Plan your journey with **smart AI suggestions**, explore the **metro map**, and even watch a **live simulation** of your route.") - - # --- Metro Stations --- - stations = { - "Wardha Junction": [20.7453, 78.6022], - "Civil Lines": [20.7458, 78.6101], - "Ram Nagar": [20.7502, 78.6187], - "Mahatma Nagar": [20.7408, 78.6202], - "Industrial Area": [20.7351, 78.6155], - } - - # --- Simulated congestion data --- - if "congestion" not in st.session_state: - np.random.seed(None) - st.session_state["congestion"] = {s: np.random.randint(10, 100) for s in stations.keys()} - - congestion_levels = st.session_state["congestion"] - - # --- Create metro network graph --- - G = nx.Graph() - G.add_edges_from([ - ("Wardha Junction", "Civil Lines", {"distance": 2}), - ("Civil Lines", "Ram Nagar", {"distance": 2}), - ("Ram Nagar", "Mahatma Nagar", {"distance": 3}), - ("Civil Lines", "Industrial Area", {"distance": 4}), - ("Industrial Area", "Mahatma Nagar", {"distance": 3}), - ]) - - # --- Passenger Input --- - start = st.selectbox("🟒 Start Station", list(stations.keys())) - end = st.selectbox("πŸ”΄ Destination Station", list(stations.keys())) - - if start and end and start != end: - # Shortest path using distance - path = nx.shortest_path(G, source=start, target=end, weight="distance") - distance = nx.shortest_path_length(G, source=start, target=end, weight="distance") - - # Estimate travel time - avg_congestion = np.mean([congestion_levels[stn] for stn in path]) - travel_time = distance * 2 + avg_congestion * 0.05 # minutes - - # Show route info - st.success(f"πŸ“ Best Route: {' β†’ '.join(path)}") - st.info(f"πŸ•’ Estimated Travel Time: {travel_time:.1f} minutes") - - # Smart Suggestion - if avg_congestion > 70: - st.warning("⚠️ High congestion detected. Consider leaving 10–15 mins earlier.") - elif avg_congestion < 40: - st.success("βœ… Smooth journey ahead! Congestion is low.") - - # Show congestion levels along the route - route_data = pd.DataFrame({ - "Station": path, - "Congestion (%)": [congestion_levels[stn] for stn in path] - }) - st.subheader("πŸ“Š Congestion along your route") - st.dataframe(route_data.style.background_gradient(cmap="RdYlGn_r")) - - # ========================= - # ENHANCED MAP VISUALIZATION - # ========================= - st.subheader("πŸ—ΊοΈ Interactive Route Map") - - # Focus map on midpoint of route - route_coords = [stations[stn] for stn in path] - mid_lat = np.mean([lat for lat, lon in route_coords]) - mid_lon = np.mean([lon for lat, lon in route_coords]) - m = folium.Map(location=[mid_lat, mid_lon], zoom_start=15, tiles="OpenStreetMap") - - # Add heatmap layer for congestion - heat_data = [[stations[s][0], stations[s][1], congestion_levels[s]] for s in stations] - HeatMap(heat_data, min_opacity=0.4, radius=25, blur=15).add_to(m) - - # Add stations with metro icons + popup cards - for stn, coords in stations.items(): - level = congestion_levels[stn] - color = "green" if level < 40 else "orange" if level < 70 else "red" - - popup_html = f""" - {stn}
- 🚦 Congestion: {level}%
- πŸ“ Lat: {coords[0]}, Lon: {coords[1]} - """ - folium.Marker( - location=coords, - popup=popup_html, - icon=folium.Icon(color=color, icon="train", prefix="fa") - ).add_to(m) - - # Add route polyline with color-coded congestion - for i in range(len(path) - 1): - seg = [stations[path[i]], stations[path[i+1]]] - seg_congestion = (congestion_levels[path[i]] + congestion_levels[path[i+1]]) / 2 - seg_color = "green" if seg_congestion < 40 else "orange" if seg_congestion < 70 else "red" - - folium.PolyLine( - locations=seg, - color=seg_color, - weight=6, - opacity=0.8, - tooltip=f"{path[i]} β†’ {path[i+1]} (Cong: {seg_congestion:.1f}%)" - ).add_to(m) - - # ========================= - # LIVE SIMULATION FEATURE - # ========================= - st.subheader("🎬 Live Simulation of Your Route") - - # AntPath creates animated moving dashes - AntPath( - locations=route_coords, - color="blue", - weight=6, - delay=800, - dash_array=[10, 20] - ).add_to(m) - - st_folium(m, width=800, height=550) - - elif start == end: - st.warning("⚠️ Start and Destination stations must be different.") +import streamlit as st +import pandas as pd +import numpy as np +import networkx as nx +import folium +from streamlit_folium import st_folium +from folium.plugins import HeatMap, AntPath + +st.set_page_config(page_title="WardhaMetroFlow - Passenger Route Planner", layout="wide") + +# --- Sidebar Navigation --- +st.sidebar.title("πŸ“‚ Navigation") +page = st.sidebar.radio("Go to:", ["About", "Passenger Route Planner"]) + +# ========================= +# ABOUT PAGE +# ========================= +if page == "About": + st.title("ℹ️ About WardhaMetroFlow") + st.markdown(""" + ## πŸš‡ Welcome to WardhaMetroFlow + + **WardhaMetroFlow** is an AI-powered metro simulation designed for **Wardha city**, built to showcase how **smart transit systems** + can improve daily commuting and city transport management. + + ### 🌟 Key Features + 1. **Passenger View** + - Plan metro routes between any two stations + - Get **real-time congestion-aware suggestions** + - View **estimated travel time** + - Explore an **interactive metro map** with congestion heatmaps and station info + - Watch a **live simulation** of your route 🎬 + + 2. **Admin View** *(future scope)* + - Monitor traffic flow across the network + - Manage stations and track congestion + - Analyze predictive AI trends for future capacity planning + + 3. **Congestion Heatmap** + - Color-coded visualization of congestion across all stations + - Helps both passengers and admins make better decisions + + ### 🧭 How to Use This App + - Use the **sidebar navigation** to switch between sections. + - In **Passenger Route Planner**: + - Select a **Start Station** and **Destination Station** + - See the **optimal route** and estimated travel time + - Check congestion levels at each station along the way + - Explore the **interactive metro map** + - Run the **live simulation** to see how your journey progresses + + ### 🎯 Vision + WardhaMetroFlow envisions **smarter, AI-driven public transit systems** for emerging smart cities like Wardha. + It's a step toward building efficient, reliable, and commuter-friendly metro systems. + + --- + """) + +# ========================= +# PASSENGER ROUTE PLANNER +# ========================= +elif page == "Passenger Route Planner": + st.title("πŸš† Passenger Route Planner") + st.markdown("Plan your journey with **smart AI suggestions**, explore the **metro map**, and even watch a **live simulation** of your route.") + + # --- Metro Stations --- + stations = { + "Wardha Junction": [20.7453, 78.6022], + "Civil Lines": [20.7458, 78.6101], + "Ram Nagar": [20.7502, 78.6187], + "Mahatma Nagar": [20.7408, 78.6202], + "Industrial Area": [20.7351, 78.6155], + } + + # --- Simulated congestion data --- + # Fixed: Removed np.random.seed(None) as it's redundant + if "congestion" not in st.session_state: + st.session_state["congestion"] = {s: np.random.randint(10, 100) for s in stations.keys()} + + congestion_levels = st.session_state["congestion"] + + # --- Create metro network graph --- + G = nx.Graph() + G.add_edges_from([ + ("Wardha Junction", "Civil Lines", {"distance": 2}), + ("Civil Lines", "Ram Nagar", {"distance": 2}), + ("Ram Nagar", "Mahatma Nagar", {"distance": 3}), + ("Civil Lines", "Industrial Area", {"distance": 4}), + ("Industrial Area", "Mahatma Nagar", {"distance": 3}), + ]) + + # --- Network Connectivity Check (Optional Enhancement) --- + # Display network status in sidebar + is_connected = nx.is_connected(G) + if is_connected: + st.sidebar.success("🟒 Metro Network: Fully Connected") + else: + st.sidebar.warning("🟑 Metro Network: Some stations may not be reachable") + + # --- Passenger Input --- + start = st.selectbox("🟒 Start Station", list(stations.keys())) + end = st.selectbox("πŸ”΄ Destination Station", list(stations.keys())) + + if start and end and start != end: + # === CRITICAL FIX: Added Error Handling === + try: + # Shortest path using distance + path = nx.shortest_path(G, source=start, target=end, weight="distance") + distance = nx.shortest_path_length(G, source=start, target=end, weight="distance") + + # Estimate travel time + # Formula: base_time (2 min/km) + congestion_delay (5% of congestion level) + avg_congestion = np.mean([congestion_levels[stn] for stn in path]) + travel_time = distance * 2 + avg_congestion * 0.05 # minutes + + # Show route info + st.success(f"πŸ“ Best Route: {' β†’ '.join(path)}") + st.info(f"πŸ•’ Estimated Travel Time: {travel_time:.1f} minutes") + + # Smart Suggestion + if avg_congestion > 70: + st.warning("⚠️ High congestion detected. Consider leaving 10–15 mins earlier.") + elif avg_congestion < 40: + st.success("βœ… Smooth journey ahead! Congestion is low.") + + # Show congestion levels along the route + route_data = pd.DataFrame({ + "Station": path, + "Congestion (%)": [congestion_levels[stn] for stn in path] + }) + st.subheader("πŸ“Š Congestion along your route") + st.dataframe(route_data.style.background_gradient(cmap="RdYlGn_r")) + + # ========================= + # ENHANCED MAP VISUALIZATION + # ========================= + st.subheader("πŸ—ΊοΈ Interactive Route Map") + + # Focus map on midpoint of route + route_coords = [stations[stn] for stn in path] + mid_lat = np.mean([lat for lat, lon in route_coords]) + mid_lon = np.mean([lon for lat, lon in route_coords]) + m = folium.Map(location=[mid_lat, mid_lon], zoom_start=15, tiles="OpenStreetMap") + + # Add heatmap layer for congestion + heat_data = [[stations[s][0], stations[s][1], congestion_levels[s]] for s in stations] + HeatMap(heat_data, min_opacity=0.4, radius=25, blur=15).add_to(m) + + # Add stations with metro icons + popup cards + for stn, coords in stations.items(): + level = congestion_levels[stn] + color = "green" if level < 40 else "orange" if level < 70 else "red" + + popup_html = f""" + {stn}
+ 🚦 Congestion: {level}%
+ πŸ“ Lat: {coords[0]}, Lon: {coords[1]} + """ + folium.Marker( + location=coords, + popup=popup_html, + icon=folium.Icon(color=color, icon="train", prefix="fa") + ).add_to(m) + + # Add route polyline with color-coded congestion + for i in range(len(path) - 1): + seg = [stations[path[i]], stations[path[i+1]]] + seg_congestion = (congestion_levels[path[i]] + congestion_levels[path[i+1]]) / 2 + seg_color = "green" if seg_congestion < 40 else "orange" if seg_congestion < 70 else "red" + + folium.PolyLine( + locations=seg, + color=seg_color, + weight=6, + opacity=0.8, + tooltip=f"{path[i]} β†’ {path[i+1]} (Cong: {seg_congestion:.1f}%)" + ).add_to(m) + + # ========================= + # LIVE SIMULATION FEATURE + # ========================= + st.subheader("🎬 Live Simulation of Your Route") + + # AntPath creates animated moving dashes + AntPath( + locations=route_coords, + color="blue", + weight=6, + delay=800, + dash_array=[10, 20] + ).add_to(m) + + st_folium(m, width=800, height=550) + + except nx.NetworkXNoPath: + # Handle case when no path exists between stations + st.error(f"❌ No route available between **{start}** and **{end}**.") + st.info("πŸ’‘ **Possible reasons:**") + st.markdown(""" + - These stations are not connected in the current metro network + - There may be maintenance or service disruptions + - Please try selecting different stations + """) + + # Optional: Show which stations are reachable from start + try: + reachable = list(nx.descendants(G, start)) + reachable.append(start) # Include the start station itself + if reachable: + st.info(f"πŸš‰ **Stations reachable from {start}:** {', '.join(reachable)}") + except: + pass # If this fails, just skip showing reachable stations + + except KeyError as e: + # Handle case when station doesn't exist in the graph + st.error(f"⚠️ Station not found in the network: {str(e)}") + st.info("πŸ’‘ Please refresh the page or contact support if this issue persists.") + + except Exception as e: + # Catch any other unexpected errors + st.error(f"⚠️ An unexpected error occurred while planning your route.") + st.warning(f"**Error details:** {str(e)}") + st.info("πŸ’‘ Please try again or contact support if the problem continues.") + + elif start == end: + st.warning("⚠️ Start and Destination stations must be different.") \ No newline at end of file