Quality-first multi-pass audiobook generation from English manuscripts. Includes: - umbraaudio/ core package (pipeline, config, voices, web review UI) - scripts/ CLI utilities + model download script - tts_server/ remote TTS server - specs/ design docs, tests/, pyproject.toml + uv.lock - Qwen3-TTS git submodule (pinned 022e286) with local demo.py UI patch saved at scripts/qwen3_tts_demo_umbra_patch.patch - .env with runtime config/secrets Excluded (see .gitignore): models/ (downloaded via scripts/download_models.sh), output/, logs/, .venv, .umbra runtime data, and book projects (DealHunterShip_*), which are committed separately.
104 lines
4.2 KiB
Python
104 lines
4.2 KiB
Python
"""Quick verification of segmenter fixes."""
|
|
from __future__ import annotations
|
|
|
|
from umbraaudio.mapping.segmenter import Segmenter
|
|
|
|
|
|
def test_apostrophe_hold_em():
|
|
"""Hold 'em with U+2018 apostrophe should not create false dialogue."""
|
|
seg = Segmenter()
|
|
apostrophe = "\u2018"
|
|
text = (
|
|
"This style of poker has been known by many names over the years. "
|
|
"In this pirate casino, it is called Pirate Hold " + apostrophe + "em. "
|
|
"The initial ante-up bet is done with a dealer puck."
|
|
)
|
|
utts = seg.segment(text, 1, character_names=["Kainda"])
|
|
print("Test 1: Hold 'em apostrophe fix")
|
|
for u in utts:
|
|
print(f" type={u['type']}, speaker={u.get('character_name')}: {u['text'][:80]}")
|
|
assert all(u["type"] == "narration" for u in utts), "FAIL: Should be all narration"
|
|
print("PASS\n")
|
|
|
|
def test_about_the_author_meta_chapter():
|
|
"""About the author chapters should not create dialogue-type utterances."""
|
|
seg = Segmenter()
|
|
left_double = "\u201c"
|
|
right_double = "\u201d"
|
|
em_dash = "\u2014"
|
|
apostrophe = "\u2019"
|
|
text = (
|
|
"B.D. Murphy started writing. If you like techy thrillers, "
|
|
f"and endings that make you say {left_double}wait, WHAT?{right_double}"
|
|
f"{em_dash}he{apostrophe}s your guy."
|
|
)
|
|
utts = seg.segment(text, 1, character_names=["Kainda"], chapter_title="About the author")
|
|
print("Test 2: About the author (special chapter type)")
|
|
for u in utts:
|
|
print(f" type={u['type']}, speaker={u.get('character_name')}: {u['text'][:80]}")
|
|
assert all(u["type"] == "narration" for u in utts), "FAIL: Should be all narration"
|
|
assert all(u["character_name"] == "narrator" for u in utts), "FAIL: Should be narrator"
|
|
print("PASS\n")
|
|
|
|
def test_bracket_about_author_title():
|
|
seg = Segmenter()
|
|
left_double = "\u201c"
|
|
right_double = "\u201d"
|
|
em_dash = "\u2014"
|
|
apostrophe = "\u2019"
|
|
text = (
|
|
f"endings that make you say {left_double}wait, WHAT?"
|
|
f"{right_double}{em_dash}he{apostrophe}s your guy."
|
|
)
|
|
utts = seg.segment(text, 1, character_names=["Kainda"], chapter_title="[about author]")
|
|
print("Test 3: [about author] title")
|
|
for u in utts:
|
|
print(f" type={u['type']}, speaker={u.get('character_name')}: {u['text'][:80]}")
|
|
assert all(u["type"] == "narration" for u in utts), "FAIL: Should be all narration"
|
|
print("PASS\n")
|
|
|
|
def test_real_curly_dialogue_still_works():
|
|
seg = Segmenter()
|
|
left_double = "\u201c"
|
|
right_double = "\u201d"
|
|
text = f"{left_double}How are you feeling, Princess?{right_double}"
|
|
utts = seg.segment(text, 1, character_names=["Nanny", "Kainda"])
|
|
print("Test 4: Real curly-quoted dialogue still works")
|
|
for u in utts:
|
|
print(f" type={u['type']}, speaker={u.get('character_name')}: {u['text'][:80]}")
|
|
assert any(u["type"] == "dialogue" for u in utts), "FAIL: Should have dialogue"
|
|
print("PASS\n")
|
|
|
|
def test_single_quote_proper_closing():
|
|
seg = Segmenter()
|
|
left_single = "\u2018"
|
|
right_single = "\u2019"
|
|
text = f"{left_single}Hello,{right_single} said the captain."
|
|
utts = seg.segment(text, 1, character_names=["Captain"])
|
|
print("Test 5: Single-quote dialogue with proper closing")
|
|
for u in utts:
|
|
print(f" type={u['type']}, speaker={u.get('character_name')}: {u['text'][:80]}")
|
|
assert any(u["type"] == "dialogue" for u in utts), "FAIL: Should have dialogue"
|
|
print("PASS\n")
|
|
|
|
def test_title_metadata_not_dialogue():
|
|
seg = Segmenter()
|
|
left_double = "\u201c"
|
|
right_double = "\u201d"
|
|
text = f"[default accent = {left_double}Canadian{right_double}]"
|
|
utts = seg.segment(text, 1, character_names=["Kainda"], chapter_title="Title")
|
|
print("Test 6: Title page with metadata bracket")
|
|
for u in utts:
|
|
print(f" type={u['type']}, speaker={u.get('character_name')}: {u['text'][:80]}")
|
|
assert all(u["type"] == "narration" for u in utts), "FAIL: Should be all narration"
|
|
print("PASS\n")
|
|
|
|
if __name__ == "__main__":
|
|
test_apostrophe_hold_em()
|
|
test_about_the_author_meta_chapter()
|
|
test_bracket_about_author_title()
|
|
test_real_curly_dialogue_still_works()
|
|
test_single_quote_proper_closing()
|
|
test_title_metadata_not_dialogue()
|
|
print("All segmenter fix tests passed!")
|