""" Gradio Web Application for Daily Household Electricity Consumption Predictor This module provides a user-friendly web interface for the electricity consumption prediction model using Gradio. """ import gradio as gr import pandas as pd import numpy as np from typing import Tuple, Dict, Any import os import sys # Add src to path for imports sys.path.append(os.path.join(os.path.dirname(__file__), "..")) from src.data_generator import DataGenerator from src.model import ElectricityConsumptionModel class ElectricityPredictorApp: """Gradio application for electricity consumption prediction.""" def __init__(self): """Initialize the application with model and data generator.""" self.data_generator = DataGenerator(seed=42) self.model = ElectricityConsumptionModel() self.is_model_trained = False def generate_and_train( self, n_samples: int, noise_level: float, train_size: float, val_size: float, test_size: float, ) -> Tuple[str, str, str]: """ Generate synthetic data and train the model. Args: n_samples: Number of data points to generate noise_level: Level of noise in the data train_size: Proportion for training set val_size: Proportion for validation set test_size: Proportion for test set Returns: Tuple of (data_info, training_metrics, evaluation_metrics) """ try: # Generate data data = self.data_generator.generate_data(n_samples, noise_level) # Split data train_data, val_data, test_data = self.data_generator.split_data( data, train_size, val_size, test_size ) # Store data for later use self.train_data = train_data self.val_data = val_data self.test_data = test_data # Train model X_train = train_data.drop("consumption_kwh", axis=1) y_train = train_data[["consumption_kwh"]] training_metrics = self.model.train(X_train, y_train) # Evaluate model X_test = test_data.drop("consumption_kwh", axis=1) y_test = test_data[["consumption_kwh"]] evaluation_metrics = self.model.evaluate(X_test, y_test) self.is_model_trained = True # Format output strings data_info = f""" **Data Generated Successfully!** - Total samples: {len(data)} - Training samples: {len(train_data)} - Validation samples: {len(val_data)} - Test samples: {len(test_data)} **Data Statistics:** - Temperature range: {data['temperature'].min():.1f}°C - {data['temperature'].max():.1f}°C - Consumption range: {data['consumption_kwh'].min():.1f} - {data['consumption_kwh'].max():.1f} kWh - Average consumption: {data['consumption_kwh'].mean():.1f} kWh """ training_metrics_str = f""" **Training Metrics:** - Mean Squared Error (MSE): {training_metrics['train_mse']:.4f} - Root Mean Squared Error (RMSE): {training_metrics['train_rmse']:.4f} - Mean Absolute Error (MAE): {training_metrics['train_mae']:.4f} - R-squared (R²): {training_metrics['train_r2']:.4f} """ evaluation_metrics_str = f""" **Test Set Evaluation:** - Mean Squared Error (MSE): {evaluation_metrics['test_mse']:.4f} - Root Mean Squared Error (RMSE): {evaluation_metrics['test_rmse']:.4f} - Mean Absolute Error (MAE): {evaluation_metrics['test_mae']:.4f} - R-squared (R²): {evaluation_metrics['test_r2']:.4f} """ return data_info, training_metrics_str, evaluation_metrics_str except Exception as e: error_msg = f"Error during data generation and training: {str(e)}" return error_msg, "", "" def predict_consumption( self, temperature: float, day_of_week: str, major_event: bool ) -> str: """ Make a prediction for electricity consumption. Args: temperature: Average daily temperature in Celsius day_of_week: Day of the week major_event: Whether there's a major event Returns: Formatted prediction result """ if not self.is_model_trained: return "**Error:** Model must be trained first. Please generate data and train the model." try: # Convert boolean to int major_event_int = 1 if major_event else 0 # Make prediction prediction = self.model.predict(temperature, day_of_week, major_event_int) # Get model coefficients for explanation coefficients = self.model.get_model_coefficients() # Format result result = f""" **Prediction Result:** **Estimated Daily Electricity Consumption: {prediction:.1f} kWh** **Input Parameters:** - Temperature: {temperature}°C - Day of Week: {day_of_week} - Major Event: {'Yes' if major_event else 'No'} **Model Information:** - Model Type: Linear Regression - Intercept: {coefficients['intercept']:.4f} - Number of Features: {len(coefficients['feature_names'])} """ return result except Exception as e: return f"**Error during prediction:** {str(e)}" def get_model_info(self) -> str: """ Get detailed information about the trained model. Returns: Formatted model information """ if not self.is_model_trained: return "**Error:** Model must be trained first." try: coefficients = self.model.get_model_coefficients() print(coefficients) # Create feature importance table feature_importance = [] for i, (feature, coef) in enumerate( zip(coefficients["feature_names"], coefficients["coefficients"]) ): feature_importance.append(f"| {feature} | {coef:.4f} |") feature_table = "\n".join(feature_importance) info = f""" **Model Information:** **Model Type:** Linear Regression **Intercept:** {coefficients['intercept']:.4f} **Feature Coefficients:** | Feature | Coefficient | |---------|-------------| {feature_table} **Interpretation:** - Positive coefficients increase predicted consumption - Negative coefficients decrease predicted consumption - Temperature coefficient shows how much consumption changes per degree Celsius - Day coefficients show consumption differences compared to Monday (baseline) - Major event coefficient shows additional consumption during events """ return info except Exception as e: return f"**Error getting model info:** {str(e)}" def create_interface(self) -> gr.Interface: """ Create the Gradio interface. Returns: Gradio Interface object """ with gr.Blocks( title="Daily Household Electricity Consumption Predictor" ) as interface: gr.Markdown( """ # ⚡ Daily Household Electricity Consumption Predictor This application helps Nigerian households estimate their daily electricity consumption based on temperature, day of the week, and major events. ## How to Use: 1. **Generate Data & Train Model**: Click the button to generate synthetic data and train the model 2. **Make Predictions**: Enter your parameters and get consumption estimates 3. **View Model Info**: See how the model works and feature importance """ ) with gr.Tab("Data Generation & Training"): gr.Markdown("### Step 1: Generate Synthetic Data and Train Model") with gr.Row(): with gr.Column(): n_samples = gr.Slider( minimum=100, maximum=5000, value=1000, step=100, label="Number of Data Points", ) noise_level = gr.Slider( minimum=0.01, maximum=0.5, value=0.1, step=0.01, label="Noise Level", ) with gr.Column(): train_size = gr.Slider( minimum=0.5, maximum=0.9, value=0.7, step=0.05, label="Training Set Proportion", ) val_size = gr.Slider( minimum=0.05, maximum=0.3, value=0.15, step=0.05, label="Validation Set Proportion", ) test_size = gr.Slider( minimum=0.05, maximum=0.3, value=0.15, step=0.05, label="Test Set Proportion", ) train_button = gr.Button( "Generate Data & Train Model", variant="primary" ) with gr.Row(): data_info = gr.Markdown("**Data information will appear here...**") with gr.Row(): training_metrics = gr.Markdown( "**Training metrics will appear here...**" ) evaluation_metrics = gr.Markdown( "**Evaluation metrics will appear here...**" ) train_button.click( fn=self.generate_and_train, inputs=[n_samples, noise_level, train_size, val_size, test_size], outputs=[data_info, training_metrics, evaluation_metrics], ) with gr.Tab("Prediction"): gr.Markdown("### Step 2: Predict Electricity Consumption") with gr.Row(): with gr.Column(): temperature = gr.Slider( minimum=15, maximum=35, value=25, step=0.5, label="Average Daily Temperature (°C)", ) day_of_week = gr.Dropdown( choices=[ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", ], value="Monday", label="Day of the Week", ) major_event = gr.Checkbox( label="Major Event (Holiday, Power Outage, etc.)", value=False, ) with gr.Column(): predict_button = gr.Button( "Predict Consumption", variant="primary" ) prediction_result = gr.Markdown( "**Prediction result will appear here...**" ) predict_button.click( fn=self.predict_consumption, inputs=[temperature, day_of_week, major_event], outputs=prediction_result, ) with gr.Tab("Model Information"): gr.Markdown("### Step 3: Understand the Model") info_button = gr.Button("Show Model Information", variant="secondary") model_info = gr.Markdown("**Model information will appear here...**") info_button.click(fn=self.get_model_info, inputs=[], outputs=model_info) gr.Markdown( """ --- **Note:** This application uses synthetic data for demonstration purposes. In a real-world scenario, you would use actual historical consumption data. """ ) return interface def main(): """Main function to launch the application.""" try: app = ElectricityPredictorApp() interface = app.create_interface() # Get port from environment variable (for Render deployment) port = int(os.environ.get("PORT", 7860)) print(f"Starting server on port {port}") print(f"Server name: 0.0.0.0") # Launch the interface interface.launch( server_name="0.0.0.0", # Allow external connections server_port=port, # Use environment port share=False, # Don't create public link debug=False, # Disable debug mode for production show_error=True, # Show errors in production quiet=False, # Show startup messages ) except Exception as e: print(f"Error starting application: {e}") import traceback traceback.print_exc() sys.exit(1) if __name__ == "__main__": main()