mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 18:11:12 -05:00
Implement ML Anomaly Detection
Introduce statistical anomaly detection for metrics via edge function, hooks, and UI components. Adds detection algorithms (z-score, moving average, rate of change), anomaly storage, auto-alerts, and dashboard rendering of detected anomalies with run-once trigger and scheduling guidance.
This commit is contained in:
101
src/hooks/admin/useAnomalyDetection.ts
Normal file
101
src/hooks/admin/useAnomalyDetection.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { queryKeys } from '@/lib/queryKeys';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
export interface AnomalyDetection {
|
||||
id: string;
|
||||
metric_name: string;
|
||||
metric_category: string;
|
||||
anomaly_type: 'spike' | 'drop' | 'trend_change' | 'outlier' | 'pattern_break';
|
||||
severity: 'critical' | 'high' | 'medium' | 'low';
|
||||
baseline_value: number;
|
||||
anomaly_value: number;
|
||||
deviation_score: number;
|
||||
confidence_score: number;
|
||||
detection_algorithm: string;
|
||||
time_window_start: string;
|
||||
time_window_end: string;
|
||||
detected_at: string;
|
||||
alert_created: boolean;
|
||||
alert_id?: string;
|
||||
alert_message?: string;
|
||||
alert_resolved_at?: string;
|
||||
}
|
||||
|
||||
export function useAnomalyDetections() {
|
||||
return useQuery({
|
||||
queryKey: queryKeys.monitoring.anomalyDetections(),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await supabase
|
||||
.from('recent_anomalies_view')
|
||||
.select('*')
|
||||
.order('detected_at', { ascending: false })
|
||||
.limit(50);
|
||||
|
||||
if (error) throw error;
|
||||
return (data || []) as AnomalyDetection[];
|
||||
},
|
||||
staleTime: 30000,
|
||||
refetchInterval: 60000,
|
||||
});
|
||||
}
|
||||
|
||||
export function useRunAnomalyDetection() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
const { data, error } = await supabase.functions.invoke('detect-anomalies', {
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
return data;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.monitoring.anomalyDetections() });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.monitoring.groupedAlerts() });
|
||||
|
||||
if (data.anomalies_detected > 0) {
|
||||
toast.success(`Detected ${data.anomalies_detected} anomalies`);
|
||||
} else {
|
||||
toast.info('No anomalies detected');
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('Failed to run anomaly detection:', error);
|
||||
toast.error('Failed to run anomaly detection');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useRecordMetric() {
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
metricName,
|
||||
metricCategory,
|
||||
metricValue,
|
||||
metadata,
|
||||
}: {
|
||||
metricName: string;
|
||||
metricCategory: string;
|
||||
metricValue: number;
|
||||
metadata?: any;
|
||||
}) => {
|
||||
const { error } = await supabase
|
||||
.from('metric_time_series')
|
||||
.insert({
|
||||
metric_name: metricName,
|
||||
metric_category: metricCategory,
|
||||
metric_value: metricValue,
|
||||
metadata,
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('Failed to record metric:', error);
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user