Imporve the predicciones page
This commit is contained in:
@@ -11,8 +11,8 @@ import uuid
|
||||
|
||||
from app.services.forecasting_service import EnhancedForecastingService
|
||||
from app.schemas.forecasts import (
|
||||
ForecastRequest, ForecastResponse, BatchForecastRequest,
|
||||
BatchForecastResponse
|
||||
ForecastRequest, ForecastResponse, BatchForecastRequest,
|
||||
BatchForecastResponse, MultiDayForecastResponse
|
||||
)
|
||||
from shared.auth.decorators import (
|
||||
get_current_user_dep,
|
||||
@@ -66,7 +66,7 @@ async def create_enhanced_single_forecast(
|
||||
forecast_id=forecast.id)
|
||||
|
||||
return forecast
|
||||
|
||||
|
||||
except ValueError as e:
|
||||
if metrics:
|
||||
metrics.increment_counter("enhanced_forecast_validation_errors_total")
|
||||
@@ -89,6 +89,70 @@ async def create_enhanced_single_forecast(
|
||||
)
|
||||
|
||||
|
||||
@router.post("/tenants/{tenant_id}/forecasts/multi-day", response_model=MultiDayForecastResponse)
|
||||
@track_execution_time("enhanced_multi_day_forecast_duration_seconds", "forecasting-service")
|
||||
async def create_enhanced_multi_day_forecast(
|
||||
request: ForecastRequest,
|
||||
tenant_id: str = Path(..., description="Tenant ID"),
|
||||
request_obj: Request = None,
|
||||
enhanced_forecasting_service: EnhancedForecastingService = Depends(get_enhanced_forecasting_service)
|
||||
):
|
||||
"""Generate multiple daily forecasts for the specified period using enhanced repository pattern"""
|
||||
metrics = get_metrics_collector(request_obj)
|
||||
|
||||
try:
|
||||
logger.info("Generating enhanced multi-day forecast",
|
||||
tenant_id=tenant_id,
|
||||
inventory_product_id=request.inventory_product_id,
|
||||
forecast_days=request.forecast_days,
|
||||
forecast_date=request.forecast_date.isoformat())
|
||||
|
||||
# Record metrics
|
||||
if metrics:
|
||||
metrics.increment_counter("enhanced_multi_day_forecasts_total")
|
||||
|
||||
# Validate forecast_days parameter
|
||||
if request.forecast_days <= 0 or request.forecast_days > 30:
|
||||
raise ValueError("forecast_days must be between 1 and 30")
|
||||
|
||||
# Generate multi-day forecast using enhanced service
|
||||
forecast_result = await enhanced_forecasting_service.generate_multi_day_forecast(
|
||||
tenant_id=tenant_id,
|
||||
request=request
|
||||
)
|
||||
|
||||
if metrics:
|
||||
metrics.increment_counter("enhanced_multi_day_forecasts_success_total")
|
||||
|
||||
logger.info("Enhanced multi-day forecast generated successfully",
|
||||
tenant_id=tenant_id,
|
||||
inventory_product_id=request.inventory_product_id,
|
||||
forecast_days=len(forecast_result.get("forecasts", [])))
|
||||
|
||||
return MultiDayForecastResponse(**forecast_result)
|
||||
|
||||
except ValueError as e:
|
||||
if metrics:
|
||||
metrics.increment_counter("enhanced_multi_day_forecast_validation_errors_total")
|
||||
logger.error("Enhanced multi-day forecast validation error",
|
||||
error=str(e),
|
||||
tenant_id=tenant_id)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=str(e)
|
||||
)
|
||||
except Exception as e:
|
||||
if metrics:
|
||||
metrics.increment_counter("enhanced_multi_day_forecasts_errors_total")
|
||||
logger.error("Enhanced multi-day forecast generation failed",
|
||||
error=str(e),
|
||||
tenant_id=tenant_id)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Enhanced multi-day forecast generation failed"
|
||||
)
|
||||
|
||||
|
||||
@router.post("/tenants/{tenant_id}/forecasts/batch", response_model=BatchForecastResponse)
|
||||
@track_execution_time("enhanced_batch_forecast_duration_seconds", "forecasting-service")
|
||||
async def create_enhanced_batch_forecast(
|
||||
|
||||
@@ -95,4 +95,15 @@ class BatchForecastResponse(BaseModel):
|
||||
forecasts: Optional[List[ForecastResponse]]
|
||||
error_message: Optional[str]
|
||||
|
||||
class MultiDayForecastResponse(BaseModel):
|
||||
"""Response schema for multi-day forecast results"""
|
||||
tenant_id: str = Field(..., description="Tenant ID")
|
||||
inventory_product_id: str = Field(..., description="Inventory product ID")
|
||||
forecast_start_date: date = Field(..., description="Start date of forecast period")
|
||||
forecast_days: int = Field(..., description="Number of forecasted days")
|
||||
forecasts: List[ForecastResponse] = Field(..., description="Daily forecasts")
|
||||
total_predicted_demand: float = Field(..., description="Total demand across all days")
|
||||
average_confidence_level: float = Field(..., description="Average confidence across all days")
|
||||
processing_time_ms: int = Field(..., description="Total processing time")
|
||||
|
||||
|
||||
|
||||
@@ -345,7 +345,101 @@ class EnhancedForecastingService:
|
||||
inventory_product_id=request.inventory_product_id,
|
||||
processing_time=processing_time)
|
||||
raise
|
||||
|
||||
|
||||
async def generate_multi_day_forecast(
|
||||
self,
|
||||
tenant_id: str,
|
||||
request: ForecastRequest
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Generate multiple daily forecasts for the specified period.
|
||||
"""
|
||||
start_time = datetime.utcnow()
|
||||
forecasts = []
|
||||
|
||||
try:
|
||||
logger.info("Generating multi-day forecast",
|
||||
tenant_id=tenant_id,
|
||||
inventory_product_id=request.inventory_product_id,
|
||||
forecast_days=request.forecast_days,
|
||||
start_date=request.forecast_date.isoformat())
|
||||
|
||||
# Generate a forecast for each day
|
||||
for day_offset in range(request.forecast_days):
|
||||
# Calculate the forecast date for this day
|
||||
current_date = request.forecast_date
|
||||
if isinstance(current_date, str):
|
||||
from dateutil.parser import parse
|
||||
current_date = parse(current_date).date()
|
||||
|
||||
if day_offset > 0:
|
||||
from datetime import timedelta
|
||||
current_date = current_date + timedelta(days=day_offset)
|
||||
|
||||
# Create a new request for this specific day
|
||||
daily_request = ForecastRequest(
|
||||
inventory_product_id=request.inventory_product_id,
|
||||
forecast_date=current_date,
|
||||
forecast_days=1, # Single day for each iteration
|
||||
location=request.location,
|
||||
confidence_level=request.confidence_level
|
||||
)
|
||||
|
||||
# Generate forecast for this day
|
||||
daily_forecast = await self.generate_forecast(tenant_id, daily_request)
|
||||
forecasts.append(daily_forecast)
|
||||
|
||||
# Calculate summary statistics
|
||||
total_demand = sum(f.predicted_demand for f in forecasts)
|
||||
avg_confidence = sum(f.confidence_level for f in forecasts) / len(forecasts)
|
||||
processing_time = int((datetime.utcnow() - start_time).total_seconds() * 1000)
|
||||
|
||||
# Convert forecasts to dictionary format for the response
|
||||
forecast_dicts = []
|
||||
for forecast in forecasts:
|
||||
forecast_dicts.append({
|
||||
"id": forecast.id,
|
||||
"tenant_id": forecast.tenant_id,
|
||||
"inventory_product_id": forecast.inventory_product_id,
|
||||
"location": forecast.location,
|
||||
"forecast_date": forecast.forecast_date.isoformat() if hasattr(forecast.forecast_date, 'isoformat') else str(forecast.forecast_date),
|
||||
"predicted_demand": forecast.predicted_demand,
|
||||
"confidence_lower": forecast.confidence_lower,
|
||||
"confidence_upper": forecast.confidence_upper,
|
||||
"confidence_level": forecast.confidence_level,
|
||||
"model_id": forecast.model_id,
|
||||
"model_version": forecast.model_version,
|
||||
"algorithm": forecast.algorithm,
|
||||
"business_type": forecast.business_type,
|
||||
"is_holiday": forecast.is_holiday,
|
||||
"is_weekend": forecast.is_weekend,
|
||||
"day_of_week": forecast.day_of_week,
|
||||
"weather_temperature": forecast.weather_temperature,
|
||||
"weather_precipitation": forecast.weather_precipitation,
|
||||
"weather_description": forecast.weather_description,
|
||||
"traffic_volume": forecast.traffic_volume,
|
||||
"created_at": forecast.created_at.isoformat() if hasattr(forecast.created_at, 'isoformat') else str(forecast.created_at),
|
||||
"processing_time_ms": forecast.processing_time_ms,
|
||||
"features_used": forecast.features_used
|
||||
})
|
||||
|
||||
return {
|
||||
"tenant_id": tenant_id,
|
||||
"inventory_product_id": request.inventory_product_id,
|
||||
"forecast_start_date": request.forecast_date.isoformat() if hasattr(request.forecast_date, 'isoformat') else str(request.forecast_date),
|
||||
"forecast_days": request.forecast_days,
|
||||
"forecasts": forecast_dicts,
|
||||
"total_predicted_demand": total_demand,
|
||||
"average_confidence_level": avg_confidence,
|
||||
"processing_time_ms": processing_time
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Multi-day forecast generation failed",
|
||||
tenant_id=tenant_id,
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def get_forecast_history(
|
||||
self,
|
||||
tenant_id: str,
|
||||
|
||||
Reference in New Issue
Block a user