Kitten Text Processing
A standalone multilingual written-to-spoken normalizer with zero runtime dependencies. It uses Python's standard library to interpret bundled NeMo 1.2.0 grammar data. No NeMo, Pynini, OpenFst, models, network access, or grammar compilation is needed when installing or running the library.
pip install kitten-text-processing
python -m kitten_text_processing --lang en 'I paid $12.50 for 3 books.'
from kitten_text_processing import normalize_text, warm, Normalizer
warm() # optional; load English ahead of the first call
normalize_text('I paid $12.50 for 3 books.')
# 'I paid twelve dollars fifty cents for three books.'
normalize_text('Tengo 2 gatos.', locale='es-ES')
# 'Tengo dos gatos.'
normalizer = Normalizer(input_case='cased', lang='ja')
normalizer.normalize('猫が2匹います。', punct_post_process=True)
Languages: en es fr de pt it zh ja ko hi ar ru vi hu sv hy rw.
Locale tags such as en-US, pt-BR, zh-CN, and hi_IN select the corresponding
language grammar; they do not select separate regional grammars. Python 3.10+.
Convenience API
normalize_text(text, locale='en-US', return_spans=False) normalizes text and
cleans up punctuation. warm(locale='en-US') preloads a language grammar.
PRESERVES_SENTINELS indicates that private-use expression markers are retained.
return_spans=True raises NotImplementedError. Empty values are preserved by
normalize_text; Normalizer.normalize requires a string. Unsupported languages
raise ValueError.
Design and scope
The runtime is Python code plus about 14 MB of compressed, portable grammar arrays. It runs weighted byte transducers over UTF-8, parses the classified tokens, tries the upstream field-order permutations, then verbalizes and applies punctuation cleanup. Grammars are loaded lazily per language. The convenience API retains at most four normalizers; explicit instances let callers control lifetime. Instances are safe to call concurrently. Normalize sentence-sized chunks: ambiguous long inputs can build large intermediate lattices.
The cased written-to-spoken grammars from the pinned NeMo release are included.
Inverse normalization, audio rescoring, custom whitelists, grammar compilation,
and separate lower_cased grammar variants are outside this package's scope.
Korean and Armenian also accept lower_cased: their upstream graphs were verified
to be identical to their cased graphs.
Russian uses NeMo's non-deterministic grammar and chooses a minimum-weight
reading; this is not a context-sensitive grammatical disambiguator.
Upstream limitations remain visible. In particular, Portuguese and Kinyarwanda can reject ordinary inputs; a no-path error is raised rather than silently claiming successful normalization. Some upstream outputs leave digits intact or choose linguistically awkward readings. Compatibility is not a claim of perfect linguistic correctness for all inputs.
Validation and reproduction
For development, clone the repository and install locally with pip install ..
The tests/corpus directory contains 1,000 manually authored input sentences
across all 17 supported languages and separately recorded NeMo outputs. This is
a regression corpus, not an untouched holdout or native-speaker quality audit.
# Standard-library-only checks and comparison with frozen reference outputs
python -m unittest discover -s tests -v
python tools/benchmark.py
# Build-time/reference tooling only (never runtime dependencies)
python -m venv .venv-reference
.venv-reference/bin/pip install -r tools/requirements-reference.txt
.venv-reference/bin/python tools/export_grammars.py
.venv-reference/bin/python tools/benchmark.py --record-reference
Expanded comparison: 22,976 exact outputs and 1,435 matching rejections, with zero mismatches across 24,411 cases. Validation also includes the original 1,000 authored sentences, every one of the 5,407 upstream fixture inputs, and over 1,000 additional generated/edge cases per language. Accepted outputs must match exactly; matching rejections are counted separately. There are 18 original fixture expectations that NeMo itself disagrees with; these remain unchanged and are explicitly recorded. Audio/n-best fixture inputs are included, but audio rescoring is outside our scope. See upstream provenance.
The optimized engine is 1.8–7.8× faster than the previous implementation on our
warm-call benchmark. English improved from 65.7 to 23.8 ms per sentence (NeMo:
7.7 ms); speed relative to NeMo varies by language. Measurements use 20
sentences per language, three repetitions, warmed grammar indexes, and rotating
execution order. Run tools/speed_benchmark.py in the reference environment to
produce a local report. Generated benchmark results are excluded from Git.
Grammar metadata records state/arc counts, upstream version, settings, and SHA-256 hashes.
The exporter skips already exported languages; to rebuild one, remove its
metadata.json and pass --languages en (or another language).
To regenerate the expanded oracle suite (development dependencies required):
.venv-reference/bin/python tools/stress_test.py --case-source upstream --count 0 --output .cache/upstream-canonical
.venv-reference/bin/python tools/stress_test.py --case-source generated --seed 20261002 --count 1000 --output .cache/generated-canonical
python tools/freeze_extended.py .cache/upstream-canonical .cache/generated-canonical
.venv-reference/bin/python tools/speed_benchmark.py
The package and NeMo-derived grammar data use Apache-2.0. Frozen Sacremoses
Unicode tables use MIT. See LICENSE, LICENSE-SACREMOSES, and NOTICE for
provenance and retained notices.
Release files for kitten-text-processing 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| kitten_text_processing-0.1.0.tar.gz | 9.8 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kitten_text_processing-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 18.8 MB
Release files / kitten_text_processing-0.1.0.tar.gz
| Download URL | kitten_text_processing-0.1.0.tar.gz |
|---|---|
| Size | 9.8 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
14f7d2855c20b4047d6acbb73b1e1c7f1e9fd49b956b2e39f2bd7ff537ec1b31
|
|
BLAKE2b-256 checksum How to use checksums |
3858d6942dd0c15a3f47957c745e3052ecbf92628eb0e393043c7806253d795a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.7
|
Release files / kitten_text_processing-0.1.0-py3-none-any.whl
| Download URL | kitten_text_processing-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.0 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a88f0cc878abf81948ed5106d8f1e86d0f4a458a611cb4f50053b4c21075f829
|
|
BLAKE2b-256 checksum How to use checksums |
742e6ed3b03410ef32a490ac0076108883f0507c2fabccb1a1d6ca971de158ec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.7
|