Spaces:
Running
Running
| """ | |
| WeatherWise Prediction Controller | |
| Handles HTTP requests for LSTM weather forecasting | |
| """ | |
| import logging | |
| from typing import Dict, Any | |
| from datetime import datetime | |
| from services.weatherwise_prediction_service import WeatherWisePredictionService | |
| logger = logging.getLogger(__name__) | |
| class WeatherWisePredictionController: | |
| """Controller for handling WeatherWise LSTM weather forecasting requests""" | |
| def __init__(self, weatherwise_service: WeatherWisePredictionService = None): | |
| """Initialize WeatherWise controller""" | |
| self.service = weatherwise_service or WeatherWisePredictionService() | |
| self.controller_stats = { | |
| 'controller_start_time': datetime.now().isoformat(), | |
| 'total_requests': 0, | |
| 'successful_requests': 0, | |
| 'failed_requests': 0 | |
| } | |
| logger.info("WeatherWise prediction controller initialized") | |
| def initialize_controller(self) -> Dict[str, Any]: | |
| """ | |
| Initialize the controller by setting up the WeatherWise service | |
| Returns: | |
| Initialize response dictionary | |
| """ | |
| try: | |
| logger.info("Initializing WeatherWise prediction controller...") | |
| # Initialize the WeatherWise service | |
| service_success, service_message = self.service.initialize_service() | |
| if service_success: | |
| available_models = self.service.get_available_models() | |
| logger.info(f"[SUCCESS] WeatherWise controller initialized with {len(available_models)} models") | |
| return self._create_response( | |
| success=True, | |
| message="WeatherWise controller initialized successfully", | |
| data={ | |
| 'service_status': 'initialized', | |
| 'available_models': available_models, | |
| 'default_forecast_days': 60, | |
| 'supported_variables': self.service.prediction_model.forecast_variables | |
| } | |
| ) | |
| else: | |
| logger.error(f"[ERROR] WeatherWise service initialization failed: {service_message}") | |
| return self._create_response( | |
| success=False, | |
| message="WeatherWise controller initialization failed", | |
| error=service_message | |
| ) | |
| except Exception as e: | |
| logger.error(f"WeatherWise controller initialization error: {e}") | |
| return self._create_response( | |
| success=False, | |
| message="WeatherWise controller initialization error", | |
| error=f"Controller error: {str(e)}" | |
| ) | |
| def forecast_weather(self, request_data: Dict[str, Any]) -> Dict[str, Any]: | |
| """ | |
| Generate weather forecast for location | |
| Args: | |
| request_data: Request dictionary with latitude, longitude, etc. | |
| Returns: | |
| Forecast response dictionary | |
| """ | |
| self.controller_stats['total_requests'] += 1 | |
| try: | |
| logger.info(f"[WEATHERWISE_CONTROLLER] ===== FORECAST REQUEST START =====") | |
| logger.info(f"[WEATHERWISE_CONTROLLER] Processing forecast request...") | |
| logger.info(f"[WEATHERWISE_CONTROLLER] Total requests so far: {self.controller_stats['total_requests']}") | |
| # Extract request parameters | |
| latitude = request_data.get('latitude') | |
| longitude = request_data.get('longitude') | |
| reference_date = request_data.get('reference_date') | |
| disaster_type = request_data.get('disaster_type', 'Normal') | |
| forecast_days = request_data.get('forecast_days', 60) | |
| logger.info(f"[WEATHERWISE_CONTROLLER] Extracted parameters:") | |
| logger.info(f"[WEATHERWISE_CONTROLLER] - latitude: {latitude}") | |
| logger.info(f"[WEATHERWISE_CONTROLLER] - longitude: {longitude}") | |
| logger.info(f"[WEATHERWISE_CONTROLLER] - reference_date: {reference_date}") | |
| logger.info(f"[WEATHERWISE_CONTROLLER] - disaster_type: {disaster_type}") | |
| logger.info(f"[WEATHERWISE_CONTROLLER] - forecast_days: {forecast_days}") | |
| # Reject if TF models are still warming up in the background thread | |
| if not self.service.service_stats.get('models_loaded'): | |
| return self._create_response( | |
| success=False, | |
| message="Service is warming up, please retry in a moment", | |
| error="models_not_ready" | |
| ) | |
| # Validate required parameters | |
| if latitude is None or longitude is None: | |
| logger.error("[WEATHERWISE_CONTROLLER] Missing required parameters") | |
| return self._create_response( | |
| success=False, | |
| message="Missing required parameters", | |
| error="Both 'latitude' and 'longitude' are required" | |
| ) | |
| logger.info(f"[WEATHERWISE_CONTROLLER] Parameters validated successfully") | |
| # Validate disaster type | |
| available_models = self.service.get_available_models() | |
| if disaster_type not in available_models and available_models: | |
| logger.warning(f"Requested disaster type '{disaster_type}' not available, using '{available_models[0]}'") | |
| disaster_type = available_models[0] | |
| # Validate forecast days | |
| try: | |
| forecast_days = int(forecast_days) | |
| if forecast_days < 1 or forecast_days > 365: | |
| forecast_days = 60 # Default | |
| except (ValueError, TypeError): | |
| forecast_days = 60 | |
| logger.info(f"[WEATHERWISE_CONTROLLER] Calling service.generate_weather_forecast()...") | |
| logger.info(f"Processing weather forecast for ({latitude}, {longitude})") | |
| logger.info(f"Parameters: disaster_type={disaster_type}, forecast_days={forecast_days}, reference_date={reference_date}") | |
| # Generate forecast using service | |
| forecast_result = self.service.generate_weather_forecast( | |
| latitude=latitude, | |
| longitude=longitude, | |
| reference_date=reference_date, | |
| disaster_type=disaster_type, | |
| forecast_days=forecast_days | |
| ) | |
| logger.info(f"[WEATHERWISE_CONTROLLER] Service call completed") | |
| logger.info(f"[WEATHERWISE_CONTROLLER] Forecast result success: {forecast_result.get('success')}") | |
| if forecast_result['success']: | |
| self.controller_stats['successful_requests'] += 1 | |
| response_data = { | |
| 'forecast': forecast_result['weather_forecast'], | |
| 'forecast_dates': forecast_result['forecast_dates'], | |
| 'forecast_variables': forecast_result['forecast_variables'], | |
| 'model_context': forecast_result['model_type'], | |
| 'location': forecast_result['location'], | |
| 'forecast_summary': { | |
| 'horizon_days': forecast_result['forecast_horizon_days'], | |
| 'variables_count': len(forecast_result['forecast_variables']), | |
| 'model_used': forecast_result['model_type'] | |
| }, | |
| 'data_collection_summary': forecast_result.get('data_collection', {}) | |
| } | |
| return self._create_response( | |
| success=True, | |
| message="Weather forecast generated successfully", | |
| data=response_data, | |
| processing_info={ | |
| 'processing_time_seconds': forecast_result.get('processing_time_seconds', 0), | |
| 'forecast_model': forecast_result['model_type'], | |
| 'forecast_horizon_days': forecast_result['forecast_horizon_days'], | |
| 'data_sources': forecast_result.get('processing_info', {}).get('data_sources', []) | |
| } | |
| ) | |
| else: | |
| self.controller_stats['failed_requests'] += 1 | |
| return self._create_response( | |
| success=False, | |
| message="Weather forecast generation failed", | |
| error=forecast_result.get('error', 'Unknown forecast error'), | |
| data={ | |
| 'location': forecast_result.get('location'), | |
| 'processing_time_seconds': forecast_result.get('processing_time_seconds', 0) | |
| } | |
| ) | |
| except Exception as e: | |
| self.controller_stats['failed_requests'] += 1 | |
| logger.error(f"WeatherWise controller forecast error: {e}") | |
| return self._create_response( | |
| success=False, | |
| message="Weather forecast error", | |
| error=f"Controller error: {str(e)}" | |
| ) | |
| def get_service_status(self) -> Dict[str, Any]: | |
| """ | |
| Get WeatherWise service status and health information | |
| Returns: | |
| Service status response | |
| """ | |
| try: | |
| # Get service health from the service layer | |
| service_health = self.service.get_service_health() | |
| # Add controller statistics | |
| response_data = { | |
| 'controller_info': { | |
| 'controller_name': 'WeatherWise Prediction Controller', | |
| 'controller_stats': self.controller_stats | |
| }, | |
| 'service_health': service_health | |
| } | |
| return self._create_response( | |
| success=True, | |
| message="WeatherWise service status retrieved successfully", | |
| data=response_data | |
| ) | |
| except Exception as e: | |
| logger.error(f"WeatherWise status error: {e}") | |
| return self._create_response( | |
| success=False, | |
| message="Failed to retrieve service status", | |
| error=f"Status error: {str(e)}" | |
| ) | |
| def get_available_models(self) -> Dict[str, Any]: | |
| """ | |
| Get available disaster context models | |
| Returns: | |
| Available models response | |
| """ | |
| try: | |
| available_models = self.service.get_available_models() | |
| model_info = self.service.prediction_model.get_model_info() | |
| return self._create_response( | |
| success=True, | |
| message="Available models retrieved successfully", | |
| data={ | |
| 'available_disaster_contexts': available_models, | |
| 'model_info': model_info, | |
| 'default_context': 'Normal', | |
| 'supported_forecast_variables': model_info.get('forecast_variables', []) | |
| } | |
| ) | |
| except Exception as e: | |
| logger.error(f"WeatherWise models list error: {e}") | |
| return self._create_response( | |
| success=False, | |
| message="Failed to retrieve available models", | |
| error=f"Models error: {str(e)}" | |
| ) | |
| def _create_response(self, success: bool, message: str, | |
| data: Dict[str, Any] = None, error: str = None, | |
| processing_info: Dict[str, Any] = None) -> Dict[str, Any]: | |
| """ | |
| Create standardized response dictionary | |
| Args: | |
| success: Success status | |
| message: Response message | |
| data: Response data (optional) | |
| error: Error message (optional) | |
| processing_info: Processing information (optional) | |
| Returns: | |
| Standardized response dictionary | |
| """ | |
| response = { | |
| 'success': success, | |
| 'message': message, | |
| 'timestamp': datetime.now().isoformat(), | |
| 'service': 'WeatherWise' | |
| } | |
| if data is not None: | |
| response['data'] = data | |
| if error is not None: | |
| response['error'] = error | |
| if processing_info is not None: | |
| response['processing_info'] = processing_info | |
| return response |