@kaitranntt/ccs 7.51.0-dev.4 → 7.51.0-dev.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cliproxy/stats-fetcher.d.ts +41 -0
- package/dist/cliproxy/stats-fetcher.d.ts.map +1 -1
- package/dist/cliproxy/stats-fetcher.js +32 -1
- package/dist/cliproxy/stats-fetcher.js.map +1 -1
- package/dist/ui/assets/{accounts-Cs_Uohn7.js → accounts-CbGqm04Q.js} +1 -1
- package/dist/ui/assets/{alert-dialog-cRwDSggu.js → alert-dialog-zpinTbtF.js} +1 -1
- package/dist/ui/assets/{api-C73W2Hb1.js → api-CalCxo_A.js} +1 -1
- package/dist/ui/assets/{auth-section-DgF431PH.js → auth-section-BjuUeaLO.js} +1 -1
- package/dist/ui/assets/{backups-section-9V2yDu_e.js → backups-section-DNkq5ZUy.js} +1 -1
- package/dist/ui/assets/{checkbox-BeoeEcEZ.js → checkbox-Df7G7a1w.js} +1 -1
- package/dist/ui/assets/{cliproxy-DAlyh7zw.js → cliproxy-DLwo08Aq.js} +1 -1
- package/dist/ui/assets/{cliproxy-control-panel-CE4y4VDk.js → cliproxy-control-panel--SMhq8Fs.js} +1 -1
- package/dist/ui/assets/{confirm-dialog-COTT5ztZ.js → confirm-dialog-Dl3qe-0j.js} +1 -1
- package/dist/ui/assets/{copilot-Cm5PT0v6.js → copilot-CdJG-Shj.js} +1 -1
- package/dist/ui/assets/{cursor-DYhCaKbC.js → cursor-DMH09Hqq.js} +1 -1
- package/dist/ui/assets/{droid-eTM2_tVh.js → droid-ufxKKFsV.js} +1 -1
- package/dist/ui/assets/{globalenv-section-Dzt_ECFK.js → globalenv-section-CZMJi0Tl.js} +1 -1
- package/dist/ui/assets/{health-Bk8Cj2vi.js → health-CU3rjKc6.js} +1 -1
- package/dist/ui/assets/{index-BXDW5hxG.js → index-CFOuEr7f.js} +1 -1
- package/dist/ui/assets/{index-CKnNRLzv.js → index-CxzNRZhe.js} +1 -1
- package/dist/ui/assets/{index-jqDLGaO4.js → index-KBHcxzj5.js} +1 -1
- package/dist/ui/assets/index-UzqXH0bn.js +47 -0
- package/dist/ui/assets/{index-D1Gx_G_A.js → index-v5UgttWm.js} +1 -1
- package/dist/ui/assets/{proxy-status-widget-D-PfDCn1.js → proxy-status-widget-FJrBfPdV.js} +1 -1
- package/dist/ui/assets/{separator-CjXUYlSy.js → separator-B8bpSt_-.js} +1 -1
- package/dist/ui/assets/{shared-C9EvhZ8u.js → shared-BK-E4ojq.js} +1 -1
- package/dist/ui/assets/{switch-DFLN6xA0.js → switch-kyFX8Qe1.js} +1 -1
- package/dist/ui/assets/{updates-FcpGeTFg.js → updates-DBinmc39.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/dist/web-server/usage/aggregator.d.ts +4 -0
- package/dist/web-server/usage/aggregator.d.ts.map +1 -1
- package/dist/web-server/usage/aggregator.js +24 -1
- package/dist/web-server/usage/aggregator.js.map +1 -1
- package/dist/web-server/usage/cliproxy-usage-syncer.d.ts +34 -0
- package/dist/web-server/usage/cliproxy-usage-syncer.d.ts.map +1 -0
- package/dist/web-server/usage/cliproxy-usage-syncer.js +152 -0
- package/dist/web-server/usage/cliproxy-usage-syncer.js.map +1 -0
- package/dist/web-server/usage/cliproxy-usage-transformer.d.ts +26 -0
- package/dist/web-server/usage/cliproxy-usage-transformer.d.ts.map +1 -0
- package/dist/web-server/usage/cliproxy-usage-transformer.js +141 -0
- package/dist/web-server/usage/cliproxy-usage-transformer.js.map +1 -0
- package/package.json +1 -1
- package/dist/ui/assets/index-hlYFfpDN.js +0 -47
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CLIProxy Usage Syncer
|
|
4
|
+
*
|
|
5
|
+
* Periodically fetches CLIProxy usage data, transforms it, and persists
|
|
6
|
+
* snapshots locally so analytics data survives CLIProxy restarts.
|
|
7
|
+
*
|
|
8
|
+
* Snapshot location: ~/.ccs/cache/cliproxy-usage/latest.json
|
|
9
|
+
* Sync interval: 5 minutes
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.stopCliproxySync = exports.startCliproxySync = exports.syncCliproxyUsage = exports.loadCachedCliproxyData = void 0;
|
|
36
|
+
const fs = __importStar(require("fs"));
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const stats_fetcher_1 = require("../../cliproxy/stats-fetcher");
|
|
39
|
+
const cliproxy_usage_transformer_1 = require("./cliproxy-usage-transformer");
|
|
40
|
+
const config_manager_1 = require("../../utils/config-manager");
|
|
41
|
+
const ui_1 = require("../../utils/ui");
|
|
42
|
+
const SNAPSHOT_VERSION = 1;
|
|
43
|
+
// Module-level interval ID
|
|
44
|
+
let syncIntervalId = null;
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Cache directory helpers
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
function getCliproxyCacheDir() {
|
|
49
|
+
return path.join((0, config_manager_1.getCcsDir)(), 'cache', 'cliproxy-usage');
|
|
50
|
+
}
|
|
51
|
+
function getLatestSnapshotPath() {
|
|
52
|
+
return path.join(getCliproxyCacheDir(), 'latest.json');
|
|
53
|
+
}
|
|
54
|
+
function ensureCliproxyCacheDir() {
|
|
55
|
+
const dir = getCliproxyCacheDir();
|
|
56
|
+
if (!fs.existsSync(dir)) {
|
|
57
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Load cached data
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
/**
|
|
64
|
+
* Read the latest CLIProxy usage snapshot from disk.
|
|
65
|
+
* Returns empty arrays on failure (file not found, parse error, version mismatch).
|
|
66
|
+
*/
|
|
67
|
+
async function loadCachedCliproxyData() {
|
|
68
|
+
const empty = { daily: [], hourly: [], monthly: [] };
|
|
69
|
+
try {
|
|
70
|
+
const snapshotPath = getLatestSnapshotPath();
|
|
71
|
+
if (!fs.existsSync(snapshotPath)) {
|
|
72
|
+
return empty;
|
|
73
|
+
}
|
|
74
|
+
const raw = fs.readFileSync(snapshotPath, 'utf-8');
|
|
75
|
+
const snapshot = JSON.parse(raw);
|
|
76
|
+
if (snapshot.version !== SNAPSHOT_VERSION) {
|
|
77
|
+
console.log((0, ui_1.info)('CLIProxy snapshot version mismatch, will refresh on next sync'));
|
|
78
|
+
return empty;
|
|
79
|
+
}
|
|
80
|
+
return { daily: snapshot.daily, hourly: snapshot.hourly, monthly: snapshot.monthly };
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
console.log((0, ui_1.warn)('Failed to read CLIProxy snapshot:') + ` ${err.message}`);
|
|
84
|
+
return empty;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.loadCachedCliproxyData = loadCachedCliproxyData;
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Sync
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
/**
|
|
92
|
+
* Fetch latest CLIProxy usage data and persist a snapshot to disk.
|
|
93
|
+
* Non-fatal: logs warning and returns early if CLIProxy is unavailable.
|
|
94
|
+
*/
|
|
95
|
+
async function syncCliproxyUsage() {
|
|
96
|
+
const raw = await (0, stats_fetcher_1.fetchCliproxyUsageRaw)();
|
|
97
|
+
if (raw === null) {
|
|
98
|
+
console.log((0, ui_1.warn)('CLIProxy usage sync skipped: proxy unavailable'));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
ensureCliproxyCacheDir();
|
|
103
|
+
const daily = (0, cliproxy_usage_transformer_1.transformCliproxyToDailyUsage)(raw);
|
|
104
|
+
const hourly = (0, cliproxy_usage_transformer_1.transformCliproxyToHourlyUsage)(raw);
|
|
105
|
+
const monthly = (0, cliproxy_usage_transformer_1.transformCliproxyToMonthlyUsage)(raw);
|
|
106
|
+
const snapshot = {
|
|
107
|
+
version: SNAPSHOT_VERSION,
|
|
108
|
+
timestamp: Date.now(),
|
|
109
|
+
daily,
|
|
110
|
+
hourly,
|
|
111
|
+
monthly,
|
|
112
|
+
};
|
|
113
|
+
// Atomic write: temp file + rename
|
|
114
|
+
const snapshotPath = getLatestSnapshotPath();
|
|
115
|
+
const tempFile = snapshotPath + '.tmp';
|
|
116
|
+
fs.writeFileSync(tempFile, JSON.stringify(snapshot), 'utf-8');
|
|
117
|
+
fs.renameSync(tempFile, snapshotPath);
|
|
118
|
+
console.log((0, ui_1.ok)('CLIProxy usage snapshot updated'));
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
// Non-fatal - stale snapshot will continue to be served
|
|
122
|
+
console.log((0, ui_1.warn)('Failed to write CLIProxy snapshot:') + ` ${err.message}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.syncCliproxyUsage = syncCliproxyUsage;
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
// Interval management
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
/**
|
|
130
|
+
* Start periodic CLIProxy usage sync (every 5 minutes).
|
|
131
|
+
* Performs an immediate sync on startup.
|
|
132
|
+
*/
|
|
133
|
+
function startCliproxySync() {
|
|
134
|
+
console.log((0, ui_1.info)('Starting CLIProxy usage sync (interval: 5 min)'));
|
|
135
|
+
// Fire-and-forget initial sync
|
|
136
|
+
void syncCliproxyUsage();
|
|
137
|
+
syncIntervalId = setInterval(() => {
|
|
138
|
+
void syncCliproxyUsage();
|
|
139
|
+
}, 5 * 60 * 1000);
|
|
140
|
+
}
|
|
141
|
+
exports.startCliproxySync = startCliproxySync;
|
|
142
|
+
/**
|
|
143
|
+
* Stop periodic CLIProxy usage sync.
|
|
144
|
+
*/
|
|
145
|
+
function stopCliproxySync() {
|
|
146
|
+
if (syncIntervalId !== null) {
|
|
147
|
+
clearInterval(syncIntervalId);
|
|
148
|
+
syncIntervalId = null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.stopCliproxySync = stopCliproxySync;
|
|
152
|
+
//# sourceMappingURL=cliproxy-usage-syncer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cliproxy-usage-syncer.js","sourceRoot":"","sources":["../../../src/web-server/usage/cliproxy-usage-syncer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLIProxy Usage Transformer
|
|
3
|
+
*
|
|
4
|
+
* Transforms CLIProxy's usage API response into DailyUsage/HourlyUsage/MonthlyUsage
|
|
5
|
+
* types compatible with the CCS analytics dashboard.
|
|
6
|
+
*/
|
|
7
|
+
import type { CliproxyUsageApiResponse, CliproxyRequestDetail } from '../../cliproxy/stats-fetcher';
|
|
8
|
+
import type { DailyUsage, HourlyUsage, MonthlyUsage } from './types';
|
|
9
|
+
/** Flat entry pairing a model name with its request detail */
|
|
10
|
+
interface FlatDetail {
|
|
11
|
+
model: string;
|
|
12
|
+
detail: CliproxyRequestDetail;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Flatten the nested response.usage.apis[provider].models[model].details[]
|
|
16
|
+
* structure into a flat array. Failed requests are skipped.
|
|
17
|
+
*/
|
|
18
|
+
export declare function flattenCliproxyDetails(response: CliproxyUsageApiResponse): FlatDetail[];
|
|
19
|
+
/** Transform CLIProxy usage response into DailyUsage array (sorted descending by date) */
|
|
20
|
+
export declare function transformCliproxyToDailyUsage(response: CliproxyUsageApiResponse): DailyUsage[];
|
|
21
|
+
/** Transform CLIProxy usage response into HourlyUsage array (sorted descending by hour) */
|
|
22
|
+
export declare function transformCliproxyToHourlyUsage(response: CliproxyUsageApiResponse): HourlyUsage[];
|
|
23
|
+
/** Transform CLIProxy usage response into MonthlyUsage array (sorted descending by month) */
|
|
24
|
+
export declare function transformCliproxyToMonthlyUsage(response: CliproxyUsageApiResponse): MonthlyUsage[];
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=cliproxy-usage-transformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cliproxy-usage-transformer.d.ts","sourceRoot":"","sources":["../../../src/web-server/usage/cliproxy-usage-transformer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAEpG,OAAO,KAAK,EAAkB,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAMrF,8DAA8D;AAC9D,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,qBAAqB,CAAC;CAC/B;AAuBD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,UAAU,EAAE,CAkBvF;AAiDD,0FAA0F;AAC1F,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,wBAAwB,GAAG,UAAU,EAAE,CAsB9F;AAED,2FAA2F;AAC3F,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,wBAAwB,GAAG,WAAW,EAAE,CA0BhG;AAED,6FAA6F;AAC7F,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,wBAAwB,GACjC,YAAY,EAAE,CAkBhB"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CLIProxy Usage Transformer
|
|
4
|
+
*
|
|
5
|
+
* Transforms CLIProxy's usage API response into DailyUsage/HourlyUsage/MonthlyUsage
|
|
6
|
+
* types compatible with the CCS analytics dashboard.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.transformCliproxyToMonthlyUsage = exports.transformCliproxyToHourlyUsage = exports.transformCliproxyToDailyUsage = exports.flattenCliproxyDetails = void 0;
|
|
10
|
+
const model_pricing_1 = require("../model-pricing");
|
|
11
|
+
/** Build ModelBreakdown from accumulated token counts */
|
|
12
|
+
function buildModelBreakdown(modelName, acc) {
|
|
13
|
+
const { inputTokens, outputTokens, cacheReadTokens } = acc;
|
|
14
|
+
const cost = (0, model_pricing_1.calculateCost)({ inputTokens, outputTokens, cacheCreationTokens: 0, cacheReadTokens }, modelName);
|
|
15
|
+
return { modelName, inputTokens, outputTokens, cacheCreationTokens: 0, cacheReadTokens, cost };
|
|
16
|
+
}
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// FLATTEN
|
|
19
|
+
// ============================================================================
|
|
20
|
+
/**
|
|
21
|
+
* Flatten the nested response.usage.apis[provider].models[model].details[]
|
|
22
|
+
* structure into a flat array. Failed requests are skipped.
|
|
23
|
+
*/
|
|
24
|
+
function flattenCliproxyDetails(response) {
|
|
25
|
+
const apis = response?.usage?.apis;
|
|
26
|
+
if (!apis)
|
|
27
|
+
return [];
|
|
28
|
+
const results = [];
|
|
29
|
+
for (const providerData of Object.values(apis)) {
|
|
30
|
+
const models = providerData?.models;
|
|
31
|
+
if (!models)
|
|
32
|
+
continue;
|
|
33
|
+
for (const [model, modelData] of Object.entries(models)) {
|
|
34
|
+
const details = modelData?.details;
|
|
35
|
+
if (!details)
|
|
36
|
+
continue;
|
|
37
|
+
for (const detail of details) {
|
|
38
|
+
if (detail.failed)
|
|
39
|
+
continue;
|
|
40
|
+
results.push({ model, detail });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return results;
|
|
45
|
+
}
|
|
46
|
+
exports.flattenCliproxyDetails = flattenCliproxyDetails;
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// GENERIC AGGREGATOR
|
|
49
|
+
// ============================================================================
|
|
50
|
+
/** Group flat details by a time key extractor, return sorted DailyUsage-like records */
|
|
51
|
+
function aggregateByKey(flat, keyFn, buildRecord, sortFn) {
|
|
52
|
+
// bucket: timeKey -> modelName -> accumulator
|
|
53
|
+
const buckets = new Map();
|
|
54
|
+
for (const { model, detail } of flat) {
|
|
55
|
+
const key = keyFn(detail.timestamp);
|
|
56
|
+
if (!buckets.has(key))
|
|
57
|
+
buckets.set(key, new Map());
|
|
58
|
+
const modelMap = buckets.get(key);
|
|
59
|
+
if (!modelMap.has(model)) {
|
|
60
|
+
modelMap.set(model, { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0 });
|
|
61
|
+
}
|
|
62
|
+
const acc = modelMap.get(model);
|
|
63
|
+
acc.inputTokens += detail.tokens?.input_tokens ?? 0;
|
|
64
|
+
acc.outputTokens += detail.tokens?.output_tokens ?? 0;
|
|
65
|
+
acc.cacheReadTokens += detail.tokens?.cached_tokens ?? 0;
|
|
66
|
+
}
|
|
67
|
+
const records = [];
|
|
68
|
+
Array.from(buckets.entries()).forEach(([key, modelMap]) => {
|
|
69
|
+
const breakdowns = Array.from(modelMap.entries()).map(([name, acc]) => buildModelBreakdown(name, acc));
|
|
70
|
+
records.push(buildRecord(key, breakdowns));
|
|
71
|
+
});
|
|
72
|
+
return records.sort(sortFn);
|
|
73
|
+
}
|
|
74
|
+
/** Sum token field across all breakdowns */
|
|
75
|
+
function sumField(breakdowns, field) {
|
|
76
|
+
return breakdowns.reduce((acc, b) => acc + b[field], 0);
|
|
77
|
+
}
|
|
78
|
+
// ============================================================================
|
|
79
|
+
// TRANSFORMS
|
|
80
|
+
// ============================================================================
|
|
81
|
+
/** Transform CLIProxy usage response into DailyUsage array (sorted descending by date) */
|
|
82
|
+
function transformCliproxyToDailyUsage(response) {
|
|
83
|
+
const flat = flattenCliproxyDetails(response);
|
|
84
|
+
return aggregateByKey(flat, (ts) => ts.slice(0, 10), (date, breakdowns) => {
|
|
85
|
+
const totalCost = sumField(breakdowns, 'cost');
|
|
86
|
+
return {
|
|
87
|
+
date,
|
|
88
|
+
source: 'cliproxy',
|
|
89
|
+
inputTokens: sumField(breakdowns, 'inputTokens'),
|
|
90
|
+
outputTokens: sumField(breakdowns, 'outputTokens'),
|
|
91
|
+
cacheCreationTokens: 0,
|
|
92
|
+
cacheReadTokens: sumField(breakdowns, 'cacheReadTokens'),
|
|
93
|
+
cost: totalCost,
|
|
94
|
+
totalCost,
|
|
95
|
+
modelsUsed: breakdowns.map((b) => b.modelName),
|
|
96
|
+
modelBreakdowns: breakdowns,
|
|
97
|
+
};
|
|
98
|
+
}, (a, b) => b.date.localeCompare(a.date));
|
|
99
|
+
}
|
|
100
|
+
exports.transformCliproxyToDailyUsage = transformCliproxyToDailyUsage;
|
|
101
|
+
/** Transform CLIProxy usage response into HourlyUsage array (sorted descending by hour) */
|
|
102
|
+
function transformCliproxyToHourlyUsage(response) {
|
|
103
|
+
const flat = flattenCliproxyDetails(response);
|
|
104
|
+
return aggregateByKey(flat, (ts) => {
|
|
105
|
+
const date = ts.slice(0, 10);
|
|
106
|
+
const hour = ts.slice(11, 13) || '00';
|
|
107
|
+
return `${date} ${hour}:00`;
|
|
108
|
+
}, (hour, breakdowns) => {
|
|
109
|
+
const totalCost = sumField(breakdowns, 'cost');
|
|
110
|
+
return {
|
|
111
|
+
hour,
|
|
112
|
+
source: 'cliproxy',
|
|
113
|
+
inputTokens: sumField(breakdowns, 'inputTokens'),
|
|
114
|
+
outputTokens: sumField(breakdowns, 'outputTokens'),
|
|
115
|
+
cacheCreationTokens: 0,
|
|
116
|
+
cacheReadTokens: sumField(breakdowns, 'cacheReadTokens'),
|
|
117
|
+
cost: totalCost,
|
|
118
|
+
totalCost,
|
|
119
|
+
modelsUsed: breakdowns.map((b) => b.modelName),
|
|
120
|
+
modelBreakdowns: breakdowns,
|
|
121
|
+
};
|
|
122
|
+
}, (a, b) => b.hour.localeCompare(a.hour));
|
|
123
|
+
}
|
|
124
|
+
exports.transformCliproxyToHourlyUsage = transformCliproxyToHourlyUsage;
|
|
125
|
+
/** Transform CLIProxy usage response into MonthlyUsage array (sorted descending by month) */
|
|
126
|
+
function transformCliproxyToMonthlyUsage(response) {
|
|
127
|
+
const flat = flattenCliproxyDetails(response);
|
|
128
|
+
return aggregateByKey(flat, (ts) => ts.slice(0, 7), (month, breakdowns) => ({
|
|
129
|
+
month,
|
|
130
|
+
source: 'cliproxy',
|
|
131
|
+
inputTokens: sumField(breakdowns, 'inputTokens'),
|
|
132
|
+
outputTokens: sumField(breakdowns, 'outputTokens'),
|
|
133
|
+
cacheCreationTokens: 0,
|
|
134
|
+
cacheReadTokens: sumField(breakdowns, 'cacheReadTokens'),
|
|
135
|
+
totalCost: sumField(breakdowns, 'cost'),
|
|
136
|
+
modelsUsed: breakdowns.map((b) => b.modelName),
|
|
137
|
+
modelBreakdowns: breakdowns,
|
|
138
|
+
}), (a, b) => b.month.localeCompare(a.month));
|
|
139
|
+
}
|
|
140
|
+
exports.transformCliproxyToMonthlyUsage = transformCliproxyToMonthlyUsage;
|
|
141
|
+
//# sourceMappingURL=cliproxy-usage-transformer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cliproxy-usage-transformer.js","sourceRoot":"","sources":["../../../src/web-server/usage/cliproxy-usage-transformer.ts"],"names":[],"mappings":"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"}
|