ttzzs's picture
Deploy Chronos2 Forecasting API v3.0.0 with new SOLID architecture
c40c447 verified
"""
Forecast API endpoints.
Responsabilidad: Manejar requests de forecasting y delegar a use cases.
"""
from fastapi import APIRouter, Depends, HTTPException, status
from typing import List
from app.api.dependencies import (
get_forecast_univariate_use_case,
get_forecast_multi_series_use_case
)
from app.application.use_cases.forecast_use_case import (
ForecastUnivariateUseCase,
ForecastMultiSeriesUseCase
)
from app.application.dtos.forecast_dtos import (
ForecastUnivariateRequestDTO,
ForecastUnivariateResponseDTO,
ForecastMultiSeriesRequestDTO,
ForecastMultiSeriesResponseDTO
)
from app.utils.logger import setup_logger
logger = setup_logger(__name__)
router = APIRouter(prefix="/forecast", tags=["Forecast"])
@router.post(
"/univariate",
response_model=ForecastUnivariateResponseDTO,
status_code=status.HTTP_200_OK,
summary="Pron贸stico univariado",
description="Genera pron贸stico para una serie temporal sin covariables"
)
async def forecast_univariate(
request: ForecastUnivariateRequestDTO,
use_case: ForecastUnivariateUseCase = Depends(get_forecast_univariate_use_case)
):
"""
Pron贸stico univariado.
Genera pron贸stico probabil铆stico para una serie temporal simple,
sin variables ex贸genas.
Args:
request: Datos de la serie y par谩metros de predicci贸n
use_case: Caso de uso inyectado
Returns:
Pron贸stico con mediana y cuantiles
Raises:
HTTPException: Si hay error en la predicci贸n
Example:
```json
{
"values": [100, 102, 105, 103, 108, 112],
"prediction_length": 3,
"freq": "D",
"quantile_levels": [0.1, 0.5, 0.9]
}
```
"""
try:
logger.info(
f"Forecast univariate request: {len(request.values)} values, "
f"{request.prediction_length} steps ahead"
)
# Ejecutar use case
response = use_case.execute(request)
logger.info(f"Forecast completed: {len(response.timestamps)} predictions")
return response
except ValueError as e:
logger.error(f"Validation error: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e)
)
except Exception as e:
logger.error(f"Unexpected error in forecast: {e}", exc_info=True)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Error interno al generar pron贸stico"
)
@router.post(
"/multi-series",
response_model=ForecastMultiSeriesResponseDTO,
status_code=status.HTTP_200_OK,
summary="Pron贸stico multi-series",
description="Genera pron贸sticos para m煤ltiples series simult谩neamente"
)
async def forecast_multi_series(
request: ForecastMultiSeriesRequestDTO,
use_case: ForecastMultiSeriesUseCase = Depends(get_forecast_multi_series_use_case)
):
"""
Pron贸stico para m煤ltiples series.
Genera pron贸sticos independientes para varias series temporales
en una sola llamada.
Args:
request: Lista de series y par谩metros
use_case: Caso de uso inyectado
Returns:
Lista de pron贸sticos, uno por cada serie
Example:
```json
{
"series_list": [
{"series_id": "sales", "values": [100, 102, 105]},
{"series_id": "revenue", "values": [200, 205, 210]}
],
"prediction_length": 3,
"freq": "D"
}
```
"""
try:
logger.info(
f"Forecast multi-series request: {len(request.series_list)} series"
)
# Ejecutar use case
response = use_case.execute(request)
logger.info(
f"Multi-series forecast completed: "
f"{len(response.forecasts)} forecasts"
)
return response
except ValueError as e:
logger.error(f"Validation error: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e)
)
except Exception as e:
logger.error(
f"Unexpected error in multi-series forecast: {e}",
exc_info=True
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Error interno al generar pron贸sticos"
)