import streamlit as st
import requests
import json
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime
import time
# Page configuration
st.set_page_config(
page_title="SuperKart Sales Forecasting",
page_icon="🛒",
layout="wide",
initial_sidebar_state="expanded"
)
# Custom CSS for better styling
st.markdown("""
""", unsafe_allow_html=True)
# API Configuration
API_BASE_URL = "https://your-backend-api-url.hf.space" # Replace with your actual API URL
def check_api_health():
"""Check if the API is healthy and accessible."""
try:
response = requests.get(f"{API_BASE_URL}/health", timeout=10)
return response.status_code == 200
except:
return False
def make_prediction(data):
"""Make a single prediction using the API."""
try:
response = requests.post(
f"{API_BASE_URL}/predict",
json=data,
headers={"Content-Type": "application/json"},
timeout=30
)
if response.status_code == 200:
return response.json(), None
else:
return None, f"API Error: {response.status_code} - {response.text}"
except requests.exceptions.Timeout:
return None, "Request timeout. Please try again."
except requests.exceptions.ConnectionError:
return None, "Cannot connect to API. Please check your internet connection."
except Exception as e:
return None, f"Unexpected error: {str(e)}"
def make_batch_prediction(data_list):
"""Make batch predictions using the API."""
try:
response = requests.post(
f"{API_BASE_URL}/batch_predict",
json=data_list,
headers={"Content-Type": "application/json"},
timeout=60
)
if response.status_code == 200:
return response.json(), None
else:
return None, f"API Error: {response.status_code} - {response.text}"
except requests.exceptions.Timeout:
return None, "Request timeout. Please try again."
except requests.exceptions.ConnectionError:
return None, "Cannot connect to API. Please check your internet connection."
except Exception as e:
return None, f"Unexpected error: {str(e)}"
def main():
"""Main Streamlit application."""
# Main header
st.markdown('
🛒 SuperKart Sales Forecasting
', unsafe_allow_html=True)
st.markdown("### AI-Powered Sales Prediction for Retail Excellence")
# Sidebar for navigation
st.sidebar.title("🎯 Navigation")
app_mode = st.sidebar.selectbox("Choose the app mode",
["Single Prediction", "Batch Prediction", "Analytics Dashboard", "API Status"])
# API Health Check
with st.sidebar:
st.markdown("---")
st.subheader("🔧 API Status")
if st.button("Check API Health"):
with st.spinner("Checking API..."):
if check_api_health():
st.success("✅ API is healthy")
else:
st.error("❌ API is not accessible")
st.markdown("---")
st.markdown("""
**Features:**
- 🎯 Single Prediction
- 📊 Batch Predictions
- 📈 Analytics Dashboard
- 🔍 Real-time Validation
""")
# Main content based on selected mode
if app_mode == "Single Prediction":
single_prediction_page()
elif app_mode == "Batch Prediction":
batch_prediction_page()
elif app_mode == "Analytics Dashboard":
analytics_dashboard_page()
elif app_mode == "API Status":
api_status_page()
def single_prediction_page():
"""Single prediction interface."""
st.header("🎯 Single Sales Prediction")
st.markdown("Enter product and store details to get an instant sales forecast.")
# Create input form
with st.form("prediction_form"):
col1, col2, col3 = st.columns(3)
with col1:
st.subheader("📦 Product Details")
product_weight = st.number_input(
"Product Weight (kg)",
min_value=0.1,
max_value=50.0,
value=12.5,
step=0.1,
help="Weight of the product in kilograms"
)
product_sugar_content = st.selectbox(
"Sugar Content",
["Low Sugar", "Regular", "No Sugar"],
help="Sugar content category of the product"
)
product_allocated_area = st.number_input(
"Allocated Display Area",
min_value=0.001,
max_value=1.0,
value=0.1,
step=0.001,
format="%.3f",
help="Ratio of allocated display area (0-1)"
)
product_type = st.selectbox(
"Product Type",
[
"Fruits and Vegetables", "Snack Foods", "Household", "Frozen Foods",
"Dairy", "Canned", "Baking Goods", "Health and Hygiene", "Meat",
"Soft Drinks", "Hard Drinks", "Starchy Foods", "Breakfast",
"Seafood", "Bread", "Others"
],
help="Category of the product"
)
product_mrp = st.number_input(
"Maximum Retail Price (₹)",
min_value=1.0,
max_value=500.0,
value=150.0,
step=1.0,
help="Maximum retail price in rupees"
)
with col2:
st.subheader("🏪 Store Details")
store_size = st.selectbox(
"Store Size",
["Small", "Medium", "High"],
index=1,
help="Size category of the store"
)
store_location_city_type = st.selectbox(
"City Type",
["Tier 1", "Tier 2", "Tier 3"],
index=1,
help="Tier classification of the city"
)
store_type = st.selectbox(
"Store Type",
["Departmental Store", "Supermarket Type1", "Supermarket Type2", "Food Mart"],
index=2,
help="Type/format of the store"
)
store_age = st.number_input(
"Store Age (years)",
min_value=0,
max_value=50,
value=15,
step=1,
help="Age of the store in years"
)
with col3:
st.subheader("📊 Prediction Summary")
st.markdown("""
**Input Validation:**
- All fields are required
- Weights: 0.1 - 50 kg
- Display Area: 0.001 - 1.0
- MRP: ₹1 - ₹500
- Store Age: 0 - 50 years
""")
st.markdown("---")
st.markdown("**Business Context:**")
st.markdown("This prediction helps with:")
st.markdown("- Inventory planning")
st.markdown("- Revenue forecasting")
st.markdown("- Store optimization")
st.markdown("- Regional strategy")
# Submit button
submitted = st.form_submit_button("🚀 Predict Sales", use_container_width=True)
if submitted:
# Prepare data for API
prediction_data = {
"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_Size": store_size,
"Store_Location_City_Type": store_location_city_type,
"Store_Type": store_type,
"Store_Age": store_age
}
# Make prediction
with st.spinner("🔮 Generating prediction..."):
result, error = make_prediction(prediction_data)
if result:
prediction = result["prediction"]
# Display result
st.success("✅ Prediction Generated Successfully!")
# Main prediction result
st.markdown(
f'💰 Predicted Sales: ₹{prediction:,.2f}
',
unsafe_allow_html=True
)
# Additional insights
col1, col2, col3 = st.columns(3)
with col1:
st.metric(
"Daily Revenue",
f"₹{prediction:,.2f}",
delta=f"{prediction*0.1:,.2f}",
delta_color="normal"
)
with col2:
monthly_estimate = prediction * 30
st.metric(
"Monthly Estimate",
f"₹{monthly_estimate:,.2f}",
delta="Projected",
delta_color="off"
)
with col3:
annual_estimate = prediction * 365
st.metric(
"Annual Potential",
f"₹{annual_estimate:,.2f}",
delta="Estimated",
delta_color="off"
)
# Business recommendations
st.markdown("### 💡 Business Insights")
if prediction > 4000:
st.success("🎯 **High Performance Expected** - This product-store combination shows excellent potential!")
elif prediction > 2500:
st.info("📈 **Good Performance Expected** - Solid sales potential with room for optimization.")
else:
st.warning("⚠️ **Moderate Performance Expected** - Consider promotional strategies or product mix optimization.")
# Performance category analysis
if store_location_city_type == "Tier 1" and store_type == "Departmental Store":
st.info("🏆 **Premium Market Position** - Tier 1 Departmental Store typically shows highest performance.")
if product_weight > 15:
st.info("📦 **Heavy Product Advantage** - Higher weight products tend to generate more sales.")
if product_mrp > 200:
st.info("💎 **Premium Product** - High MRP products often indicate better margins.")
else:
st.error(f"❌ Prediction Failed: {error}")
st.markdown("""
**Troubleshooting Steps:**
1. Check your internet connection
2. Verify API URL in the sidebar
3. Ensure all input values are within valid ranges
4. Try again in a few moments
""")
def batch_prediction_page():
"""Batch prediction interface."""
st.header("📊 Batch Sales Prediction")
st.markdown("Upload a CSV file or enter multiple records for bulk predictions.")
# Option selection
batch_option = st.radio(
"Choose input method:",
["Upload CSV File", "Manual Entry"]
)
if batch_option == "Upload CSV File":
st.subheader("📁 Upload CSV File")
# File upload
uploaded_file = st.file_uploader(
"Choose a CSV file",
type="csv",
help="Upload a CSV file with the required columns"
)
# Show required format
with st.expander("📋 Required CSV Format"):
sample_df = pd.DataFrame({
"Product_Weight": [12.5, 16.2, 8.9],
"Product_Sugar_Content": ["Low Sugar", "Regular", "No Sugar"],
"Product_Allocated_Area": [0.1, 0.15, 0.05],
"Product_Type": ["Fruits and Vegetables", "Dairy", "Snack Foods"],
"Product_MRP": [150.0, 180.0, 95.0],
"Store_Size": ["Medium", "High", "Small"],
"Store_Location_City_Type": ["Tier 2", "Tier 1", "Tier 3"],
"Store_Type": ["Supermarket Type2", "Departmental Store", "Food Mart"],
"Store_Age": [15, 20, 8]
})
st.dataframe(sample_df)
if uploaded_file is not None:
try:
# Read CSV
df = pd.read_csv(uploaded_file)
st.success(f"✅ File uploaded successfully! {len(df)} records found.")
# Show preview
st.subheader("📋 Data Preview")
st.dataframe(df.head())
# Validate columns
required_columns = [
"Product_Weight", "Product_Sugar_Content", "Product_Allocated_Area",
"Product_Type", "Product_MRP", "Store_Size",
"Store_Location_City_Type", "Store_Type", "Store_Age"
]
missing_columns = [col for col in required_columns if col not in df.columns]
if missing_columns:
st.error(f"❌ Missing required columns: {missing_columns}")
else:
st.success("✅ All required columns found!")
if st.button("🚀 Generate Batch Predictions"):
# Convert DataFrame to list of dictionaries
data_list = df.to_dict('records')
with st.spinner(f"🔮 Generating predictions for {len(data_list)} records..."):
result, error = make_batch_prediction(data_list)
if result:
predictions = result["predictions"]
# Add predictions to DataFrame
df_results = df.copy()
df_results["Predicted_Sales"] = predictions
# Display results
st.success("✅ Batch Predictions Generated Successfully!")
# Summary metrics
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("Total Records", len(predictions))
with col2:
successful = len([p for p in predictions if p is not None])
st.metric("Successful", successful)
with col3:
avg_prediction = sum([p for p in predictions if p is not None]) / successful
st.metric("Average Sales", f"₹{avg_prediction:,.2f}")
with col4:
total_predicted = sum([p for p in predictions if p is not None])
st.metric("Total Predicted", f"₹{total_predicted:,.2f}")
# Results table
st.subheader("📊 Prediction Results")
st.dataframe(df_results)
# Download results
csv_results = df_results.to_csv(index=False)
st.download_button(
"📥 Download Results",
csv_results,
"superkart_predictions.csv",
"text/csv"
)
# Visualization
if successful > 0:
st.subheader("📈 Prediction Analysis")
# Distribution plot
valid_predictions = [p for p in predictions if p is not None]
fig = px.histogram(
x=valid_predictions,
title="Distribution of Predicted Sales",
labels={"x": "Predicted Sales (₹)", "y": "Frequency"}
)
st.plotly_chart(fig, use_container_width=True)
else:
st.error(f"❌ Batch Prediction Failed: {error}")
except Exception as e:
st.error(f"❌ Error reading file: {str(e)}")
else: # Manual Entry
st.subheader("✏️ Manual Entry")
st.markdown("Add multiple records manually for batch prediction.")
# Initialize session state for manual entries
if "manual_entries" not in st.session_state:
st.session_state.manual_entries = []
# Add new entry form
with st.expander("➕ Add New Entry"):
with st.form("manual_entry_form"):
col1, col2 = st.columns(2)
with col1:
weight = st.number_input("Weight (kg)", 0.1, 50.0, 12.5, key="manual_weight")
sugar = st.selectbox("Sugar Content", ["Low Sugar", "Regular", "No Sugar"], key="manual_sugar")
area = st.number_input("Display Area", 0.001, 1.0, 0.1, key="manual_area")
product_type = st.selectbox("Product Type", [
"Fruits and Vegetables", "Snack Foods", "Household", "Frozen Foods",
"Dairy", "Canned", "Baking Goods", "Health and Hygiene"
], key="manual_type")
mrp = st.number_input("MRP (₹)", 1.0, 500.0, 150.0, key="manual_mrp")
with col2:
size = st.selectbox("Store Size", ["Small", "Medium", "High"], key="manual_size")
city = st.selectbox("City Type", ["Tier 1", "Tier 2", "Tier 3"], key="manual_city")
store_type = st.selectbox("Store Type", [
"Departmental Store", "Supermarket Type1", "Supermarket Type2", "Food Mart"
], key="manual_store_type")
age = st.number_input("Store Age", 0, 50, 15, key="manual_age")
if st.form_submit_button("➕ Add Entry"):
entry = {
"Product_Weight": weight,
"Product_Sugar_Content": sugar,
"Product_Allocated_Area": area,
"Product_Type": product_type,
"Product_MRP": mrp,
"Store_Size": size,
"Store_Location_City_Type": city,
"Store_Type": store_type,
"Store_Age": age
}
st.session_state.manual_entries.append(entry)
st.success("✅ Entry added!")
# Display current entries
if st.session_state.manual_entries:
st.subheader(f"📝 Current Entries ({len(st.session_state.manual_entries)})")
# Convert to DataFrame for display
entries_df = pd.DataFrame(st.session_state.manual_entries)
st.dataframe(entries_df)
col1, col2 = st.columns(2)
with col1:
if st.button("🚀 Generate Predictions"):
with st.spinner("🔮 Generating predictions..."):
result, error = make_batch_prediction(st.session_state.manual_entries)
if result:
predictions = result["predictions"]
entries_df["Predicted_Sales"] = predictions
st.success("✅ Predictions Generated!")
st.dataframe(entries_df)
# Download option
csv_data = entries_df.to_csv(index=False)
st.download_button(
"📥 Download Results",
csv_data,
"manual_predictions.csv",
"text/csv"
)
else:
st.error(f"❌ Prediction Failed: {error}")
with col2:
if st.button("🗑️ Clear All Entries"):
st.session_state.manual_entries = []
st.experimental_rerun()
def analytics_dashboard_page():
"""Analytics dashboard interface."""
st.header("📈 Analytics Dashboard")
st.markdown("Explore sales patterns and model insights.")
# Mock analytics data for demonstration
st.subheader("🎯 Model Performance Metrics")
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("Model Accuracy", "92.8%", "2.1%")
with col2:
st.metric("Avg Prediction Error", "₹249", "-₹15")
with col3:
st.metric("Total Predictions", "1,247", "156")
with col4:
st.metric("API Uptime", "99.2%", "0.3%")
# Feature importance chart
st.subheader("🎯 Feature Importance")
feature_data = {
"Feature": ["Product_Weight", "Product_MRP", "Store_Type", "City_Type", "Store_Size"],
"Importance": [0.35, 0.28, 0.18, 0.12, 0.07]
}
fig = px.bar(
x=feature_data["Importance"],
y=feature_data["Feature"],
orientation='h',
title="Top 5 Most Important Features",
labels={"x": "Importance Score", "y": "Features"}
)
fig.update_layout(yaxis={'categoryorder':'total ascending'})
st.plotly_chart(fig, use_container_width=True)
# Sample insights
st.subheader("💡 Business Insights")
insight_tabs = st.tabs(["Store Performance", "Product Analysis", "Regional Trends"])
with insight_tabs[0]:
st.markdown("""
**Store Performance Insights:**
- Departmental Stores show 40% higher sales on average
- Medium-sized stores have the best cost-to-performance ratio
- Tier 1 cities generate 2.8x more revenue than Tier 3
""")
with insight_tabs[1]:
st.markdown("""
**Product Analysis:**
- Heavy products (>15kg) correlate with higher sales
- Premium MRP products (>₹200) show better margins
- Dairy and Frozen Foods are top performing categories
""")
with insight_tabs[2]:
st.markdown("""
**Regional Trends:**
- Tier 1 cities: Focus on premium product mix
- Tier 2 cities: Balanced approach with growth potential
- Tier 3 cities: Price-sensitive, high-volume strategy
""")
def api_status_page():
"""API status and configuration page."""
global API_BASE_URL
st.header("🔧 API Status & Configuration")
# API URL configuration
st.subheader("⚙️ API Configuration")
current_url = st.text_input(
"Backend API URL",
value=API_BASE_URL,
help="Enter your backend API URL"
)
if st.button("💾 Update API URL"):
API_BASE_URL = current_url
st.success("✅ API URL updated!")
# Health check
st.subheader("🏥 Health Check")
if st.button("🔍 Check API Health"):
with st.spinner("Checking API health..."):
health_status = check_api_health()
if health_status:
st.success("✅ API is healthy and responsive!")
# Try to get API info
try:
response = requests.get(f"{API_BASE_URL}/", timeout=10)
if response.status_code == 200:
api_info = response.json()
st.json(api_info)
except:
pass
else:
st.error("❌ API is not accessible")
st.markdown("""
**Troubleshooting:**
1. Check if the API URL is correct
2. Ensure the backend service is running
3. Verify your internet connection
4. Check if the API allows CORS requests
""")
# API documentation
st.subheader("📚 API Documentation")
st.markdown("""
**Available Endpoints:**
- `GET /` - API information and sample input
- `GET /health` - Health check endpoint
- `GET /model_info` - Model details and performance metrics
- `POST /predict` - Single prediction endpoint
- `POST /batch_predict` - Batch prediction endpoint
**Sample Request Format:**
```json
{
"Product_Weight": 12.5,
"Product_Sugar_Content": "Low Sugar",
"Product_Allocated_Area": 0.15,
"Product_Type": "Fruits and Vegetables",
"Product_MRP": 150.0,
"Store_Size": "Medium",
"Store_Location_City_Type": "Tier 2",
"Store_Type": "Supermarket Type2",
"Store_Age": 15
}
```
""")
# Footer
def show_footer():
"""Show application footer."""
st.markdown("---")
st.markdown("""
🛒 SuperKart Sales Forecasting System | Powered by AI & Machine Learning
Built with Streamlit & Flask | © 2025 SuperKart Analytics Team
""", unsafe_allow_html=True)
# Run the application
if __name__ == "__main__":
main()
show_footer()