feat: sync batch benchmark results into My Voices (v1.12.16)

After a batch benchmark completes, successful entries are saved to each
voice's meta.json via POST /api/voice/meta. window.loadVoiceLibrary() is
then called so My Voices Factor + WPM columns update instantly without
a manual reload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mARTin-B78 2026-06-28 00:20:15 +02:00
parent ef5321cb18
commit 373aee8423
4 changed files with 36 additions and 2 deletions

View File

@ -9,6 +9,13 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
--- ---
## [1.12.16] — 2026-06-28
### Added
- **Batch benchmark → My Voices sync** — after a batch benchmark run completes, results are automatically saved to each voice's `meta.json` via `POST /api/voice/meta`, and My Voices Factor + WPM columns update immediately without a manual page refresh.
---
## [1.12.15] — 2026-06-28 ## [1.12.15] — 2026-06-28
### Added ### Added

View File

@ -26,7 +26,7 @@
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── --> <!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css"> <link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
<link rel="stylesheet" href="/static/style.css?v=1.12.15"> <link rel="stylesheet" href="/static/style.css?v=1.12.16">
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── --> <!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
@ -336,7 +336,7 @@
<script src="/static/vendor/wavesurfer-regions.min.js"></script> <script src="/static/vendor/wavesurfer-regions.min.js"></script>
<!-- loader.js: fetches sections → loads JS modules → removes skeleton --> <!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
<script src="/static/loader.js?v=1.12.15"></script> <script src="/static/loader.js?v=1.12.16"></script>
</body> </body>
</html> </html>

View File

@ -403,6 +403,31 @@
(best ? `, best RTF ${best.avgRtf.toFixed(2)} (${best.voice})` : ''), (best ? `, best RTF ${best.avgRtf.toFixed(2)} (${best.voice})` : ''),
ok.length < batchResults.length ? 'error' : 'success' ok.length < batchResults.length ? 'error' : 'success'
); );
// Sync results into voice meta so My Voices Factor/WPM columns update
const syncable = batchResults.filter(r => r.ok && r.avgRtf > 0 && r.avgAudio > 0);
if (syncable.length && typeof window.loadVoiceLibrary === 'function') {
const benchText = ($('perf-text')?.value || '').trim();
await Promise.allSettled(syncable.map(r =>
fetch('/api/voice/meta', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
voice_id: r.voice,
benchmark: {
ok: true,
text: benchText,
elapsed_sec: r.avgLatency / 1000,
audio_sec: r.avgAudio,
speed: 1 / r.avgRtf,
rtf: r.avgRtf,
ttfa_ms: r.minLatency,
}
})
})
));
await window.loadVoiceLibrary();
}
} }
batchRunBtn.addEventListener('click', runBatchBenchmark); batchRunBtn.addEventListener('click', runBatchBenchmark);

View File

@ -926,6 +926,8 @@ function mergeBenchmarkResults(d) {
if (hit && hit.benchmark) v.benchmark = hit.benchmark; if (hit && hit.benchmark) v.benchmark = hit.benchmark;
}); });
} }
window.loadVoiceLibrary = () => loadVoiceLibrary();
window.mergeBenchmarkResults = mergeBenchmarkResults;
function activeBenchmarkVoices() { function activeBenchmarkVoices() {
return (_voices || []).filter(v => v.enabled !== false); return (_voices || []).filter(v => v.enabled !== false);