Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

espyak

A pure-Python reimplementation of espeak-ng's grapheme-to-phoneme (G2P) front-end. Text → phonemes only: no synthesis, no audio, no C extension, no runtime dependencies.

Reproduces the espeak-ng binary (pinned 1.52.0) byte-for-byte. The full-headword parity audit (every *_list word, force_compat mode) is 99.71% across 105 languages — 59 at 100% — and 99.69% across 22 sub-dialect variants (pt-br, en-us, es-419, …). 117 languages bundled. The remaining fails are catalogued in docs/remaining-gaps.md.

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 projects espeak-ng's phonemes without the native dependency: nothing to shell out to, no C-extension to build, and the rules are readable and patchable in Python. It drops in 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. The espeak-ng dictsource/, phsource/, and lang/ data are bundled under espyak/data/ at the pinned 1.52.0 tag, so nothing is needed system-wide.

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 / sub-dialect variants

A variant code (pt-br, en-us, es-419, fr-be, …) is loaded 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 is inherited from the bundled data; the matcher, stress, number, and phoneme-program logic are re-implemented to match the binary, espeak-ng's quirks included. 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 (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 ~136 remaining base fails are concentrated 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). They are catalogued, classified, and prioritized in docs/remaining-gaps.md. The default engine (force_compat=False) is the linguistically-correct G2P and may deviate 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. The Python was written by an AI coding assistant that read and instrumented espeak-ng's C source; human review has been minimal. It is not an independent clean-room implementation.

License

espyak is GPL-3.0-or-later, the same 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

espyak-0.0.3a1.tar.gz (11.8 MB view details)

Uploaded Source

Built Distribution

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

espyak-0.0.3a1-py3-none-any.whl (12.2 MB view details)

Uploaded Python 3

File details

Details for the file espyak-0.0.3a1.tar.gz.

File metadata

  • Download URL: espyak-0.0.3a1.tar.gz
  • Upload date:
  • Size: 11.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for espyak-0.0.3a1.tar.gz
Algorithm Hash digest
SHA256 6527f9871aeeaf4376386a6c7fd64494baa8a0ac63b1809ba03d1f4bcb5010a4
MD5 94774464a44d5f341cd8fd02d09ee7cd
BLAKE2b-256 89b0bc05d83d4c3cdfe41b19416ac148e4a85f27387dc8b9fba2b74b3205ea8e

See more details on using hashes here.

File details

Details for the file espyak-0.0.3a1-py3-none-any.whl.

File metadata

  • Download URL: espyak-0.0.3a1-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

Hashes for espyak-0.0.3a1-py3-none-any.whl
Algorithm Hash digest
SHA256 1774b8c85dec3c58ee37971d8c00323b78dbd4e29388787c70ec55c2738354d6
MD5 4c6e3f49db43560ad964a40b0cebc7cc
BLAKE2b-256 9445659536f4d03dd185658b1f40e562c4eee25bfedf8babdc282b164f44fd46

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 Sentry Error logging StatusPage Status page