show costs as % of weekly budget ($800) instead of dollar amounts
This commit is contained in:
1 parent
807ecac7b9
commit
86e4f402ca
1 file changed
+18
-13
+18
-13
@@ -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, ''').replace(/"/g, '"');
|
||||
}
|
||||
|
||||
function pct(cost) {
|
||||
return (cost / WEEKLY_BUDGET * 100).toFixed(2) + '%';
|
||||
}
|
||||
Reference in new issue
Block a user