diff --git a/stackvox/text.py b/stackvox/text.py index e272b29..8cff294 100644 --- a/stackvox/text.py +++ b/stackvox/text.py @@ -65,6 +65,7 @@ def strip_emoji(text: str) -> str: (r"\s*÷\s*", " divided by "), (r"\s*×\s*", " times "), (r"\s*=\s*", " equals "), + (r"~\s*(?=\d)", "about "), # ~123 -> "about 123" (else espeak says "tilde 123"); leaves ~/path alone ], } DEFAULT_LOCALE = "en-GB" @@ -183,6 +184,13 @@ def apply_pronunciations(text: str, mapping: dict[str, str] | None) -> str: "postgresql": "postgres", "kubectl": "kube control", "stackone": "stack one", # org name espeak garbles as "stac kone" + # "dedupe" glued reads as "de-dup" (short u); split + long "dee" gives "dee doop". + # Inflections listed explicitly — apply_pronunciations matches whole words only. + "dedupe": "dee dupe", + "deduped": "dee duped", + "deduping": "dee duping", + "dedupes": "dee dupes", + "dedup": "dee dupe", } diff --git a/tests/test_text.py b/tests/test_text.py index 161ca2f..bf6e11c 100644 --- a/tests/test_text.py +++ b/tests/test_text.py @@ -113,6 +113,20 @@ def test_math_symbols(): assert expand_units("770 ÷ 2 × 3 = 5").strip() == "770 divided by 2 times 3 equals 5" +def test_tilde_before_number_is_approximately(): + assert expand_units("~123") == "about 123" + assert expand_units("~ 50 items") == "about 50 items" + + +def test_tilde_not_before_number_is_left_alone(): + # home dir / approx-equal — not an approximated quantity + assert expand_units("~/projects") == "~/projects" + + +def test_tilde_approx_end_to_end_with_decimal(): + assert normalize_for_speech("took ~1.5 hours", markdown=False) == "took about 1 point 5 hours." + + def test_unknown_locale_falls_back_to_en_gb(): assert expand_units("£5", locale="xx-YY") == "5 pounds" @@ -306,6 +320,18 @@ def test_dev_terms_leave_correctly_voiced_acronyms_alone(): assert "API" in out +def test_dedupe_respelled_for_speech(): + assert normalize_for_speech("dedupe the list", markdown=False) == "dee dupe the list." + # inflections and case + assert "dee duped" in normalize_for_speech("we Deduped it", markdown=False) + assert "dee duping" in normalize_for_speech("deduping now", markdown=False) + + +def test_dedupe_does_not_touch_other_words(): + # whole-word only — must not rewrite the middle of a longer token + assert "dee dupe" not in normalize_for_speech("dedupelicated", markdown=False) + + def test_dev_terms_can_be_disabled(): assert normalize_for_speech("Use the CLI.", markdown=False, dev_terms=False) == "Use the CLI."