Files
UmbraAudio/tests/test_web_proper_names.py
B.D. Murphy c86e323d7a Initial commit: UmbraAudio audiobook generation program
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.
2026-08-30 07:58:24 -07:00

112 lines
3.6 KiB
Python

from __future__ import annotations
from umbraaudio.web.routes import (
_extract_proper_nouns,
_lowercase_words,
_mid_sentence_counts,
_proper_name_candidates,
_speaker_name_words,
)
_TEXT = (
"Kainda walked in. Princess Kainda Murphy smiled. The Warbots roared. "
"They went there and they left after what happened. "
"Wow, that is odd. Additionally, I have a plan. "
"Captain Weston spoke. Weston is a friend. The ship is the Deal Hunter. "
"Gisfrid arrived. Karel waited. It was a good deal, the captain said to the princess."
)
_SPEAKERS = [
{"primary_name": "Kainda Walters Foster Murphy", "aliases": ["Princess Kainda"]},
{"primary_name": "Captain Weston", "aliases": []},
{"primary_name": "Deal Hunter", "aliases": []},
{"primary_name": "Gisfrid", "aliases": []},
]
def _records() -> dict:
return {
"Kainda": {"phonetic": "KAYN-duh", "source": "user", "confirmed": True, "common": False},
}
def test_extract_proper_nouns_flattens_multiword() -> None:
nouns = {entry["name"]: entry["count"] for entry in _extract_proper_nouns(_TEXT)}
assert "Princess Kainda Murphy" not in nouns
assert "Captain Weston" not in nouns
assert nouns["Kainda"] == 2
assert nouns["Murphy"] == 1
assert nouns["Weston"] == 2
def test_extract_proper_nouns_excludes_titles_and_stopwords() -> None:
nouns = {entry["name"] for entry in _extract_proper_nouns(_TEXT)}
assert "Captain" not in nouns
assert "Princess" not in nouns
assert "The" not in nouns
assert "It" not in nouns
def test_lowercase_words_only_literal_lowercase() -> None:
words = _lowercase_words(_TEXT)
assert "they" in words
assert "after" in words
assert "deal" in words
assert "kainda" not in words
assert "murphy" not in words
def test_mid_sentence_counts() -> None:
counts = _mid_sentence_counts(_TEXT, {"Kainda", "Weston", "Wow", "Gisfrid"})
assert counts["Kainda"] == 1
assert counts["Weston"] >= 1
assert counts.get("Wow", 0) == 0
assert counts.get("Gisfrid", 0) == 0
def test_speaker_name_words_excludes_descriptors() -> None:
words = _speaker_name_words(_SPEAKERS, _lowercase_words(_TEXT))
assert "kainda" in words
assert "murphy" in words
assert "weston" in words
assert "gisfrid" in words
assert "captain" not in words
assert "princess" not in words
def test_proper_name_candidates_keeps_names() -> None:
kept = {
entry["name"]: entry
for entry in _proper_name_candidates(
_extract_proper_nouns(_TEXT), _TEXT, _SPEAKERS, _records()
)
}
for name in ("Kainda", "Murphy", "Warbots", "Weston", "Hunter", "Gisfrid"):
assert name in kept, f"{name} should be kept"
assert kept["Kainda"]["is_speaker"] is True
assert kept["Murphy"]["is_speaker"] is True
assert kept["Gisfrid"]["is_speaker"] is True
def test_proper_name_candidates_drops_prose() -> None:
kept = {
entry["name"]
for entry in _proper_name_candidates(
_extract_proper_nouns(_TEXT), _TEXT, _SPEAKERS, _records()
)
}
for name in ("They", "After", "What", "That", "Wow", "Additionally", "Deal", "Karel"):
assert name not in kept, f"{name} should be dropped"
def test_proper_name_candidates_keeps_confirmed_name() -> None:
records = _records()
records["Karel"] = {"phonetic": "KAH-rel", "source": "user", "confirmed": True, "common": False}
kept = {
entry["name"]
for entry in _proper_name_candidates(
_extract_proper_nouns(_TEXT), _TEXT, _SPEAKERS, records
)
}
assert "Karel" in kept