Never merge adjacent Unknown dialogue lines into one segment (v1.20.27)
Adjacent segments merge when they share a speaker, but an unattributed line carries the speaker "Unknown", so two consecutive Unknown lines compared as equal and were fused into a single block joined by a blank line. Confirmed against the source text: Lysandra's line and Perdia's interruption — two separate paragraphs in the book — became one segment, after which no attribution pass could separate them and one voice would read both sides of the exchange. "Unknown" means the speaker is not known, never that two lines share one. Narration and lines with a real speaker name merge exactly as before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
14ed0c89e7
commit
ca654608ac
@ -22,6 +22,11 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
|
||||
- **Emotion instructions are now always written in English**, even for non-English voices (the spoken text and the native-accent clause stay in the book's own language). Confirmed by controlled A/B testing — same line, same voice, only the instruct language varying — that Qwen3-TTS follows English emotion instructions far more reliably: German instructs produced barely-differentiated output, while English instructs yield a clean, correctly-ordered prosodic gradient (whisper 128 Hz → sad 142 → neutral 179 → scared 203 → happy 225 → angry 269 Hz), with sensible duration changes too (sad slowest, scared fastest).
|
||||
- **Fish-Speech generation parameters (`temperature` / `top_p` / `repetition_penalty`) were never forwarded.** Every Fish-Speech line synthesized at the server's fixed defaults, ignoring the app's per-backend stability settings — the only backend not routed through the shared `_apply_tts_extra_params` helper.
|
||||
|
||||
## [1.20.27] — 2026-08-12
|
||||
|
||||
### Fixed
|
||||
- **Two different characters' lines were being permanently fused into one segment.** Adjacent segments are merged when they share a speaker, but an unattributed line carries the speaker "Unknown" — so two consecutive Unknown lines compared as "the same speaker" and were joined into a single block. Confirmed against the source text: Lysandra's line and Perdia's interruption, two separate paragraphs in the book, became one segment, after which no attribution pass could separate them and a single voice would have read both sides of the exchange. "Unknown" means the speaker is *not known*, never that two lines share one, so Unknown dialogue lines are no longer merged. Narration and lines with a real speaker name merge exactly as before.
|
||||
|
||||
## [1.20.26] — 2026-08-12
|
||||
|
||||
### Fixed
|
||||
|
||||
2
static/dist/main.min.js
vendored
2
static/dist/main.min.js
vendored
File diff suppressed because one or more lines are too long
@ -10,7 +10,7 @@
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<meta name="theme-color" content="#2563EB">
|
||||
<meta name="app-version" content="1.20.26">
|
||||
<meta name="app-version" content="1.20.27">
|
||||
<link rel="manifest" href="/manifest.webmanifest">
|
||||
<link rel="icon" href="/static/icon.svg" type="image/svg+xml">
|
||||
<link rel="apple-touch-icon" href="/static/icon.svg">
|
||||
@ -27,7 +27,7 @@
|
||||
|
||||
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
|
||||
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
|
||||
<link rel="stylesheet" href="/static/style.css?v=1.20.26">
|
||||
<link rel="stylesheet" href="/static/style.css?v=1.20.27">
|
||||
|
||||
|
||||
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
||||
@ -378,7 +378,7 @@ window.toggleNavTree = function(treeId, chevronId) {
|
||||
</script>
|
||||
|
||||
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
||||
<script src="/static/loader.js?v=1.20.26"></script>
|
||||
<script src="/static/loader.js?v=1.20.27"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1020,7 +1020,15 @@ function _audiobookMergeAdjacentSameSpeaker(segments) {
|
||||
// Dialogue keeps its emotion tag distinct — merging "happy Marcus" text
|
||||
// into "angry Marcus" text would silently discard one of the two moods.
|
||||
const sameEmotion = s.type !== 'dialogue' || (last.emotion || '').toLowerCase() === (s.emotion || '').toLowerCase();
|
||||
if (lastSpeaker === curSpeaker && sameEmotion) {
|
||||
// Two adjacent UNKNOWN lines are not evidence of one speaker — "Unknown"
|
||||
// means precisely that we do not know who spoke. Both normalise to the
|
||||
// same string here, so they compared as equal and were fused into a single
|
||||
// block: confirmed live, Lysandra's line and Perdia's interruption (two
|
||||
// separate paragraphs in the book) became one segment joined by a blank
|
||||
// line, after which no attribution pass could ever separate them again and
|
||||
// one voice would read both sides of the exchange. Never merge on Unknown.
|
||||
const unknownSpeaker = !lastSpeaker || lastSpeaker === 'unknown' || lastSpeaker === 'unbekannt';
|
||||
if (lastSpeaker === curSpeaker && sameEmotion && !(s.type === 'dialogue' && unknownSpeaker)) {
|
||||
const lastText = last.text.trimEnd(), curText = s.text.trimStart();
|
||||
last.text = /[.!?…»«”"’']$/.test(lastText) ? lastText + '\n\n' + curText : lastText + ' ' + curText;
|
||||
continue;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user