Fix new services implementation 3
This commit is contained in:
@@ -78,7 +78,7 @@ class EnhancedForecastingService:
|
||||
logger.error("Batch forecast generation failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def get_tenant_forecasts(self, tenant_id: str, product_name: str = None,
|
||||
async def get_tenant_forecasts(self, tenant_id: str, inventory_product_id: str = None,
|
||||
start_date: date = None, end_date: date = None,
|
||||
skip: int = 0, limit: int = 100) -> List[Dict]:
|
||||
"""Get tenant forecasts with filtering"""
|
||||
@@ -149,7 +149,7 @@ class EnhancedForecastingService:
|
||||
logger.error("Batch predictions failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def get_cached_predictions(self, tenant_id: str, product_name: str = None,
|
||||
async def get_cached_predictions(self, tenant_id: str, inventory_product_id: str = None,
|
||||
skip: int = 0, limit: int = 100) -> List[Dict]:
|
||||
"""Get cached predictions"""
|
||||
try:
|
||||
@@ -159,7 +159,7 @@ class EnhancedForecastingService:
|
||||
logger.error("Failed to get cached predictions", error=str(e))
|
||||
raise
|
||||
|
||||
async def clear_prediction_cache(self, tenant_id: str, product_name: str = None) -> int:
|
||||
async def clear_prediction_cache(self, tenant_id: str, inventory_product_id: str = None) -> int:
|
||||
"""Clear prediction cache"""
|
||||
try:
|
||||
# Implementation would use repository pattern
|
||||
@@ -195,7 +195,7 @@ class EnhancedForecastingService:
|
||||
try:
|
||||
logger.info("Generating enhanced forecast",
|
||||
tenant_id=tenant_id,
|
||||
product=request.product_name,
|
||||
inventory_product_id=request.inventory_product_id,
|
||||
date=request.forecast_date.isoformat())
|
||||
|
||||
# Get session and initialize repositories
|
||||
@@ -204,20 +204,20 @@ class EnhancedForecastingService:
|
||||
|
||||
# Step 1: Check cache first
|
||||
cached_prediction = await repos['cache'].get_cached_prediction(
|
||||
tenant_id, request.product_name, request.location, request.forecast_date
|
||||
tenant_id, request.inventory_product_id, request.location, request.forecast_date
|
||||
)
|
||||
|
||||
if cached_prediction:
|
||||
logger.debug("Using cached prediction",
|
||||
tenant_id=tenant_id,
|
||||
product=request.product_name)
|
||||
inventory_product_id=request.inventory_product_id)
|
||||
return self._create_forecast_response_from_cache(cached_prediction)
|
||||
|
||||
# Step 2: Get model with validation
|
||||
model_data = await self._get_latest_model_with_fallback(tenant_id, request.product_name)
|
||||
model_data = await self._get_latest_model_with_fallback(tenant_id, request.inventory_product_id)
|
||||
|
||||
if not model_data:
|
||||
raise ValueError(f"No valid model available for product: {request.product_name}")
|
||||
raise ValueError(f"No valid model available for product: {request.inventory_product_id}")
|
||||
|
||||
# Step 3: Prepare features with fallbacks
|
||||
features = await self._prepare_forecast_features_with_fallbacks(tenant_id, request)
|
||||
@@ -244,7 +244,7 @@ class EnhancedForecastingService:
|
||||
|
||||
forecast_data = {
|
||||
"tenant_id": tenant_id,
|
||||
"product_name": request.product_name,
|
||||
"inventory_product_id": request.inventory_product_id,
|
||||
"location": request.location,
|
||||
"forecast_date": forecast_datetime,
|
||||
"predicted_demand": adjusted_prediction['prediction'],
|
||||
@@ -271,7 +271,7 @@ class EnhancedForecastingService:
|
||||
# Step 7: Cache the prediction
|
||||
await repos['cache'].cache_prediction(
|
||||
tenant_id=tenant_id,
|
||||
product_name=request.product_name,
|
||||
inventory_product_id=request.inventory_product_id,
|
||||
location=request.location,
|
||||
forecast_date=forecast_datetime,
|
||||
predicted_demand=adjusted_prediction['prediction'],
|
||||
@@ -296,14 +296,14 @@ class EnhancedForecastingService:
|
||||
logger.error("Error generating enhanced forecast",
|
||||
error=str(e),
|
||||
tenant_id=tenant_id,
|
||||
product=request.product_name,
|
||||
inventory_product_id=request.inventory_product_id,
|
||||
processing_time=processing_time)
|
||||
raise
|
||||
|
||||
async def get_forecast_history(
|
||||
self,
|
||||
tenant_id: str,
|
||||
product_name: Optional[str] = None,
|
||||
inventory_product_id: Optional[str] = None,
|
||||
start_date: Optional[date] = None,
|
||||
end_date: Optional[date] = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
@@ -314,7 +314,7 @@ class EnhancedForecastingService:
|
||||
|
||||
if start_date and end_date:
|
||||
forecasts = await repos['forecast'].get_forecasts_by_date_range(
|
||||
tenant_id, start_date, end_date, product_name
|
||||
tenant_id, start_date, end_date, inventory_product_id
|
||||
)
|
||||
else:
|
||||
# Get recent forecasts (last 30 days)
|
||||
@@ -374,7 +374,7 @@ class EnhancedForecastingService:
|
||||
self,
|
||||
tenant_id: str,
|
||||
batch_name: str,
|
||||
products: List[str],
|
||||
inventory_product_ids: List[str],
|
||||
forecast_days: int = 7
|
||||
) -> Dict[str, Any]:
|
||||
"""Create batch prediction job using repository"""
|
||||
@@ -386,7 +386,7 @@ class EnhancedForecastingService:
|
||||
batch_data = {
|
||||
"tenant_id": tenant_id,
|
||||
"batch_name": batch_name,
|
||||
"total_products": len(products),
|
||||
"total_products": len(inventory_product_ids),
|
||||
"forecast_days": forecast_days,
|
||||
"status": "pending"
|
||||
}
|
||||
@@ -396,12 +396,12 @@ class EnhancedForecastingService:
|
||||
logger.info("Batch prediction created",
|
||||
batch_id=batch.id,
|
||||
tenant_id=tenant_id,
|
||||
total_products=len(products))
|
||||
total_products=len(inventory_product_ids))
|
||||
|
||||
return {
|
||||
"batch_id": str(batch.id),
|
||||
"status": batch.status,
|
||||
"total_products": len(products),
|
||||
"total_products": len(inventory_product_ids),
|
||||
"created_at": batch.requested_at.isoformat()
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@ class EnhancedForecastingService:
|
||||
"forecast_id": forecast.id,
|
||||
"alert_type": "high_demand",
|
||||
"severity": "high" if prediction['prediction'] > 200 else "medium",
|
||||
"message": f"High demand predicted for {forecast.product_name}: {prediction['prediction']:.1f} units"
|
||||
"message": f"High demand predicted for inventory product {forecast.inventory_product_id}: {prediction['prediction']:.1f} units"
|
||||
})
|
||||
|
||||
# Check for low demand alert
|
||||
@@ -433,7 +433,7 @@ class EnhancedForecastingService:
|
||||
"forecast_id": forecast.id,
|
||||
"alert_type": "low_demand",
|
||||
"severity": "low",
|
||||
"message": f"Low demand predicted for {forecast.product_name}: {prediction['prediction']:.1f} units"
|
||||
"message": f"Low demand predicted for inventory product {forecast.inventory_product_id}: {prediction['prediction']:.1f} units"
|
||||
})
|
||||
|
||||
# Check for stockout risk (very low prediction with narrow confidence interval)
|
||||
@@ -444,7 +444,7 @@ class EnhancedForecastingService:
|
||||
"forecast_id": forecast.id,
|
||||
"alert_type": "stockout_risk",
|
||||
"severity": "critical",
|
||||
"message": f"Stockout risk for {forecast.product_name}: predicted {prediction['prediction']:.1f} units with high confidence"
|
||||
"message": f"Stockout risk for inventory product {forecast.inventory_product_id}: predicted {prediction['prediction']:.1f} units with high confidence"
|
||||
})
|
||||
|
||||
# Create alerts
|
||||
@@ -462,7 +462,7 @@ class EnhancedForecastingService:
|
||||
return ForecastResponse(
|
||||
id=str(cache_entry.id),
|
||||
tenant_id=str(cache_entry.tenant_id),
|
||||
product_name=cache_entry.product_name,
|
||||
inventory_product_id=cache_entry.inventory_product_id,
|
||||
location=cache_entry.location,
|
||||
forecast_date=cache_entry.forecast_date,
|
||||
predicted_demand=cache_entry.predicted_demand,
|
||||
@@ -486,7 +486,7 @@ class EnhancedForecastingService:
|
||||
return ForecastResponse(
|
||||
id=str(forecast.id),
|
||||
tenant_id=str(forecast.tenant_id),
|
||||
product_name=forecast.product_name,
|
||||
inventory_product_id=forecast.inventory_product_id,
|
||||
location=forecast.location,
|
||||
forecast_date=forecast.forecast_date,
|
||||
predicted_demand=forecast.predicted_demand,
|
||||
@@ -514,7 +514,7 @@ class EnhancedForecastingService:
|
||||
return {
|
||||
"id": str(forecast.id),
|
||||
"tenant_id": str(forecast.tenant_id),
|
||||
"product_name": forecast.product_name,
|
||||
"inventory_product_id": forecast.inventory_product_id,
|
||||
"location": forecast.location,
|
||||
"forecast_date": forecast.forecast_date.isoformat(),
|
||||
"predicted_demand": forecast.predicted_demand,
|
||||
@@ -527,17 +527,17 @@ class EnhancedForecastingService:
|
||||
}
|
||||
|
||||
# Additional helper methods from original service
|
||||
async def _get_latest_model_with_fallback(self, tenant_id: str, product_name: str) -> Optional[Dict[str, Any]]:
|
||||
async def _get_latest_model_with_fallback(self, tenant_id: str, inventory_product_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""Get the latest trained model with fallback strategies"""
|
||||
try:
|
||||
model_data = await self.model_client.get_best_model_for_forecasting(
|
||||
tenant_id=tenant_id,
|
||||
product_name=product_name
|
||||
inventory_product_id=inventory_product_id
|
||||
)
|
||||
|
||||
if model_data:
|
||||
logger.info("Found specific model for product",
|
||||
product=product_name,
|
||||
inventory_product_id=inventory_product_id,
|
||||
model_id=model_data.get('model_id'))
|
||||
return model_data
|
||||
|
||||
|
||||
Reference in New Issue
Block a user