""" Main application entry point for Hugging Face Spaces. """ import gradio as gr import pandas as pd import numpy as np import plotly.graph_objects as go from datetime import datetime, timedelta # Simple in-memory data storage class AppState: def __init__(self): self.data = None self.forecast = None app_state = AppState() def load_sample_data(dataset_name): """Load or generate sample data.""" try: # Generate synthetic data dates = pd.date_range(start='2023-01-01', periods=365, freq='D') if "Retail" in dataset_name: # Retail pattern with weekly seasonality base = 100 trend = np.linspace(0, 20, 365) seasonal = 20 * np.sin(2 * np.pi * np.arange(365) / 7) noise = np.random.normal(0, 5, 365) values = base + trend + seasonal + noise elif "Walmart" in dataset_name: # Walmart M5 style base = 150 trend = np.linspace(0, 30, 365) weekly = 40 * np.sin(2 * np.pi * np.arange(365) / 7) noise = np.random.normal(0, 10, 365) values = base + trend + weekly + noise else: # Synthetic random walk values = 100 + np.cumsum(np.random.randn(365) * 5) values = np.maximum(values, 10) # Keep positive data = pd.DataFrame({ 'date': dates, 'value': values }) app_state.data = data # Create stats stats = f""" 📊 Dataset Statistics: • Total Rows: {len(data)} • Date Range: {data['date'].min().date()} to {data['date'].max().date()} • Mean Value: {data['value'].mean():.2f} • Std Dev: {data['value'].std():.2f} • Min Value: {data['value'].min():.2f} • Max Value: {data['value'].max():.2f} """ # Create plot fig = go.Figure() fig.add_trace(go.Scatter( x=data['date'], y=data['value'], mode='lines', name='Historical Data', line=dict(color='blue', width=2) )) fig.update_layout( title="Time Series Data", xaxis_title="Date", yaxis_title="Value", template='plotly_white', height=400 ) return data.head(100), stats, fig, "✅ Data loaded successfully!" except Exception as e: return None, f"❌ Error: {str(e)}", None, "Failed to load data" def simple_forecast(horizon): """Generate simple moving average forecast.""" try: if app_state.data is None: return None, "❌ Please load data first!", "Please load data in Data Upload tab" data = app_state.data # Simple moving average forecast window = min(30, len(data) // 2) ma = data['value'].tail(window).mean() std = data['value'].tail(window).std() # Generate future dates last_date = data['date'].iloc[-1] future_dates = pd.date_range(start=last_date + timedelta(days=1), periods=horizon, freq='D') # Simple forecast forecast_values = np.ones(horizon) * ma lower = forecast_values - 1.96 * std upper = forecast_values + 1.96 * std forecast_df = pd.DataFrame({ 'date': future_dates, 'forecast': forecast_values, 'lower_bound': lower, 'upper_bound': upper }) app_state.forecast = forecast_df # Create plot fig = go.Figure() # Historical fig.add_trace(go.Scatter( x=data['date'], y=data['value'], mode='lines', name='Historical', line=dict(color='blue', width=2) )) # Forecast fig.add_trace(go.Scatter( x=forecast_df['date'], y=forecast_df['forecast'], mode='lines', name='Forecast', line=dict(color='red', width=2, dash='dash') )) # Confidence interval fig.add_trace(go.Scatter( x=forecast_df['date'].tolist() + forecast_df['date'].tolist()[::-1], y=forecast_df['upper_bound'].tolist() + forecast_df['lower_bound'].tolist()[::-1], fill='toself', fillcolor='rgba(255,0,0,0.2)', line=dict(color='rgba(255,255,255,0)'), name='95% Confidence', showlegend=True )) fig.update_layout( title=f"{horizon}-Day Forecast", xaxis_title="Date", yaxis_title="Value", template='plotly_white', height=400 ) info = f""" 📈 Forecast Information: • Model: Moving Average (Simple) • Horizon: {horizon} days • Mean Forecast: {forecast_values.mean():.2f} • Confidence Level: 95% """ return fig, info, "✅ Forecast generated successfully!" except Exception as e: return None, f"❌ Error: {str(e)}", "Forecast generation failed" def calculate_eoq(): """Calculate Economic Order Quantity.""" try: if app_state.forecast is None: return "❌ Please generate forecast first!", "" # Simple EOQ calculation annual_demand = app_state.forecast['forecast'].sum() * (365 / len(app_state.forecast)) ordering_cost = 100.0 holding_cost = 10.0 * 0.20 # EOQ formula eoq = np.sqrt(2 * annual_demand * ordering_cost / holding_cost) num_orders = annual_demand / eoq total_cost = (num_orders * ordering_cost) + ((eoq / 2) * holding_cost) results = f""" 📦 Inventory Optimization Results (EOQ Model): • Optimal Order Quantity: {eoq:.2f} units • Number of Orders per Year: {num_orders:.2f} • Order Cycle Time: {365 / num_orders:.1f} days • Total Annual Cost: ${total_cost:.2f} - Ordering Cost: ${num_orders * ordering_cost:.2f} - Holding Cost: ${(eoq / 2) * holding_cost:.2f} • Annual Demand: {annual_demand:.2f} units """ recommendations = f""" 💡 Recommendations: • Place an order of {eoq:.0f} units every {365 / num_orders:.0f} days • Maintain safety stock of {eoq * 0.2:.0f} units • Monitor demand patterns for adjustments """ return results, recommendations except Exception as e: return f"❌ Error: {str(e)}", "" # Create Gradio interface with gr.Blocks(title="ForecastIQ Pro", theme=gr.themes.Soft()) as demo: gr.Markdown(""" # 🎯 ForecastIQ Pro **AI-Powered Demand Forecasting & Inventory Optimization** """) with gr.Tabs(): # Tab 1: Data Upload with gr.Tab("📁 Data Upload"): with gr.Row(): with gr.Column(): dataset_selector = gr.Radio( choices=["Sample: Retail Sales", "Sample: Walmart M5", "Sample: Synthetic"], label="Select Dataset", value="Sample: Retail Sales" ) load_btn = gr.Button("Load Data", variant="primary") status_text = gr.Textbox(label="Status", lines=1) with gr.Column(): data_stats = gr.Textbox(label="Statistics", lines=8) data_preview = gr.Dataframe(label="Data Preview") data_plot = gr.Plot(label="Time Series Visualization") load_btn.click( load_sample_data, inputs=[dataset_selector], outputs=[data_preview, data_stats, data_plot, status_text] ) # Tab 2: Forecasting with gr.Tab("🔮 Forecasting"): with gr.Row(): with gr.Column(): horizon_slider = gr.Slider( minimum=7, maximum=90, value=30, step=1, label="Forecast Horizon (days)" ) forecast_btn = gr.Button("Generate Forecast", variant="primary") forecast_status = gr.Textbox(label="Status", lines=1) with gr.Column(): forecast_info = gr.Textbox(label="Forecast Information", lines=8) forecast_plot = gr.Plot(label="Forecast Results") forecast_btn.click( simple_forecast, inputs=[horizon_slider], outputs=[forecast_plot, forecast_info, forecast_status] ) # Tab 3: Optimization with gr.Tab("📦 Inventory Optimization"): gr.Markdown("### Economic Order Quantity (EOQ) Model") optimize_btn = gr.Button("Calculate Optimal Inventory", variant="primary") with gr.Row(): opt_results = gr.Textbox(label="Optimization Results", lines=12) opt_recommendations = gr.Textbox(label="Recommendations", lines=12) optimize_btn.click( calculate_eoq, inputs=[], outputs=[opt_results, opt_recommendations] ) gr.Markdown(""" --- ### 📚 About ForecastIQ Pro A production-grade platform for demand forecasting and inventory optimization. Combines time series analysis with operations research for data-driven decision making. """) if __name__ == "__main__": demo.launch(share=True)