From b08aa5b479395441462effed59ff1ee02d9d8c7f Mon Sep 17 00:00:00 2001 From: Agando Date: Wed, 24 Jun 2026 06:01:05 +0200 Subject: auto: 2026-06-24_06:01 changes --- modules/core/terminal.js | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'modules/core/terminal.js') diff --git a/modules/core/terminal.js b/modules/core/terminal.js index 2b41fd3..3abb074 100644 --- a/modules/core/terminal.js +++ b/modules/core/terminal.js @@ -1603,6 +1603,61 @@ } return; } + if (cmd === 'usage') { + const om = this.ollamaManager; + if (!om) { this.print('Ollama manager not available', 'error'); return; } + const filters = {}; + for (let i = 0; i < args.length; i++) { + if (args[i] === '--json') { filters._json = true; } + else if (args[i] === '--reset') { + om._usageLog = []; + om._usageBuffer = []; + om._saveUsageLog(); + this.print('Usage log cleared.', 'success'); + return; + } + else if (args[i] === '--model' && args[i+1]) { filters.model = args[++i]; } + else if (args[i] === '--provider' && args[i+1]) { filters.provider = args[++i]; } + else if (args[i] === '--since' && args[i+1]) { filters.since_hours = parseFloat(args[++i]); } + } + const stats = om.getUsageStats(filters); + if (filters._json) { + this.print(JSON.stringify(stats, null, 2), ''); + return; + } + if (stats.total === 0) { + this.print('No usage data recorded yet.', 'info'); + return; + } + const fmt = (n) => n.toLocaleString(); + const timeStr = stats.timeSpan < 60 ? stats.timeSpan + 's' : + stats.timeSpan < 3600 ? Math.round(stats.timeSpan / 60) + 'm' : + Math.round(stats.timeSpan / 3600) + 'h ' + Math.round((stats.timeSpan % 3600) / 60) + 'm'; + this.print('╔══════════════════════════════════════════════════════╗', 'info'); + this.print('║ LLM Usage Stats ║', 'info'); + this.print('╠══════════════════════════════════════════════════════╣', 'info'); + this.print(`║ Total requests: ${fmt(stats.total).padStart(30)} ║`, 'info'); + this.print(`║ Total tokens: ${fmt(stats.totalPrompt + stats.totalCompletion).padStart(30)} ║`, 'info'); + this.print(`║ Input: ${fmt(stats.totalPrompt).padStart(37)} ║`, 'info'); + this.print(`║ Output: ${fmt(stats.totalCompletion).padStart(37)} ║`, 'info'); + this.print(`║ Avg latency: ${(stats.avgLatency / 1000).toFixed(1) + 's'.padStart(30)} ║`, 'info'); + this.print(`║ Time span: ${timeStr.padStart(30)} ║`, 'info'); + this.print('╠══════════════════════════════════════════════════════╣', 'info'); + this.print('║ Per model: ║', 'info'); + for (const [model, data] of Object.entries(stats.byModel).sort((a, b) => b[1].requests - a[1].requests)) { + const label = (model.length > 30 ? model.slice(0, 27) + '...' : model).padEnd(30); + this.print(`║ ${label} ${fmt(data.requests).padStart(4)} req ${fmt(data.tokens).padStart(8)} tok ║`, ''); + } + this.print('╠══════════════════════════════════════════════════════╣', 'info'); + this.print('║ Per provider: ║', 'info'); + for (const [prov, data] of Object.entries(stats.byProvider).sort((a, b) => b[1].requests - a[1].requests)) { + const label = (prov.length > 30 ? prov.slice(0, 27) + '...' : prov).padEnd(30); + this.print(`║ ${label} ${fmt(data.requests).padStart(4)} req ${fmt(data.tokens).padStart(8)} tok ║`, ''); + } + this.print('╚══════════════════════════════════════════════════════╝', 'info'); + this.print('Flags: --json, --model=, --provider=, --since=, --reset', 'text-muted'); + return; + } if (cmd === 'history') { const entries = this.history; if (!entries.length) { this.print('No command history.', 'info'); return; } -- cgit v1.2.3