YakYak
YakYak provides command-line and Python access to local text-to-speech. It connects to Wyoming services such as Piper over TCP, or runs Kokoro locally through ONNX Runtime.
See CHANGELOG.md for release notes.
Install YakYak, Docker Compose & FFMPEG
To install YakYak, a python virtual environment is recommended.
Step 1, create a python virtual environment and activate it
cd some_directory
sudo apt install python3.10-venv
python3 -m venv .venv
source .venv/bin/activate
Step 2, install the YakYak package
pip install yakyak
Step 3, Install ffmpeg
Install ffmpeg for mac
brew install ffmpeg
Install ffmpeg for Ubuntu
sudo apt install ffmpeg
Setup wyoming-piper in docker, on your local area network.
If you don't already have docker, or better yet docker-desktop, you can download and install it from docker.com.
If you don't already have a wyoming-piper docker-compose.yml file, create one using YakYak. Warning, this will overwrite an existing docker-compose.yml file.
yakyak --docker > docker-compose.yml
Now you can start wyoming-piper in a docker container
docker compose up -d --force-recreate
Piper stores downloaded voice files in ~/.cache/yakyak/piper on the host, mounted as /data in the container. The Compose example refreshes Piper's voice catalog at startup so newer voices can be found and downloaded. To keep voices from the previous default location, copy them before starting the updated Compose file:
mkdir -p ~/.cache/yakyak/piper
cp -a ~/.rhasspy3-piper-data/. ~/.cache/yakyak/piper/
Test Piper installation
It will take a little longer the first time running YakYak, the Wyoming-Piper app needs time to download voice files.
yakyak --host localhost -t mp3
Observe successful test results
INFO:root:Server localhost:10200 is online
INFO:root:Success, test: mp3
Use Kokoro locally
On Python 3.10–3.13, installing or upgrading YakYak installs the kokoro-onnx runtime too. The first Kokoro run downloads the model and voice data (about 350 MB total) into ~/.cache/yakyak/kokoro; set YAKYAK_CACHE_DIR to use another cache location. The model runs locally after download. Kokoro's ONNX dependency does not support Python 3.14, so use Python 3.10–3.13 for Kokoro; the Wyoming backend remains available on Python 3.14.
Select Kokoro with --backend kokoro. For US English, af_heart is a good voice to start with. Voice IDs and their language codes are listed in Kokoro's voice guide.
# Run a short Kokoro synthesis check
yakyak --backend kokoro --voice af_heart --test wav
# Convert text from stdin to WAV
echo "Hello from Kokoro" | yakyak --backend kokoro -v af_heart -f wav -o hello.wav
# Read a Markdown or text file and save speech as MP3
yakyak --backend kokoro -v af_heart --language en-us \
-i ~/tmp/sage_example.md -o ~/tmp/heart.mp3 -f mp3
Use --language to choose the voice language (for example, en-us or en-gb) and --speed to set a rate from 0.5 to 2.0. Use -f mp3 for MP3 output; MP3 conversion requires ffmpeg. Kokoro is selected explicitly with --backend kokoro; YakYak continues to use Wyoming-Piper by default.
Run the test suite
From the repository root, run:
python -m unittest discover -s tests -v
These unit tests mock Wyoming events and Kokoro inference, so they do not require Docker, model downloads, a running TTS service, or FFmpeg.
How to use YakYak from the command line
As with many Linux applications, YakYak supports standard in, and standard out. It also supports file input with the -i command and -o for file output. For a complete set of commands type yakyak --help.
yakyak --help
Create an mp3 file with "Hello world"
echo Hello world | yakyak -f mp3 -o hello_world.mp3
If you are on Linux and have aplay installed, you can do this:
echo Hello world | yakyak | aplay
This assumes that Docker is running on the same machine.
If Docker is running on a different machine on your network, you can do this:
echo Hello world | yakyak --host a_different_machine.local | aplay
How to use YakYak from Python
Create the file test_yakyak.py with the following content:
from yakyak import is_server_online, piper_tts_server
print(f"{is_server_online(
'localhost',
10200,
)=}")
print(f"{piper_tts_server(
'localhost',
10200,
'Hello World',
'hello_world.mp3',
'mp3',
'en_US-amy-medium'
)=}")
Now test it
python3 test_yakyak.py
Observe that the server is online and a file hello_world.mp3 is created. Play the mp3 and you will hear "Hello world".
run.py
check_ffmpeg_version()='ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers'
is_server_online(
'localhost',
10200,
)=True
INFO:root:Server localhost:10200 is online
run_test(
'localhost',
10200,
'mp3',
)=(True, 'Success, test: mp3')
INFO:root:Success, test: mp3
await piper_tts_server(
'localhost',
10200,
'Hello World',
'run_test.mp3',
'mp3',
'en_US-amy-medium'
)=None
Process finished with exit code 0
Error handling
The Python helpers do not share a single error-handling contract:
| Helper | Return values and failure behavior |
|---|---|
is_server_online(host, port) |
Returns True if a TCP connection succeeds; otherwise returns False, including for handled socket errors. A successful check does not guarantee that subsequent synthesis will succeed. |
piper_tts_server(...) |
An async function that must be awaited, or called with asyncio.run(...) outside an existing event loop. Returns None on success and on handled failures, so its return value is not a success indicator. Handled connection, output I/O, and FFmpeg process errors are logged; other exceptions may propagate. |
kokoro_tts_server(...) |
An async function that runs Kokoro locally and writes WAV or MP3 output. The first call downloads model files; MP3 requires ffmpeg. Pass a supported Kokoro voice and language code. |
run_test(host, port, audio_format, voice="en_US-amy-medium") |
Returns (True, message) for non-empty output and (False, message) for an offline server or missing/empty output. Pass a voice ID supported by the service; the default is the Piper voice. Raises ValueError for formats other than mp3 or wav. Other errors, such as temporary-file access or cleanup failures, may propagate. It uses asyncio.run internally and cannot be called directly from a running event loop. |
check_ffmpeg_version() |
Returns version information or a diagnostic string. If the ffmpeg executable is missing, it raises FileNotFoundError; the missing-FFmpeg diagnostic string is returned when the executable runs but exits with an error. |
Check the run_test status tuple when using it from Python. For direct synthesis,
inspect the logs and the output: a None return does not establish success, and
an existing output file could be left over from an earlier invocation.
The CLI logs handled failures but does not consistently translate them into
nonzero exit codes. In particular, --test discards the status tuple returned by
run_test, so a zero exit code alone does not prove that synthesis succeeded.
Metadata
Release files for yakyak 1.8.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 | |
|---|---|---|---|
| yakyak-1.8.0.tar.gz | 15.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| yakyak-1.8.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 26.5 kB
Release files / yakyak-1.8.0.tar.gz
| Download URL | yakyak-1.8.0.tar.gz |
|---|---|
| Size | 15.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fd0af74d80e771d5a6631649cf47ba828b86bd697b269b8b6506cd5fa1b3154e
|
|
BLAKE2b-256 checksum How to use checksums |
521975191f827ed6b93b8885a08c82958ad50b91f07dcf90fa90f9c16bdf4db0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|
Release files / yakyak-1.8.0-py3-none-any.whl
| Download URL | yakyak-1.8.0-py3-none-any.whl |
|---|---|
| Size | 10.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c775fb7891371f9d76c331ca6dff629d391c528cf1b4f5c7b4c2b3287349e1e9
|
|
BLAKE2b-256 checksum How to use checksums |
58b38c96a20163ba266906cb701d09040bf088d5a914e03b821ab628a2acb5ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|