Module agents.tokenize.verbalize
Functions
def expand_cardinals(text: str, *, language: str) ‑> str-
Expand source code
def expand_cardinals(text: str, *, language: str) -> str: """Verbalize standalone cardinal numbers (≥100 or comma-grouped). Skips 4-digit years (1700–2099) and numbers inside ``<spell>…</spell>``. Decimals are read as "integer point digit-digit". """ lang = (language or "en").lower() verb = _pick_verbalizer(lang) def _sub(m: re.Match[str]) -> str: int_part, frac, suffix = m.group(1), m.group(2), m.group(3) digits_only = int_part.replace(",", "") if ( not frac and not suffix and "," not in int_part and len(digits_only) == 4 and 1700 <= int(digits_only) <= 2099 ): return m.group(0) if frac and all(d == "0" for d in frac): frac = None if frac and not suffix: return verbalize_decimal(int_part, frac, lang) value, _ = _expand_scale(int_part, frac, suffix) return verb(value) return _apply_outside_spell(text, lambda t: _CARDINAL_RE.sub(_sub, t))Verbalize standalone cardinal numbers (≥100 or comma-grouped).
Skips 4-digit years (1700–2099) and numbers inside
<spell>…</spell>. Decimals are read as "integer point digit-digit". def expand_currency(text: str, *, language: str, hint: str | None) ‑> str-
Expand source code
def expand_currency(text: str, *, language: str, hint: str | None) -> str: """Replace ``$500,000`` / ``₹10,00,000`` with spoken form. All-zero fractional parts (``₹50,00,000.00``, ``$1,000.00``) are dropped: voice agents should not read "fifty lakh point zero zero rupees" when the intent is just "fifty lakh rupees". LLMs (especially Gemini) routinely append ``.00`` to round rupee/dollar amounts — treat it as display formatting, not spoken content. """ lang = (language or "en").lower() verb = _pick_verbalizer(lang) def _sub(m: re.Match[str]) -> str: symbol, int_part, frac, suffix = m.group(1), m.group(2), m.group(3), m.group(4) currency_word = _resolve_currency_word(symbol, hint, lang) if frac and all(d == "0" for d in frac): frac = None if frac and not suffix: number_words = verbalize_decimal(int_part, frac, lang) else: value, _ = _expand_scale(int_part, frac, suffix) number_words = verb(value) if currency_word: return f"{number_words} {currency_word}" return number_words return _apply_outside_spell(text, lambda t: _CURRENCY_AMOUNT_RE.sub(_sub, t))Replace
$500,000/₹10,00,000with spoken form.All-zero fractional parts (
₹50,00,000.00,$1,000.00) are dropped: voice agents should not read "fifty lakh point zero zero rupees" when the intent is just "fifty lakh rupees". LLMs (especially Gemini) routinely append.00to round rupee/dollar amounts — treat it as display formatting, not spoken content. def verbalize_decimal(int_part: str, frac_part: str, lang: str) ‑> str-
Expand source code
def verbalize_decimal(int_part: str, frac_part: str, lang: str) -> str: """Verbalize a decimal like ``3.5`` → ``three point five``. The fractional part is read digit-by-digit (so ``3.14`` → ``three point one four``) which is the natural spoken form for non-money decimals. """ int_val = int(int_part.replace(",", "")) if int_part else 0 verb = _pick_verbalizer(lang) head = verb(int_val) if frac_part: return f"{head} {_point_word(lang)} {_digit_words(frac_part, lang)}" return headVerbalize a decimal like
3.5→three point five.The fractional part is read digit-by-digit (so
3.14→three point one four) which is the natural spoken form for non-money decimals. def verbalize_en(n: int) ‑> str-
Expand source code
def verbalize_en(n: int) -> str: """Return English cardinal words for an integer.""" if n == 0: return "zero" sign = "" if n < 0: sign = "minus " n = -n groups: list[int] = [] while n > 0: n, r = divmod(n, 1000) groups.append(r) parts: list[str] = [] for i in range(len(groups) - 1, -1, -1): g = groups[i] if g == 0: continue words = _en_under_1000(g) if i < len(_EN_SCALES) and _EN_SCALES[i]: parts.append(f"{words} {_EN_SCALES[i]}") else: parts.append(words) return sign + " ".join(parts)Return English cardinal words for an integer.
def verbalize_gu(n: int) ‑> str-
Expand source code
def verbalize_gu(n: int) -> str: """Gujarati cardinal words via Indian grouping (હજાર / લાખ / કરોડ).""" return _indic_verbalize( n, zero_to_99=_GU_0_99, hundred=_GU_HUNDRED, thousand=_GU_THOUSAND, lakh=_GU_LAKH, crore=_GU_CRORE, arab=_GU_ARAB, neg_prefix="ઓછું", )Gujarati cardinal words via Indian grouping (હજાર / લાખ / કરોડ).
def verbalize_hi(n: int) ‑> str-
Expand source code
def verbalize_hi(n: int) -> str: """Hindi cardinal words via Indian grouping (हज़ार / लाख / करोड़).""" return _indic_verbalize( n, zero_to_99=_HI_0_99, hundred=_HI_HUNDRED, thousand=_HI_THOUSAND, lakh=_HI_LAKH, crore=_HI_CRORE, arab=_HI_ARAB, neg_prefix="ऋण", )Hindi cardinal words via Indian grouping (हज़ार / लाख / करोड़).
def verbalize_mr(n: int) ‑> str-
Expand source code
def verbalize_mr(n: int) -> str: """Marathi cardinal words via Indian grouping (हजार / लाख / कोटी).""" return _indic_verbalize( n, zero_to_99=_MR_0_99, hundred=_MR_HUNDRED, thousand=_MR_THOUSAND, lakh=_MR_LAKH, crore=_MR_CRORE, arab=_MR_ARAB, neg_prefix="उणे", )Marathi cardinal words via Indian grouping (हजार / लाख / कोटी).