matteobardelle's picture
Update app.py
ff8e621 verified
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()