async function renderCost() { const content = document.getElementById('pageContent'); content.innerHTML = `
Usage by Agent
Usage Over Time
Recent Cost Entries
`; try { const data = await api.getCost(); const entries = data.entries || []; const totals = data.daily_totals || {}; const alerts = data.free_tier_alerts || []; const totalCost = entries.reduce((s, e) => s + (e.cost || 0), 0); const totalTokens = entries.reduce((s, e) => s + (e.tokens || 0), 0); const days = Object.keys(totals).length; document.getElementById('costStats').innerHTML = `
💰
$${totalCost.toFixed(4)}
Total Cost
🔤
${totalTokens.toLocaleString()}
Total Tokens
${alerts.length > 0 ? '⚠' : '✓'}
${alerts.length}
Free Tier Alerts
`; const entriesContainer = document.getElementById('costEntries'); if (entries.length === 0) { entriesContainer.innerHTML = '
📊
No cost data yet
'; } else { entriesContainer.innerHTML = `
${entries.slice(-20).reverse().map(e => ` `).join('')}
TimeAgentModelTokensCost
${formatDate(e.timestamp)} ${e.agent} ${e.model} ${(e.tokens || 0).toLocaleString()} $${(e.cost || 0).toFixed(6)}
`; } if (alerts.length > 0) { const header = document.querySelector('.page-header'); header.insertAdjacentHTML('afterend', `
âš 
Free Tier Alerts ${alerts.map(a => `
${escapeHtml(a)}
`).join('')}
`); } // Build agent chart const agentTotals = {}; entries.forEach(e => { const a = e.agent || 'unknown'; agentTotals[a] = (agentTotals[a] || 0) + (e.tokens || 0); }); const agentLabels = Object.keys(agentTotals); const agentData = Object.values(agentTotals); if (entries.length > 0) { new Chart(document.getElementById('agentChart'), { type: 'doughnut', data: { labels: agentLabels, datasets: [{ data: agentData, backgroundColor: ['rgba(108,92,231,0.8)', 'rgba(0,212,170,0.8)', 'rgba(69,170,242,0.8)', 'rgba(255,165,2,0.8)'] }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom', labels: { color: getComputedStyle(document.documentElement).getPropertyValue('--text-secondary').trim(), font: { size: 11 } } } } } }); const timeTotals = {}; entries.forEach(e => { const day = e.timestamp ? e.timestamp.slice(0, 10) : 'unknown'; timeTotals[day] = (timeTotals[day] || 0) + (e.tokens || 0); }); const timeLabels = Object.keys(timeTotals).sort(); const timeData = timeLabels.map(d => timeTotals[d]); new Chart(document.getElementById('timeChart'), { type: 'line', data: { labels: timeLabels, datasets: [{ label: 'Tokens', data: timeData, borderColor: 'rgba(108,92,231,0.8)', backgroundColor: 'rgba(108,92,231,0.1)', fill: true, tension: 0.4, pointRadius: 3 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { x: { ticks: { color: getComputedStyle(document.documentElement).getPropertyValue('--text-muted').trim(), font: { size: 10 } } }, y: { ticks: { color: getComputedStyle(document.documentElement).getPropertyValue('--text-muted').trim(), font: { size: 10 } } } } } }); } } catch (err) { document.getElementById('costStats').innerHTML = `
âš 
${escapeHtml(err.message)}
`; } } async function recordTestCost() { showModal('Record Cost Entry', `
`, ` `); } async function submitCostRecord() { try { await api.recordCost({ agent: document.getElementById('rcAgent').value, model: document.getElementById('rcModel').value, tokens: parseInt(document.getElementById('rcTokens').value) || 0, cost: parseFloat(document.getElementById('rcCost').value) || 0, }); closeModal(); showToast('Cost recorded', 'success'); renderCost(); } catch (err) { showToast(`Error: ${err.message}`, 'error'); } }