// frontend/src/api/hooks/useTraining.ts /** * Training Operations Hooks */ import { useState, useCallback, useEffect } from 'react'; import { trainingService } from '../services'; import type { TrainingJobRequest, TrainingJobResponse, ModelInfo, ModelTrainingStats, SingleProductTrainingRequest, } from '../types'; interface UseTrainingOptions { disablePolling?: boolean; // New option to disable HTTP status polling } export const useTraining = (options: UseTrainingOptions = {}) => { const { disablePolling = false } = options; const [jobs, setJobs] = useState([]); const [currentJob, setCurrentJob] = useState(null); const [models, setModels] = useState([]); const [stats, setStats] = useState(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const startTrainingJob = useCallback(async ( tenantId: string, request: TrainingJobRequest ): Promise => { try { setIsLoading(true); setError(null); const job = await trainingService.startTrainingJob(tenantId, request); setCurrentJob(job); setJobs(prev => [job, ...prev]); return job; } catch (error) { const message = error instanceof Error ? error.message : 'Failed to start training job'; setError(message); throw error; } finally { setIsLoading(false); } }, []); const startSingleProductTraining = useCallback(async ( tenantId: string, request: SingleProductTrainingRequest ): Promise => { try { setIsLoading(true); setError(null); const job = await trainingService.startSingleProductTraining(tenantId, request); setCurrentJob(job); setJobs(prev => [job, ...prev]); return job; } catch (error) { const message = error instanceof Error ? error.message : 'Failed to start product training'; setError(message); throw error; } finally { setIsLoading(false); } }, []); const getTrainingJobStatus = useCallback(async ( tenantId: string, jobId: string ): Promise => { try { const job = await trainingService.getTrainingJobStatus(tenantId, jobId); // Update job in state setJobs(prev => prev.map(j => j.job_id === jobId ? job : j)); if (currentJob?.job_id === jobId) { setCurrentJob(job); } return job; } catch (error) { const message = error instanceof Error ? error.message : 'Failed to get job status'; setError(message); throw error; } }, [currentJob]); const cancelTrainingJob = useCallback(async ( tenantId: string, jobId: string ): Promise => { try { setIsLoading(true); setError(null); await trainingService.cancelTrainingJob(tenantId, jobId); // Update job status in state setJobs(prev => prev.map(j => j.job_id === jobId ? { ...j, status: 'cancelled' } : j )); if (currentJob?.job_id === jobId) { setCurrentJob({ ...currentJob, status: 'cancelled' }); } } catch (error) { const message = error instanceof Error ? error.message : 'Failed to cancel job'; setError(message); throw error; } finally { setIsLoading(false); } }, [currentJob]); const getTrainingJobs = useCallback(async (tenantId: string): Promise => { try { setIsLoading(true); setError(null); const response = await trainingService.getTrainingJobs(tenantId); setJobs(response.data); return response.data; } catch (error) { const message = error instanceof Error ? error.message : 'Failed to get training jobs'; setError(message); throw error; } finally { setIsLoading(false); } }, []); const getModels = useCallback(async (tenantId: string): Promise => { try { setIsLoading(true); setError(null); const response = await trainingService.getModels(tenantId); setModels(response.data); return response.data; } catch (error) { const message = error instanceof Error ? error.message : 'Failed to get models'; setError(message); throw error; } finally { setIsLoading(false); } }, []); const validateTrainingData = useCallback(async (tenantId: string): Promise<{ is_valid: boolean; message: string; details?: any; }> => { try { setIsLoading(true); setError(null); const result = await trainingService.validateTrainingData(tenantId); return result; } catch (error) { const message = error instanceof Error ? error.message : 'Data validation failed'; setError(message); throw error; } finally { setIsLoading(false); } }, []); const getTrainingStats = useCallback(async (tenantId: string): Promise => { try { setIsLoading(true); setError(null); const trainingStats = await trainingService.getTrainingStats(tenantId); setStats(trainingStats); return trainingStats; } catch (error) { const message = error instanceof Error ? error.message : 'Failed to get training stats'; setError(message); throw error; } finally { setIsLoading(false); } }, []); useEffect(() => { // Skip polling if disabled or no running jobs if (disablePolling) { console.log('🚫 HTTP status polling disabled - using WebSocket instead'); return; } const runningJobs = jobs.filter(job => job.status === 'running' || job.status === 'pending'); if (runningJobs.length === 0) return; console.log('🔄 Starting HTTP status polling for', runningJobs.length, 'jobs'); const interval = setInterval(async () => { for (const job of runningJobs) { try { const tenantId = job.tenant_id; await getTrainingJobStatus(tenantId, job.job_id); } catch (error) { console.error('Failed to refresh job status:', error); } } }, 5000); // Refresh every 5 seconds return () => { console.log('🛑 Stopping HTTP status polling'); clearInterval(interval); }; }, [jobs, getTrainingJobStatus, disablePolling]); return { jobs, currentJob, models, stats, isLoading, error, startTrainingJob, startSingleProductTraining, getTrainingJobStatus, cancelTrainingJob, getTrainingJobs, getModels, validateTrainingData, getTrainingStats, clearError: () => setError(null), }; };