Files
bifrost/ui/app/workspace/dashboard/utils/exportUtils.ts
Beyhan Oğur 880f412e2c first commit
2026-04-26 21:52:23 +03:00

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;
}