Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import pandas as pd | |
| import plotly.express as px | |
| from pathlib import Path | |
| st.set_page_config( | |
| page_title="Food Delivery Analytics", | |
| page_icon="🍔", | |
| layout="wide" | |
| ) | |
| def find_file(filename: str) -> Path: | |
| candidates = [ | |
| Path("/app") / filename, | |
| Path("/app/src") / filename, | |
| Path(__file__).resolve().parent / filename, | |
| Path(__file__).resolve().parent.parent / filename, | |
| ] | |
| for path in candidates: | |
| if path.exists(): | |
| return path | |
| raise FileNotFoundError( | |
| f"Could not find {filename}. Checked: " + ", ".join(str(p) for p in candidates) | |
| ) | |
| def load_data(): | |
| real_df = pd.read_csv(find_file("real_world_driver_data.csv")) | |
| metrics_df = pd.read_csv(find_file("synthetic_delivery_metrics.csv")) | |
| reviews_df = pd.read_csv(find_file("synthetic_customer_reviews.csv")) | |
| features_df = pd.read_csv(find_file("synthetic_driver_features.csv")) | |
| monthly_df = pd.read_csv(find_file("synthetic_monthly_delivery_series.csv")) | |
| return real_df, metrics_df, reviews_df, features_df, monthly_df | |
| real_df, metrics_df, reviews_df, features_df, monthly_df = load_data() | |
| monthly_df["month"] = pd.to_datetime(monthly_df["month"]) | |
| # KPIs | |
| total_drivers = features_df["driver_id"].nunique() | |
| total_deliveries = int(metrics_df["deliveries_completed"].sum()) | |
| avg_rating = round(features_df["Delivery_person_Ratings"].mean(), 2) | |
| total_reviews = int(reviews_df.shape[0]) | |
| # Sidebar | |
| st.sidebar.title("Filters") | |
| city_options = ["All"] + sorted(features_df["City"].dropna().unique().tolist()) | |
| vehicle_options = ["All"] + sorted(features_df["Type_of_vehicle"].dropna().unique().tolist()) | |
| selected_city = st.sidebar.selectbox("City", city_options) | |
| selected_vehicle = st.sidebar.selectbox("Vehicle Type", vehicle_options) | |
| filtered_features = features_df.copy() | |
| if selected_city != "All": | |
| filtered_features = filtered_features[filtered_features["City"] == selected_city] | |
| if selected_vehicle != "All": | |
| filtered_features = filtered_features[filtered_features["Type_of_vehicle"] == selected_vehicle] | |
| filtered_driver_ids = filtered_features["driver_id"].unique() | |
| filtered_metrics = metrics_df[metrics_df["driver_id"].isin(filtered_driver_ids)].copy() | |
| filtered_reviews = reviews_df[reviews_df["driver_id"].isin(filtered_driver_ids)].copy() | |
| filtered_total_drivers = filtered_features["driver_id"].nunique() | |
| filtered_total_deliveries = int(filtered_metrics["deliveries_completed"].sum()) if not filtered_metrics.empty else 0 | |
| filtered_avg_rating = round(filtered_features["Delivery_person_Ratings"].mean(), 2) if not filtered_features.empty else 0 | |
| filtered_total_reviews = int(filtered_reviews.shape[0]) | |
| # Header | |
| st.markdown(""" | |
| <h1 style='text-align: center;'>🍔 Food Delivery Analytics Dashboard</h1> | |
| <p style='text-align: center; font-size:18px;'> | |
| Analyze driver performance, customer sentiment, and delivery trends | |
| </p> | |
| """, unsafe_allow_html=True) | |
| st.markdown("---") | |
| # KPI cards | |
| col1, col2, col3, col4 = st.columns(4) | |
| col1.metric("🚚 Drivers", filtered_total_drivers) | |
| col2.metric("📦 Deliveries", f"{filtered_total_deliveries:,}") | |
| col3.metric("⭐ Avg Rating", filtered_avg_rating) | |
| col4.metric("💬 Reviews", f"{filtered_total_reviews:,}") | |
| st.markdown("---") | |
| tab1, tab2, tab3, tab4 = st.tabs([ | |
| "Overview", | |
| "Driver Performance", | |
| "Customer Reviews", | |
| "Monthly Trends" | |
| ]) | |
| with tab1: | |
| st.subheader("Dataset Overview") | |
| st.write("This dashboard combines driver performance, delivery activity, and customer sentiment data.") | |
| col_a, col_b = st.columns(2) | |
| with col_a: | |
| if not filtered_features.empty: | |
| fig_overview_1 = px.histogram( | |
| filtered_features, | |
| x="performance_tier", | |
| title="Performance Tier Distribution" | |
| ) | |
| st.plotly_chart(fig_overview_1, use_container_width=True) | |
| with col_b: | |
| if not filtered_features.empty: | |
| city_counts = filtered_features["City"].value_counts().reset_index() | |
| city_counts.columns = ["City", "count"] | |
| fig_overview_2 = px.bar( | |
| city_counts, | |
| x="City", | |
| y="count", | |
| title="Drivers by City" | |
| ) | |
| st.plotly_chart(fig_overview_2, use_container_width=True) | |
| st.markdown("### Data Preview") | |
| st.dataframe(filtered_features.head(10), use_container_width=True) | |
| with tab2: | |
| st.subheader("Driver Performance") | |
| if not filtered_features.empty: | |
| top_drivers = filtered_features.sort_values("total_deliveries", ascending=False).head(10) | |
| fig1 = px.bar( | |
| top_drivers, | |
| x="driver_id", | |
| y="total_deliveries", | |
| color="performance_tier", | |
| title="Top 10 Drivers by Total Deliveries" | |
| ) | |
| st.plotly_chart(fig1, use_container_width=True) | |
| fig2 = px.scatter( | |
| filtered_features, | |
| x="avg_delivery_time", | |
| y="Delivery_person_Ratings", | |
| color="sentiment_label", | |
| hover_name="driver_id", | |
| title="Average Delivery Time vs Driver Rating" | |
| ) | |
| st.plotly_chart(fig2, use_container_width=True) | |
| else: | |
| st.warning("No driver data available for the selected filters.") | |
| with tab3: | |
| st.subheader("Customer Reviews") | |
| if not filtered_reviews.empty: | |
| col_a, col_b = st.columns(2) | |
| with col_a: | |
| sentiment_counts = filtered_reviews["sentiment_label"].value_counts().reset_index() | |
| sentiment_counts.columns = ["sentiment_label", "count"] | |
| fig3 = px.pie( | |
| sentiment_counts, | |
| names="sentiment_label", | |
| values="count", | |
| title="Customer Review Sentiment Distribution" | |
| ) | |
| st.plotly_chart(fig3, use_container_width=True) | |
| with col_b: | |
| avg_rating_by_sentiment = ( | |
| filtered_reviews.groupby("sentiment_label", as_index=False)["driver_rating"] | |
| .mean() | |
| ) | |
| fig4 = px.bar( | |
| avg_rating_by_sentiment, | |
| x="sentiment_label", | |
| y="driver_rating", | |
| title="Average Rating by Sentiment" | |
| ) | |
| st.plotly_chart(fig4, use_container_width=True) | |
| st.write("Sample reviews:") | |
| st.dataframe( | |
| filtered_reviews[["driver_id", "sentiment_label", "driver_rating", "review_text"]].head(15), | |
| use_container_width=True | |
| ) | |
| else: | |
| st.warning("No review data available for the selected filters.") | |
| with tab4: | |
| st.subheader("Monthly Delivery Trends") | |
| if not filtered_metrics.empty: | |
| monthly_trend = ( | |
| filtered_metrics.groupby("month", as_index=False)["deliveries_completed"] | |
| .sum() | |
| .rename(columns={"deliveries_completed": "total_deliveries"}) | |
| ) | |
| monthly_trend["month"] = pd.to_datetime(monthly_trend["month"]) | |
| fig4 = px.line( | |
| monthly_trend, | |
| x="month", | |
| y="total_deliveries", | |
| markers=True, | |
| title="Total Deliveries Over Time" | |
| ) | |
| st.plotly_chart(fig4, use_container_width=True) | |
| else: | |
| st.warning("No monthly delivery data available for the selected filters.") | |
| import requests | |
| st.markdown("---") | |
| st.subheader("🤖 AI Insight") | |
| webhook_url = "https://jq7hhh.app.n8n.cloud/webhook/3dc59db1-0e3d-4b73-bdc1-bbe5168feb6f" | |
| if st.button("Generate AI Insight", key="n8n_ai_insight_button"): | |
| payload = { | |
| "city": selected_city, | |
| "vehicle_type": selected_vehicle, | |
| "drivers": int(filtered_total_drivers), | |
| "deliveries": int(filtered_total_deliveries), | |
| "avg_rating": float(filtered_avg_rating), | |
| "reviews": int(filtered_total_reviews) | |
| } | |
| try: | |
| response = requests.post(webhook_url, json=payload, timeout=20) | |
| if response.status_code == 200: | |
| result = response.json() | |
| st.success(result.get("Insight", "Insight generated successfully.")) | |
| else: | |
| st.error(f"Webhook error: {response.status_code}") | |
| st.write(response.text) | |
| except Exception as e: | |
| st.error(f"Request failed: {e}") |