Skip to main content

A lightweight, explainable semantic TTS normalizer for Python apps and voice-agent pipelines.

Project description

Utterwise

Utterwise is a lightweight semantic text normalizer for Python voice assistants, TTS apps, tutoring tools, and small developer projects.

It exists because compact TTS models often read useful assistant text badly: versions, dates, money, temperatures, URLs, formulas, and ambiguous numbers can sound strange unless they are normalized first.

from utterwise import normalize

normalize("Call 911 if it reaches 25°C on 03/04/2026.")

# Output:
# "Call nine one one if it reaches twenty five degrees Celsius on third of April twenty twenty six"

Install

pip install utterwise

Math and LaTeX parser support is optional:

pip install "utterwise[math]"

For local development with uv:

.venv\Scripts\uv.exe sync --extra dev --extra math

Quick Start

from utterwise import explain, explain_pretty, normalize, normalize_ssml

normalize("Python 3.12 costs $12.50 on Jan 3, 2026")
normalize_ssml("hello@example.com")
explain("Flight 911 departs at 6")
print(explain_pretty("Call 911 immediately"))

Examples

Input Output
Born in 1998 Born in nineteen ninety eight
The value is 1998 The value is one thousand nine hundred ninety eight
Call 911 immediately Call nine one one immediately
Flight 911 departs at 6 Flight nine eleven departs at six
Python 3.12 Python three point twelve
25°C twenty five degrees Celsius
$12.50 twelve dollars and fifty cents
03/04/2026 third of April twenty twenty six
https://openai.com open ai dot com
x^2 x squared
\frac{a+b}{c} a plus b over c

Why Not Just Regex?

Regex can replace symbols, but it cannot reliably decide what something means. Utterwise keeps candidates and uses context before verbalizing.

Call 911 immediately      -> nine one one
Flight 911 departs at 6   -> nine eleven
911 divided by 3 is 303   -> nine hundred eleven

That distinction is the point of the project: small, deterministic, explainable normalization before text reaches a speech model.

Supported Features

Feature Status Example
Numbers and years Supported 2024, 42
Contextual ambiguity Supported 911, 1998
URLs and emails Supported https://openai.com, hello@example.com
Versions Supported Python 3.12, v3.12
Phones Supported 9876543210, +1-800-555-0100
Acronyms Supported NASA, HTTP
Percentages Supported 12.5%
Temperatures Supported 25°C, 98.6°F
Currency Supported $12.50, €45, £9.99
Dates Supported Jan 3, 2026, 2026-04-03, 03/04/2026
Math and LaTeX Optional extra x^2, \sqrt{x+1}
SSML Minimal <speak>...</speak>

Slash dates use day/month/year by default.

Explain Mode

from utterwise import explain

explain("Call 911 immediately")

Returns a dictionary with the normalized output, detection flags, token spans, candidates, winner, rule chain, signals, confidence, and metadata.

For humans, use:

from utterwise import explain_pretty

print(explain_pretty("Call 911 immediately"))

Example shape:

raw          type   spoken         rule                     conf
-----------  -----  -------------  -----------------------  ----
Call         WORD   Call           identity                 1.00
911          PHONE  nine one one   verb_call_before_number  0.94
immediately  WORD   immediately    identity                 1.00

Runtime Configuration

Use NormalizeConfig or convenience keyword flags to disable optional semantic normalizers at runtime.

from utterwise import NormalizeConfig, normalize

normalize("x^2", enable_math=False)

config = NormalizeConfig(enable_currency=False, enable_dates=False)
normalize("$12.50 on 03/04/2026", config=config)

CLI

utterwise "Call 911 immediately"
utterwise --ssml "hello@example.com"
utterwise --explain "Flight 911 departs at 6"
utterwise --pretty 'Python 3.12 costs $12.50'

Limitations

  • Utterwise is deterministic and rule-based; confidence scores are rule confidence, not statistical probabilities.
  • Date parsing uses day/month/year for slash dates.
  • SSML output is currently minimal.
  • Chemistry normalization, rich policy-specific SSML, and locale-aware date formatting are planned for later.

Development

Run tests with:

.venv\Scripts\uv.exe run --extra dev pytest
.venv\Scripts\python.exe -m pytest

Run the interactive development menu:

.venv\Scripts\python.exe tests\menu.py

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

utterwise-0.1.0.tar.gz (25.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

utterwise-0.1.0-py3-none-any.whl (30.6 kB view details)

Uploaded Python 3

File details

Details for the file utterwise-0.1.0.tar.gz.

File metadata

  • Download URL: utterwise-0.1.0.tar.gz
  • Upload date:
  • Size: 25.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for utterwise-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4d051d8fd4dca3ffaec968cc7fad01f18b5bdf023fb119d6efbb0d74b4abf945
MD5 64e1f5f13ba710730ce4b369850fded8
BLAKE2b-256 4d49b3b2109064cc92bc856e2768b522b63424e9a022a0f7e858196d3450484d

See more details on using hashes here.

File details

Details for the file utterwise-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: utterwise-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 30.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for utterwise-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 abd3c61d3e16700dfbc281556fa818dad4b34931247f7217639e57f26880d156
MD5 731d84d3bad589b6f5010b6c9a5ab6d7
BLAKE2b-256 87ef85bd058af6e97ca04914282135dbc14e61f753cf5f5318addeea00d81fc5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page