Himadri1102's picture
Upload folder using huggingface_hub
bc9f8c2 verified
import streamlit as st
import pandas as pd
import requests
import json
BACKEND_URL = "https://Himadri1102-SuperKart-Model-Backend11.hf.space"
SINGLE_PREDICT_ENDPOINT = f"{BACKEND_URL}/v1/sales"
BATCH_PREDICT_ENDPOINT = f"{BACKEND_URL}/v1/salesbatch"
# --- UI Setup ---
st.title("SuperKart Sales Revenue Forecast")
st.markdown("Predicts the total sales revenue for a specific product and store combination.")
st.subheader("1. Product and Store Inputs")
st.markdown("⚠️ **WARNING**: The model requires ALL 29+ features (scaled/encoded). This UI collects only key features and defaults the rest for demonstration.")
# --- Collect Key User Input (Based on Bivariate Analysis) ---
product_mrp = st.number_input("Product MRP (Maximum Retail Price)", min_value=30.0, max_value=300.0, value=150.0, step=5.0)
product_weight = st.number_input("Product Weight", min_value=4.0, max_value=22.0, value=12.0, step=0.1)
store_age = st.number_input("Store Age (Years)", min_value=5, max_value=40, value=20)
store_size = st.selectbox("Store Size", ["Small", "Medium", "High"])
# --- Feature Preparation (Simulating Preprocessing Pipeline) ---
# CRITICAL: This mapping MUST match the Label Encoding in your training/pipeline code
store_size_encoded = {'Small': 0, 'Medium': 1, 'High': 2}[store_size]
def create_payload(mrp, weight, age, size_enc):
"""
Creates the full, complete feature payload required by the XGBoost pipeline.
All missing OHE features are set to False (0) or a continuous feature is set to its mean.
"""
# NOTE: The final payload MUST contain every column the model pipeline expects.
payload = {
# --- 1. USER INPUTS (Numerical/Encoded) ---
'Product_MRP': mrp,
'Product_Weight': weight,
'Store_Age': age,
'Store_Size_Encoded': size_enc,
# --- 2. MISSING CONTINUOUS FEATURE (Set to a mean value) ---
# Mean Product_Allocated_Area from EDA was approx 0.0687
'Product_Allocated_Area': 0.0687,
# --- 3. ALL OHE FEATURES (Defaulted to False/0) ---
# Default all OHE features to False, except for one selection in each group
# to represent a valid input case.
# --- Product Sugar Content (Only 'Regular' is True by default for this test case) ---
'Product_Sugar_Content_No Sugar': False,
'Product_Sugar_Content_Regular': True,
'Product_Sugar_Content_Low Sugar': False,
# Note: If 'Low Sugar' was also a required column, it should be added here.
# --- Product Type (Defaulting 'Snack Foods' to True) ---
'Product_Type_Baking Goods': False,
'Product_Type_Breads': False,
'Product_Type_Breakfast': False,
'Product_Type_Canned': False,
'Product_Type_Dairy': False,
'Product_Type_Frozen Foods': False,
'Product_Type_Fruits and Vegetables': False,
'Product_Type_Hard Drinks': False,
'Product_Type_Health and Hygiene': False,
'Product_Type_Household': False,
'Product_Type_Meat': False,
'Product_Type_Others': False,
'Product_Type_Seafood': False,
'Product_Type_Snack Foods': True, # Representing the active category
'Product_Type_Soft Drinks': False,
'Product_Type_Starchy Foods': False,
# --- Store Location City Type (Defaulting 'Tier 2' to True) ---
'Store_Location_City_Type_Tier 1': False,
'Store_Location_City_Type_Tier 2': True,
'Store_Location_City_Type_Tier 3': False,
# --- Store Type (Defaulting 'Supermarket Type1' to True) ---
'Store_Type_Departmental Store': False,
'Store_Type_Food Mart': False,
'Store_Type_Supermarket Type1': True,
'Store_Type_Supermarket Type2': False,
}
# Check if the store size is Medium/High and adjust Store Type accordingly
# to avoid errors if the model logic was built on specific assumptions.
if store_size == 'High':
# If High, typically Supermarket Type2 is also a variable. Adjusting a mock OHE:
payload['Store_Type_Supermarket Type1'] = False
payload['Store_Type_Supermarket Type2'] = True
return payload
# --- Prediction Logic ---
if st.button("Predict Sales Revenue"):
# 1. Create the full data payload
input_payload = create_payload(product_mrp, product_weight, store_age, store_size_encoded)
# 2. Call the Backend API
response = requests.post(SINGLE_PREDICT_ENDPOINT, json=input_payload)
if response.status_code == 200:
try:
prediction = response.json()['Predicted Total Sales']
st.success(f"📈 Predicted Sales Revenue: **${prediction:,.2f}**")
except KeyError:
st.error("Prediction successful but key 'Predicted Total Sales' was missing from API response.")
st.json(response.json())
else:
st.error(f"Error making prediction. Status Code: {response.status_code}")
st.json(response.json())
# --- Batch Prediction Section ---
st.subheader("2. Batch Prediction (CSV Upload)")
uploaded_file = st.file_uploader("Upload CSV file for batch prediction", type=["csv"])
if uploaded_file is not None:
if st.button("Predict Batch Sales"):
response = requests.post(BATCH_PREDICT_ENDPOINT, files={"file": uploaded_file})
if response.status_code == 200:
predictions = response.json()
st.success("Batch predictions completed!")
st.dataframe(pd.DataFrame(list(predictions.items()), columns=['ID', 'Predicted Sales']))
else:
st.error(f"Error making batch prediction. Status Code: {response.status_code}")
st.json(response.json())