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:
+12
-1
@@ -59,7 +59,16 @@
|
||||
<canvas id="session-chart"></canvas>
|
||||
</div>
|
||||
</section>
|
||||
<section class="tables-section">
|
||||
<section class="chart-row">
|
||||
<div class="table-container">
|
||||
<h3>TTS Providers</h3>
|
||||
<table id="tts-table">
|
||||
<thead>
|
||||
<tr><th>Provider</th><th>Calls</th><th>Characters</th><th>Cost</th></tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<h3>Most Expensive Calls</h3>
|
||||
<table id="expensive-table">
|
||||
@@ -69,6 +78,8 @@
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
<section class="tables-section">
|
||||
<div class="table-container">
|
||||
<h3>Sessions</h3>
|
||||
<table id="sessions-table">
|
||||
|
||||
+14
-1
@@ -108,11 +108,24 @@ header button {
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
header button:hover {
|
||||
header button:hover, .header-link-btn:hover {
|
||||
background: #3a2e1f;
|
||||
border-color: rgba(232, 121, 29, 0.3);
|
||||
}
|
||||
|
||||
.header-link-btn {
|
||||
background: var(--bg-light);
|
||||
color: var(--text);
|
||||
border: 1px solid rgba(232, 121, 29, 0.15);
|
||||
padding: 8px 16px;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
text-decoration: none;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.theme-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<button id="export-session-btn">Export</button>
|
||||
<button id="preflight-btn" class="preflight-btn">Preflight</button>
|
||||
<button id="settings-btn">Settings</button>
|
||||
<a href="/costs" class="header-link-btn" title="Cost Dashboard">Costs</a>
|
||||
</div>
|
||||
<div class="theme-bar">
|
||||
<label for="show-theme-input" class="theme-label">Theme:</label>
|
||||
|
||||
+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