fix(tts/kokoro-ane): stem possessives instead of G2P-ing the whole token - #884
Conversation
|
Calling For example, I reproduced both against the parent commit using the real cached lexicon. Could we preserve explicit possessive entries for compound components before deriving their pronunciation, and add regression tests for these cases? |
|
Good catch, and thank you for reproducing it against the real cache. The lexicon does carry glued The follow-up commit splits hyphenated compounds before the possessive rule, so a part with its own glued entry wins ( |
|
Thanks, the Add one step between the whole-token miss and the hyphen split: if the token ends in |
|
Addressed in 85d1f8a. After a whole inflected-token miss, hyphenated possessives now probe the whole stem directly in the custom and bundled lexicons, preserving their existing lookup precedence. This probe cannot split, recurse, or call G2P. Only a whole-stem miss proceeds to component resolution, so Added regressions for Validation: the new whole-compound regressions failed on the previous head and pass with this change; all 70 related Kokoro ANE and StyleTTS2 phonemizer tests pass. A separate local sweep against the real cached US lexicon passed for 3,726 tokenizable compound stems and 372 explicit possessives, with no G2P fallback. Formatting and whitespace checks also pass. This validates phoneme resolution; it is not an audio listening or end-to-end synthesis claim. |
The Misaki lexicon stores the `-s` clitic as its own `'s` entry and carries no glued possessive keys, so `today's` / `someone's` / `the boss's` miss every lexicon tier in `KokoroAneEnglishPhonemizer.resolveWord` and the whole inflected token reaches the BART G2P fallback, which mangles it (`someone's` was heard as "Samian's" in a whisper transcription of the rendered audio). Python Misaki does not have this problem because `Lexicon.__call__` falls through to `stem_s`: the stem is looked up on its own and the clitic phoneme is appended by rule. This ports that rule. After a full lexicon miss (and after the FluidInference#710 initialism spell-out), a token ending in `'s` — case-insensitively, and post the FluidInference#774 apostrophe folding, so `Today's`, `TODAY'S` and `Today\u{2019}s` all qualify — resolves its stem through the normal chain minus the G2P fallback, then appends the clitic per `Lexicon._s`: * `/s/` after a voiceless non-sibilant (`p t k f θ`) — `cat's` -> `kˈæts` * `/ᵻz/` after a sibilant (`s z ʃ ʒ ʧ ʤ`) — `boss's` -> `bˈɑsᵻz` * `/z/` otherwise — `today's` -> `tədˈAz` `ᵻ` is Misaki's US form of the epenthetic vowel (`ɪ` is the `british=True` form); this frontend loads the US lexicon and `ᵻ` is present in the chain's `vocab.json`. Faithful to `stem_s`, the rule only fires when the stem is a *known* word, so an OOV stem leaves the token on the existing whole-word G2P path rather than being re-shaped from a guess. The stem going through the normal chain means FluidInference#775's hyphen split still applies underneath the clitic (`mother-in-law's` -> `mˈʌðɜɹ ɪn lˈɔz`), and a glued lexicon entry that does exist (`it's`) still wins, because stemming runs only after the miss. `resolveWord` / `resolveHyphenatedCompound` gain an `allowFallback` flag (defaulting to today's behavior) to express "resolve, but only if known". Tests: voiced / voiceless / sibilant / vowel-final stems, curly apostrophe, uppercase `'S` with a case-sensitive stem, hyphenated-compound stem, OOV-stem fallback, lexicon-entry precedence, and a direct table check of the clitic rule against `Lexicon._s`. `swift build`, `swift test --filter TTS` (57 tests) and `swift-format lint` are clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ssives The `-'s` stem+clitic rule was placed before the hyphenated-compound split in `resolveWord`, which broke lexicon precedence for compounds whose final part has a glued possessive entry of its own. The US lexicon carries 347 glued `-'s` keys, mostly noun/verb heteronyms whose possessive does not read as the bare word plus a clitic: use = jˈuz use's = jˈusᵻz produce = pɹədˈus produce's = pɹˈOdˌusᵻz With the possessive rule first, `land-use's` stemmed to `land-use`, split to `land` + `use`, and picked up the *verb* reading plus a clitic. Running the hyphen split first restores the pre-existing behaviour: parts are `land` + `use's`, and `use's` hits its own entry directly. Same for `fresh-produce's`. Compounds with no glued entry are unaffected, because each part is resolved through the same chain: `mother-in-law's` splits to `mother`, `in`, `law's`; `law's` misses, recurses, and stems to `law` + /z/. Adds regression tests for both heteronym compounds (they fail on the previous ordering) and updates the ordered resolution doc-comment.
85d1f8a to
35ffe11
Compare
Problem
Kokoro ANE sends ordinary possessives absent from Misaki's lexicon to neural G2P as whole tokens, which can produce incorrect pronunciations. Derive known stems with the appropriate /s/, /ᵻz/, or /z/ clitic while preserving explicit dictionary pronunciations.
Resolution order
C-section'sandmother-in-law's. The probe cannot recurse, split, or invoke G2P.use'sandproduce'snoun readings inland-use'sandfresh-produce's.Apostrophe variants are folded before tokenization. The change is confined to possessive
's; it does not add general plural stemming.Validation
git diff --checkpass.Validation covers phoneme resolution; no new audio listening or end-to-end synthesis evaluation is claimed.