vinoSpeak
Intel NPU-powered text-to-speech using the Kokoro-82M INT8 OpenVINO model. Text goes in, a WAV comes out, and nothing leaves your machine after the one-time model download.
Requirements
- Python 3.11 or newer
- An Intel NPU with a compatible driver. GPU and CPU also work
(
--device GPU,--device CPU). - Internet access on first run to download the model (~160 MB)
OpenVINO is pinned to the release vinoPop and vinoWhisper use, so programs sharing one NPU never run mismatched runtimes.
Install
From PyPI, with uv:
uv tool install --python 3.14 vinospeak
vinospeak "Hello."
--python 3.14 because OpenVINO 2026.4.1 has no wheels for 3.15 yet, and uv
otherwise uses your default Python. OpenVINO is pinned exactly; everything else resolves to the newest release
that fits. To install exactly what uv.lock pins, hashes included, use a
checkout. --locked fails if the lock is out of date:
git clone https://github.com/karanshukla/vinoSpeak && cd vinoSpeak
uv sync --locked
uv run vinospeak "Hello."
To put that checkout's vinospeak on your PATH with the lock's versions as
constraints (uv tool install doesn't read uv.lock by itself):
uv export --locked --no-dev --no-emit-project --no-hashes -o constraints.txt
uv tool install --constraints constraints.txt .
Immutable distros
Fedora Atomic (Silverblue, Kinoite, Bazzite) and openSUSE Aeon need nothing
layered for vinoSpeak itself: uv tool install puts it in ~/.local/bin, uv
downloads its own Python 3.14, and the wheels carry espeak-ng and libsndfile.
Get uv the same way, into your home directory:
curl -LsSf https://astral.sh/uv/install.sh | sh
Two things live outside your home directory and stay system packages:
- The NPU driver. Its user-space half (Level Zero and the NPU compiler) has
to be on the host for
--device NPU; layer it withrpm-ostree installortransactional-update pkg installif your image doesn't ship it.vinospeak-doctorshows whether OpenVINO sees the NPU. CPU works without it. - A player, if
vinospeak-doctorfinds none: layer one from the table under Synthesize speech, or pass--output.
Synthesize speech
The first run downloads OpenVINO/Kokoro-82M-int8-ov from Hugging Face, at one
pinned commit, and checks every file against its sha256 (see
SECURITY.md). The model is cached under
${XDG_CACHE_HOME:-~/.cache}/vinospeak/ by default, and OpenVINO keeps the
compiled model in vinospeak/ov-cache/ beside it, so later runs skip the
compile. That can be a few hundred MB; delete it whenever you like.
vinospeak "Hello from vinoSpeak." # plays it on your speakers
vinospeak "Hello from vinoSpeak." --output hello.wav # saves a WAV instead
Playback goes through pw-play (PipeWire, what Wayland desktops run), falling
back to paplay or aplay. A pw-play too old to stream raw audio (PipeWire
1.0 on Ubuntu 24.04, 0.3 on Debian 12) is skipped for paplay, which
PipeWire's PulseAudio layer serves just as well. vinospeak-doctor says which
player it picked. --audio-device plays on another output: a sink name from
pactl list short sinks, or an ALSA device for aplay.
If none of them is installed:
| Distro | pw-play |
paplay |
|---|---|---|
| Fedora | pipewire-utils |
pulseaudio-utils |
| Ubuntu / Debian | pipewire-bin |
pulseaudio-utils |
| Arch | pipewire |
libpulse |
| openSUSE | pipewire-tools |
pulseaudio-utils |
Read a file aloud
vinospeak --file notes.md # markdown is cleaned up for listening
vinospeak --file notes.md --print-text # what it would say, without loading the model
some-command | vinospeak --file - # plain text from stdin
Markdown headings, list items and table rows become sentences, links keep
their text, a URL is said as its host, and code blocks are skipped. In other
files a line that ends without punctuation ends a sentence unless the next line
carries on in lowercase, and a word hyphenated over a line end is rejoined.
Stdin is plain text unless --kind says otherwise; anything that isn't UTF-8
text is refused. A full stop after e.g., Dr., U.S. and the like doesn't
end a sentence. --kind document is for text with one heading, paragraph or
table cell a line, as vinoSearch
extracts PDFs and Office documents, and gui/ is a proof-of-concept
window for finding a file with vinoSearch and listening to it.
A vinoWhisper session reads its summary, or its transcript when it isn't summarised yet:
vinospeak --file ~/.local/share/vinowhisper/transcripts/2026-10-27-140512.vwsession
vinospeak --file 2026-10-27-140512.vwsession --part transcript
A summary starts with "This summary was machine-written." and loses its time stamps; a transcript starts with the day it was recorded and loses its paragraph stamps.
The default inference device is the Intel NPU. Choose a different OpenVINO device, voice, language, speed, or model directory with the corresponding options:
vinospeak "A sample sentence." \
--device NPU \
--voice af_heart \
--language en-us \
--speed 1.0 \
--model-dir ./kokoro-model \
--output speech.wav
Use vinospeak --help to see all options. The audio uses the sample rate
reported by OpenVINO GenAI.
Check this machine
vinospeak-doctor # --json for a bug report
Reports the OpenVINO packages and devices, whether the cached model still
matches its pins, and, if ovfetch is
on your PATH, whether your OpenVINO version is inside the range recorded as
working with your NPU driver. Install it with cargo install ovfetch --locked.
ovfetch is advisory here: it never changes what gets installed or run, with one
exception. If your distro's NPU driver package has no compiler (Fedora's
intel-npu-driver 1.32.0), the NPU enumerates and every compile fails;
ovfetch npu install (0.6.0 or newer) fetches Intel's compiler into
~/.local/lib/ovfetch-npu, no root, and vinoSpeak loads it from there before
it opens the NPU. The doctor's npu: ovfetch line says when that applies.
Use it from Python
from vino_speak import Synthesizer
synth = Synthesizer("NPU") # compiles the model once; reuse it
audio = synth.synthesize("Hello.") # audio.samples (float32), audio.sample_rate
speech = synth.speak("A long passage.") # returns at once, plays in the background
speech.stop() # cuts it off; speech.wait() blocks until it finishes instead
speak() synthesizes the first sentence on its own and plays it while the
rest is synthesized in chunks that at most double in size, so speech starts
after about 1.5 s on the NPU however long the text is.
Development
See CONTRIBUTING.md. uv run poe check runs everything CI
does; none of it needs OpenVINO or an NPU.
Metadata
Release files for vinospeak 0.3.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 | Provenance | Actions |
|---|---|---|---|---|
| vinospeak-0.3.0.tar.gz | 55.3 kB | Without provenance | Details for vinospeak-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| vinospeak-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for vinospeak-0.3.0-py3-none-any.whl |
Total release size: 90.4 kB
Release files / vinospeak-0.3.0.tar.gz
| Download URL | vinospeak-0.3.0.tar.gz |
|---|---|
| Size | 55.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
17aac88efe52ed57b9e5c246cd43ac4164b49600f273471cc35e97e3ad9f996c
|
|
BLAKE2b-256 checksum How to use checksums |
f6791daab017dad2d51f8a7c5474e9c4fa2969769a04d35c7d546d3c905e85cc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / vinospeak-0.3.0-py3-none-any.whl
| Download URL | vinospeak-0.3.0-py3-none-any.whl |
|---|---|
| Size | 35.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8ab00a29a46f951be39793be00236519462dc4ff3b9ca31bb60472e17bab61cd
|
|
BLAKE2b-256 checksum How to use checksums |
ed9d56f7a8393ad488306c734c15944dcad3a64a426ece86f9c8a7099831284a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for vinospeak 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.