Fix new services implementation 5
This commit is contained in:
@@ -7,13 +7,13 @@ import SmartHistoricalDataImport from '../../components/onboarding/SmartHistoric
|
||||
|
||||
import {
|
||||
useTenant,
|
||||
useTraining,
|
||||
useSales,
|
||||
useTrainingWebSocket,
|
||||
useOnboarding,
|
||||
TenantCreate,
|
||||
TrainingJobRequest
|
||||
} from '../../api';
|
||||
import { useTraining } from '../../api/hooks/useTraining';
|
||||
|
||||
import { OnboardingRouter } from '../../utils/onboardingRouter';
|
||||
|
||||
@@ -134,7 +134,7 @@ const OnboardingPage: React.FC<OnboardingPageProps> = ({ user, onComplete }) =>
|
||||
fetchTenantIdFromBackend();
|
||||
}, [tenantId, user, getUserTenants]);
|
||||
|
||||
// WebSocket connection for real-time training updates
|
||||
// Enhanced WebSocket connection for real-time training updates
|
||||
const {
|
||||
status,
|
||||
jobUpdates,
|
||||
@@ -143,7 +143,11 @@ const OnboardingPage: React.FC<OnboardingPageProps> = ({ user, onComplete }) =>
|
||||
isConnected,
|
||||
lastMessage,
|
||||
tenantId: resolvedTenantId,
|
||||
wsUrl
|
||||
wsUrl,
|
||||
connectionError,
|
||||
isAuthenticationError,
|
||||
refreshConnection,
|
||||
retryWithAuth
|
||||
} = useTrainingWebSocket(trainingJobId || 'pending', tenantId);
|
||||
|
||||
// Handle WebSocket job updates
|
||||
@@ -203,12 +207,19 @@ const OnboardingPage: React.FC<OnboardingPageProps> = ({ user, onComplete }) =>
|
||||
currentStep: 'Error en el entrenamiento'
|
||||
}));
|
||||
|
||||
} else if (messageType === 'initial_status') {
|
||||
} else if (messageType === 'initial_status' || messageType === 'current_status') {
|
||||
console.log('Received training status update:', messageType, data);
|
||||
setTrainingProgress(prev => ({
|
||||
...prev,
|
||||
progress: typeof data.progress === 'number' ? data.progress : prev.progress,
|
||||
status: data.status || prev.status,
|
||||
currentStep: data.current_step || data.currentStep || prev.currentStep
|
||||
currentStep: data.current_step || data.currentStep || prev.currentStep,
|
||||
productsCompleted: data.products_completed || data.productsCompleted || prev.productsCompleted,
|
||||
productsTotal: data.products_total || data.productsTotal || prev.productsTotal,
|
||||
estimatedTimeRemaining: data.estimated_time_remaining_minutes ||
|
||||
data.estimated_time_remaining ||
|
||||
data.estimatedTimeRemaining ||
|
||||
prev.estimatedTimeRemaining
|
||||
}));
|
||||
}
|
||||
}, []);
|
||||
@@ -228,10 +239,94 @@ const OnboardingPage: React.FC<OnboardingPageProps> = ({ user, onComplete }) =>
|
||||
}
|
||||
}, [jobUpdates, processWebSocketMessage]);
|
||||
|
||||
// Connect to WebSocket when training starts
|
||||
// Enhanced WebSocket connection management with polling fallback
|
||||
useEffect(() => {
|
||||
if (tenantId && trainingJobId && currentStep === 3) {
|
||||
console.log('Connecting to training WebSocket:', { tenantId, trainingJobId, wsUrl });
|
||||
connect();
|
||||
|
||||
// Simple polling fallback for training completion detection (now that we fixed the 404 issue)
|
||||
const pollingInterval = setInterval(async () => {
|
||||
if (trainingProgress.status === 'running' || trainingProgress.status === 'pending') {
|
||||
try {
|
||||
// Check training job status via REST API as fallback
|
||||
const response = await fetch(`http://localhost:8000/api/v1/tenants/${tenantId}/training/jobs/${trainingJobId}/status`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`,
|
||||
'X-Tenant-ID': tenantId
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const jobStatus = await response.json();
|
||||
|
||||
// If the job is completed but we haven't received WebSocket notification
|
||||
if (jobStatus.status === 'completed' && (trainingProgress.status === 'running' || trainingProgress.status === 'pending')) {
|
||||
console.log('Training completed detected via REST polling fallback');
|
||||
|
||||
setTrainingProgress(prev => ({
|
||||
...prev,
|
||||
progress: 100,
|
||||
status: 'completed',
|
||||
currentStep: 'Entrenamiento completado',
|
||||
estimatedTimeRemaining: 0
|
||||
}));
|
||||
|
||||
// Mark training step as completed in onboarding API
|
||||
completeStep('training_completed', {
|
||||
training_completed_at: new Date().toISOString(),
|
||||
user_id: user?.id,
|
||||
tenant_id: tenantId,
|
||||
completion_detected_via: 'rest_polling_fallback'
|
||||
}).catch(error => {
|
||||
console.warn('Failed to mark training as completed in API:', error);
|
||||
});
|
||||
|
||||
// Show celebration and auto-advance to final step after 3 seconds
|
||||
toast.success('🎉 Training completed! Your AI model is ready to use.', {
|
||||
duration: 5000,
|
||||
icon: '🤖'
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
manualNavigation.current = true;
|
||||
setCurrentStep(4);
|
||||
}, 3000);
|
||||
|
||||
// Clear the polling interval
|
||||
clearInterval(pollingInterval);
|
||||
}
|
||||
|
||||
// If job failed, update status
|
||||
if (jobStatus.status === 'failed' && (trainingProgress.status === 'running' || trainingProgress.status === 'pending')) {
|
||||
console.log('Training failure detected via REST polling fallback');
|
||||
|
||||
setTrainingProgress(prev => ({
|
||||
...prev,
|
||||
status: 'failed',
|
||||
error: jobStatus.error_message || 'Error en el entrenamiento',
|
||||
currentStep: 'Error en el entrenamiento'
|
||||
}));
|
||||
|
||||
clearInterval(pollingInterval);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore polling errors to avoid noise
|
||||
console.debug('REST polling error (expected if training not started):', error);
|
||||
}
|
||||
} else if (trainingProgress.status === 'completed' || trainingProgress.status === 'failed') {
|
||||
// Clear polling if training is finished
|
||||
clearInterval(pollingInterval);
|
||||
}
|
||||
}, 15000); // Poll every 15 seconds (less aggressive than before)
|
||||
|
||||
return () => {
|
||||
if (isConnected) {
|
||||
disconnect();
|
||||
}
|
||||
clearInterval(pollingInterval);
|
||||
};
|
||||
}
|
||||
|
||||
return () => {
|
||||
@@ -239,7 +334,35 @@ const OnboardingPage: React.FC<OnboardingPageProps> = ({ user, onComplete }) =>
|
||||
disconnect();
|
||||
}
|
||||
};
|
||||
}, [tenantId, trainingJobId, currentStep, connect, disconnect, isConnected]);
|
||||
}, [tenantId, trainingJobId, currentStep]); // Removed problematic dependencies that cause reconnection loops
|
||||
|
||||
// Handle connection errors with user feedback
|
||||
useEffect(() => {
|
||||
if (connectionError) {
|
||||
if (isAuthenticationError) {
|
||||
toast.error('Sesión expirada. Reintentando conexión...');
|
||||
// Auto-retry authentication errors after 3 seconds
|
||||
setTimeout(() => {
|
||||
retryWithAuth();
|
||||
}, 3000);
|
||||
} else {
|
||||
console.warn('WebSocket connection error:', connectionError);
|
||||
// Don't show error toast for non-auth errors as they auto-retry
|
||||
}
|
||||
}
|
||||
}, [connectionError, isAuthenticationError, retryWithAuth]);
|
||||
|
||||
// Enhanced WebSocket status logging
|
||||
useEffect(() => {
|
||||
console.log('WebSocket status changed:', {
|
||||
status,
|
||||
isConnected,
|
||||
jobId: trainingJobId,
|
||||
tenantId,
|
||||
connectionError,
|
||||
isAuthenticationError
|
||||
});
|
||||
}, [status, isConnected, trainingJobId, tenantId, connectionError, isAuthenticationError]);
|
||||
|
||||
|
||||
const storeTenantId = (tenantId: string) => {
|
||||
@@ -632,6 +755,10 @@ const OnboardingPage: React.FC<OnboardingPageProps> = ({ user, onComplete }) =>
|
||||
estimatedTimeRemaining: trainingProgress.estimatedTimeRemaining,
|
||||
error: trainingProgress.error
|
||||
}}
|
||||
websocketStatus={status}
|
||||
connectionError={connectionError}
|
||||
isConnected={isConnected}
|
||||
onRetryConnection={refreshConnection}
|
||||
onTimeout={() => {
|
||||
toast.success('El entrenamiento continuará en segundo plano. ¡Puedes empezar a explorar!');
|
||||
onComplete(); // Navigate to dashboard
|
||||
|
||||
Reference in New Issue
Block a user