vksfdc2024's picture
Upload folder using huggingface_hub
4231826 verified
# Import the os module for environment variable operations
import os
# Import streamlit for creating the web application interface
import streamlit as st
# Import pandas for data manipulation and DataFrame operations
import pandas as pd
# Import requests for making HTTP requests to the backend API
import requests
# Configure the Streamlit page with title, icon, and layout
st.set_page_config(page_title="Super Kart Sales Predictor", page_icon="🛒", layout="centered")
# API configuration (set your deployed Backend Space URL)
# Get the backend URL from environment variable, with a default fallback
default_backend = os.getenv("BACKEND_URL", "https://vksfdc2024-SuperKartbackend.hf.space")
# Create a text input in the sidebar for users to modify the backend API URL
api_base_url = st.sidebar.text_input(
"Backend API base URL", # Label for the input field
value=default_backend, # Default value from environment or fallback
help="Example: https://<username>-backend.hf.space" # Help text for users
)
# Helper function to normalize the base URL format
def normalize_base(url: str) -> str:
# Check if the URL is empty or None
if not url:
# Return empty string if no URL provided
return ""
# Remove leading and trailing whitespace from the URL
url = url.strip()
# Check if URL ends with a trailing slash
if url.endswith('/'):
# Remove the trailing slash for consistency
url = url[:-1]
# Return the normalized URL
return url
# Apply the normalization function to the API base URL
api_base_url = normalize_base(api_base_url)
# Display the main title of the application
st.title("Super Kart - Product Store Sales Prediction")
# Display descriptive text explaining what the app does
st.write("Enter product and store details to predict Product_Store_Sales_Total.")
# Create a sidebar section for additional controls
with st.sidebar:
# Create a button to test the backend health endpoint
if st.button("Test backend /health"):
# Start try block for error handling
try:
# Make a GET request to the health endpoint with 10-second timeout
r = requests.get(f"{api_base_url}/health", timeout=10)
# Display success message with status code and response text
st.success(f"Health OK {r.status_code}: {r.text}")
# Catch any exceptions during the health check
except Exception as e:
# Display error message with exception details
st.error(f"Health check failed: {e}")
# ---------------------------------------------
# Input form
# ---------------------------------------------
# Create a form container for user inputs
with st.form("predict_form"):
# Create two columns for organizing input fields
col1, col2 = st.columns(2)
# Left column inputs
with col1:
# Text input for product identifier with default value
Product_Identifier = st.text_input("Product Identifier", value="PROD_0001")
# Number input for product weight with constraints and default
Product_Weight = st.number_input("Product Weight", min_value=0.0, step=0.01, value=12.3)
# Dropdown selection for product sugar content categories
Product_Sugar_Content = st.selectbox(
"Product Sugar Content", # Label for the selectbox
["Low Sugar", "Regular", "No Sugar"] # Available options
)
# Number input for product allocated area with specific constraints
Product_Allocated_Area = st.number_input("Product Allocated Area", min_value=0.0, max_value=1.0, step=0.0001, value=0.065)
# Dropdown selection for product type with multiple categories
Product_Type = st.selectbox(
"Product Type", # Label for the selectbox
[ # List of available product types
"Fruits and Vegetables", "Snack Foods", "Household", "Frozen Foods",
"Dairy", "Canned", "Baking Goods", "Health and Hygiene",
"Soft Drinks", "Meat", "Breads", "Hard Drinks",
"Starchy Foods", "Breakfast", "Seafood", "Others"
],
index=1 # Default to second option (Snack Foods)
)
# Right column inputs
with col2:
# Number input for Maximum Retail Price with constraints
Product_MRP = st.number_input("Product MRP", min_value=0.0, step=0.01, value=249.99)
# Text input for store identifier with default value
Store_Identifier = st.text_input("Store Identifier", value="OUT013")
# Number input for store establishment year with realistic range
Store_Establishment_Year = st.number_input("Store Establishment Year", min_value=1900, max_value=2100, value=2009, step=1)
# Dropdown selection for store size categories
Store_Size = st.selectbox("Store Size", ["Small", "Medium", "High"], index=1)
# Dropdown selection for store location tier
Store_Location_Type = st.selectbox("Store Location Type", ["Tier 1", "Tier 2", "Tier 3"], index=1)
# Dropdown selection for store type with multiple categories
Store_Type = st.selectbox(
"Store Type", # Label for the selectbox
["Supermarket Type1", "Supermarket Type2", "Supermarket Type3", "Grocery Store"], # Available options
index=0 # Default to first option
)
# Create a submit button for the form with primary styling
submitted = st.form_submit_button("Predict", type="primary")
# Prepare payload dictionary as expected by the backend API
payload = {
"Product_Identifier": Product_Identifier, # Product ID from form input
"Product_Weight": Product_Weight, # Product weight from form input
"Product_Sugar_Content": Product_Sugar_Content, # Sugar content selection from form
"Product_Allocated_Area": Product_Allocated_Area, # Allocated area from form input
"Product_Type": Product_Type, # Product type selection from form
"Product_MRP": Product_MRP, # MRP from form input
"Store_Identifier": Store_Identifier, # Store ID from form input
"Store_Establishment_Year": int(Store_Establishment_Year), # Convert year to integer
"Store_Size": Store_Size, # Store size selection from form
"Store_Location_Type": Store_Location_Type, # Location type selection from form
"Store_Type": Store_Type # Store type selection from form
}
# ---------------------------------------------
# Single prediction
# ---------------------------------------------
# Check if the form was submitted
if submitted:
# Start try block for error handling
try:
# Construct the full URL for the single product prediction endpoint
url = f"{api_base_url}/v1/product"
# Make POST request to API with JSON payload and 30-second timeout
resp = requests.post(url, json=payload, timeout=30)
# Check if the response status code indicates success
if resp.status_code == 200:
# Parse the JSON response
out = resp.json()
# Display success message with the predicted sales value
st.success(f"Predicted Sales: {out.get('Predicted_Sales', 'N/A')}")
# Display additional information about the prediction
st.caption(f"Product: {out.get('Product_Identifier', Product_Identifier)} | Store: {out.get('Store_Identifier', Store_Identifier)}")
# Handle non-200 status codes
else:
# Try to parse error response as JSON
try:
# Display error message with JSON error details
st.error(f"Request failed ({resp.status_code}): {resp.json()}")
# If JSON parsing fails, show raw text
except Exception:
# Display error message with raw response text
st.error(f"Request failed ({resp.status_code}): {resp.text}")
# Catch any exceptions during API communication
except Exception as e:
# Display error message with exception details
st.error(f"Error contacting API: {e}")
# Add a horizontal line separator
st.markdown("---")
# ---------------------------------------------
# Batch prediction
# ---------------------------------------------
# Display subheader for batch prediction section
st.subheader("Batch Prediction (CSV Upload)")
# Display instruction text for CSV upload
st.write("Upload a CSV with the following columns:")
# Define the list of required columns for batch prediction
required_cols = [
"Product_Identifier", "Product_Weight", "Product_Sugar_Content", "Product_Allocated_Area",
"Product_Type", "Product_MRP", "Store_Identifier", "Store_Establishment_Year",
"Store_Size", "Store_Location_Type", "Store_Type"
]
# Display the required columns in a code block format
st.code(", ".join(required_cols))
# Provide a small downloadable template
# Create a sample DataFrame with one row of example data
template_df = pd.DataFrame([{
"Product_Identifier": "PROD_0001", # Example product ID
"Product_Weight": 12.3, # Example weight
"Product_Sugar_Content": "Regular", # Example sugar content
"Product_Allocated_Area": 0.065, # Example allocated area
"Product_Type": "Snack Foods", # Example product type
"Product_MRP": 249.99, # Example MRP
"Store_Identifier": "OUT013", # Example store ID
"Store_Establishment_Year": 2009, # Example establishment year
"Store_Size": "Medium", # Example store size
"Store_Location_Type": "Tier 2", # Example location type
"Store_Type": "Supermarket Type1" # Example store type
}])
# Create a download button for the CSV template
st.download_button(
"Download CSV Template", # Button label
data=template_df.to_csv(index=False), # Convert DataFrame to CSV without index
file_name="super_kart_batch_template.csv", # Downloaded filename
mime="text/csv" # MIME type for CSV files
)
# Create file uploader widget for CSV files
uploaded = st.file_uploader("Upload CSV", type=["csv"])
# Check if a file has been uploaded
if uploaded is not None:
# Start try block for error handling
try:
# Read the uploaded CSV file into a DataFrame
df_preview = pd.read_csv(uploaded)
# Display a preview of the first few rows
st.write("Preview:", df_preview.head())
# Catch exceptions during CSV reading
except Exception as e:
# Display error message if CSV cannot be read
st.error(f"Could not read CSV: {e}")
# Create a button to trigger batch prediction
if st.button("Predict for Batch", type="primary"):
# Start try block for error handling
try:
# Construct the URL for batch prediction endpoint
url = f"{api_base_url}/v1/productbatch"
# Prepare file data for multipart form upload
files = {"file": (uploaded.name, uploaded.getvalue(), "text/csv")}
# Make POST request with file upload and 60-second timeout
resp = requests.post(url, files=files, timeout=60)
# Check if the response status code indicates success
if resp.status_code == 200:
# Parse the JSON response containing predictions
result = resp.json()
# Display success message
st.success("Batch predictions received.")
# Convert the result dictionary to a DataFrame for display
st.write(pd.DataFrame(list(result.items()), columns=["Product_Identifier", "Predicted_Sales"]))
# Handle non-200 status codes
else:
# Try to parse error response as JSON
try:
# Display error message with JSON error details
st.error(f"Request failed ({resp.status_code}): {resp.json()}")
# If JSON parsing fails, show raw text
except Exception:
# Display error message with raw response text
st.error(f"Request failed ({resp.status_code}): {resp.text}")
# Catch any exceptions during batch API communication
except Exception as e:
# Display error message with exception details
st.error(f"Error contacting API: {e}")