Record token usage per turn and show daily, weekly and all-time totals by host

This commit is contained in:
Gmer4Lfe
2026-08-04 18:04:46 -04:00
parent 961c57c6f0
commit 969a85f303
8 changed files with 340 additions and 3 deletions
+27
View File
@@ -12,6 +12,7 @@
// are.
// ═══════════════════════════════════════════════════════════════════════════════════════════════
const fs = require('fs');
const { buildIndex } = require('./index.js');
const { search } = require('./search.js');
@@ -24,6 +25,27 @@ function flag(name) {
return process.argv.includes(`--${name}`);
}
// Token accounting. Writes the same row shape as the WebGUI worker into the same file — one
// ledger for both paths, or the totals quietly come to mean "whatever the tab happened to do".
// Skipped silently when the caller passes neither flag, because cli.js has to stay runnable by
// hand. Best-effort: a failed append must never cost a caller an answer it already has.
//
// Trimming is deliberately not done here. The PHP side prunes on write, and duplicating a
// read-modify-write of the whole file in a second language is how the two drift apart.
function recordTokens(profile, prompt, completion, tokS) {
const db = arg('token-db', ''), host = arg('token-host', '');
if (!db || !host || (prompt <= 0 && completion <= 0)) return;
const d = new Date();
const p2 = n => String(n).padStart(2, '0');
const row = [
`${d.getFullYear()}-${p2(d.getMonth() + 1)}-${p2(d.getDate())}`,
`${p2(d.getHours())}:${p2(d.getMinutes())}:${p2(d.getSeconds())}`,
host, profile, 'cli', prompt, completion,
tokS === null ? '' : tokS.toFixed(1),
].join('|') + '\n';
try { fs.appendFileSync(db, row); } catch { /* accounting is not the answer */ }
}
function fail(msg, code = 1) {
console.error(msg);
process.exit(code);
@@ -165,6 +187,11 @@ ANSWER`;
if (!res.ok) fail(`generation HTTP ${res.status}`, 2);
const j = await res.json();
// 'varaverk' rather than a CLI-specific name: this path retrieves and cites, so it is the
// same kind of turn the tab's default profile runs, and the two should aggregate together.
recordTokens('varaverk', j.prompt_eval_count || 0, j.eval_count || 0,
j.eval_duration > 0 ? (j.eval_count / (j.eval_duration / 1e9)) : null);
if (flag('json')) {
console.log(JSON.stringify({ answer: j.response, sources: r.results.map(x => ({ path: x.path, section: x.section, heading: x.heading, score: x.score })) }));
return;