File size: 3,074 Bytes
165af41
180fd0b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165af41
180fd0b
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import streamlit as st
import joblib
import pandas as pd
import numpy as np

MODEL_PATH = 'src/r_tips.joblib' 
SCALER_PATH = 'src/scaler_tips.joblib' 

FEATURES = [
    'total_bill', 'size', 'bill_per_person', 
    'sex_Male', 'smoker_Yes', 
    'day_Sat', 'day_Sun', 'day_Thur', 
    'time_Lunch'
]

NUMERICAL_COLS = ['total_bill', 'size', 'bill_per_person']

@st.cache_resource
def load_assets():
    try:
        model = joblib.load(MODEL_PATH)
        scaler = joblib.load(SCALER_PATH)
        return model, scaler
    except Exception as e:
        st.error(f"Error loading assets. Ensure '{MODEL_PATH}' and '{SCALER_PATH}' are uploaded. Error: {e}")
        return None, None

def preprocess_and_predict(model, scaler, input_data):
    
    df_input = pd.DataFrame([input_data])

    df_processed = pd.get_dummies(df_input, columns=["sex", "smoker", "day", "time"], drop_first=True)
    
    for col in FEATURES:
        if col not in df_processed.columns:
            df_processed[col] = 0
            
    final_features = df_processed[FEATURES]
    
    numerical_part = final_features[NUMERICAL_COLS]
    
    scaled_numerical = scaler.transform(numerical_part)
    
    final_input_array = final_features.values.copy()
    final_input_array[:, 0:len(NUMERICAL_COLS)] = scaled_numerical
    
    prediction = model.predict(final_input_array)
    
    return float(prediction[0])

# --- Streamlit Interface ---
st.set_page_config(page_title="Waiter Tip Predictor", layout="centered")
st.title("💰 Waiter Tip Prediction")
st.markdown("Enter bill details and dining context to predict the tip amount ($).")

model, scaler = load_assets()

if model is not None and scaler is not None:
    st.sidebar.header("Dining Details")

    total_bill = st.sidebar.number_input("Total Bill ($):", min_value=1.0, value=25.0, step=0.5)
    size = st.sidebar.number_input("Party Size:", min_value=1, max_value=10, value=3)
    
    bill_per_person = total_bill / size if size > 0 else 0 

    sex = st.sidebar.selectbox("Server/Diner Sex:", options=["Female", "Male"])
    smoker = st.sidebar.selectbox("Smoker at Table?", options=["No", "Yes"])
    day = st.sidebar.selectbox("Day of the Week:", options=["Thur", "Fri", "Sat", "Sun"])
    time = st.sidebar.selectbox("Time of Day:", options=["Lunch", "Dinner"])

    input_data = {
        'total_bill': total_bill,
        'size': size,
        'bill_per_person': bill_per_person,
        'sex': sex,
        'smoker': smoker,
        'day': day,
        'time': time
    }

    st.subheader("Input Summary:")
    st.dataframe(pd.DataFrame([input_data]), hide_index=True)

    if st.button("Predict Tip Amount"):
        with st.spinner('Calculating prediction...'):
            predicted_tip = preprocess_and_predict(model, scaler, input_data)
            
            st.success("Prediction Successful!")
            st.markdown("### Predicted Tip:")
            st.markdown(f"**${predicted_tip:,.2f}**")
            
            st.info(f"The predicted tip is approximately {predicted_tip/total_bill:.1%} of the total bill.")