Spaces:
Sleeping
Sleeping
| import os | |
| import requests | |
| import pandas as pd | |
| import gradio as gr | |
| import plotly.graph_objects as go | |
| N8N_WEBHOOK_URL = os.environ.get("N8N_WEBHOOK_URL", "").strip() | |
| def make_demo_df(): | |
| return pd.DataFrame([ | |
| ["Paris", "E-Scooter", 4.6, 4.1, 0.12, 0.06], | |
| ["Paris", "E-Bike", 4.3, 4.2, 0.14, 0.05], | |
| ["Berlin", "E-Scooter", 4.9, 3.8, 0.05, 0.08], | |
| ["Berlin", "E-Bike", 4.5, 4.0, 0.09, 0.06], | |
| ["Madrid", "E-Scooter", 4.2, 4.3, 0.17, 0.05], | |
| ["Warsaw", "Shared-EV", 5.0, 4.0, 0.07, 0.05], | |
| ], columns=[ | |
| "city", "vehicle_type", "avg_final_price_eur", | |
| "avg_rating", "avg_sentiment", "cancellation_rate" | |
| ]) | |
| def load_data(): | |
| try: | |
| df = pd.read_csv("merged_summary.csv") | |
| except Exception: | |
| return make_demo_df() | |
| df.columns = [str(c).strip() for c in df.columns] | |
| rename_map = {} | |
| for c in df.columns: | |
| cl = c.lower().strip() | |
| if cl == "city": | |
| rename_map[c] = "city" | |
| elif cl in ["vehicle_type", "ride_type", "vehicle", "vehicletype"]: | |
| rename_map[c] = "vehicle_type" | |
| elif cl in ["avg_final_price_eur", "final_price_eur", "avg_price", "avg_final_price", "price"]: | |
| rename_map[c] = "avg_final_price_eur" | |
| elif cl in ["avg_rating", "rating", "avg_star_rating", "star_rating"]: | |
| rename_map[c] = "avg_rating" | |
| elif cl in ["avg_sentiment", "sentiment", "compound", "vader_compound", "avg_compound_score"]: | |
| rename_map[c] = "avg_sentiment" | |
| elif cl in ["cancellation_rate", "cancel_rate", "avg_cancellation_rate"]: | |
| rename_map[c] = "cancellation_rate" | |
| df = df.rename(columns=rename_map) | |
| required = [ | |
| "city", | |
| "vehicle_type", | |
| "avg_final_price_eur", | |
| "avg_rating", | |
| "avg_sentiment", | |
| "cancellation_rate", | |
| ] | |
| for col in required: | |
| if col not in df.columns: | |
| if col in ["city", "vehicle_type"]: | |
| df[col] = "Unknown" | |
| else: | |
| df[col] = 0.0 | |
| for col in ["avg_final_price_eur", "avg_rating", "avg_sentiment", "cancellation_rate"]: | |
| df[col] = pd.to_numeric(df[col], errors="coerce").fillna(0) | |
| return df | |
| def render_dashboard(city, vehicle): | |
| df = load_data().copy() | |
| if city != "All": | |
| df = df[df["city"] == city] | |
| if vehicle != "All": | |
| df = df[df["vehicle_type"] == vehicle] | |
| if df.empty: | |
| empty = go.Figure() | |
| empty.update_layout(title="No data for selected filters") | |
| return "### No data available", empty, empty, empty | |
| avg_price = df["avg_final_price_eur"].mean() | |
| avg_rating = df["avg_rating"].mean() | |
| avg_cancel = df["cancellation_rate"].mean() | |
| kpi = f""" | |
| ### KPIs | |
| - Avg Price: EUR {avg_price:.2f} | |
| - Avg Rating: {avg_rating:.2f} | |
| - Cancellation Rate: {avg_cancel:.2%} | |
| """ | |
| seg = df.groupby(["city", "vehicle_type"], as_index=False).agg( | |
| avg_final_price_eur=("avg_final_price_eur", "mean"), | |
| avg_rating=("avg_rating", "mean"), | |
| cancellation_rate=("cancellation_rate", "mean"), | |
| ) | |
| fig1 = go.Figure() | |
| fig1.add_bar( | |
| x=[f"{r['city']} - {r['vehicle_type']}" for _, r in seg.iterrows()], | |
| y=seg["avg_final_price_eur"] | |
| ) | |
| fig1.update_layout(title="Average Price by City / Vehicle") | |
| fig2 = go.Figure() | |
| fig2.add_bar( | |
| x=[f"{r['city']} - {r['vehicle_type']}" for _, r in seg.iterrows()], | |
| y=seg["avg_rating"] | |
| ) | |
| fig2.update_layout(title="Average Rating by City / Vehicle") | |
| city_agg = df.groupby("city", as_index=False).agg( | |
| cancellation_rate=("cancellation_rate", "mean") | |
| ) | |
| fig3 = go.Figure() | |
| fig3.add_bar( | |
| x=city_agg["city"], | |
| y=city_agg["cancellation_rate"] | |
| ) | |
| fig3.update_layout(title="Cancellation Rate by City") | |
| return kpi, fig1, fig2, fig3 | |
| def predict(price, discount): | |
| score = 0.5 | |
| if price < 5: | |
| score += 0.2 | |
| if discount > 10: | |
| score += 0.1 | |
| score = min(max(score, 0), 1) | |
| return { | |
| "satisfaction_probability": round(score, 2), | |
| "label": "High" if score > 0.5 else "Low" | |
| } | |
| def get_n8n_recommendation(city, vehicle): | |
| if not N8N_WEBHOOK_URL: | |
| return {"error": "N8N_WEBHOOK_URL is not configured in Hugging Face secrets."} | |
| payload = { | |
| "city": city, | |
| "vehicle_type": vehicle | |
| } | |
| try: | |
| response = requests.post(N8N_WEBHOOK_URL, json=payload, timeout=20) | |
| response.raise_for_status() | |
| try: | |
| return response.json() | |
| except Exception: | |
| return { | |
| "error": "n8n did not return valid JSON", | |
| "status_code": response.status_code, | |
| "raw_response": response.text, | |
| "payload_sent": payload | |
| } | |
| except Exception as e: | |
| return { | |
| "error": str(e), | |
| "payload_sent": payload | |
| } | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# Urban Mobility App") | |
| with gr.Tab("Dashboard"): | |
| city = gr.Dropdown( | |
| ["All", "Paris", "Berlin", "Madrid", "Warsaw", "Turin"], | |
| value="All", | |
| label="City" | |
| ) | |
| vehicle = gr.Dropdown( | |
| ["All", "E-Scooter", "E-Bike", "Shared-EV", "Bus-Connect"], | |
| value="All", | |
| label="Vehicle" | |
| ) | |
| btn = gr.Button("Refresh") | |
| kpi = gr.Markdown() | |
| chart1 = gr.Plot() | |
| chart2 = gr.Plot() | |
| chart3 = gr.Plot() | |
| btn.click( | |
| render_dashboard, | |
| inputs=[city, vehicle], | |
| outputs=[kpi, chart1, chart2, chart3] | |
| ) | |
| with gr.Tab("Prediction"): | |
| price = gr.Number(label="Price", value=4.0) | |
| discount = gr.Number(label="Discount %", value=10) | |
| btn2 = gr.Button("Predict") | |
| out = gr.JSON() | |
| btn2.click(predict, inputs=[price, discount], outputs=out) | |
| with gr.Tab("n8n Recommendation"): | |
| n8n_city = gr.Dropdown( | |
| ["Paris", "Berlin", "Madrid", "Warsaw", "Turin"], | |
| value="Berlin", | |
| label="City" | |
| ) | |
| n8n_vehicle = gr.Dropdown( | |
| ["E-Scooter", "E-Bike", "Shared-EV", "Bus-Connect"], | |
| value="E-Scooter", | |
| label="Vehicle" | |
| ) | |
| n8n_btn = gr.Button("Get n8n Recommendation") | |
| n8n_output = gr.JSON(label="n8n Response") | |
| n8n_btn.click( | |
| get_n8n_recommendation, | |
| inputs=[n8n_city, n8n_vehicle], | |
| outputs=[n8n_output] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |