File size: 3,698 Bytes
f1dd159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { apiRequest } from "@/shared/api/client";
import { createObjectDecoder, hasShape, isArrayOf, isNumber, isOneOf, isOptional, isString } from "@/shared/api/decoder";
import type { PeriodValue } from "@/shared/lib/period";

export type DashboardPeriod = PeriodValue;

export type DashboardUsageDTO = {
  requests: number;
  successfulRequests: number;
  failedRequests: number;
  inputTokens: number;
  cachedInputTokens: number;
  outputTokens: number;
  reasoningTokens: number;
  tokens: number;
  billedCostUsdTicks: number;
  successRate: number;
  averageFirstTokenMs?: number;
  outputTokensPerSecond?: number;
  firstTokenSamples?: number;
  throughputSamples?: number;
};

export type DashboardDTO = {
  period: DashboardPeriod;
  generatedAt: string;
  range: { start: string; end: string };
  resources: {
    activeAccounts: number;
    totalAccounts: number;
    buildAccounts: number;
    webAccounts: number;
    consoleAccounts: number;
    enabledModels: number;
    totalModels: number;
	activeClientKeys: number;
	totalClientKeys: number;
  };
  usage: DashboardUsageDTO;
  series: Array<{ start: string; end: string; requests: number; inputTokens: number; cachedInputTokens: number; outputTokens: number; reasoningTokens: number; tokens: number; billedCostUsdTicks: number }>;
  activity: Array<{ start: string; requests: number }>;
  topModels: Array<{ model: string; requests: number; inputTokens: number; cachedInputTokens: number; outputTokens: number; reasoningTokens: number; tokens: number; billedCostUsdTicks: number }>;
  providers: Array<{ provider: string; requests: number; successfulRequests: number; tokens: number }>;
};

const dashboardSeriesItem = hasShape({
  start: isString, end: isString, requests: isNumber, inputTokens: isNumber, cachedInputTokens: isNumber,
  outputTokens: isNumber, reasoningTokens: isNumber, tokens: isNumber, billedCostUsdTicks: isNumber,
});
const dashboardUsage = hasShape({
  requests: isNumber, successfulRequests: isNumber, failedRequests: isNumber, inputTokens: isNumber,
  cachedInputTokens: isNumber, outputTokens: isNumber, reasoningTokens: isNumber, tokens: isNumber,
  billedCostUsdTicks: isNumber, successRate: isNumber, averageFirstTokenMs: isOptional(isNumber),
  outputTokensPerSecond: isOptional(isNumber), firstTokenSamples: isOptional(isNumber), throughputSamples: isOptional(isNumber),
});
const dashboardModelItem = hasShape({
  model: isString, requests: isNumber, inputTokens: isNumber, cachedInputTokens: isNumber,
  outputTokens: isNumber, reasoningTokens: isNumber, tokens: isNumber, billedCostUsdTicks: isNumber,
});
const decodeDashboard = createObjectDecoder<DashboardDTO>("dashboard", {
  period: isOneOf("24h", "7d", "30d", "90d"),
  generatedAt: isString,
  range: hasShape({ start: isString, end: isString }),
  resources: hasShape({
    activeAccounts: isNumber, totalAccounts: isNumber, buildAccounts: isNumber, webAccounts: isNumber, consoleAccounts: isNumber, enabledModels: isNumber, totalModels: isNumber,
		activeClientKeys: isNumber, totalClientKeys: isNumber,
  }),
  usage: dashboardUsage,
  series: isArrayOf(dashboardSeriesItem),
  activity: isArrayOf(hasShape({ start: isString, requests: isNumber })),
  topModels: isArrayOf(dashboardModelItem),
  providers: isArrayOf(hasShape({ provider: isString, requests: isNumber, successfulRequests: isNumber, tokens: isNumber })),
});

export function getDashboard(period: DashboardPeriod, timezone: string, refresh = false): Promise<DashboardDTO> {
  const query = new URLSearchParams({ period, timezone });
  if (refresh) query.set("refresh", "1");
  return apiRequest(`/api/admin/v1/dashboard?${query.toString()}`, {}, decodeDashboard);
}