File size: 5,742 Bytes
55d48a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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<void>;
  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<ModelHealthStatus[]>([]);

  // 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<ModelHealthStatus | undefined>();

  // 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),
  };
}