212 lines
7.5 KiB
TypeScript
212 lines
7.5 KiB
TypeScript
/**
|
|
* Dashboard-specific CSV data converters.
|
|
*
|
|
* Each function takes the dashboard data and returns { headers, rows } ready
|
|
* for `buildCSV()`.
|
|
*/
|
|
|
|
import type {
|
|
CostHistogramResponse,
|
|
LatencyHistogramResponse,
|
|
LogsHistogramResponse,
|
|
MCPCostHistogramResponse,
|
|
MCPHistogramResponse,
|
|
MCPTopToolsResponse,
|
|
ModelHistogramResponse,
|
|
ModelRankingsResponse,
|
|
ProviderCostHistogramResponse,
|
|
ProviderLatencyHistogramResponse,
|
|
ProviderTokenHistogramResponse,
|
|
TokenHistogramResponse,
|
|
} from "@/lib/types/logs";
|
|
|
|
type CSVData = { headers: string[]; rows: unknown[][] };
|
|
|
|
export function overviewVolumeToCSV(data: LogsHistogramResponse | null): CSVData {
|
|
const headers = ["Timestamp", "Total Requests", "Success", "Error"];
|
|
const rows = (data?.buckets ?? []).map((b) => [b.timestamp, b.count, b.success, b.error]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export function overviewTokensToCSV(data: TokenHistogramResponse | null): CSVData {
|
|
const headers = ["Timestamp", "Prompt Tokens", "Completion Tokens", "Total Tokens", "Cached Read Tokens"];
|
|
const rows = (data?.buckets ?? []).map((b) => [b.timestamp, b.prompt_tokens, b.completion_tokens, b.total_tokens, b.cached_read_tokens]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export function overviewCostToCSV(data: CostHistogramResponse | null): CSVData {
|
|
const models = data?.models ?? [];
|
|
const headers = ["Timestamp", "Total Cost", ...models];
|
|
const rows = (data?.buckets ?? []).map((b) => [b.timestamp, b.total_cost, ...models.map((m) => b.by_model?.[m] ?? 0)]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export function overviewModelUsageToCSV(data: ModelHistogramResponse | null): CSVData {
|
|
const models = data?.models ?? [];
|
|
const modelHeaders = models.flatMap((m) => [`${m} Total`, `${m} Success`, `${m} Error`]);
|
|
const headers = ["Timestamp", ...modelHeaders];
|
|
const rows = (data?.buckets ?? []).map((b) => [
|
|
b.timestamp,
|
|
...models.flatMap((m) => {
|
|
const stats = b.by_model?.[m];
|
|
return [stats?.total ?? 0, stats?.success ?? 0, stats?.error ?? 0];
|
|
}),
|
|
]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export function overviewLatencyToCSV(data: LatencyHistogramResponse | null): CSVData {
|
|
const headers = ["Timestamp", "Avg Latency (ms)", "P90 (ms)", "P95 (ms)", "P99 (ms)", "Total Requests"];
|
|
const rows = (data?.buckets ?? []).map((b) => [
|
|
b.timestamp,
|
|
b.avg_latency,
|
|
b.p90_latency,
|
|
b.p95_latency,
|
|
b.p99_latency,
|
|
b.total_requests,
|
|
]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export function providerCostToCSV(data: ProviderCostHistogramResponse | null): CSVData {
|
|
const providers = data?.providers ?? [];
|
|
const headers = ["Timestamp", "Total Cost", ...providers];
|
|
const rows = (data?.buckets ?? []).map((b) => [b.timestamp, b.total_cost, ...providers.map((p) => b.by_provider?.[p] ?? 0)]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export function providerTokensToCSV(data: ProviderTokenHistogramResponse | null): CSVData {
|
|
const providers = data?.providers ?? [];
|
|
const provHeaders = providers.flatMap((p) => [`${p} Prompt`, `${p} Completion`, `${p} Total`]);
|
|
const headers = ["Timestamp", ...provHeaders];
|
|
const rows = (data?.buckets ?? []).map((b) => [
|
|
b.timestamp,
|
|
...providers.flatMap((p) => {
|
|
const stats = b.by_provider?.[p];
|
|
return [stats?.prompt_tokens ?? 0, stats?.completion_tokens ?? 0, stats?.total_tokens ?? 0];
|
|
}),
|
|
]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export function providerLatencyToCSV(data: ProviderLatencyHistogramResponse | null): CSVData {
|
|
const providers = data?.providers ?? [];
|
|
const provHeaders = providers.flatMap((p) => [`${p} Avg (ms)`, `${p} P90 (ms)`, `${p} P95 (ms)`, `${p} P99 (ms)`]);
|
|
const headers = ["Timestamp", ...provHeaders];
|
|
const rows = (data?.buckets ?? []).map((b) => [
|
|
b.timestamp,
|
|
...providers.flatMap((p) => {
|
|
const stats = b.by_provider?.[p];
|
|
return [stats?.avg_latency ?? 0, stats?.p90_latency ?? 0, stats?.p95_latency ?? 0, stats?.p99_latency ?? 0];
|
|
}),
|
|
]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export function modelRankingsToCSV(data: ModelRankingsResponse | null): CSVData {
|
|
const headers = [
|
|
"Model",
|
|
"Provider",
|
|
"Total Requests",
|
|
"Success Count",
|
|
"Success Rate (%)",
|
|
"Total Tokens",
|
|
"Total Cost ($)",
|
|
"Avg Latency (ms)",
|
|
"Requests Trend (%)",
|
|
"Tokens Trend (%)",
|
|
"Cost Trend (%)",
|
|
"Latency Trend (%)",
|
|
];
|
|
const rows = (data?.rankings ?? []).map((r) => [
|
|
r.model,
|
|
r.provider,
|
|
r.total_requests,
|
|
r.success_count,
|
|
r.success_rate,
|
|
r.total_tokens,
|
|
r.total_cost,
|
|
r.avg_latency,
|
|
r.trend.has_previous_period ? r.trend.requests_trend : "N/A",
|
|
r.trend.has_previous_period ? r.trend.tokens_trend : "N/A",
|
|
r.trend.has_previous_period ? r.trend.cost_trend : "N/A",
|
|
r.trend.has_previous_period ? r.trend.latency_trend : "N/A",
|
|
]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export function mcpVolumeToCSV(data: MCPHistogramResponse | null): CSVData {
|
|
const headers = ["Timestamp", "Total Executions", "Success", "Error"];
|
|
const rows = (data?.buckets ?? []).map((b) => [b.timestamp, b.count, b.success, b.error]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export function mcpCostToCSV(data: MCPCostHistogramResponse | null): CSVData {
|
|
const headers = ["Timestamp", "Total Cost ($)"];
|
|
const rows = (data?.buckets ?? []).map((b) => [b.timestamp, b.total_cost]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export function mcpTopToolsToCSV(data: MCPTopToolsResponse | null): CSVData {
|
|
const headers = ["Tool Name", "Execution Count", "Cost ($)"];
|
|
const rows = (data?.tools ?? []).map((t) => [t.tool_name, t.count, t.cost]);
|
|
return { headers, rows };
|
|
}
|
|
|
|
export interface DashboardData {
|
|
// Overview
|
|
histogramData: LogsHistogramResponse | null;
|
|
tokenData: TokenHistogramResponse | null;
|
|
costData: CostHistogramResponse | null;
|
|
modelData: ModelHistogramResponse | null;
|
|
latencyData: LatencyHistogramResponse | null;
|
|
// Provider Usage
|
|
providerCostData: ProviderCostHistogramResponse | null;
|
|
providerTokenData: ProviderTokenHistogramResponse | null;
|
|
providerLatencyData: ProviderLatencyHistogramResponse | null;
|
|
// Rankings
|
|
rankingsData: ModelRankingsResponse | null;
|
|
// MCP
|
|
mcpHistogramData: MCPHistogramResponse | null;
|
|
mcpCostData: MCPCostHistogramResponse | null;
|
|
mcpTopToolsData: MCPTopToolsResponse | null;
|
|
}
|
|
|
|
export type ExportTab = "all" | "overview" | "provider-usage" | "rankings" | "mcp";
|
|
|
|
/** Return all CSV sections for the selected scope. Each entry becomes its own sheet / file section. */
|
|
export function getCSVSections(data: DashboardData, tab: ExportTab): { name: string; csv: CSVData }[] {
|
|
const sections: { name: string; csv: CSVData }[] = [];
|
|
|
|
if (tab === "all" || tab === "overview") {
|
|
sections.push(
|
|
{ name: "overview-volume", csv: overviewVolumeToCSV(data.histogramData) },
|
|
{ name: "overview-tokens", csv: overviewTokensToCSV(data.tokenData) },
|
|
{ name: "overview-cost", csv: overviewCostToCSV(data.costData) },
|
|
{ name: "overview-model-usage", csv: overviewModelUsageToCSV(data.modelData) },
|
|
{ name: "overview-latency", csv: overviewLatencyToCSV(data.latencyData) },
|
|
);
|
|
}
|
|
|
|
if (tab === "all" || tab === "provider-usage") {
|
|
sections.push(
|
|
{ name: "provider-cost", csv: providerCostToCSV(data.providerCostData) },
|
|
{ name: "provider-tokens", csv: providerTokensToCSV(data.providerTokenData) },
|
|
{ name: "provider-latency", csv: providerLatencyToCSV(data.providerLatencyData) },
|
|
);
|
|
}
|
|
|
|
if (tab === "all" || tab === "rankings") {
|
|
sections.push({ name: "model-rankings", csv: modelRankingsToCSV(data.rankingsData) });
|
|
}
|
|
|
|
if (tab === "all" || tab === "mcp") {
|
|
sections.push(
|
|
{ name: "mcp-volume", csv: mcpVolumeToCSV(data.mcpHistogramData) },
|
|
{ name: "mcp-cost", csv: mcpCostToCSV(data.mcpCostData) },
|
|
{ name: "mcp-top-tools", csv: mcpTopToolsToCSV(data.mcpTopToolsData) },
|
|
);
|
|
}
|
|
|
|
return sections;
|
|
} |