File size: 2,436 Bytes
96bba34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
const BASE = "/api";

export interface FlightSummary {
  id: number;
  score: number;
  anomalous: boolean;
}

export interface PathPoint {
  lat: number;
  lon: number;
  alt: number;
  t: number;
}

export interface FlightDetail {
  id: number;
  path: PathPoint[];
  reconstructed: PathPoint[];
  scores: number[];
  window_score: number;
  threshold: number;
  step_threshold: number;
}

export interface SimulationRequest {
  id: number;
  kind: string;
  magnitude: number;
  onset: number;
}

export interface SimulationResult {
  id: number;
  kind: string;
  path: PathPoint[];
  scores: number[];
  window_score: number;
  threshold: number;
  step_threshold: number;
  onset_index: number;
  latency_seconds: number | null;
}

async function getJson<T>(path: string): Promise<T> {
  const response = await fetch(`${BASE}${path}`);
  if (!response.ok) throw new Error(`request failed: ${response.status}`);
  return response.json();
}

export interface SceneFlight {
  id: number;
  callsign: string;
  path: PathPoint[];
  scores: number[];
  anomalous: boolean;
  start_offset: number;
}

export interface InjectedFlight extends SceneFlight {
  injected: true;
  kind: string;
}

export interface Scene {
  flights: SceneFlight[];
  step_threshold: number;
  step_seconds: number;
  center: { lat: number; lon: number };
}

export function getScene(count = 12): Promise<Scene> {
  return getJson(`/scene?count=${count}`);
}

export interface MetricRow {
  model: string;
  real_roc_auc: number;
  real_pr_auc: number;
  synthetic_mean_roc_auc: number;
  synthetic_per_type: Record<string, number>;
}

export interface Metrics {
  selected_model: string | null;
  results: MetricRow[];
}

export function getFlights(
  limit = 30,
  order: "anomalous" | "normal" | "typical" = "anomalous",
): Promise<FlightSummary[]> {
  return getJson(`/flights?limit=${limit}&order=${order}`);
}

export function getMetrics(): Promise<Metrics> {
  return getJson("/metrics");
}

export function getFlight(id: number): Promise<FlightDetail> {
  return getJson(`/flights/${id}`);
}

export async function simulate(request: SimulationRequest): Promise<SimulationResult> {
  const response = await fetch(`${BASE}/simulate`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(request),
  });
  if (!response.ok) throw new Error(`request failed: ${response.status}`);
  return response.json();
}