MBG0903 commited on
Commit
ebd6e2b
Β·
verified Β·
1 Parent(s): eea822e

Deploy docker Streamlit app

Browse files
Files changed (5) hide show
  1. Dockerfile +11 -0
  2. README.md +6 -5
  3. app.py +78 -0
  4. requirements.txt +5 -0
  5. streamlit_app.py +91 -0
Dockerfile ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+ ENV PYTHONUNBUFFERED=1
3
+ # HF Spaces sets PORT; default to 7860 for local dev
4
+ ENV PORT=7860
5
+ WORKDIR /app
6
+ COPY requirements.txt /app/requirements.txt
7
+ RUN apt-get update && apt-get install -y --no-install-recommends build-essential && rm -rf /var/lib/apt/lists/* && pip install --no-cache-dir -r /app/requirements.txt
8
+ COPY app.py /app/app.py
9
+ EXPOSE 7860
10
+ # Use shell form so $PORT expands
11
+ CMD streamlit run app.py --server.port $PORT --server.address 0.0.0.0
README.md CHANGED
@@ -1,10 +1,11 @@
1
  ---
2
- title: Customer Prediction App
3
- emoji: πŸ“ˆ
4
- colorFrom: blue
5
- colorTo: indigo
6
  sdk: docker
 
7
  pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Tourism Prediction App
3
+ emoji: 🏝️
4
+ colorFrom: yellow
5
+ colorTo: green
6
  sdk: docker
7
+ app_port: 7860
8
  pinned: false
9
  ---
10
 
11
+ <!-- redeploy 1756565971 -->
app.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, json, joblib
2
+ import pandas as pd
3
+ import streamlit as st
4
+ from huggingface_hub import hf_hub_download
5
+
6
+ st.set_page_config(page_title="Wellness Package Predictor", page_icon="🏝️", layout="centered")
7
+ st.title("🏝️ Wellness Tourism Package β€” Purchase Propensity")
8
+
9
+ def get_secret(name: str, default=None):
10
+ try:
11
+ return st.secrets[name]
12
+ except Exception:
13
+ return os.getenv(name, default)
14
+
15
+ MODEL_REPO = get_secret("MODEL_REPO", "MBG0903/tourism_customer_xgb")
16
+ HF_TOKEN = get_secret("HF_TOKEN", None)
17
+
18
+ @st.cache_resource(show_spinner=True)
19
+ def load_artifacts(repo_id: str, token: str | None):
20
+ model_path = hf_hub_download(repo_id=repo_id, filename="model.joblib", token=token)
21
+ meta_path = hf_hub_download(repo_id=repo_id, filename="metadata.json", token=token)
22
+ model = joblib.load(model_path)
23
+ with open(meta_path, "r") as f:
24
+ meta = json.load(f)
25
+ return model, meta
26
+
27
+ try:
28
+ model, meta = load_artifacts(MODEL_REPO, HF_TOKEN)
29
+ except Exception as e:
30
+ st.error(f"Failed to load model artifacts from {MODEL_REPO}. Details: {e}")
31
+ st.stop()
32
+
33
+ st.caption("Model metrics (from training)")
34
+ st.json(meta.get("metrics", {}))
35
+
36
+ st.sidebar.header("Enter Customer Profile")
37
+ def i_num(label, value, minv=None, maxv=None, step=1):
38
+ return st.sidebar.number_input(label, value=value, min_value=minv, max_value=maxv, step=step)
39
+
40
+ inputs = {}
41
+ inputs["CustomerID"] = st.sidebar.text_input("CustomerID", "CUST_000001")
42
+ inputs["Age"] = i_num("Age", 32, 18, 90)
43
+ inputs["TypeofContact"] = st.sidebar.selectbox("TypeofContact", ["Company Invited","Self Inquiry"])
44
+ inputs["CityTier"] = st.sidebar.selectbox("CityTier", ["Tier 1","Tier 2","Tier 3"])
45
+ inputs["Occupation"] = st.sidebar.selectbox("Occupation", ["Salaried","Freelancer","Self Employed","Student","Retired"])
46
+ inputs["Gender"] = st.sidebar.selectbox("Gender", ["Male","Female"])
47
+ inputs["NumberOfPersonVisiting"] = i_num("NumberOfPersonVisiting", 2, 1, 10)
48
+ inputs["PreferredPropertyStar"] = i_num("PreferredPropertyStar", 4, 1, 5)
49
+ inputs["MaritalStatus"] = st.sidebar.selectbox("MaritalStatus", ["Single","Married","Divorced"])
50
+ inputs["NumberOfTrips"] = i_num("NumberOfTrips", 3, 0, 50)
51
+ inputs["Passport"] = st.sidebar.selectbox("Passport", [0,1])
52
+ inputs["OwnCar"] = st.sidebar.selectbox("OwnCar", [0,1])
53
+ inputs["NumberOfChildrenVisiting"] = i_num("NumberOfChildrenVisiting", 0, 0, 10)
54
+ inputs["Designation"] = st.sidebar.selectbox("Designation", ["Executive","Manager","Senior Manager","AVP","VP","Director"])
55
+ inputs["MonthlyIncome"] = i_num("MonthlyIncome", 70000, 0, 1_000_000, 1000)
56
+ inputs["PitchSatisfactionScore"] = i_num("PitchSatisfactionScore", 4, 1, 5)
57
+ inputs["ProductPitched"] = st.sidebar.selectbox("ProductPitched", ["Basic","Deluxe","Super Deluxe","King","Queen"])
58
+ inputs["NumberOfFollowups"] = i_num("NumberOfFollowups", 2, 0, 20)
59
+ inputs["DurationOfPitch"] = i_num("DurationOfPitch", 15, 0, 120)
60
+
61
+ df_in = pd.DataFrame([inputs])
62
+ for junk in ["Unnamed: 0", "index"]:
63
+ if junk in df_in.columns: df_in = df_in.drop(columns=[junk])
64
+
65
+ feature_order = meta.get("feature_order")
66
+ if feature_order: df_in = df_in[[c for c in feature_order if c in df_in.columns]]
67
+
68
+ threshold = float(meta.get("threshold", 0.5))
69
+
70
+ if st.button("Predict"):
71
+ try:
72
+ proba = float(model.predict_proba(df_in)[:, 1][0])
73
+ pred = int(proba >= threshold)
74
+ st.metric("Purchase Probability", f"{proba:.3f}")
75
+ st.write("Prediction:", "Will Purchase (1)" if pred else "Will Not Purchase (0)")
76
+ with st.expander("Input snapshot"): st.dataframe(df_in)
77
+ except Exception as e:
78
+ st.error(f"Prediction failed: {e}")
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ streamlit>=1.33
2
+ pandas
3
+ scikit-learn
4
+ joblib
5
+ huggingface_hub>=0.23
streamlit_app.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, json, joblib
2
+ import pandas as pd
3
+ import streamlit as st
4
+ from huggingface_hub import hf_hub_download
5
+
6
+ st.set_page_config(page_title="Wellness Package Predictor", page_icon="🏝️", layout="centered")
7
+ st.title("🏝️ Wellness Tourism Package β€” Purchase Propensity")
8
+
9
+ def get_secret(name: str, default=None):
10
+ try:
11
+ return st.secrets[name]
12
+ except Exception:
13
+ return os.getenv(name, default)
14
+
15
+ # ---- Model location & token ----
16
+ MODEL_REPO = get_secret("MODEL_REPO", "MBG0903/tourism_customer_xgb")
17
+ HF_TOKEN = get_secret("HF_TOKEN", None) # only needed if the model repo is private
18
+
19
+ @st.cache_resource(show_spinner=True)
20
+ def load_artifacts(repo_id: str, token: str | None):
21
+ model_path = hf_hub_download(repo_id=repo_id, filename="model.joblib", token=token)
22
+ meta_path = hf_hub_download(repo_id=repo_id, filename="metadata.json", token=token)
23
+ model = joblib.load(model_path)
24
+ with open(meta_path, "r") as f:
25
+ meta = json.load(f)
26
+ return model, meta
27
+
28
+ try:
29
+ model, meta = load_artifacts(MODEL_REPO, HF_TOKEN)
30
+ except Exception as e:
31
+ st.error(f"Failed to load model artifacts from {MODEL_REPO}. Details: {e}")
32
+ st.stop()
33
+
34
+ st.caption("Model metrics (from training)")
35
+ st.json(meta.get("metrics", {}))
36
+
37
+ # ---- Inputs ----
38
+ st.sidebar.header("Enter Customer Profile")
39
+
40
+ def i_num(label, value, minv=None, maxv=None, step=1):
41
+ return st.sidebar.number_input(label, value=value, min_value=minv, max_value=maxv, step=step)
42
+
43
+ inputs = {}
44
+ inputs["CustomerID"] = st.sidebar.text_input("CustomerID", "CUST_000001")
45
+ inputs["Age"] = i_num("Age", 32, 18, 90)
46
+ inputs["TypeofContact"] = st.sidebar.selectbox("TypeofContact", ["Company Invited","Self Inquiry"])
47
+ inputs["CityTier"] = st.sidebar.selectbox("CityTier", ["Tier 1","Tier 2","Tier 3"])
48
+ inputs["Occupation"] = st.sidebar.selectbox("Occupation", ["Salaried","Freelancer","Self Employed","Student","Retired"])
49
+ inputs["Gender"] = st.sidebar.selectbox("Gender", ["Male","Female"])
50
+ inputs["NumberOfPersonVisiting"] = i_num("NumberOfPersonVisiting", 2, 1, 10)
51
+ inputs["PreferredPropertyStar"] = i_num("PreferredPropertyStar", 4, 1, 5)
52
+ inputs["MaritalStatus"] = st.sidebar.selectbox("MaritalStatus", ["Single","Married","Divorced"])
53
+ inputs["NumberOfTrips"] = i_num("NumberOfTrips", 3, 0, 50)
54
+ inputs["Passport"] = st.sidebar.selectbox("Passport", [0,1])
55
+ inputs["OwnCar"] = st.sidebar.selectbox("OwnCar", [0,1])
56
+ inputs["NumberOfChildrenVisiting"] = i_num("NumberOfChildrenVisiting", 0, 0, 10)
57
+ inputs["Designation"] = st.sidebar.selectbox("Designation", ["Executive","Manager","Senior Manager","AVP","VP","Director"])
58
+ inputs["MonthlyIncome"] = i_num("MonthlyIncome", 70000, 0, 1_000_000, 1000)
59
+ inputs["PitchSatisfactionScore"] = i_num("PitchSatisfactionScore", 4, 1, 5)
60
+ inputs["ProductPitched"] = st.sidebar.selectbox("ProductPitched", ["Basic","Deluxe","Super Deluxe","King","Queen"])
61
+ inputs["NumberOfFollowups"] = i_num("NumberOfFollowups", 2, 0, 20)
62
+ inputs["DurationOfPitch"] = i_num("DurationOfPitch", 15, 0, 120)
63
+
64
+ df_in = pd.DataFrame([inputs])
65
+
66
+ # Defensive cleanup (if any junk cols appear)
67
+ for junk in ["Unnamed: 0", "index"]:
68
+ if junk in df_in.columns:
69
+ df_in = df_in.drop(columns=[junk])
70
+
71
+ # Respect training feature order if provided
72
+ feature_order = meta.get("feature_order")
73
+ if feature_order:
74
+ missing = [c for c in feature_order if c not in df_in.columns]
75
+ if missing:
76
+ st.warning(f"Input missing expected columns: {missing}")
77
+ df_in = df_in[[c for c in feature_order if c in df_in.columns]]
78
+
79
+ threshold = float(meta.get("threshold", 0.5))
80
+
81
+ if st.button("Predict"):
82
+ try:
83
+ proba = float(model.predict_proba(df_in)[:, 1][0])
84
+ pred = int(proba >= threshold)
85
+ st.metric("Purchase Probability", f"{proba:.3f}")
86
+ st.write("Prediction:", "Will Purchase (1)" if pred == 1 else "Will Not Purchase (0)")
87
+ with st.expander("Input snapshot"):
88
+ st.dataframe(df_in)
89
+ except Exception as e:
90
+ st.error(f"Prediction failed: {e}")
91
+