diff --git a/frontend/src/pages/onboarding.tsx b/frontend/src/pages/onboarding.tsx index 4b43f0fb..d6db140a 100644 --- a/frontend/src/pages/onboarding.tsx +++ b/frontend/src/pages/onboarding.tsx @@ -100,30 +100,84 @@ const OnboardingPage = () => { } ]; - // Mock WebSocket for training progress useEffect(() => { - if (formData.trainingTaskId && currentStep === 4) { - const interval = setInterval(async () => { + const startTrainingWhenReachingStep4 = async () => { + // Only trigger if we just reached step 4 and haven't started training yet + if (currentStep === 4 && !formData.trainingTaskId && !loading) { + console.log('Auto-starting training for step 4...'); + + setLoading(true); + try { - const status = await api.training.getTrainingStatus(formData.trainingTaskId); - setTrainingProgress(status); - - if (status.status === 'completed') { - setCompletedSteps([...completedSteps, 4]); - clearInterval(interval); - showNotification('success', '¡Entrenamiento completado!', 'Los modelos están listos para usar.'); - } else if (status.status === 'failed') { - clearInterval(interval); - showNotification('error', 'Error en entrenamiento', 'Hubo un problema durante el entrenamiento.'); + // Check if we have required data + if (!formData.selected_products || formData.selected_products.length === 0) { + showNotification('error', 'No hay productos', 'No se han seleccionado productos para entrenar.'); + setLoading(false); + return; } + + if (!currentTenantId) { + showNotification('error', 'Error de configuración', 'No se ha configurado el tenant ID.'); + setLoading(false); + return; + } + + // Training configuration + const trainingConfig = { + include_weather: true, + include_traffic: true, + products: formData.selected_products, + min_data_points: 30, + forecast_horizon_days: 7, + cross_validation_folds: 3, + hyperparameter_tuning: true + }; + + console.log('Starting training with config:', trainingConfig); + + // Start training via API + const trainingJob = await api.training.startTraining(trainingConfig); + + // Update form data with training job ID + setFormData(prev => ({ + ...prev, + trainingTaskId: trainingJob.id, + trainingStatus: 'running' + })); + + showNotification('info', 'Entrenamiento iniciado', 'Los modelos se están entrenando...'); + } catch (error) { - console.error('Error fetching training status:', error); + console.error('Error starting training:', error); + + let errorMessage = 'No se pudo iniciar el entrenamiento.'; + let errorTitle = 'Error de entrenamiento'; + + if (error.response?.status === 400) { + errorMessage = error.response.data?.detail || 'Configuración de entrenamiento inválida.'; + } else if (error.response?.status === 401) { + errorMessage = 'No autorizado. Por favor, inicia sesión nuevamente.'; + errorTitle = 'Error de autenticación'; + } else if (error.response?.status === 403) { + errorMessage = 'No tienes permisos para iniciar el entrenamiento.'; + errorTitle = 'Error de permisos'; + } else if (error.response?.status === 500) { + errorMessage = 'Error interno del servidor. Inténtalo más tarde.'; + errorTitle = 'Error del servidor'; + } + + showNotification('error', errorTitle, errorMessage); + + // Optionally go back to previous step on error + // setCurrentStep(3); + } finally { + setLoading(false); } - }, 2000); - - return () => clearInterval(interval); - } - }, [formData.trainingTaskId, currentStep]); + } + }; + + startTrainingWhenReachingStep4(); + }, [currentStep, formData.trainingTaskId, formData.selected_products, currentTenantId, loading]); const showNotification = (type, title, message) => { const id = Date.now().toString();