Cost dashboard: TTS providers endpoint, header link, polish

Adds /api/costs/tts endpoint backed by get_tts_providers() in cost_db,
surfaces a Costs link in the control panel header, and small polish
to the costs page HTML/JS.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-09 23:39:40 -06:00
co-authored by Claude Opus 4.6
parent 1b988a0303
commit c087c0362a
6 changed files with 68 additions and 3 deletions
+15 -1
View File
@@ -50,19 +50,21 @@ function destroyChart(key) {
async function loadDashboard() {
const p = currentPeriod;
try {
const [summary, timeline, models, categories, sessions, expensive] = await Promise.all([
const [summary, timeline, models, categories, sessions, expensive, tts] = await Promise.all([
fetch(`/api/costs/summary?period=${p}`).then(r => r.json()),
fetch(`/api/costs/timeline?period=${p}&group_by=session`).then(r => r.json()),
fetch(`/api/costs/models?period=${p}`).then(r => r.json()),
fetch(`/api/costs/categories?period=${p}`).then(r => r.json()),
fetch(`/api/costs/sessions?period=${p}`).then(r => r.json()),
fetch(`/api/costs/expensive?period=${p}&limit=10`).then(r => r.json()),
fetch(`/api/costs/tts?period=${p}`).then(r => r.json()),
]);
renderSummary(summary);
renderTimeline(timeline);
renderModels(models);
renderCategories(categories);
renderSessionBars(timeline);
renderTtsTable(tts);
renderExpensiveTable(expensive);
renderSessionsTable(sessions);
} catch (e) {
@@ -201,6 +203,18 @@ function renderSessionBars(data) {
});
}
function renderTtsTable(data) {
const tbody = document.querySelector('#tts-table tbody');
tbody.innerHTML = data.map(d => `
<tr>
<td>${d.provider}</td>
<td>${d.calls.toLocaleString()}</td>
<td>${d.chars.toLocaleString()}</td>
<td>${formatCost(d.cost)}</td>
</tr>
`).join('');
}
function renderExpensiveTable(data) {
const tbody = document.querySelector('#expensive-table tbody');
tbody.innerHTML = data.map(d => `