import { useState, useEffect, useCallback } from 'react'; import { localModelHealthMonitor, type ModelHealthStatus } from '~/lib/services/localModelHealthMonitor'; export interface UseLocalModelHealthOptions { autoStart?: boolean; checkInterval?: number; } export interface UseLocalModelHealthReturn { healthStatuses: ModelHealthStatus[]; getHealthStatus: (provider: 'Ollama' | 'LMStudio' | 'OpenAILike', baseUrl: string) => ModelHealthStatus | undefined; startMonitoring: (provider: 'Ollama' | 'LMStudio' | 'OpenAILike', baseUrl: string, checkInterval?: number) => void; stopMonitoring: (provider: 'Ollama' | 'LMStudio' | 'OpenAILike', baseUrl: string) => void; performHealthCheck: (provider: 'Ollama' | 'LMStudio' | 'OpenAILike', baseUrl: string) => Promise; isHealthy: (provider: 'Ollama' | 'LMStudio' | 'OpenAILike', baseUrl: string) => boolean; getOverallHealth: () => { healthy: number; unhealthy: number; checking: number; unknown: number }; } /** * React hook for monitoring local model health */ export function useLocalModelHealth(options: UseLocalModelHealthOptions = {}): UseLocalModelHealthReturn { const { checkInterval } = options; const [healthStatuses, setHealthStatuses] = useState([]); // Update health statuses when they change useEffect(() => { const handleStatusChanged = (status: ModelHealthStatus) => { setHealthStatuses((current) => { const index = current.findIndex((s) => s.provider === status.provider && s.baseUrl === status.baseUrl); if (index >= 0) { const updated = [...current]; updated[index] = status; return updated; } else { return [...current, status]; } }); }; localModelHealthMonitor.on('statusChanged', handleStatusChanged); // Initialize with current statuses setHealthStatuses(localModelHealthMonitor.getAllHealthStatuses()); return () => { localModelHealthMonitor.off('statusChanged', handleStatusChanged); }; }, []); // Get health status for a specific provider const getHealthStatus = useCallback((provider: 'Ollama' | 'LMStudio' | 'OpenAILike', baseUrl: string) => { return localModelHealthMonitor.getHealthStatus(provider, baseUrl); }, []); // Start monitoring a provider const startMonitoring = useCallback( (provider: 'Ollama' | 'LMStudio' | 'OpenAILike', baseUrl: string, interval?: number) => { console.log(`[Health Monitor] Starting monitoring for ${provider} at ${baseUrl}`); localModelHealthMonitor.startMonitoring(provider, baseUrl, interval || checkInterval); }, [checkInterval], ); // Stop monitoring a provider const stopMonitoring = useCallback((provider: 'Ollama' | 'LMStudio' | 'OpenAILike', baseUrl: string) => { console.log(`[Health Monitor] Stopping monitoring for ${provider} at ${baseUrl}`); localModelHealthMonitor.stopMonitoring(provider, baseUrl); // Remove from local state setHealthStatuses((current) => current.filter((s) => !(s.provider === provider && s.baseUrl === baseUrl))); }, []); // Perform manual health check const performHealthCheck = useCallback(async (provider: 'Ollama' | 'LMStudio' | 'OpenAILike', baseUrl: string) => { await localModelHealthMonitor.performHealthCheck(provider, baseUrl); }, []); // Check if a provider is healthy const isHealthy = useCallback( (provider: 'Ollama' | 'LMStudio' | 'OpenAILike', baseUrl: string) => { const status = getHealthStatus(provider, baseUrl); return status?.status === 'healthy'; }, [getHealthStatus], ); // Get overall health statistics const getOverallHealth = useCallback(() => { const stats = { healthy: 0, unhealthy: 0, checking: 0, unknown: 0 }; healthStatuses.forEach((status) => { stats[status.status]++; }); return stats; }, [healthStatuses]); return { healthStatuses, getHealthStatus, startMonitoring, stopMonitoring, performHealthCheck, isHealthy, getOverallHealth, }; } /** * Hook for monitoring a specific provider */ export function useProviderHealth( provider: 'Ollama' | 'LMStudio' | 'OpenAILike', baseUrl: string, options: UseLocalModelHealthOptions = {}, ) { const { autoStart = true, checkInterval } = options; const { getHealthStatus, startMonitoring, stopMonitoring, performHealthCheck, isHealthy } = useLocalModelHealth(); const [status, setStatus] = useState(); // Update status when it changes useEffect(() => { const updateStatus = () => { setStatus(getHealthStatus(provider, baseUrl)); }; const handleStatusChanged = (changedStatus: ModelHealthStatus) => { if (changedStatus.provider === provider && changedStatus.baseUrl === baseUrl) { setStatus(changedStatus); } }; localModelHealthMonitor.on('statusChanged', handleStatusChanged); updateStatus(); return () => { localModelHealthMonitor.off('statusChanged', handleStatusChanged); }; }, [provider, baseUrl, getHealthStatus]); // Auto-start monitoring if enabled useEffect(() => { if (autoStart && baseUrl) { startMonitoring(provider, baseUrl, checkInterval); return () => { stopMonitoring(provider, baseUrl); }; } return undefined; }, [autoStart, provider, baseUrl, checkInterval, startMonitoring, stopMonitoring]); return { status, isHealthy: isHealthy(provider, baseUrl), performHealthCheck: () => performHealthCheck(provider, baseUrl), startMonitoring: (interval?: number) => startMonitoring(provider, baseUrl, interval), stopMonitoring: () => stopMonitoring(provider, baseUrl), }; }