| |
| const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || ''; |
| const API_KEY = process.env.NEXT_PUBLIC_DASHBOARD_API_KEY || ''; |
|
|
| async function fetchAPI<T>(endpoint: string, options: RequestInit = {}): Promise<T> { |
| const url = `${API_BASE_URL}${endpoint}`; |
| |
| const headers: HeadersInit = { |
| 'Content-Type': 'application/json', |
| ...(API_KEY ? { 'X-Dashboard-Key': API_KEY } : {}), |
| ...options.headers, |
| }; |
|
|
| try { |
| const response = await fetch(url, { |
| ...options, |
| headers, |
| }); |
|
|
| if (!response.ok) { |
| console.error(`API error: ${response.status} ${response.statusText} for ${endpoint}`); |
| throw new Error(`API error: ${response.status} ${response.statusText}`); |
| } |
|
|
| return response.json(); |
| } catch (error) { |
| console.error(`Failed to fetch ${endpoint}:`, error); |
| throw error; |
| } |
| } |
|
|
| |
| const defaultStats = { |
| uptime_seconds: 0, |
| total_requests: 0, |
| total_errors: 0, |
| error_rate: 0, |
| active_requests: 0, |
| total_input_tokens: 0, |
| total_output_tokens: 0, |
| requests_by_model: {}, |
| tokens_by_model: {}, |
| avg_latency_ms: 0, |
| p50_latency_ms: 0, |
| p95_latency_ms: 0, |
| p99_latency_ms: 0, |
| accounts_total: 0, |
| accounts_healthy: 0, |
| accounts_unhealthy: 0, |
| }; |
|
|
| export const api = { |
| getStats: async () => { |
| try { |
| return await fetchAPI<import('@/types/metrics').DashboardStats>('/api/dashboard/stats'); |
| } catch { |
| return defaultStats as import('@/types/metrics').DashboardStats; |
| } |
| }, |
| |
| getMetrics: async (params?: { start_time?: string; end_time?: string; model?: string; granularity?: string; limit?: number }) => { |
| try { |
| const searchParams = new URLSearchParams(); |
| if (params?.start_time) searchParams.set('start_time', params.start_time); |
| if (params?.end_time) searchParams.set('end_time', params.end_time); |
| if (params?.model) searchParams.set('model', params.model); |
| if (params?.granularity) searchParams.set('granularity', params.granularity); |
| if (params?.limit) searchParams.set('limit', params.limit.toString()); |
| const queryString = searchParams.toString(); |
| return await fetchAPI<import('@/types/metrics').MetricsResponse>( |
| `/api/dashboard/metrics${queryString ? `?${queryString}` : ''}` |
| ); |
| } catch { |
| return { query: { granularity: '1m', limit: 100 }, data: [], total_requests: 0, total_errors: 0, total_input_tokens: 0, total_output_tokens: 0 } as import('@/types/metrics').MetricsResponse; |
| } |
| }, |
| |
| getAccounts: async () => { |
| try { |
| return await fetchAPI<import('@/types/metrics').Account[]>('/api/dashboard/accounts'); |
| } catch { |
| return [] as import('@/types/metrics').Account[]; |
| } |
| }, |
| |
| getConfig: async () => { |
| try { |
| return await fetchAPI<import('@/types/metrics').GatewayConfig>('/api/dashboard/config'); |
| } catch { |
| return null; |
| } |
| }, |
| |
| getHealth: async () => { |
| try { |
| return await fetchAPI<import('@/types/metrics').HealthResponse>('/api/dashboard/health'); |
| } catch { |
| return { status: 'unhealthy', version: 'unknown', uptime_seconds: 0, auth_healthy: false, api_reachable: false, accounts_status: null, metrics_enabled: false, prometheus_ready: false } as import('@/types/metrics').HealthResponse; |
| } |
| }, |
| }; |
|
|
| export default api; |
|
|