"""SmartChain AI - Streamlit Application for Hugging Face Space.""" import streamlit as st import pandas as pd import numpy as np from datetime import datetime, timedelta import plotly.graph_objects as go import plotly.express as px # Page configuration st.set_page_config( page_title="SmartChain AI", page_icon="🚚", layout="wide", initial_sidebar_state="expanded", ) # Custom CSS st.markdown(""" """, unsafe_allow_html=True) # Sidebar st.sidebar.title("🚚 SmartChain AI") st.sidebar.markdown("**Enterprise Supply Chain Optimization**") page = st.sidebar.selectbox( "Select Module", ["🏠 Home", "πŸ“ˆ Demand Forecasting", "πŸ“¦ Inventory Optimization", "🚚 Route Optimization"] ) # Helper functions for demo data def generate_forecast_data(days=30): """Generate demo forecast data.""" dates = pd.date_range(start=datetime.now(), periods=days, freq='D') base_demand = 100 trend = np.linspace(0, 20, days) seasonality = 30 * np.sin(np.linspace(0, 4*np.pi, days)) noise = np.random.normal(0, 10, days) predictions = base_demand + trend + seasonality + noise lower_bound = predictions - 20 upper_bound = predictions + 20 return pd.DataFrame({ 'date': dates, 'prediction': predictions, 'lower_bound': lower_bound, 'upper_bound': upper_bound }) def generate_inventory_data(): """Generate demo inventory metrics.""" return { 'eoq': 450, 'reorder_point': 120, 'safety_stock': 45, 'holding_cost': 2400, 'ordering_cost': 800, 'total_cost': 3200, 'service_level': 0.95 } def generate_route_data(): """Generate demo route optimization data.""" np.random.seed(42) num_locations = 8 depot = {'lat': 40.7128, 'lon': -74.0060, 'name': 'Distribution Center'} locations = [] for i in range(num_locations): locations.append({ 'id': i+1, 'name': f'Customer {i+1}', 'lat': depot['lat'] + np.random.uniform(-0.5, 0.5), 'lon': depot['lon'] + np.random.uniform(-0.5, 0.5), 'demand': np.random.randint(10, 100) }) return depot, locations # Home Page if page == "🏠 Home": st.title("🚚 SmartChain AI") st.subheader("Enterprise Supply Chain Optimization Platform") st.markdown(""" Welcome to **SmartChain AI**, an AI-powered platform for optimizing end-to-end supply chain operations. ### 🎯 Key Features - **πŸ“ˆ Demand Forecasting**: Predict future demand using advanced ML models (Prophet + XGBoost) - **πŸ“¦ Inventory Optimization**: Optimize stock levels using EOQ, safety stock, and reorder points - **🚚 Route Optimization**: Solve vehicle routing problems efficiently with Google OR-Tools - **🎯 Scenario Analysis**: Perform what-if analysis for strategic planning ### πŸ› οΈ Technology Stack - **ML/AI**: Prophet, XGBoost, OR-Tools, CVXPY - **Backend**: FastAPI, PostgreSQL, Redis - **Frontend**: Streamlit, Plotly ### πŸš€ Getting Started Use the sidebar to explore different modules and see SmartChain AI in action! --- """) # Quick stats col1, col2, col3, col4 = st.columns(4) with col1: st.metric("Products", "1,000", "+10%") with col2: st.metric("Warehouses", "5", "0%") with col3: st.metric("Daily Orders", "2,500", "+15%") with col4: st.metric("Delivery Locations", "500", "+5%") st.markdown("---") st.info("ℹ️ **Demo Mode**: This is a demonstration version with synthetic data. The full version includes backend API integration.") # Demand Forecasting Page elif page == "πŸ“ˆ Demand Forecasting": st.title("πŸ“ˆ Demand Forecasting") st.markdown("Generate AI-powered demand forecasts using Prophet, XGBoost, or Hybrid models.") # Sidebar controls st.sidebar.header("Forecast Configuration") product_id = st.sidebar.number_input("Product ID", min_value=1, max_value=1000, value=1) horizon_days = st.sidebar.slider("Forecast Horizon (days)", min_value=7, max_value=90, value=30) model_type = st.sidebar.selectbox("Model Type", ["Hybrid", "Prophet", "XGBoost"]) col1, col2 = st.columns([2, 1]) with col1: st.subheader("Generate Forecast") if st.button("πŸš€ Generate Forecast", type="primary", use_container_width=True): with st.spinner("Generating forecast..."): # Generate demo data forecast_df = generate_forecast_data(horizon_days) st.success(f"βœ… Forecast generated for Product {product_id} using {model_type} model") # Create forecast chart fig = go.Figure() # Confidence interval fig.add_trace(go.Scatter( x=forecast_df['date'], y=forecast_df['upper_bound'], fill=None, mode='lines', line_color='rgba(37, 99, 235, 0.2)', showlegend=False, )) fig.add_trace(go.Scatter( x=forecast_df['date'], y=forecast_df['lower_bound'], fill='tonexty', mode='lines', line_color='rgba(37, 99, 235, 0.2)', fillcolor='rgba(37, 99, 235, 0.1)', name='95% Confidence Interval', )) # Forecast line fig.add_trace(go.Scatter( x=forecast_df['date'], y=forecast_df['prediction'], mode='lines+markers', name='Forecast', line=dict(color='#2563eb', width=3), marker=dict(size=6), )) fig.update_layout( title=f'Demand Forecast - Product {product_id}', xaxis_title='Date', yaxis_title='Demand (units)', hovermode='x unified', template='plotly_white', height=500, ) st.plotly_chart(fig, use_container_width=True) # Forecast table st.subheader("πŸ“‹ Forecast Data") st.dataframe( forecast_df.style.format({ 'prediction': '{:.2f}', 'lower_bound': '{:.2f}', 'upper_bound': '{:.2f}' }), use_container_width=True, height=300, ) # Download button csv = forecast_df.to_csv(index=False) st.download_button( "⬇️ Download Forecast CSV", data=csv, file_name=f"forecast_product_{product_id}.csv", mime="text/csv", ) with col2: st.subheader("ℹ️ Model Information") if model_type == "Hybrid": st.info(""" **Hybrid Model** Combines Prophet and XGBoost: - Prophet: Captures seasonality - XGBoost: Learns complex patterns - Best accuracy for most cases """) elif model_type == "Prophet": st.info(""" **Prophet Model** Meta's time-series forecaster: - Automatic seasonality detection - Handles holidays - Robust to missing data """) else: st.info(""" **XGBoost Model** Gradient boosting approach: - Feature-rich predictions - Captures non-linear patterns - Fast training and inference """) st.metric("Forecast Accuracy (MAPE)", "8.5%", "-1.2%") st.metric("RΒ² Score", "0.92", "+0.05") # Inventory Optimization Page elif page == "πŸ“¦ Inventory Optimization": st.title("πŸ“¦ Inventory Optimization") st.markdown("Optimize inventory policies using EOQ, safety stock, and reorder point calculations.") # Sidebar controls st.sidebar.header("Optimization Parameters") product_id = st.sidebar.number_input("Product ID", min_value=1, max_value=1000, value=1) service_level = st.sidebar.slider("Service Level", min_value=0.80, max_value=0.99, value=0.95, step=0.01) holding_cost_rate = st.sidebar.number_input("Holding Cost Rate (%)", min_value=1.0, max_value=50.0, value=20.0) ordering_cost = st.sidebar.number_input("Ordering Cost ($)", min_value=10, max_value=1000, value=100) if st.button("🎯 Optimize Inventory Policy", type="primary", use_container_width=True): with st.spinner("Optimizing inventory policy..."): inventory_data = generate_inventory_data() st.success(f"βœ… Inventory policy optimized for Product {product_id}") # Metrics col1, col2, col3 = st.columns(3) with col1: st.metric("Economic Order Quantity (EOQ)", f"{inventory_data['eoq']} units") st.metric("Reorder Point", f"{inventory_data['reorder_point']} units") with col2: st.metric("Safety Stock", f"{inventory_data['safety_stock']} units") st.metric("Service Level", f"{inventory_data['service_level']*100:.1f}%") with col3: st.metric("Annual Holding Cost", f"${inventory_data['holding_cost']:,.0f}") st.metric("Annual Ordering Cost", f"${inventory_data['ordering_cost']:,.0f}") # Cost breakdown chart st.subheader("πŸ“Š Cost Analysis") fig = go.Figure(data=[ go.Bar( x=['Holding Cost', 'Ordering Cost', 'Total Cost'], y=[ inventory_data['holding_cost'], inventory_data['ordering_cost'], inventory_data['total_cost'], ], marker_color=['#10b981', '#f59e0b', '#2563eb'], text=[ f"${inventory_data['holding_cost']:,.0f}", f"${inventory_data['ordering_cost']:,.0f}", f"${inventory_data['total_cost']:,.0f}", ], textposition='auto', ) ]) fig.update_layout( title='Annual Inventory Costs', yaxis_title='Cost ($)', template='plotly_white', height=400, ) st.plotly_chart(fig, use_container_width=True) # Recommendations st.subheader("πŸ’‘ Recommendations") st.markdown(f""" - **Order Quantity**: Place orders of **{inventory_data['eoq']} units** each time - **Reorder Trigger**: Reorder when inventory reaches **{inventory_data['reorder_point']} units** - **Safety Buffer**: Maintain **{inventory_data['safety_stock']} units** as safety stock - **Cost Savings**: Optimized policy can save up to **15-20%** on total inventory costs """) # Route Optimization Page elif page == "🚚 Route Optimization": st.title("🚚 Route Optimization") st.markdown("Optimize delivery routes using Vehicle Routing Problem (VRP) algorithms.") # Sidebar controls st.sidebar.header("Route Configuration") num_vehicles = st.sidebar.slider("Number of Vehicles", min_value=1, max_value=5, value=2) vehicle_capacity = st.sidebar.number_input("Vehicle Capacity (kg)", min_value=100, max_value=2000, value=500) if st.button("πŸ—ΊοΈ Optimize Routes", type="primary", use_container_width=True): with st.spinner("Optimizing delivery routes..."): depot, locations = generate_route_data() st.success(f"βœ… Routes optimized for {num_vehicles} vehicles") # Metrics col1, col2, col3, col4 = st.columns(4) with col1: st.metric("Total Distance", "127.5 km") with col2: st.metric("Total Time", "3h 45m") with col3: st.metric("Cost", "$255") with col4: st.metric("Efficiency", "92%", "+8%") # Map st.subheader("πŸ—ΊοΈ Route Visualization") # Create map figure fig = go.Figure() colors = px.colors.qualitative.Plotly # Split locations into routes for visualization locations_per_vehicle = len(locations) // num_vehicles for v in range(num_vehicles): start_idx = v * locations_per_vehicle end_idx = start_idx + locations_per_vehicle if v < num_vehicles - 1 else len(locations) route_locs = locations[start_idx:end_idx] lats = [depot['lat']] + [loc['lat'] for loc in route_locs] + [depot['lat']] lons = [depot['lon']] + [loc['lon'] for loc in route_locs] + [depot['lon']] names = [depot['name']] + [loc['name'] for loc in route_locs] + [depot['name']] fig.add_trace(go.Scattermapbox( lat=lats, lon=lons, mode='lines+markers', name=f'Vehicle {v+1}', marker=dict(size=10, color=colors[v]), line=dict(width=2, color=colors[v]), text=names, )) # Depot marker fig.add_trace(go.Scattermapbox( lat=[depot['lat']], lon=[depot['lon']], mode='markers', name='Depot', marker=dict(size=20, color='red', symbol='star'), text=[depot['name']], )) fig.update_layout( mapbox=dict( style='open-street-map', center=dict(lat=depot['lat'], lon=depot['lon']), zoom=10, ), height=600, showlegend=True, ) st.plotly_chart(fig, use_container_width=True) # Route details st.subheader("πŸ“‹ Route Details") for v in range(num_vehicles): with st.expander(f"πŸš› Vehicle {v+1} Route"): start_idx = v * locations_per_vehicle end_idx = start_idx + locations_per_vehicle if v < num_vehicles - 1 else len(locations) route_locs = locations[start_idx:end_idx] route_df = pd.DataFrame(route_locs) st.dataframe(route_df, use_container_width=True) total_demand = sum(loc['demand'] for loc in route_locs) st.metric("Total Demand", f"{total_demand} kg") # Footer st.sidebar.markdown("---") st.sidebar.markdown(""" **Version**: 0.1.0 **Author**: Alireza Aminzadeh **License**: Apache 2.0 [GitHub](https://github.com/syeedalireza) | [HuggingFace](https://huggingface.co/syeedalireza) """) st.markdown("---") st.markdown("""

Built with ❀️ using FastAPI + Streamlit + OR-Tools

SmartChain AI - Enterprise Supply Chain Optimization Platform

""", unsafe_allow_html=True)