mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-20 05:11:48 +00:00
fix(cli-proxy): preserve historical analytics across syncs
This commit is contained in:
1 parent
69b75c0449
commit
01fcd77573
4 files changed
+66
-9
No files matched your search
@@ -87,6 +87,14 @@ function buildDailyTimestamp(date: string): string {
|
||||
return `${date}T00:00:00.000Z`;
|
||||
}
|
||||
|
||||
function distributeRequestCounts(total: number, buckets: number): number[] {
|
||||
if (buckets <= 0) return [];
|
||||
const normalizedTotal = Math.max(buckets, total);
|
||||
const base = Math.floor(normalizedTotal / buckets);
|
||||
const remainder = normalizedTotal % buckets;
|
||||
return Array.from({ length: buckets }, (_value, index) => base + (index < remainder ? 1 : 0));
|
||||
}
|
||||
|
||||
function buildLegacyHistoryDetails(
|
||||
snapshot: LegacyCliproxyUsageSnapshot
|
||||
): CliproxyUsageHistoryDetail[] {
|
||||
@@ -94,7 +102,12 @@ function buildLegacyHistoryDetails(
|
||||
const coveredDailyKeys = new Set<string>();
|
||||
|
||||
for (const hour of snapshot.hourly ?? []) {
|
||||
for (const breakdown of hour.modelBreakdowns) {
|
||||
const requestCounts = distributeRequestCounts(
|
||||
hour.requestCount ?? hour.modelBreakdowns.length,
|
||||
hour.modelBreakdowns.length
|
||||
);
|
||||
|
||||
hour.modelBreakdowns.forEach((breakdown, index) => {
|
||||
details.push({
|
||||
model: breakdown.modelName,
|
||||
timestamp: buildHourlyTimestamp(hour.hour),
|
||||
@@ -103,10 +116,12 @@ function buildLegacyHistoryDetails(
|
||||
inputTokens: breakdown.inputTokens,
|
||||
outputTokens: breakdown.outputTokens,
|
||||
cacheReadTokens: breakdown.cacheReadTokens,
|
||||
requestCount: requestCounts[index] ?? 1,
|
||||
cost: breakdown.cost,
|
||||
failed: false,
|
||||
});
|
||||
coveredDailyKeys.add(`${hour.hour.slice(0, 10)}|${breakdown.modelName}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (const day of snapshot.daily ?? []) {
|
||||
@@ -124,6 +139,8 @@ function buildLegacyHistoryDetails(
|
||||
inputTokens: breakdown.inputTokens,
|
||||
outputTokens: breakdown.outputTokens,
|
||||
cacheReadTokens: breakdown.cacheReadTokens,
|
||||
requestCount: 1,
|
||||
cost: breakdown.cost,
|
||||
failed: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ export interface CliproxyUsageHistoryDetail {
|
||||
inputTokens: number;
|
||||
outputTokens: number;
|
||||
cacheReadTokens: number;
|
||||
requestCount: number;
|
||||
cost: number;
|
||||
failed: boolean;
|
||||
}
|
||||
|
||||
@@ -30,15 +32,12 @@ interface ModelAccumulator {
|
||||
inputTokens: number;
|
||||
outputTokens: number;
|
||||
cacheReadTokens: number;
|
||||
cost: number;
|
||||
}
|
||||
|
||||
/** Build ModelBreakdown from accumulated token counts */
|
||||
function buildModelBreakdown(modelName: string, acc: ModelAccumulator): ModelBreakdown {
|
||||
const { inputTokens, outputTokens, cacheReadTokens } = acc;
|
||||
const cost = calculateCost(
|
||||
{ inputTokens, outputTokens, cacheCreationTokens: 0, cacheReadTokens },
|
||||
modelName
|
||||
);
|
||||
const { inputTokens, outputTokens, cacheReadTokens, cost } = acc;
|
||||
return { modelName, inputTokens, outputTokens, cacheCreationTokens: 0, cacheReadTokens, cost };
|
||||
}
|
||||
|
||||
@@ -54,6 +53,16 @@ function createHistoryDetail(
|
||||
inputTokens: detail.tokens?.input_tokens ?? 0,
|
||||
outputTokens: detail.tokens?.output_tokens ?? 0,
|
||||
cacheReadTokens: detail.tokens?.cached_tokens ?? 0,
|
||||
requestCount: 1,
|
||||
cost: calculateCost(
|
||||
{
|
||||
inputTokens: detail.tokens?.input_tokens ?? 0,
|
||||
outputTokens: detail.tokens?.output_tokens ?? 0,
|
||||
cacheCreationTokens: 0,
|
||||
cacheReadTokens: detail.tokens?.cached_tokens ?? 0,
|
||||
},
|
||||
model
|
||||
),
|
||||
failed: detail.failed,
|
||||
};
|
||||
}
|
||||
@@ -107,6 +116,7 @@ function createHistorySignature(detail: CliproxyUsageHistoryDetail): string {
|
||||
detail.inputTokens,
|
||||
detail.outputTokens,
|
||||
detail.cacheReadTokens,
|
||||
detail.requestCount,
|
||||
detail.failed ? '1' : '0',
|
||||
].join('|');
|
||||
}
|
||||
@@ -185,15 +195,21 @@ function aggregateByKey<T>(
|
||||
for (const detail of flat) {
|
||||
const key = keyFn(detail.timestamp);
|
||||
if (!buckets.has(key)) buckets.set(key, new Map());
|
||||
requestCounts.set(key, (requestCounts.get(key) ?? 0) + 1);
|
||||
requestCounts.set(key, (requestCounts.get(key) ?? 0) + detail.requestCount);
|
||||
const modelMap = buckets.get(key) as Map<string, ModelAccumulator>;
|
||||
if (!modelMap.has(detail.model)) {
|
||||
modelMap.set(detail.model, { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0 });
|
||||
modelMap.set(detail.model, {
|
||||
inputTokens: 0,
|
||||
outputTokens: 0,
|
||||
cacheReadTokens: 0,
|
||||
cost: 0,
|
||||
});
|
||||
}
|
||||
const acc = modelMap.get(detail.model) as ModelAccumulator;
|
||||
acc.inputTokens += detail.inputTokens;
|
||||
acc.outputTokens += detail.outputTokens;
|
||||
acc.cacheReadTokens += detail.cacheReadTokens;
|
||||
acc.cost += detail.cost;
|
||||
}
|
||||
|
||||
const records: T[] = [];
|
||||
|
||||
Reference in new issue
Block a user