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()