frontend / app.py
Rizwan9's picture
Update app.py
6c5e526 verified
import os
import streamlit as st
import requests
import pandas as pd
st.set_page_config(page_title="πŸ›’ SuperKart Sales Forecast", layout="centered")
st.title("SuperKart Sales Forecast")
st.caption("Frontend powered by Streamlit β†’ calls Flask backend for predictions")
# -----------------------------
# Backend URL (no st.secrets)
# -----------------------------
def resolve_backend_url() -> str:
# Use HF Space variable if set, else fallback to your backend
return (os.getenv("BACKEND_URL") or "https://rizwan9-backend.hf.space").strip()
BACKEND_URL = resolve_backend_url()
# -----------------------------
# Sidebar: Backend Health
# -----------------------------
st.sidebar.title("βš™οΈ Backend")
backend_url_input = st.sidebar.text_input("Backend URL", value=BACKEND_URL)
BACKEND_URL = backend_url_input.strip() or BACKEND_URL
st.sidebar.markdown(f"**URL:** [{BACKEND_URL}]({BACKEND_URL})")
@st.cache_data(ttl=60, show_spinner=False)
def check_backend_health(url: str, timeout: int = 45):
try:
r = requests.get(f"{url}/health", timeout=timeout)
return r.status_code, r.text
except Exception as e:
return None, str(e)
status_box = st.sidebar.empty()
auto_check = st.sidebar.toggle("Auto check health on load", value=True)
def run_health_check():
with status_box, st.spinner("Checking backend health..."):
code, msg = check_backend_health(BACKEND_URL)
if code == 200:
status_box.success("βœ… Healthy (200)")
elif code is None:
status_box.error(f"❌ Unreachable\n{msg}")
else:
status_box.warning(f"⚠️ Status {code}\n{msg}")
if auto_check:
run_health_check()
if st.sidebar.button("πŸ” Check Health Now"):
check_backend_health.clear()
run_health_check()
# -----------------------------
# Form
# -----------------------------
st.divider()
st.subheader("Enter Product and Store Details")
with st.form("input_form"):
col1, col2 = st.columns(2)
with col1:
Product_Weight = st.number_input("Product Weight", min_value=0.0, step=0.1)
Product_Allocated_Area = st.number_input("Product Allocated Area", min_value=0.0, step=0.001, format="%.3f")
Product_MRP = st.number_input("Product MRP", min_value=0.0, step=0.5)
Store_Establishment_Year = st.number_input("Store Establishment Year", min_value=1950, max_value=2025, step=1)
with col2:
Product_Sugar_Content = st.selectbox("Product Sugar Content", ["Low Sugar", "Regular", "No Sugar"])
# note the lowercase "and" to match dataset
Product_Type = st.selectbox("Product Type", [
"Meat","Snack Foods","Hard Drinks","Dairy","Canned","Soft Drinks","Health and Hygiene",
"Baking Goods","Bread","Breakfast","Frozen Foods","Fruits and Vegetables","Household",
"Seafood","Starchy Foods","Others"
])
Store_Size = st.selectbox("Store Size", ["Low","Medium","High"])
Store_Location_City_Type = st.selectbox("City Tier", ["Tier 1","Tier 2","Tier 3"])
Store_Type = st.selectbox("Store Type", ["Departmental Store","Supermarket Type 1","Supermarket Type 2","Food Mart"])
submitted = st.form_submit_button("πŸš€ Predict Sales")
# -----------------------------
# Call backend
# -----------------------------
if submitted:
payload = {
"Product_Weight": Product_Weight,
"Product_Sugar_Content": Product_Sugar_Content,
"Product_Allocated_Area": Product_Allocated_Area,
"Product_Type": Product_Type,
"Product_MRP": Product_MRP,
"Store_Establishment_Year": int(Store_Establishment_Year),
"Store_Size": Store_Size,
"Store_Location_City_Type": Store_Location_City_Type,
"Store_Type": Store_Type
}
try:
with st.spinner("Fetching prediction from backend..."):
r = requests.post(f"{BACKEND_URL}/predict", json=payload, timeout=60)
if r.status_code != 200:
# show backend's detailed message to make debugging easy
try:
st.error(f"❌ Prediction failed ({r.status_code}):\n\n{r.json()}")
except Exception:
st.error(f"❌ Prediction failed ({r.status_code}):\n\n{r.text}")
else:
prediction = r.json()["predictions"][0]
st.success(f"πŸ“ˆ Predicted Product Store Sales Total: **{prediction:,.2f}**")
except Exception as e:
st.error(f"❌ Prediction failed:\n\n{e}")