Kraft102's picture
fix: sql.js Docker/Alpine compatibility layer for PatternMemory and FailureMemory
5a81b95
/**
* 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;