LUXERATEHF / app.py
marcch1234's picture
Update app.py
30ea6fe verified
import gradio as gr
import pandas as pd
import numpy as np
import os
import requests
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import LabelEncoder
# =========================
# NLTK FIX (HF SAFE)
# =========================
import nltk
from nltk.sentiment import SentimentIntensityAnalyzer
try:
nltk.data.find('sentiment/vader_lexicon.zip')
except:
nltk.download('vader_lexicon')
sia = SentimentIntensityAnalyzer()
# =========================
# LOAD DATA
# =========================
bookings = pd.read_csv("bookings_small.csv")
X = bookings.drop(columns=["is_canceled"])
y = bookings["is_canceled"]
# =========================
# ENCODERS
# =========================
encoders = {}
for col in X.select_dtypes(include="object").columns:
le = LabelEncoder()
X[col] = le.fit_transform(X[col].astype(str))
encoders[col] = le
# =========================
# MODEL
# =========================
model = RandomForestClassifier(n_estimators=150, max_depth=12)
model.fit(X, y)
WEBHOOK_URL = os.getenv("N8N_WEBHOOK_URL")
# =========================
# SAFE ENCODE
# =========================
def safe_encode(df):
for col, le in encoders.items():
if col in df:
df[col] = df[col].apply(
lambda x: le.transform([x])[0] if x in le.classes_ else 0
)
return df
# =========================
# BOOKING PREDICTION
# =========================
def predict_booking(hotel, lead_time, adr, total_nights, total_guests):
try:
lead_time = int(lead_time)
total_nights = int(total_nights)
total_guests = int(total_guests)
adr = float(adr)
input_dict = {
"hotel": hotel,
"lead_time": lead_time,
"adr": adr,
"total_nights": total_nights,
"total_guests": total_guests,
# SAFE VALUES FROM DATA
"market_segment": bookings["market_segment"].mode()[0],
"deposit_type": bookings["deposit_type"].mode()[0],
"is_repeated_guest": 0,
"previous_cancellations": 0,
"total_of_special_requests": 1,
"seasonality_index": 1.0,
"competitor_price_index": 1.0,
"service_quality_proxy": 50,
"booking_value_score": adr * total_nights * max(total_guests, 1)
}
df_input = pd.DataFrame([input_dict])
df_input = safe_encode(df_input)
for col in X.columns:
if col not in df_input:
df_input[col] = 0
df_input = df_input[X.columns]
prob = model.predict_proba(df_input)[0][1]
# πŸ”₯ FIXED THRESHOLDS (WIDER RANGE)
if prob > 0.5:
risk = "πŸ”΄ HIGH RISK"
rec = "High cancellation probability β†’ reduce price or verify booking"
elif prob > 0.25:
risk = "🟠 MEDIUM RISK"
rec = "Moderate uncertainty β†’ monitor demand"
else:
risk = "🟒 LOW RISK"
rec = "Stable demand β†’ pricing power available"
return prob, risk, rec, input_dict
except Exception as e:
return 0, "ERROR", str(e), {}
# =========================
# SENTIMENT (BOOSTED)
# =========================
def run_sentiment(text):
try:
text = text.lower()
score = sia.polarity_scores(text)["compound"]
# πŸ”₯ BOOST FOR SHORT NEGATIVE TEXT
if any(word in text for word in ["trash", "bad", "terrible", "awful"]):
score -= 0.4
if score > 0.2:
label = "🟒 Positive"
elif score < -0.2:
label = "πŸ”΄ Negative"
else:
label = "🟑 Neutral"
return f"""
### πŸ’¬ Sentiment Analysis
**Score:** {score:.2f}
**Label:** {label}
**Insight:**
{"🚨 Negative feedback β†’ improve service before pricing increases" if "Negative" in label else "βœ… Customer perception supports pricing strategy"}
""", {"sentiment_label": label, "sentiment_score": score}
except Exception as e:
return f"❌ ERROR: {str(e)}", {}
# =========================
# SEND TO N8N (FIXED PAYLOAD)
# =========================
def send_to_n8n(source_tab, payload):
if not WEBHOOK_URL:
return "❌ Missing webhook secret"
try:
response = requests.post(
WEBHOOK_URL,
json=payload, # πŸ”₯ IMPORTANT: send FLAT payload
timeout=10
)
if response.status_code == 200:
data = response.json()
return f"""
### πŸ”— n8n Response
**Message:** {data.get("message")}
**Decision:** {data.get("decision")}
**Severity:** {data.get("severity")}
**Recommendation:**
{data.get("recommendation")}
"""
else:
return f"❌ Error {response.status_code}: {response.text}"
except Exception as e:
return f"❌ Request failed: {str(e)}"
# =========================
# UI
# =========================
with gr.Blocks() as demo:
gr.Markdown("# 🏨 LuxeRate AI")
gr.Markdown("Smart hotel pricing & risk decision system")
# BOOKING TAB
with gr.Tab("πŸ“Š Booking Risk"):
hotel = gr.Dropdown(["City Hotel", "Resort Hotel"], label="Hotel Type")
lead_time = gr.Slider(0, 200, value=30, label="Lead Time")
adr = gr.Slider(50, 300, value=120, label="Price (€)")
total_nights = gr.Slider(1, 10, value=2, label="Nights")
total_guests = gr.Slider(1, 5, value=2, label="Guests")
output = gr.Markdown()
state_payload = gr.State()
def run_booking(hotel, lead_time, adr, total_nights, total_guests):
prob, risk, rec, payload = predict_booking(
hotel, lead_time, adr, total_nights, total_guests
)
return f"""
### πŸ“Š Booking Analysis
**Cancellation Probability:** {prob:.2%}
**Risk Level:** {risk}
**Recommendation:**
{rec}
""", {
"risk_label": risk,
"cancellation_probability": prob
}
gr.Button("πŸ” Analyze Booking").click(
fn=run_booking,
inputs=[hotel, lead_time, adr, total_nights, total_guests],
outputs=[output, state_payload]
)
send_output = gr.Markdown()
gr.Button("πŸš€ Send to n8n").click(
lambda p: send_to_n8n("booking", p),
state_payload,
send_output
)
# SENTIMENT TAB
with gr.Tab("πŸ’¬ Review Sentiment"):
review = gr.Textbox(label="Paste Review", lines=4)
sentiment_output = gr.Markdown()
state_review = gr.State()
gr.Button("πŸ” Analyze Sentiment").click(
fn=run_sentiment,
inputs=review,
outputs=[sentiment_output, state_review]
)
send_output2 = gr.Markdown()
gr.Button("πŸš€ Send to n8n").click(
lambda p: send_to_n8n("review", p),
state_review,
send_output2
)
demo.launch()