Untitled
unknown
plain_text
9 months ago
5.2 kB
6
Indexable
// /hooks/useMetrics.ts
'use client';
import { useState, useEffect, useMemo } from 'react';
import type { MetricsData } from '@/app/api/metrics/route';
interface ProcessedFillLevelData {
timestamp: string;
fill_level: number;
bin_id: string;
}
export function useMetrics() {
const [metrics, setMetrics] = useState<MetricsData | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
async function fetchMetrics() {
try {
const response = await fetch('/api/metrics');
if (!response.ok) throw new Error('Failed to fetch metrics');
const data = await response.json();
setMetrics(data);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load metrics');
} finally {
setLoading(false);
}
}
fetchMetrics();
const intervalId = setInterval(fetchMetrics, 5000);
return () => clearInterval(intervalId);
}, []);
// Memoized helper functions for accessing fill level data
const helpers = useMemo(() => {
if (!metrics) return null;
return {
// Get all unique bin IDs that have any kind of data
getActiveBinIds: () => {
const binIds = new Set<string>();
// Check fill predictions
Object.keys(metrics.fill_predictions || {}).forEach(id => binIds.add(id));
// Check fill level history
Object.keys(metrics.fill_level_history || {}).forEach(id => binIds.add(id));
// Check classification results
metrics.basic_metrics.classification_results.forEach(result => binIds.add(result.bin_id));
return Array.from(binIds);
},
// Get processed fill level history for a specific bin or all bins
getFillLevelHistory: (binId?: string, timeRange?: {start: Date, end: Date}) => {
const results = metrics.basic_metrics.classification_results
.map(result => ({
timestamp: result.timestamp,
fill_level: result.fill_level,
bin_id: result.bin_id
}));
let filtered = results;
// Filter by bin if specified
if (binId) {
filtered = filtered.filter(result => result.bin_id === binId);
}
// Filter by time range if specified
if (timeRange) {
filtered = filtered.filter(result => {
const timestamp = new Date(result.timestamp);
return timestamp >= timeRange.start && timestamp <= timeRange.end;
});
}
return filtered.sort((a, b) =>
new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
);
},
// Get emptying events for a specific bin or all bins
getEmptyingEvents: (binId?: string, timeRange?: {start: Date, end: Date}) => {
const history = metrics.fill_level_history;
const events: Array<{
timestamp: string;
fill_level: number;
bin_id: string;
}> = [];
Object.entries(history).forEach(([id, data]) => {
if (!binId || id === binId) {
data.emptying_timestamps.forEach((timestamp, index) => {
events.push({
timestamp,
fill_level: data.fill_levels_at_empty[index],
bin_id: id
});
});
}
});
let filtered = events;
// Filter by time range if specified
if (timeRange) {
filtered = filtered.filter(event => {
const timestamp = new Date(event.timestamp);
return timestamp >= timeRange.start && timestamp <= timeRange.end;
});
}
return filtered.sort((a, b) =>
new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
);
},
// Get the latest fill level prediction for a specific bin or all bins
getLatestPredictions: (binId?: string) => {
const predictions = metrics.fill_predictions;
if (binId) {
return predictions[binId] ? { [binId]: predictions[binId] } : {};
}
return predictions;
},
// Get proactive emptying statistics
getProactiveEmptyingStats: () => {
const emptyingEvents = Object.values(metrics.fill_level_history).flatMap(
history => history.fill_levels_at_empty
);
// Group emptying events by fill level ranges (0-20%, 21-40%, etc.)
const ranges = Array.from({ length: 5 }, (_, i) => ({
range: `${i * 20 + 1}-${(i + 1) * 20}%`,
count: emptyingEvents.filter(
level => level > i * 20 && level <= (i + 1) * 20
).length
}));
ranges.push({
range: '81-100%',
count: emptyingEvents.filter(level => level > 80).length
});
return ranges;
}
};
}, [metrics]);
return {
metrics,
loading,
error,
helpers
};
}Editor is loading...
Leave a Comment