This release is a pre-release and may not be stable for production use.
espyak
espyak is a pure-Python reimplementation of espeak-ng's
grapheme-to-phoneme (G2P) front-end. It converts text to phonemes only: no synthesis, no
audio, no C extension, no runtime dependencies.
espyakreproduces theespeak-ngbinary (pinned 1.52.0) byte-for-byte. The full-headword parity audit (every*_listword,force_compatmode) reaches 99.71% across 105 languages - 59 at 100% - and 99.69% across 22 sub-dialect variants (pt-br, en-us, es-419, …). The package bundles 117 languages.docs/remaining-gaps.mdlists the remaining fails.
from espyak import G2P
g2p = G2P("en")
g2p.phonemize("hello world") # 'həlˈəʊ wˈɜːld' (IPA)
g2p.phonemize("hello world", ipa=False) # "h@l'oU w'3:ld" (Kirshenbaum / -x)
G2P("es").phonemize("buenos días") # 'bwˈenos dˈias'
G2P("de").phonemize("straße") # 'ʃtɾˈɑːsə'
G2P("ru").phonemize("привет") # 'prʲivʲˈet'
Why
espyak gives a project espeak-ng's phonemes without the native dependency. There is
nothing to shell out to and no C extension to build, and the rules stay readable and
patchable in Python. It works as a backend for phoonnx.
Install
pip install -e . # from a clone (the espeak-ng source data is bundled, ~44 MB)
# or: uv pip install -e .
Python 3.9 or later is required. The espeak-ng dictsource/, phsource/, and lang/ data
ship bundled under espyak/data/ at the pinned 1.52.0 tag, so no system-wide install is
needed.
Usage
Python
from espyak import G2P
g2p = G2P("en") # one translator per language - construct once, reuse
g2p.phonemize("read") # 'ɹˈiːd'
g2p.phonemize("2024 dogs") # numbers expand to words, then phonemes
g2p.phonemize("cat", ipa=True) # 'kˈat' - Unicode IPA (default)
g2p.phonemize("cat", ipa=False) # "k'at" - Kirshenbaum ASCII (espeak -x)
g2p.phonemize("cat", separator="_") # 'k_ˈa_t' - separate phonemes
g2p.phonemize("cat", tie="͡") # tie multi-char phoneme names
Dialects and sub-dialect variants
A variant code (pt-br, en-us, es-419, fr-be, …) loads the same way: pass it to
G2P. espeak-ng models a sub-dialect as a small voice file that layers over the shared
base language (its dictionary, rules, and translator config), overriding only the phoneme
table, the dictionary conditionals, and a few post-translation phoneme substitutions:
G2P("pt-br").phonemize("dia") # 'dʒˈiæ' - Brazilian di palatalization
G2P("pt").phonemize("dia") # 'dˈiɐ' - base (European) Portuguese
G2P("en-us").phonemize("better") # 'bˈɛɾɚ' - rhotic, the en-us replace table
G2P("es-419").phonemize("cielo") # 'sjˈelo' - seseo (θ→s); base es → 'θjˈelo'
The 22 supported variants (codes are case-insensitive):
| family | variants |
|---|---|
| en | en-us, en-us-nyc, en-gb-scotland, en-gb-x-rp, en-gb-x-gbclan, en-gb-x-gbcwmd, en-029, en-shaw |
| ca | ca-va, ca-ba, ca-nw |
| fr | fr-be, fr-ch |
| pt / es | pt-br, es-419 |
| ru | ru-cl, ru-lv |
| vi | vi-vn-x-central, vi-vn-x-south |
| cmn / yue / fa | cmn-latn-pinyin, yue-latn-jyutping, fa-latn |
Command line
espyak -v en "hello world" # həlˈəʊ wˈɜːld
espyak -v es "díganme" # dˈiɣanme
espyak -v fr -x "bonjour" # bO~Z'ur (Kirshenbaum)
espyak -v de --sep _ "haus" # h_ˈaʊ_s
echo "привет" | espyak -v ru - # read from stdin
Output formats
| API argument | CLI flag | effect |
|---|---|---|
| (default) | --ipa |
Unicode IPA with ˈ/ˌ stress |
ipa=False |
-x |
Kirshenbaum ASCII |
separator="_" |
--sep=_ |
insert a separator between phonemes |
tie="͡" |
--tie |
tie character within multi-char names |
G2P(lang).phonemize(text, ipa=True, tie=None, separator=None) is the whole surface. See
docs/usage.md for details and render() (raw phoneme-string rendering).
How it works
espyak parses espeak-ng's own source data at load time and replays its pipeline in Python:
text → dictionary _list lookup → prefix/suffix retranslation → letter-to-sound rules
→ SetWordStress → phoneme programs (ChangePhoneme/InsertPhoneme) → render (IPA / -x)
Fidelity comes from the bundled data. The matcher, stress, number, and phoneme-program
logic are re-implemented to match the binary, including espeak-ng's quirks.
docs/architecture.md has the module map and pipeline.
Verification
pytest -q # unit + fixture tests
python test/sweep.py 25 # per-language _list-headword sweep vs the oracle
python test/corpus_sweep.py # real-sentence corpus vs the oracle
python test/parity_audit.py --cap 2000 # full-headword parity, every language
python test/parity_audit.py --variants --cap 2000 # the same for the 22 sub-dialect variants
The reference ("oracle") is a pinned espeak-ng 1.52.0 build, used only to generate
expected outputs. espyak never calls it at runtime. Every dictionary *_list headword is
a free test case. parity_audit.py tests every headword in force_compat mode, where the
edge cases (single accented letters, abbreviations, codepoint names) are where parity
breaks, and writes a per-language table plus a JSONL of every mismatch. --variants audits
each dialect's base headwords through its voice layer. test/report.md holds the
per-language sweep pass rate.
Coverage
Full-headword parity is 99.71% (105 languages, --cap 2000) and 99.69% across the
22 variants, with 59 base languages at 100%. The remaining ~136 base fails concentrate in
phoneme-level language switches, letter-name/abbreviation spelling (LookupDictList),
unported numbers.c branches, and a small irreducible floor (formant-synthesis allophones,
the ru a/ɑ reduction, oracle self-inconsistencies). docs/remaining-gaps.md
catalogs, classifies, and prioritizes them. The default engine (force_compat=False) is the
linguistically correct G2P, and it deviates from espeak-ng only at the entries in
docs/divergences.md.
Project layout
espyak/ the engine (one module per espeak-ng translation unit)
api.py public G2P entry point
dictionary.py MatchRule / TranslateRules / SetWordStress / LookupDict2
rule_compiler.py compiledict.c - rule byte encoding + groups
phoneme_tab.py phsource loader; phoneme_program.py - ChangePhoneme/InsertPhoneme
language_data.py per-language translator config (tr_languages.c + voice files)
voice.py sub-dialect VARIANT loader (voices.c LoadVoice) - pt-br/en-us/es-419/…
numbers.py TranslateNumber + ordinals/fractions
render.py phoneme list → IPA / Kirshenbaum / stress / tie / separator
data/ bundled espeak-ng dictsource/ phsource/ lang/ @ 1.52.0
docs/ architecture, usage, divergences, remaining-gaps, code-review/
examples/ runnable usage examples
test/ unit tests, oracle fixtures, sweep + corpus + parity_audit harnesses
Provenance
espyak is an AI-assisted port. An AI coding assistant wrote the Python after reading and
instrumenting espeak-ng's C source, and human review has been minimal. It is not an
independent clean-room implementation.
License
espyak is GPL-3.0-or-later, the same license as espeak-ng, from which it is derived and
whose data it bundles under espyak/data/. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file espyak-0.0.3a2.tar.gz.
File metadata
- Download URL: espyak-0.0.3a2.tar.gz
- Upload date:
- Size: 11.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.9.25
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
654fff6fa50a7bd2fbff4a82384fef3d8daa098e92ee808d741afb19530dcf93
|
|
| MD5 |
1065a5cd14276a18d817f3394b316dd9
|
|
| BLAKE2b-256 |
abae8f44b582a67dc54ec99711fcad644a7de2121e8a6ab0ba759480689c0e04
|
File details
Details for the file espyak-0.0.3a2-py3-none-any.whl.
File metadata
- Download URL: espyak-0.0.3a2-py3-none-any.whl
- Upload date:
- Size: 12.2 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.9.25
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d831d956c33e88baf3db0609e0253f3bfa51b33f9432043c009df715574bd90
|
|
| MD5 |
16a866ee4188094e2eff1f5e2e50769b
|
|
| BLAKE2b-256 |
29a8ae4f6fa31601b1adf29854ed93bc37e4f948950de627c2e341689f4d45ce
|