fix(tts/kokoro-ane): stem possessives instead of G2P-ing the whole token - #884
Open
akmittal006 wants to merge 1 commit into
Open
fix(tts/kokoro-ane): stem possessives instead of G2P-ing the whole token#884akmittal006 wants to merge 1 commit into
akmittal006 wants to merge 1 commit into
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Misaki lexicon stores the
-sclitic as its own'sentry and carries noglued possessive keys, so
today's,someone'sandthe boss'smiss everylexicon tier in
KokoroAneEnglishPhonemizer.resolveWordand the whole inflectedtoken reaches the BART G2P fallback, which mangles it.
Rendered and transcribed with
whisper.cppggml-small.en:Someone's coat is here.Today's plan is simple.the boss's officethe cat's bowlPython Misaki does not have this problem because
Lexicon.__call__fallsthrough to
stem_s: the stem is looked up on its own and the clitic phoneme isappended by rule. This ports that rule.
The rule
After a full lexicon miss (and after the #710 initialism spell-out), a token
ending in
's— case-insensitively, and after the #774 apostrophe folding, soToday's,TODAY'SandToday’sall qualify — resolves its stem through thenormal chain and appends the clitic per
Lexicon._s:p t k f θ/s/cat's→kˈætss z ʃ ʒ ʧ ʤ/ᵻz/boss's→bˈɑsᵻz/z/today's→tədˈAzᵻis Misaki's US form of the epenthetic vowel (ɪis thebritish=Trueform). This frontend loads the US lexicon and
ᵻis present in the chain'svocab.json, so the US form is the correct one here.Scope, deliberately narrow
Faithful to
stem_s, the rule fires only when the stem is a known word, soan OOV stem leaves the token on the existing whole-word G2P path rather than
being re-shaped from a guess. Because the stem goes through the normal chain,
#775's hyphen split still applies underneath the clitic
(
mother-in-law's→mˈʌðɜɹ ɪn lˈɔz), and a glued entry that does exist(
it's) still wins, since stemming runs only after the miss.Contractions are unaffected in practice —
it's,he's,that'sare lexiconentries — and where one is not, the clitic rule gives the phonologically
identical result, since the
is/hasclitic and the possessive share the-sphonology.resolveWord/resolveHyphenatedCompoundgain anallowFallbackflag(defaulting to today's behavior) to express "resolve, but only if known".
Only
stem_s's'sbranch is ported. Misaki'sword.endswith("s'")andtrailing-
'branches are unreachable here:splitWordsonly keeps anapostrophe word-internally, so a trailing apostrophe is already emitted as its
own punctuation token. The
es/iesplural branches are a separate change.Tests
Adds coverage for voiced / voiceless / sibilant / vowel-final stems, curly
apostrophe, uppercase
'Swith a case-sensitive stem, a hyphenated-compoundstem, 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, incl. 40 phonemizer) andswift-format lintare clean.