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:
+15
-1
@@ -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 => `
|
||||
|
||||
Reference in New Issue
Block a user