110 lines
3.1 KiB
TypeScript
110 lines
3.1 KiB
TypeScript
type LatencyTotalsLike = {
|
|
count: number;
|
|
sum: number;
|
|
min: number;
|
|
max: number;
|
|
p95Max: number;
|
|
};
|
|
|
|
type DailyLatencyLike = {
|
|
date: string;
|
|
count: number;
|
|
sum: number;
|
|
min: number;
|
|
max: number;
|
|
p95Max: number;
|
|
};
|
|
|
|
type DailyLike = {
|
|
date: string;
|
|
};
|
|
|
|
type LatencyLike = {
|
|
count: number;
|
|
avgMs: number;
|
|
minMs: number;
|
|
maxMs: number;
|
|
p95Ms: number;
|
|
};
|
|
|
|
type DailyLatencyInput = LatencyLike & { date: string };
|
|
|
|
export function mergeUsageLatency(
|
|
totals: LatencyTotalsLike,
|
|
latency: LatencyLike | undefined,
|
|
): void {
|
|
if (!latency || latency.count <= 0) {
|
|
return;
|
|
}
|
|
totals.count += latency.count;
|
|
totals.sum += latency.avgMs * latency.count;
|
|
totals.min = Math.min(totals.min, latency.minMs);
|
|
totals.max = Math.max(totals.max, latency.maxMs);
|
|
totals.p95Max = Math.max(totals.p95Max, latency.p95Ms);
|
|
}
|
|
|
|
export function mergeUsageDailyLatency(
|
|
dailyLatencyMap: Map<string, DailyLatencyLike>,
|
|
dailyLatency?: DailyLatencyInput[] | null,
|
|
): void {
|
|
for (const day of dailyLatency ?? []) {
|
|
const existing = dailyLatencyMap.get(day.date) ?? {
|
|
date: day.date,
|
|
count: 0,
|
|
sum: 0,
|
|
min: Number.POSITIVE_INFINITY,
|
|
max: 0,
|
|
p95Max: 0,
|
|
};
|
|
existing.count += day.count;
|
|
existing.sum += day.avgMs * day.count;
|
|
existing.min = Math.min(existing.min, day.minMs);
|
|
existing.max = Math.max(existing.max, day.maxMs);
|
|
existing.p95Max = Math.max(existing.p95Max, day.p95Ms);
|
|
dailyLatencyMap.set(day.date, existing);
|
|
}
|
|
}
|
|
|
|
export function buildUsageAggregateTail<
|
|
TTotals extends { totalCost: number },
|
|
TDaily extends DailyLike,
|
|
TModelDaily extends { date: string; cost: number },
|
|
>(params: {
|
|
byChannelMap: Map<string, TTotals>;
|
|
latencyTotals: LatencyTotalsLike;
|
|
dailyLatencyMap: Map<string, DailyLatencyLike>;
|
|
modelDailyMap: Map<string, TModelDaily>;
|
|
dailyMap: Map<string, TDaily>;
|
|
}) {
|
|
return {
|
|
byChannel: Array.from(params.byChannelMap.entries())
|
|
.map(([channel, totals]) => ({ channel, totals }))
|
|
.toSorted((a, b) => b.totals.totalCost - a.totals.totalCost),
|
|
latency:
|
|
params.latencyTotals.count > 0
|
|
? {
|
|
count: params.latencyTotals.count,
|
|
avgMs: params.latencyTotals.sum / params.latencyTotals.count,
|
|
minMs:
|
|
params.latencyTotals.min === Number.POSITIVE_INFINITY ? 0 : params.latencyTotals.min,
|
|
maxMs: params.latencyTotals.max,
|
|
p95Ms: params.latencyTotals.p95Max,
|
|
}
|
|
: undefined,
|
|
dailyLatency: Array.from(params.dailyLatencyMap.values())
|
|
.map((entry) => ({
|
|
date: entry.date,
|
|
count: entry.count,
|
|
avgMs: entry.count ? entry.sum / entry.count : 0,
|
|
minMs: entry.min === Number.POSITIVE_INFINITY ? 0 : entry.min,
|
|
maxMs: entry.max,
|
|
p95Ms: entry.p95Max,
|
|
}))
|
|
.toSorted((a, b) => a.date.localeCompare(b.date)),
|
|
modelDaily: Array.from(params.modelDailyMap.values()).toSorted(
|
|
(a, b) => a.date.localeCompare(b.date) || b.cost - a.cost,
|
|
),
|
|
daily: Array.from(params.dailyMap.values()).toSorted((a, b) => a.date.localeCompare(b.date)),
|
|
};
|
|
}
|