From 0606db101a5178781786ca3b5db46b1a1cdfee24 Mon Sep 17 00:00:00 2001 From: mARTin-B78 Date: Sat, 27 Jun 2026 22:54:54 +0200 Subject: [PATCH] feat: reorder columns, add Duration column, benchmark sentence presets (v1.12.12) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Column order now: Img·Play·Name·Lang·Gender·Length·Duration·WPM·Speed· Seed·dBFS·Type·Source·Rating·Tags·Note·Active. Duration shows synthesised audio length (b.audio_sec), sortable. Preset dropdown offers 4 benchmark sentences (DE/EN narrative + DE/EN tongue-twister) and a reset option. Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 11 +++++++++ static/index.html | 4 ++-- static/js/voice-library.js | 43 +++++++++++++++++++++++++++++++++++ static/sections/s-voices.html | 22 ++++++++++++------ static/style.css | 33 ++++++++++++++------------- 5 files changed, 88 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b76c72a..e6e5145 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,17 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi --- +## [1.12.12] — 2026-06-27 + +### Added +- **Duration column** in the voice table — shows the length of the synthesised benchmark audio (e.g. `11.4s`), sortable. Distinct from Length (original clip) and WPM (speaking rate). +- **Benchmark sentence presets** dropdown — four ready-made sentences (DE narrative, EN narrative, DE pangram, EN tongue-twister) plus a Reset option. Selecting a preset loads it instantly without overwriting anything else. + +### Changed +- **Column order** rearranged to: Img · Play · Name · Lang · Gender · Length · Duration · WPM · Speed · Seed · dBFS · Type · Source · Rating · Tags · Note · Active. + +--- + ## [1.12.11] — 2026-06-27 ### Fixed diff --git a/static/index.html b/static/index.html index 8ff9591..17ca153 100644 --- a/static/index.html +++ b/static/index.html @@ -26,7 +26,7 @@ - + @@ -336,7 +336,7 @@ - + diff --git a/static/js/voice-library.js b/static/js/voice-library.js index 84c3b49..2344cf8 100644 --- a/static/js/voice-library.js +++ b/static/js/voice-library.js @@ -45,6 +45,14 @@ const BENCHMARK_SAMPLE_STORAGE_KEY = 'vcf-benchmark-sample-text'; const _libraryFilters = {text:'', lang:'', sex:'', type:'', rating:''}; const DEFAULT_BENCHMARK_SAMPLE_TEXT = 'Hello, how are you today? Please read this sample clearly for a fair voice benchmark.'; +const BENCHMARK_PRESETS = { + de: 'Die Welt ist voller Geschichten, die darauf warten, erzählt zu werden — von mutigen Helden und stillen Träumern.', + en: 'The old lighthouse stood firm against the crashing waves, its beam sweeping silently across the dark and restless sea.', + de2: 'Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Im Winter ist es kalt und die Tage sind kurz.', + en2: 'She sells seashells by the seashore. Peter Piper picked a peck of pickled peppers on a perfectly pleasant afternoon.', + reset: DEFAULT_BENCHMARK_SAMPLE_TEXT, +}; + function benchmarkSampleText() { const el = $('benchmark-sample-text'); return (el && el.value.trim()) || DEFAULT_BENCHMARK_SAMPLE_TEXT; @@ -63,6 +71,17 @@ function initBenchmarkSampleControls() { localStorage.setItem(BENCHMARK_SAMPLE_STORAGE_KEY, sample.value); status('Benchmark sample sentence reset'); }); + const presetSel = $('benchmark-preset-select'); + if (presetSel) { + presetSel.addEventListener('change', () => { + const key = presetSel.value; + if (!key || !BENCHMARK_PRESETS[key]) { presetSel.value = ''; return; } + sample.value = BENCHMARK_PRESETS[key]; + localStorage.setItem(BENCHMARK_SAMPLE_STORAGE_KEY, sample.value); + presetSel.value = ''; + status('Benchmark sample sentence loaded'); + }); + } $('benchmark-use-preview-btn')?.addEventListener('click', () => { const text = $('preview-text-area')?.value.trim(); if (!text) { toast('Preview text is empty', 'error'); return; } @@ -98,6 +117,7 @@ function getSortValue(v, field) { case 'duration': return v.duration || 0; case 'dbfs': return voiceDbfs(v) ?? -999; case 'benchmark': { const b = voiceBenchmark(v); return b && b.speed != null ? -Number(b.speed) : 999; } + case 'bench_audio': return voiceBenchmarkAudioSec(v) ?? 999; case 'wpm': return voiceWpm(v) ?? -1; case 'transcript': return (v.transcript || '').toLowerCase(); case 'note': return (v.note || '').toLowerCase(); @@ -377,6 +397,16 @@ function benchmarkClass(v) { return elapsed != null && elapsed <= 4 ? 'bench-ok' : 'bench-warn'; } +function voiceBenchmarkAudioSec(v) { + const b = voiceBenchmark(v); + return b && b.ok && b.audio_sec != null ? Number(b.audio_sec) : null; +} + +function fmtBenchmarkAudio(v) { + const sec = voiceBenchmarkAudioSec(v); + return sec != null ? sec.toFixed(1) + 's' : '-'; +} + function voiceWpm(v) { const b = voiceBenchmark(v); if (!b || !b.ok || !b.audio_sec || !b.text) return null; @@ -836,11 +866,17 @@ async function runVoiceBenchmarkBatch() { // Live-update the row cells so results appear immediately if (row) { const benchCell = row.querySelector('.vl-tbl-bench'); + const durCell = row.querySelector('.vl-tbl-dur'); const wpmCell = row.querySelector('.vl-tbl-wpm'); if (benchCell) { const bt = fmtBenchmark(voice), bc = benchmarkClass(voice), btitle = benchmarkTitle(voice); benchCell.innerHTML = bt !== '-' ? ` ${escHtml(bt)}` : '-'; } + if (durCell) { + const sec = voiceBenchmarkAudioSec(voice); + durCell.textContent = fmtBenchmarkAudio(voice); + durCell.title = sec != null ? `${fmtBenchmarkAudio(voice)} of synthesised audio for the benchmark sentence` : ''; + } if (wpmCell) { const wpm = voiceWpm(voice); wpmCell.textContent = fmtWpm(voice); @@ -1978,6 +2014,7 @@ function makeVoiceRow(v) {
${benchText !== '-' ? ` ${escHtml(benchText)}` : '-'}
${dbfs} dB
${fmtDuration(v.duration)}
+
${escHtml(fmtBenchmarkAudio(v))}
${escHtml(fmtWpm(v))}
${window._voiceTableEditMode @@ -2945,11 +2982,17 @@ function makeVoiceRow(v) { const tblRow = document.querySelector(`.vl-row[data-id="${CSS.escape(v.id)}"]`); if (tblRow) { const tblBench = tblRow.querySelector('.vl-tbl-bench'); + const tblDur = tblRow.querySelector('.vl-tbl-dur'); const tblWpm = tblRow.querySelector('.vl-tbl-wpm'); if (tblBench) { const bt = fmtBenchmark(v), bc = benchmarkClass(v), btitle = benchmarkTitle(v); tblBench.innerHTML = bt !== '-' ? ` ${escHtml(bt)}` : '-'; } + if (tblDur) { + const sec = voiceBenchmarkAudioSec(v); + tblDur.textContent = fmtBenchmarkAudio(v); + tblDur.title = sec != null ? `${fmtBenchmarkAudio(v)} of synthesised audio for the benchmark sentence` : ''; + } if (tblWpm) { const wpm = voiceWpm(v); tblWpm.textContent = fmtWpm(v); diff --git a/static/sections/s-voices.html b/static/sections/s-voices.html index ed5c4c6..0ed015c 100644 --- a/static/sections/s-voices.html +++ b/static/sections/s-voices.html @@ -108,16 +108,17 @@
Name
Lang
Gender
-
Type
-
Speed
-
dBFS
Length
+
Duration
WPM
-
Rating
-
Source
+
Speed
Seed
-
Note
+
dBFS
+
Type
+
Source
+
Rating
Tags
+
Note
Active
@@ -174,7 +175,14 @@ - + diff --git a/static/style.css b/static/style.css index a0c5bed..b1f1f27 100644 --- a/static/style.css +++ b/static/style.css @@ -1516,7 +1516,7 @@ code { background: var(--panel); border-radius: 4px; padding: 1px 5px; font-fami .vl-dbfs { display: none; } /* Table View mode */ -.vl-tbl-lang, .vl-tbl-gender, .vl-tbl-type, .vl-tbl-bench, .vl-tbl-dbfs, .vl-tbl-len, .vl-tbl-wpm, .vl-tbl-rating, .vl-tbl-source, .vl-tbl-seed, .vl-tbl-note, .vl-tbl-tag, .vl-tbl-active { display: none; } +.vl-tbl-lang, .vl-tbl-gender, .vl-tbl-type, .vl-tbl-bench, .vl-tbl-dbfs, .vl-tbl-len, .vl-tbl-dur, .vl-tbl-wpm, .vl-tbl-rating, .vl-tbl-source, .vl-tbl-seed, .vl-tbl-note, .vl-tbl-tag, .vl-tbl-active { display: none; } .vl-table-header { display: none; } .voices-workbench.table-view .voices-list-pane { width: 100% !important; max-width: 100%; } @@ -1524,7 +1524,7 @@ code { background: var(--panel); border-radius: 4px; padding: 1px 5px; font-fami .voices-workbench.table-view .vl-table-header { display: grid; - grid-template-columns: 24px 32px 60px minmax(140px, 1.2fr) 60px 70px 60px 80px 70px 60px 55px 90px 70px 60px minmax(120px, 1fr) minmax(80px, 1fr) 50px; + grid-template-columns: 24px 32px 60px minmax(140px, 1.2fr) 60px 70px 55px 55px 55px 80px 55px 70px 60px 90px 70px minmax(80px, 1fr) minmax(120px, 1fr) 50px; gap: 10px; align-items: center; padding: 8px 10px; @@ -1543,7 +1543,7 @@ code { background: var(--panel); border-radius: 4px; padding: 1px 5px; font-fami .voices-workbench.table-view .vl-compact { display: grid; - grid-template-columns: 24px 32px 60px minmax(140px, 1.2fr) 60px 70px 60px 80px 70px 60px 55px 90px 70px 60px minmax(120px, 1fr) minmax(80px, 1fr) 50px; + grid-template-columns: 24px 32px 60px minmax(140px, 1.2fr) 60px 70px 55px 55px 55px 80px 55px 70px 60px 90px 70px minmax(80px, 1fr) minmax(120px, 1fr) 50px; gap: 10px; align-items: center; } @@ -1554,20 +1554,21 @@ code { background: var(--panel); border-radius: 4px; padding: 1px 5px; font-fami .voices-workbench.table-view .vr-play-group { order: 2; flex-shrink: 0; } .voices-workbench.table-view .vl-name, .voices-workbench.table-view .vl-name-input { order: 3; display: block; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text); } -.voices-workbench.table-view .vl-tbl-lang { display: block; order: 4; font-size: 12px; } -.voices-workbench.table-view .vl-tbl-gender { display: block; order: 5; font-size: 12px; } -.voices-workbench.table-view .vl-tbl-type { display: block; order: 6; font-size: 12px; } -.voices-workbench.table-view .vl-tbl-bench { display: block; order: 7; font-size: 12px; } -.voices-workbench.table-view .vl-tbl-dbfs { display: block; order: 8; font-size: 12px; font-family: monospace; } -.voices-workbench.table-view .vl-tbl-len { display: block; order: 9; font-size: 12px; font-family: monospace; } -.voices-workbench.table-view .vl-tbl-wpm { display: block; order: 10; font-size: 12px; font-family: monospace; } -.voices-workbench.table-view .vl-tbl-rating { display: flex; order: 11; font-size: 14px; color: var(--subtext); } +.voices-workbench.table-view .vl-tbl-lang { display: block; order: 4; font-size: 12px; } +.voices-workbench.table-view .vl-tbl-gender { display: block; order: 5; font-size: 12px; } +.voices-workbench.table-view .vl-tbl-len { display: block; order: 6; font-size: 12px; font-family: monospace; } +.voices-workbench.table-view .vl-tbl-dur { display: block; order: 7; font-size: 12px; font-family: monospace; } +.voices-workbench.table-view .vl-tbl-wpm { display: block; order: 8; font-size: 12px; font-family: monospace; } +.voices-workbench.table-view .vl-tbl-bench { display: block; order: 9; font-size: 12px; } +.voices-workbench.table-view .vl-tbl-seed { display: block; order: 10; font-size: 12px; font-family: monospace; } +.voices-workbench.table-view .vl-tbl-dbfs { display: block; order: 11; font-size: 12px; font-family: monospace; } +.voices-workbench.table-view .vl-tbl-type { display: block; order: 12; font-size: 12px; } +.voices-workbench.table-view .vl-tbl-source { display: block; order: 13; font-size: 12px; overflow: hidden; text-overflow: ellipsis; } +.voices-workbench.table-view .vl-tbl-rating { display: flex; order: 14; font-size: 14px; color: var(--subtext); } .voices-workbench.table-view .vl-tbl-rating .star.on { color: #f59e0b; } -.voices-workbench.table-view .vl-tbl-source { display: block; order: 12; font-size: 12px; overflow: hidden; text-overflow: ellipsis; } -.voices-workbench.table-view .vl-tbl-seed { display: block; order: 13; font-size: 12px; font-family: monospace; } -.voices-workbench.table-view .vl-tbl-note { display: block; order: 14; font-size: 12px; color: var(--subtext); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-style: italic; } -.voices-workbench.table-view .vl-tbl-tag { display: block; order: 15; font-size: 12px; color: var(--accent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; } -.voices-workbench.table-view .vl-tbl-active { display: block; order: 16; font-size: 16px; text-align: center; } +.voices-workbench.table-view .vl-tbl-tag { display: block; order: 15; font-size: 12px; color: var(--accent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; } +.voices-workbench.table-view .vl-tbl-note { display: block; order: 16; font-size: 12px; color: var(--subtext); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-style: italic; } +.voices-workbench.table-view .vl-tbl-active { display: block; order: 17; font-size: 16px; text-align: center; } .voices-workbench.table-edit-mode .vl-compact { background: rgba(37,99,235,0.03);