Spaces:
Paused
Paused
| /** | |
| * Real Data Hook - Fetches live data from WidgetTDC Backend | |
| * Replaces mock/simulated data with real API data | |
| */ | |
| import { useState, useEffect, useCallback } from 'react'; | |
| import { API_URL } from '../config/api'; | |
| // Types for real data | |
| export interface LogEntry { | |
| id: string; | |
| timestamp: string; | |
| level: 'debug' | 'info' | 'warn' | 'error'; | |
| source: string; | |
| message: string; | |
| } | |
| export interface GraphStats { | |
| nodes: number; | |
| relationships: number; | |
| timestamp: string; | |
| } | |
| export interface SystemHealth { | |
| status: string; | |
| registeredTools: number; | |
| services: { | |
| neo4j: { healthy: boolean }; | |
| vectorStore: { healthy: boolean; backend: string }; | |
| }; | |
| } | |
| export interface HyperMetrics { | |
| totalThoughts: number; | |
| toolUsageRate: number; | |
| activeAgents: number; | |
| } | |
| export interface RealDataState { | |
| logs: LogEntry[]; | |
| graphStats: GraphStats | null; | |
| health: SystemHealth | null; | |
| hyperMetrics: HyperMetrics | null; | |
| isLoading: boolean; | |
| error: string | null; | |
| lastUpdated: number; | |
| } | |
| export const useRealData = (refreshInterval = 5000) => { | |
| const [state, setState] = useState<RealDataState>({ | |
| logs: [], | |
| graphStats: null, | |
| health: null, | |
| hyperMetrics: null, | |
| isLoading: true, | |
| error: null, | |
| lastUpdated: 0, | |
| }); | |
| const fetchData = useCallback(async () => { | |
| try { | |
| const [logsRes, graphRes, healthRes, hyperRes] = await Promise.all([ | |
| fetch(`${API_URL}/api/logs`).catch(() => null), | |
| fetch(`${API_URL}/api/evolution/graph/stats`).catch(() => null), | |
| fetch(`${API_URL}/health`).catch(() => null), | |
| fetch(`${API_URL}/api/hyper/status`).catch(() => null), | |
| ]); | |
| const logs = logsRes?.ok ? (await logsRes.json()).entries?.slice(0, 50) || [] : []; | |
| const graphStats = graphRes?.ok ? await graphRes.json() : null; | |
| const health = healthRes?.ok ? await healthRes.json() : null; | |
| const hyperData = hyperRes?.ok ? await hyperRes.json() : null; | |
| setState({ | |
| logs, | |
| graphStats: graphStats | |
| ? { | |
| nodes: graphStats.stats?.nodes || 0, | |
| relationships: graphStats.stats?.relationships || 0, | |
| timestamp: graphStats.timestamp, | |
| } | |
| : null, | |
| health: health | |
| ? { | |
| status: health.status, | |
| registeredTools: health.registeredTools || 0, | |
| services: health.services || {}, | |
| } | |
| : null, | |
| hyperMetrics: hyperData?.metrics || null, | |
| isLoading: false, | |
| error: null, | |
| lastUpdated: Date.now(), | |
| }); | |
| } catch (err) { | |
| setState(prev => ({ | |
| ...prev, | |
| isLoading: false, | |
| error: (err as Error).message, | |
| })); | |
| } | |
| }, []); | |
| useEffect(() => { | |
| fetchData(); | |
| const interval = setInterval(fetchData, refreshInterval); | |
| return () => clearInterval(interval); | |
| }, [fetchData, refreshInterval]); | |
| // Derived metrics from real data | |
| const metrics = { | |
| totalNodes: state.graphStats?.nodes || 0, | |
| totalRelationships: state.graphStats?.relationships || 0, | |
| totalTools: state.health?.registeredTools || 0, | |
| activeAgents: state.hyperMetrics?.activeAgents || 0, | |
| systemStatus: state.health?.status || 'unknown', | |
| neo4jHealthy: state.health?.services?.neo4j?.healthy || false, | |
| vectorStoreHealthy: state.health?.services?.vectorStore?.healthy || false, | |
| recentErrors: state.logs.filter(l => l.level === 'error').length, | |
| recentWarnings: state.logs.filter(l => l.level === 'warn').length, | |
| }; | |
| // Transform logs to events for widgets | |
| const events = state.logs.map(log => ({ | |
| id: log.id, | |
| time: new Date(log.timestamp).toLocaleTimeString('da-DK'), | |
| message: log.message, | |
| level: log.level, | |
| source: log.source, | |
| })); | |
| return { | |
| ...state, | |
| metrics, | |
| events, | |
| refresh: fetchData, | |
| }; | |
| }; | |
| // Hook for real-time log streaming | |
| export const useLogStream = (maxLogs = 20) => { | |
| const [logs, setLogs] = useState<LogEntry[]>([]); | |
| useEffect(() => { | |
| const fetchLogs = async () => { | |
| try { | |
| const res = await fetch(`${API_URL}/api/logs`); | |
| if (res.ok) { | |
| const data = await res.json(); | |
| setLogs(data.entries?.slice(0, maxLogs) || []); | |
| } | |
| } catch { | |
| // Silent fail | |
| } | |
| }; | |
| fetchLogs(); | |
| const interval = setInterval(fetchLogs, 3000); | |
| return () => clearInterval(interval); | |
| }, [maxLogs]); | |
| return logs; | |
| }; | |
| export default useRealData; | |