show costs as % of weekly budget ($800) instead of dollar amounts

This commit is contained in:
Meleki committed 2026-02-21 14:53:34 +01:00
1 parent 807ecac7b9
commit 86e4f402ca
1 file changed
+18 -13
+18 -13
View File
@@ -8,6 +8,7 @@ const ZOOM_LEVELS = [
{ name: '1 Tag', days: 1 },
{ name: '12 Stunden', days: 0.5 },
];
const WEEKLY_BUDGET = 800; // $ pro Woche
const BAR_COUNT = 30;
const CHAIN_COLORS = [
'#4ade80','#60a5fa','#f97316','#c084fc','#f472b6',
@@ -97,7 +98,7 @@ async function loadView() {
function renderSummary(s) {
$('summary').innerHTML = `
<span>Zeitraum: <span class="cost">$${s.totalCost.toFixed(2)}</span></span>
<span>Zeitraum: <span class="cost">${pct(s.totalCost)}</span></span>
<span>Einträge: <span class="val">${s.totalEntries}</span></span>
`;
}
@@ -118,7 +119,7 @@ function renderBucketChart(buckets, bucketMinutes) {
const b = bucketMap[i];
const cost = b ? b.cost : 0;
const count = b ? b.count : 0;
const pct = (cost / maxCost) * 100;
const barPct = (cost / maxCost) * 100;
const bucketStart = new Date(viewFrom.getTime() + i * bucketMinutes * 60000);
const bucketEnd = new Date(viewFrom.getTime() + (i + 1) * bucketMinutes * 60000);
@@ -126,8 +127,8 @@ function renderBucketChart(buckets, bucketMinutes) {
const wrapper = document.createElement('div');
wrapper.className = 'bar-wrapper';
wrapper.innerHTML = `
<div class="bar-tooltip">$${cost.toFixed(3)} / ${count}</div>
<div class="bar" style="height:${Math.max(pct, cost > 0 ? 2 : 0)}%"></div>
<div class="bar-tooltip">${pct(cost)} / ${count}</div>
<div class="bar" style="height:${Math.max(barPct, cost > 0 ? 2 : 0)}%"></div>
`;
if (isMaxZoom) {
@@ -184,15 +185,15 @@ function renderEntryChart(entries) {
chain.forEach((e, ei) => {
const cost = Number(e.cost);
const pct = (cost / maxCost) * 100;
const barPct = (cost / maxCost) * 100;
window._entryChainColors.set(e.id, color);
const wrapper = document.createElement('div');
wrapper.className = 'bar-wrapper bar-in-chain';
wrapper.innerHTML = `
<div class="bar-tooltip">$${cost.toFixed(4)} / ${e.model || '?'}<br>Kette: $${chainTotal.toFixed(2)}</div>
<div class="bar" style="height:${Math.max(pct, 2)}%;background:${color}"></div>
<div class="bar-tooltip">${pct(cost)} / ${e.model || '?'}<br>Kette: ${pct(chainTotal)}</div>
<div class="bar" style="height:${Math.max(barPct, 2)}%;background:${color}"></div>
`;
wrapper.addEventListener('click', () => openModal(e.data, e.id));
chart.appendChild(wrapper);
@@ -202,7 +203,7 @@ function renderEntryChart(entries) {
const totalLbl = document.createElement('div');
totalLbl.className = 'chain-cost-label';
totalLbl.style.color = color;
totalLbl.textContent = `$${chainTotal.toFixed(2)}`;
totalLbl.textContent = pct(chainTotal);
wrapper.prepend(totalLbl);
}
@@ -232,7 +233,7 @@ function renderChainBlocks(chains) {
<span class="block-label">${fmtShort(new Date(c.first))} - ${fmtShort(new Date(c.last))}</span>
<span class="block-stats">
<span class="block-count">${c.count} Einträge</span>
<span class="block-cost">$${c.totalCost.toFixed(4)}</span>
<span class="block-cost">${pct(c.totalCost)}</span>
</span>
</div>
`;
@@ -273,7 +274,7 @@ function renderEntryList(entries) {
<span class="entry-time">${fmtTime(e.timestamp)}</span>
<span class="entry-model">${e.model || '-'}</span>
<span class="entry-tokens">${shortNum(e.inputTokens)}/${shortNum(e.outputTokens)}</span>
<span class="entry-cost">$${Number(e.cost).toFixed(4)}</span>
<span class="entry-cost">${pct(Number(e.cost))}</span>
<span class="entry-type">${e.type}</span>
`;
row.addEventListener('click', () => openModal(e.data, e.id));
@@ -299,7 +300,7 @@ async function toggleChainBlock(idx, chainId) {
<span class="entry-time">${fmtTime(entry.timestamp)}</span>
<span class="entry-model">${msg.model || '-'}</span>
<span class="entry-tokens">${shortNum(msg.usage?.input)}/${shortNum(msg.usage?.output)}</span>
<span class="entry-cost">${cost ? '$' + cost.toFixed(4) : '-'}</span>
<span class="entry-cost">${cost ? pct(cost) : '-'}</span>
<span class="entry-type">${msg.role || entry.type}</span>
</div>
`;
@@ -389,7 +390,7 @@ async function openModal(dataStr, clickedId) {
const chainCount = chainCosts.filter(c => c > 0).length;
let html = `<div class="chain-summary">
<span class="chain-summary-cost">Kette: $${chainTotal.toFixed(4)}</span>
<span class="chain-summary-cost">Kette: ${pct(chainTotal)}</span>
<span class="chain-summary-count">${chainCount} Einträge mit Kosten / ${chain.length} gesamt</span>
</div>`;
@@ -412,7 +413,7 @@ async function openModal(dataStr, clickedId) {
<span class="chain-role">${role}</span>
<span class="chain-time">${time}</span>
${model ? `<span class="chain-model">${model}</span>` : ''}
${cost ? `<span class="chain-cost">$${cost.toFixed(4)}</span>` : ''}
${cost ? `<span class="chain-cost">${pct(cost)}</span>` : ''}
</div>
<div class="chain-body">${escHtml(content)}</div>
</div>
@@ -470,3 +471,7 @@ function escHtml(s) {
function escAttr(s) {
return String(s).replace(/'/g, '&#39;').replace(/"/g, '&quot;');
}
function pct(cost) {
return (cost / WEEKLY_BUDGET * 100).toFixed(2) + '%';
}