2026-10-01 11:48:17 +08:00
|
|
|
import apiClient from './client'
|
|
|
|
|
import type { GatewayMetricsSummary, AdminMonitoringResilienceStatus } from './monitoring'
|
|
|
|
|
import type { ProviderPerformanceResponse } from './admin'
|
|
|
|
|
|
|
|
|
|
export interface OverviewRange {
|
|
|
|
|
from: string
|
|
|
|
|
to: string
|
|
|
|
|
timezone: string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface OverviewQuery extends OverviewRange {
|
|
|
|
|
user_id?: string
|
|
|
|
|
api_key_id?: string
|
|
|
|
|
request_type?: string
|
|
|
|
|
credential_owner_id?: string
|
|
|
|
|
attribution_kind?: string
|
|
|
|
|
model?: string
|
|
|
|
|
provider_id?: string
|
|
|
|
|
api_format?: string
|
|
|
|
|
endpoint_kind?: string
|
|
|
|
|
is_stream?: boolean
|
|
|
|
|
has_format_conversion?: boolean
|
|
|
|
|
slow_threshold_ms?: number
|
|
|
|
|
status?: string
|
|
|
|
|
search?: string
|
|
|
|
|
account_status?: string
|
|
|
|
|
usage_status?: string
|
|
|
|
|
sort?: string
|
|
|
|
|
order?: 'asc' | 'desc'
|
|
|
|
|
group_by?: string
|
|
|
|
|
amount_basis?: string
|
|
|
|
|
granularity?: 'hour' | 'day'
|
|
|
|
|
limit?: number
|
|
|
|
|
offset?: number
|
|
|
|
|
payment_limit?: number
|
|
|
|
|
payment_offset?: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface OverviewAmount {
|
|
|
|
|
value: string | null
|
|
|
|
|
currency: string
|
|
|
|
|
basis: string
|
|
|
|
|
status: 'known' | 'known_subtotal' | 'unknown' | 'estimated' | string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface OverviewMetrics {
|
|
|
|
|
request_count: number
|
|
|
|
|
successful_request_count: number
|
|
|
|
|
failed_request_count: number
|
|
|
|
|
cancelled_request_count: number
|
|
|
|
|
in_flight_request_count: number
|
|
|
|
|
unclassified_failure_count: number
|
|
|
|
|
input_tokens: number | null
|
|
|
|
|
output_tokens: number | null
|
|
|
|
|
total_tokens: number | null
|
|
|
|
|
usage_source?: 'reported' | 'estimated' | 'mixed' | 'unknown'
|
|
|
|
|
usage_source_counts?: { reported: number; estimated: number; mixed: number; unknown: number }
|
|
|
|
|
requests_per_second?: number
|
|
|
|
|
requests_per_minute?: number
|
|
|
|
|
tokens_per_minute?: number | null
|
|
|
|
|
window_seconds?: number
|
|
|
|
|
usage_active_users?: number
|
|
|
|
|
enabled_users?: number
|
|
|
|
|
success_rate: { value: number | null; numerator: number; denominator: number }
|
|
|
|
|
latency_ms: { avg: number | null; p50: number | null; p95: number | null; p99: number | null; sample_count: number }
|
|
|
|
|
rated_amount: OverviewAmount
|
|
|
|
|
billable_amount: OverviewAmount
|
|
|
|
|
quota_covered_amount: OverviewAmount
|
|
|
|
|
wallet_consumed_amount: OverviewAmount
|
|
|
|
|
wallet_debit_amount: OverviewAmount
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface OverviewMeta {
|
|
|
|
|
schema_version: number
|
|
|
|
|
metric_version: string
|
|
|
|
|
scope: { kind: string; user_id?: string }
|
|
|
|
|
range: OverviewRange & { time_basis: string }
|
|
|
|
|
generated_at: string
|
|
|
|
|
data_through: string | null
|
|
|
|
|
read_revision: string
|
|
|
|
|
available_metrics?: string[]
|
|
|
|
|
projection?: {
|
|
|
|
|
projection_from: string | null
|
|
|
|
|
projection_through: string | null
|
|
|
|
|
dirty_bucket_count: number
|
|
|
|
|
missing_bucket_count: number
|
|
|
|
|
read_enabled: boolean
|
|
|
|
|
}
|
|
|
|
|
coverage: {
|
|
|
|
|
status: string
|
|
|
|
|
request_count: number
|
|
|
|
|
usage_available_count: number
|
|
|
|
|
pricing_available_count: number
|
|
|
|
|
settled_count: number
|
|
|
|
|
attribution_available_count?: number
|
|
|
|
|
unrecoverable_bucket_count?: number
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface OverviewResponse<T> { meta: OverviewMeta; data: T }
|
|
|
|
|
export type OverviewDashboardTotals = Pick<OverviewMetrics, 'request_count' | 'total_tokens' | 'billable_amount' | 'enabled_users'>
|
|
|
|
|
export interface OverviewDashboard {
|
|
|
|
|
today: OverviewResponse<OverviewMetrics>
|
|
|
|
|
total: OverviewResponse<OverviewDashboardTotals>
|
|
|
|
|
history_complete: boolean | null
|
|
|
|
|
}
|
|
|
|
|
export type OverviewDashboardTotal = { status: 'pending' } | {
|
|
|
|
|
status: 'ready'
|
|
|
|
|
total: OverviewResponse<OverviewDashboardTotals>
|
|
|
|
|
history_complete: boolean | null
|
|
|
|
|
stale: boolean
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewDashboardSummary {
|
|
|
|
|
stats_since: string
|
|
|
|
|
generated_at: string
|
|
|
|
|
timezone: string
|
2026-10-05 19:03:33 +08:00
|
|
|
activity_timezone?: string
|
2026-10-01 11:48:17 +08:00
|
|
|
today_from: string
|
|
|
|
|
window_seconds: number
|
|
|
|
|
today: {
|
|
|
|
|
request_count: number
|
|
|
|
|
input_tokens: number | null
|
|
|
|
|
output_tokens: number | null
|
|
|
|
|
total_tokens: number | null
|
|
|
|
|
billable_amount: OverviewAmount
|
|
|
|
|
active_users: number
|
|
|
|
|
cache_read_tokens: number | null
|
|
|
|
|
cache_creation_tokens: number | null
|
|
|
|
|
cache_input_tokens: number | null
|
|
|
|
|
avg_first_byte_ms: number | null
|
|
|
|
|
avg_response_ms: number | null
|
|
|
|
|
stream_requests: number
|
|
|
|
|
standard_requests: number
|
|
|
|
|
}
|
|
|
|
|
total: {
|
|
|
|
|
request_count: number
|
|
|
|
|
total_tokens: number | null
|
|
|
|
|
billable_amount: OverviewAmount
|
|
|
|
|
cache_read_tokens: number | null
|
|
|
|
|
cache_input_tokens: number | null
|
|
|
|
|
}
|
|
|
|
|
users: { total: number; created_today: number; deleted_today: number }
|
|
|
|
|
consecutive_active_days: number
|
|
|
|
|
active_days: number
|
|
|
|
|
activity_days: { date: string; requests: number }[]
|
|
|
|
|
concurrency: {
|
|
|
|
|
avg: number | null
|
|
|
|
|
peak: number | null
|
|
|
|
|
observed_from: string | null
|
|
|
|
|
observed_through: string | null
|
|
|
|
|
scope: 'node'
|
|
|
|
|
coverage: 'partial' | 'complete' | 'unavailable'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewPage<T> { items: T[]; total: number; limit: number; offset: number }
|
|
|
|
|
export interface OverviewSeriesPoint extends OverviewMetrics { bucket_start: string }
|
|
|
|
|
export interface OverviewBreakdown extends OverviewMetrics { id: string | null; label: string | null }
|
|
|
|
|
export interface OverviewDashboardCharts {
|
|
|
|
|
summary: OverviewMetrics
|
|
|
|
|
series: OverviewSeriesPoint[]
|
|
|
|
|
models: (OverviewBreakdown & { bucket_start: string })[]
|
|
|
|
|
providers: OverviewBreakdown[]
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewEmployee extends OverviewMetrics {
|
|
|
|
|
user_id: string
|
|
|
|
|
username: string
|
|
|
|
|
email: string | null
|
|
|
|
|
is_active: boolean
|
|
|
|
|
last_used_at: string | null
|
|
|
|
|
active_days: number
|
|
|
|
|
finance?: OverviewUserFinance | null
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewUserFinance {
|
|
|
|
|
wallet_balance: OverviewAmount
|
|
|
|
|
recharge_balance: OverviewAmount
|
|
|
|
|
gift_balance: OverviewAmount
|
|
|
|
|
recharge_amount: OverviewAmount
|
|
|
|
|
recharge_count: number
|
|
|
|
|
plan_purchase_amount: OverviewAmount
|
|
|
|
|
plan_purchase_count: number
|
|
|
|
|
gift_credit_amount: OverviewAmount
|
|
|
|
|
gift_credit_count: number
|
|
|
|
|
balance_time_basis: 'current'
|
|
|
|
|
payment_time_basis: 'credited_at'
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewUserPayment {
|
|
|
|
|
id: string
|
|
|
|
|
order_no: string
|
|
|
|
|
kind: 'wallet_recharge' | 'plan_purchase' | 'gift_credit'
|
|
|
|
|
amount: OverviewAmount
|
|
|
|
|
payment_method: string
|
|
|
|
|
credited_at: string
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewUsers extends OverviewPage<OverviewEmployee> {
|
|
|
|
|
summary?: OverviewMetrics & { user_count: number; active_user_count: number }
|
|
|
|
|
finance_summary?: OverviewUserFinance | null
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewEmployeeDetail {
|
|
|
|
|
user: { id: string; username: string; email: string | null; is_active: boolean }
|
|
|
|
|
summary: OverviewMetrics
|
|
|
|
|
finance?: OverviewUserFinance | null
|
|
|
|
|
payments?: OverviewPage<OverviewUserPayment> | null
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewConsumption {
|
|
|
|
|
id: string
|
|
|
|
|
request_id: string
|
|
|
|
|
started_at: string
|
|
|
|
|
user_id: string | null
|
|
|
|
|
model: string | null
|
|
|
|
|
provider: string | null
|
|
|
|
|
status: string
|
|
|
|
|
settlement_status: string
|
|
|
|
|
attribution_kind: string
|
|
|
|
|
rated_amount: OverviewAmount
|
|
|
|
|
billable_amount: OverviewAmount
|
|
|
|
|
quota_covered_amount: OverviewAmount
|
|
|
|
|
wallet_consumed_amount: OverviewAmount
|
|
|
|
|
wallet_debit_amount: OverviewAmount
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewCosts {
|
|
|
|
|
summary: OverviewMetrics
|
|
|
|
|
timeseries?: OverviewSeriesPoint[]
|
|
|
|
|
supplier_estimated_cost: OverviewAmount
|
|
|
|
|
supplier_verified_cost: OverviewAmount
|
|
|
|
|
cache: { read_tokens: number | null; creation_tokens: number | null; read_cost: OverviewAmount; creation_cost: OverviewAmount; estimated_full_cost: OverviewAmount; estimated_savings: OverviewAmount; pricing_available_count?: number; request_count?: number }
|
|
|
|
|
forecast: { amount: OverviewAmount; method: string; status: string; sample_days: number; period_end: string | null }
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewExecutionActivity {
|
|
|
|
|
observed_at: string
|
|
|
|
|
observed_from: string
|
|
|
|
|
window_seconds: number
|
|
|
|
|
observed_window_seconds: number
|
|
|
|
|
scope: { kind: 'node' }
|
|
|
|
|
coverage: 'complete' | 'partial'
|
|
|
|
|
providers: { provider_id: string; provider: string | null; requests_per_minute: number; current_concurrency: number }[]
|
|
|
|
|
models: { model: string | null; requests_per_minute: number; current_concurrency: number }[]
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewLive {
|
|
|
|
|
observed_at: string | null
|
|
|
|
|
window_seconds: number | null
|
|
|
|
|
node_id: string | null
|
|
|
|
|
scope: { kind: string; node_ids?: string[] }
|
|
|
|
|
metrics?: GatewayMetricsSummary | null
|
|
|
|
|
metrics_text?: string | null
|
|
|
|
|
resilience: AdminMonitoringResilienceStatus | null
|
|
|
|
|
unavailable_sections: string[]
|
|
|
|
|
recent_activity?: OverviewResponse<OverviewMetrics>
|
|
|
|
|
execution_activity?: OverviewExecutionActivity | null
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewModelPerformance {
|
|
|
|
|
model: string | null
|
|
|
|
|
request_count: number
|
|
|
|
|
success_count: number
|
|
|
|
|
error_count: number
|
|
|
|
|
success_rate: number | null
|
|
|
|
|
avg_first_byte_time_ms: number | null
|
|
|
|
|
avg_output_tps: number | null
|
|
|
|
|
avg_response_time_ms: number | null
|
|
|
|
|
}
|
|
|
|
|
export interface OverviewPerformance {
|
|
|
|
|
summary: OverviewMetrics
|
|
|
|
|
timeseries: OverviewSeriesPoint[]
|
|
|
|
|
providers: ProviderPerformanceResponse | null
|
|
|
|
|
models?: OverviewModelPerformance[]
|
|
|
|
|
errors: { reason: string; count: number }[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function get<T>(path: string, params?: OverviewQuery, signal?: AbortSignal): Promise<OverviewResponse<T>> {
|
|
|
|
|
return (await apiClient.get<OverviewResponse<T>>(`/api/admin/overview/${path}`, { params, signal })).data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const overviewApi = {
|
|
|
|
|
async dashboardSummary(timezone: string, signal?: AbortSignal): Promise<OverviewDashboardSummary> {
|
|
|
|
|
return (await apiClient.get<OverviewDashboardSummary>('/api/admin/overview/dashboard/summary', { params: { timezone }, signal })).data
|
|
|
|
|
},
|
|
|
|
|
async dashboard(timezone: string, signal?: AbortSignal): Promise<OverviewDashboard> {
|
|
|
|
|
return (await apiClient.get<OverviewDashboard>('/api/admin/overview/dashboard', { params: { timezone }, signal })).data
|
|
|
|
|
},
|
|
|
|
|
async dashboardTotal(timezone: string, signal?: AbortSignal): Promise<OverviewDashboardTotal> {
|
|
|
|
|
return (await apiClient.get<OverviewDashboardTotal>('/api/admin/overview/dashboard/total', { params: { timezone }, signal })).data
|
|
|
|
|
},
|
|
|
|
|
async dashboardCharts(range: OverviewRange, signal?: AbortSignal): Promise<OverviewResponse<OverviewDashboardCharts>> {
|
|
|
|
|
const { from, to, timezone } = range
|
|
|
|
|
return (await apiClient.get<OverviewResponse<OverviewDashboardCharts>>('/api/admin/overview/dashboard/charts', { params: { from, to, timezone, granularity: 'day' }, signal })).data
|
|
|
|
|
},
|
|
|
|
|
summary: (query: OverviewQuery, signal?: AbortSignal) => get<OverviewMetrics>('summary', query, signal),
|
|
|
|
|
timeseries: (query: OverviewQuery, signal?: AbortSignal) => get<{ items: OverviewSeriesPoint[]; granularity: string }>('timeseries', query, signal),
|
|
|
|
|
breakdown: (query: OverviewQuery, signal?: AbortSignal) => get<OverviewPage<OverviewBreakdown>>('breakdown', query, signal),
|
|
|
|
|
users: (query: OverviewQuery, signal?: AbortSignal) => get<OverviewUsers>('users', query, signal),
|
|
|
|
|
user: (id: string, query: OverviewQuery, signal?: AbortSignal) => get<OverviewEmployeeDetail>(`users/${encodeURIComponent(id)}`, query, signal),
|
|
|
|
|
consumption: (query: OverviewQuery, signal?: AbortSignal) => get<OverviewPage<OverviewConsumption>>('consumption', query, signal),
|
|
|
|
|
costs: (query: OverviewQuery, signal?: AbortSignal) => get<OverviewCosts>('costs', query, signal),
|
|
|
|
|
performance: (query: OverviewQuery, signal?: AbortSignal) => get<OverviewPerformance>('operations/performance', query, signal),
|
|
|
|
|
live: (signal?: AbortSignal) => get<OverviewLive>('operations/live', undefined, signal),
|
|
|
|
|
resources: (signal?: AbortSignal) => get<OverviewLive>('operations/resources', undefined, signal),
|
|
|
|
|
async exportCsv(path: 'users' | 'consumption' | 'breakdown', query: OverviewQuery, signal?: AbortSignal): Promise<Blob> {
|
|
|
|
|
const { limit: _limit, offset: _offset, ...filters } = query
|
|
|
|
|
return (await apiClient.get<Blob>(`/api/admin/overview/${path}`, {
|
|
|
|
|
params: { ...filters, format: 'csv' }, responseType: 'blob', signal,
|
|
|
|
|
})).data
|
|
|
|
|
},
|
|
|
|
|
}
|