Start fixing forecast service API 7
This commit is contained in:
@@ -33,26 +33,19 @@ forecasting_service = ForecastingService()
|
|||||||
async def create_single_forecast(
|
async def create_single_forecast(
|
||||||
request: ForecastRequest,
|
request: ForecastRequest,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
tenant_id: str = Path(..., description="Tenant ID"),
|
tenant_id: str = Path(..., description="Tenant ID")
|
||||||
current_user: dict = Depends(get_current_user_dep)
|
|
||||||
):
|
):
|
||||||
"""Generate a single product forecast"""
|
"""Generate a single product forecast"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Verify tenant access
|
|
||||||
if str(request.tenant_id) != tenant_id:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail="Access denied to this tenant"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generate forecast
|
# Generate forecast
|
||||||
forecast = await forecasting_service.generate_forecast(request, db)
|
forecast = await forecasting_service.generate_forecast(tenant_id, request, db)
|
||||||
|
|
||||||
# Convert to response model
|
# Convert to response model
|
||||||
return ForecastResponse(
|
return ForecastResponse(
|
||||||
id=str(forecast.id),
|
id=str(forecast.id),
|
||||||
tenant_id=str(forecast.tenant_id),
|
tenant_id=tenant_id,
|
||||||
product_name=forecast.product_name,
|
product_name=forecast.product_name,
|
||||||
location=forecast.location,
|
location=forecast.location,
|
||||||
forecast_date=forecast.forecast_date,
|
forecast_date=forecast.forecast_date,
|
||||||
|
|||||||
@@ -38,19 +38,19 @@ class ForecastingService:
|
|||||||
self.model_client = ModelClient()
|
self.model_client = ModelClient()
|
||||||
self.data_client = DataClient()
|
self.data_client = DataClient()
|
||||||
|
|
||||||
async def generate_forecast(self, request: ForecastRequest, db: AsyncSession) -> Forecast:
|
async def generate_forecast(self, tenant_id: str, request: ForecastRequest, db: AsyncSession) -> Forecast:
|
||||||
"""Generate a single forecast for a product"""
|
"""Generate a single forecast for a product"""
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.info("Generating forecast",
|
logger.info("Generating forecast",
|
||||||
tenant_id=request.tenant_id,
|
tenant_id=tenant_id,
|
||||||
product=request.product_name,
|
product=request.product_name,
|
||||||
date=request.forecast_date)
|
date=request.forecast_date)
|
||||||
|
|
||||||
# Get the latest trained model for this tenant/product
|
# Get the latest trained model for this tenant/product
|
||||||
model_info = await self._get_latest_model(
|
model_info = await self._get_latest_model(
|
||||||
request.tenant_id,
|
tenant_id,
|
||||||
request.product_name,
|
request.product_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ class ForecastingService:
|
|||||||
raise ValueError(f"No trained model found for {request.product_name}")
|
raise ValueError(f"No trained model found for {request.product_name}")
|
||||||
|
|
||||||
# Prepare features for prediction
|
# Prepare features for prediction
|
||||||
features = await self._prepare_forecast_features(request)
|
features = await self._prepare_forecast_features(tenant_id, request)
|
||||||
|
|
||||||
# Generate prediction using ML service
|
# Generate prediction using ML service
|
||||||
prediction_result = await self.prediction_service.predict(
|
prediction_result = await self.prediction_service.predict(
|
||||||
@@ -69,7 +69,7 @@ class ForecastingService:
|
|||||||
|
|
||||||
# Create forecast record
|
# Create forecast record
|
||||||
forecast = Forecast(
|
forecast = Forecast(
|
||||||
tenant_id=uuid.UUID(request.tenant_id),
|
tenant_id=uuid.UUID(tenant_id),
|
||||||
product_name=request.product_name,
|
product_name=request.product_name,
|
||||||
forecast_date=datetime.combine(request.forecast_date, datetime.min.time()),
|
forecast_date=datetime.combine(request.forecast_date, datetime.min.time()),
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ class ForecastingService:
|
|||||||
# Publish event
|
# Publish event
|
||||||
await publish_forecast_completed({
|
await publish_forecast_completed({
|
||||||
"forecast_id": str(forecast.id),
|
"forecast_id": str(forecast.id),
|
||||||
"tenant_id": request.tenant_id,
|
"tenant_id": tenant_id,
|
||||||
"product_name": request.product_name,
|
"product_name": request.product_name,
|
||||||
"predicted_demand": forecast.predicted_demand
|
"predicted_demand": forecast.predicted_demand
|
||||||
})
|
})
|
||||||
@@ -256,7 +256,7 @@ class ForecastingService:
|
|||||||
logger.error("Error getting latest model", error=str(e))
|
logger.error("Error getting latest model", error=str(e))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
async def _prepare_forecast_features(self, request: ForecastRequest) -> Dict[str, Any]:
|
async def _prepare_forecast_features(self, tenant_id: str, request: ForecastRequest) -> Dict[str, Any]:
|
||||||
"""Prepare features for forecasting model"""
|
"""Prepare features for forecasting model"""
|
||||||
|
|
||||||
features = {
|
features = {
|
||||||
@@ -269,7 +269,7 @@ class ForecastingService:
|
|||||||
features["is_holiday"] = await self._is_spanish_holiday(request.forecast_date)
|
features["is_holiday"] = await self._is_spanish_holiday(request.forecast_date)
|
||||||
|
|
||||||
|
|
||||||
weather_data = await self._get_weather_forecast(request.tenant_id, 1)
|
weather_data = await self._get_weather_forecast(tenant_id, 1)
|
||||||
features.update(weather_data)
|
features.update(weather_data)
|
||||||
|
|
||||||
return features
|
return features
|
||||||
|
|||||||
@@ -563,31 +563,73 @@ echo ""
|
|||||||
# STEP 5: ONBOARDING COMPLETION (DASHBOARD ACCESS)
|
# STEP 5: ONBOARDING COMPLETION (DASHBOARD ACCESS)
|
||||||
# =================================================================
|
# =================================================================
|
||||||
|
|
||||||
echo -e "${STEP_ICONS[4]} ${PURPLE}STEP 5: ONBOARDING COMPLETION${NC}"
|
|
||||||
echo "Simulating completion and dashboard access"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
log_step "5.1. Testing basic dashboard functionality"
|
log_step "5.1. Testing basic dashboard functionality"
|
||||||
|
|
||||||
# Use a real product name from our CSV for forecasting
|
# Get a real product name from CSV (fix the product extraction)
|
||||||
FIRST_PRODUCT=$(echo "$REAL_PRODUCTS" | sed 's/"//g' | cut -d',' -f1)
|
FIRST_PRODUCT=$(head -2 "$REAL_CSV_FILE" | tail -1 | cut -d',' -f3 | sed 's/"//g' | head -1)
|
||||||
|
|
||||||
FORECAST_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/tenants/$TENANT_ID/forecasts/single" \
|
if [ -z "$FIRST_PRODUCT" ]; then
|
||||||
|
FIRST_PRODUCT="Pan Integral" # Fallback product name
|
||||||
|
log_warning "Could not extract product from CSV, using fallback: $FIRST_PRODUCT"
|
||||||
|
else
|
||||||
|
log_success "Using product from CSV: $FIRST_PRODUCT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# CORRECTED forecast request with proper schema
|
||||||
|
FORECAST_REQUEST="{
|
||||||
|
\"product_name\": \"$FIRST_PRODUCT\",
|
||||||
|
\"forecast_date\": \"2025-07-30\",
|
||||||
|
\"forecast_days\": 1,
|
||||||
|
\"location\": \"madrid_centro\",
|
||||||
|
\"confidence_level\": 0.85
|
||||||
|
}"
|
||||||
|
|
||||||
|
echo "Forecast Request:"
|
||||||
|
echo "$FORECAST_REQUEST" | python3 -m json.tool
|
||||||
|
|
||||||
|
# Make the API call
|
||||||
|
FORECAST_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X POST "$API_BASE/api/v1/tenants/$TENANT_ID/forecasts/single" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||||
-d "{
|
-d "$FORECAST_REQUEST")
|
||||||
\"product_name\": [\"$FIRST_PRODUCT\"],
|
|
||||||
\"forecast_date\": "2025-11-30",
|
|
||||||
\"forecast_days\": 1,
|
|
||||||
\"date\": \"2025-09-15\",
|
|
||||||
\"location\": \"madrid_centro\",
|
|
||||||
\"confidence_level\": 0.85
|
|
||||||
}")
|
|
||||||
|
|
||||||
if echo "$FORECAST_RESPONSE" | grep -q '"predictions"\|"forecast"'; then
|
# Extract HTTP code and response
|
||||||
log_success "Forecasting service is accessible"
|
HTTP_CODE=$(echo "$FORECAST_RESPONSE" | grep "HTTP_CODE:" | cut -d: -f2)
|
||||||
|
FORECAST_RESPONSE=$(echo "$FORECAST_RESPONSE" | sed '/HTTP_CODE:/d')
|
||||||
|
|
||||||
|
echo "Forecast HTTP Status: $HTTP_CODE"
|
||||||
|
echo "Forecast Response:"
|
||||||
|
echo "$FORECAST_RESPONSE" | python3 -m json.tool 2>/dev/null || echo "$FORECAST_RESPONSE"
|
||||||
|
|
||||||
|
# Validate response
|
||||||
|
if [ "$HTTP_CODE" = "200" ]; then
|
||||||
|
if echo "$FORECAST_RESPONSE" | grep -q '"predicted_demand"\|"id"'; then
|
||||||
|
log_success "Forecasting service is working correctly"
|
||||||
|
|
||||||
|
# Extract key values for validation
|
||||||
|
PREDICTED_DEMAND=$(extract_json_field "$FORECAST_RESPONSE" "predicted_demand")
|
||||||
|
CONFIDENCE_LOWER=$(extract_json_field "$FORECAST_RESPONSE" "confidence_lower")
|
||||||
|
CONFIDENCE_UPPER=$(extract_json_field "$FORECAST_RESPONSE" "confidence_upper")
|
||||||
|
|
||||||
|
if [ -n "$PREDICTED_DEMAND" ]; then
|
||||||
|
echo " Predicted Demand: $PREDICTED_DEMAND"
|
||||||
|
echo " Confidence Range: [$CONFIDENCE_LOWER, $CONFIDENCE_UPPER]"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_error "Forecast response missing expected fields"
|
||||||
|
echo "Response: $FORECAST_RESPONSE"
|
||||||
|
fi
|
||||||
|
elif [ "$HTTP_CODE" = "422" ]; then
|
||||||
|
log_error "Forecast request validation failed"
|
||||||
|
echo "Validation errors: $FORECAST_RESPONSE"
|
||||||
|
elif [ "$HTTP_CODE" = "404" ]; then
|
||||||
|
log_warning "Forecast endpoint not found - check API routing"
|
||||||
|
elif [ "$HTTP_CODE" = "500" ]; then
|
||||||
|
log_error "Internal server error in forecasting service"
|
||||||
|
echo "Error details: $FORECAST_RESPONSE"
|
||||||
else
|
else
|
||||||
log_warning "Forecasting may not be ready yet (model training required)"
|
log_warning "Forecasting may not be ready yet (HTTP $HTTP_CODE)"
|
||||||
|
echo "Response: $FORECAST_RESPONSE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
Reference in New Issue
Block a user