File size: 12,705 Bytes
5ccd893
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
"""
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