From 024290e4c0e29fd65648647603c4883dd4a5bf47 Mon Sep 17 00:00:00 2001 From: Urtzi Alfaro Date: Wed, 30 Jul 2025 08:41:47 +0200 Subject: [PATCH] Start fixing forecast service 18 --- .../app/services/forecasting_service.py | 8 +++-- services/training/app/ml/data_processor.py | 31 ++++++++++++------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/services/forecasting/app/services/forecasting_service.py b/services/forecasting/app/services/forecasting_service.py index 6b8c4a85..a0fe7540 100644 --- a/services/forecasting/app/services/forecasting_service.py +++ b/services/forecasting/app/services/forecasting_service.py @@ -122,15 +122,17 @@ class ForecastingService: # Metadata created_at=forecast.created_at, - processing_time_ms=forecast.processing_time_ms, + processing_time_ms=int((datetime.now() - start_time).total_seconds() * 1000), features_used=forecast.features_used ) except Exception as e: + processing_time = int((datetime.now() - start_time).total_seconds() * 1000) logger.error("Error generating forecast", error=str(e), product=request.product_name, - tenant_id=tenant_id) + tenant_id=tenant_id, + processing_time=processing_time) raise async def _get_latest_model_with_fallback( @@ -422,6 +424,8 @@ class ForecastingService: ) -> Forecast: """Save forecast to database""" + start_time = datetime.now() + forecast = Forecast( tenant_id=tenant_id, product_name=request.product_name, diff --git a/services/training/app/ml/data_processor.py b/services/training/app/ml/data_processor.py index 045c3f13..57dedeed 100644 --- a/services/training/app/ml/data_processor.py +++ b/services/training/app/ml/data_processor.py @@ -324,15 +324,18 @@ class BakeryDataProcessor: if 'date' not in weather_clean.columns and 'ds' in weather_clean.columns: weather_clean = weather_clean.rename(columns={'ds': 'date'}) - # ✅ FIX: Ensure timezone consistency + # 🔧 CRITICAL FIX: Ensure both DataFrames have compatible datetime formats weather_clean['date'] = pd.to_datetime(weather_clean['date']) daily_sales['date'] = pd.to_datetime(daily_sales['date']) - # Remove timezone info from both to make them compatible + # ✅ NEW FIX: Normalize both to timezone-naive datetime for merge compatibility if weather_clean['date'].dt.tz is not None: - weather_clean['date'] = weather_clean['date'].dt.tz_localize(None) + # Convert timezone-aware to UTC then remove timezone info + weather_clean['date'] = weather_clean['date'].dt.tz_convert('UTC').dt.tz_localize(None) + if daily_sales['date'].dt.tz is not None: - daily_sales['date'] = daily_sales['date'].dt.tz_localize(None) + # Convert timezone-aware to UTC then remove timezone info + daily_sales['date'] = daily_sales['date'].dt.tz_convert('UTC').dt.tz_localize(None) # Map weather columns to standard names weather_mapping = { @@ -390,15 +393,19 @@ class BakeryDataProcessor: if 'date' not in traffic_clean.columns and 'ds' in traffic_clean.columns: traffic_clean = traffic_clean.rename(columns={'ds': 'date'}) - # 🔧 FIX: Ensure timezone awareness before merge + # 🔧 CRITICAL FIX: Ensure both DataFrames have compatible datetime formats traffic_clean['date'] = pd.to_datetime(traffic_clean['date']) - - # If timezone-naive, localize to UTC - if traffic_clean['date'].dt.tz is None: - traffic_clean['date'] = traffic_clean['date'].dt.tz_localize('UTC') - # If already timezone-aware but not UTC, convert to UTC - elif str(traffic_clean['date'].dt.tz) != 'UTC': - traffic_clean['date'] = traffic_clean['date'].dt.tz_convert('UTC') + daily_sales['date'] = pd.to_datetime(daily_sales['date']) + + # ✅ NEW FIX: Normalize both to timezone-naive datetime for merge compatibility + # This prevents the "datetime64[ns] and datetime64[ns, UTC]" merge error + if traffic_clean['date'].dt.tz is not None: + # Convert timezone-aware to UTC then remove timezone info + traffic_clean['date'] = traffic_clean['date'].dt.tz_convert('UTC').dt.tz_localize(None) + + if daily_sales['date'].dt.tz is not None: + # Convert timezone-aware to UTC then remove timezone info + daily_sales['date'] = daily_sales['date'].dt.tz_convert('UTC').dt.tz_localize(None) # Map traffic columns to standard names traffic_mapping = {