Skip to main content

voxport

Small Python interfaces for text-to-speech and speech-to-text, with swappable engine adapters. Your code calls one method, synthesize() or transcribe(), and never touches an engine's API directly, so switching engines means changing one line where the adapter is created.

TTSEngine.synthesize(text, voice) -> audio
STTEngine.transcribe(audio) -> text

Included adapters:

  • KokoroDirectTTS: runs the Kokoro TTS model in your own process. The model loads once and stays in memory, with no server and no network hop.
  • WyomingWhisperSTT: a client for a Wyoming protocol Whisper server, the same kind of server Home Assistant's voice pipeline uses. It loads no model itself; transcription happens on the server.

voxport is a library only: it has no command-line tool or app of its own. It is pre-1.0, so the API may still change between minor versions (see the changelog).

Installation

Requires Python 3.10+. Each adapter's dependencies are an optional extra, so you install only what you use:

pip install "voxport[kokoro]"    # KokoroDirectTTS
pip install "voxport[wyoming]"   # WyomingWhisperSTT
pip install "voxport[all]"       # both
Extra Adds For
kokoro Kokoro, torch (about 2 GB) KokoroDirectTTS
wyoming wyoming WyomingWhisperSTT
all both of the above everything

A plain pip install voxport includes only the interfaces and numpy. Importing an adapter without its extra raises an ImportError that names the extra to install.

Things voxport doesn't install for you:

  • WyomingWhisperSTT needs a running Wyoming Whisper server. See Running a Wyoming Whisper server.
  • On first use, Kokoro downloads its model weights and voice packs from Hugging Face, and spaCy's en_core_web_sm English model. See Offline use for machines that can't reach those.
  • soundfile, used in the examples below to write WAV files.

Usage

Text to speech

import soundfile as sf
from voxport.tts.kokoro_direct import KokoroDirectTTS

tts = KokoroDirectTTS()  # reuse one instance; models load once per accent
audio = tts.synthesize("Hello from voxport.", voice="af_heart", speed=1.0)
sf.write("hello.wav", audio, tts.sample_rate)  # 24 kHz mono

synthesize() returns a 1-D numpy array. The first letter of the voice name picks the accent (a American, b British, ...), following Kokoro's voice naming; pass lang_code= to override it. Kokoro splits long text into segments itself, so there is no length limit.

Speech to text

from voxport.stt.wyoming_whisper import WyomingWhisperSTT

stt = WyomingWhisperSTT(host="localhost", port=10300)  # the defaults
text = stt.transcribe(audio_16k, language="en")

audio_16k is a 1-D numpy array of mono audio at stt.sample_rate (16 kHz), either int16 samples or floats in [-1, 1]. Resample first if your audio has a different rate; Kokoro's output, for example, is 24 kHz. Each call opens a new connection to the server.

From async code

Both calls block, and transcribe() runs its own asyncio event loop, so from code that already has a running loop, call them in a worker thread:

audio = await asyncio.to_thread(tts.synthesize, text, "bm_george")
text = await asyncio.to_thread(stt.transcribe, audio_16k, "en")

Writing your own adapter

An adapter subclasses TTSEngine or STTEngine, sets sample_rate, and implements the one abstract method:

import numpy as np
from voxport.tts.base import TTSEngine

class SilenceTTS(TTSEngine):
    """A toy engine: one second of silence, whatever the text."""

    sample_rate = 16000

    def synthesize(self, text: str, voice: str, speed: float = 1.0):
        return np.zeros(self.sample_rate, dtype=np.float32)

Code written against TTSEngine works with SilenceTTS and KokoroDirectTTS unchanged. Adapters may accept extra, engine-specific keyword arguments (like KokoroDirectTTS's lang_code), as long as the base signature still works.

Offline use

By default, Kokoro's weights and voice packs download to Hugging Face's standard cache (~/.cache/huggingface, or wherever HF_HOME points). To run on a machine that can't reach huggingface.co:

  1. On a machine with internet access, synthesize once with each voice you plan to use, so the model and those voice packs are cached.
  2. Copy that cache to the offline machine, keeping Hugging Face's hub/models--<org>--<name>/... layout, and point HF_HOME at it.
  3. Set HF_HUB_OFFLINE=1 on the offline machine. voxport never sets this for you. With it set, only voices already in the cache work; an uncached voice fails with a Hub connection error instead of downloading.

Kokoro's English phonemizer also needs spaCy's en_core_web_sm model, which downloads from GitHub, not Hugging Face, so HF_HUB_OFFLINE doesn't cover it. It downloads once per Python environment, so install it while online:

python -m spacy download en_core_web_sm

Repo-local cache (source checkouts only). If you run voxport from a clone, you can keep the cache inside it instead: create an hf_cache/ folder at the repo root (it's gitignored) and KokoroDirectTTS uses it as HF_HOME, unless you've set HF_HOME yourself. That makes the cache easy to copy along with the checkout.

Running a Wyoming Whisper server

WyomingWhisperSTT needs a server to talk to. For local testing, the easiest option is the rhasspy/wyoming-whisper Docker image:

docker run -d --name whisper --restart unless-stopped -p 10300:10300 -v wyoming-data:/data rhasspy/wyoming-whisper --model tiny-int8 --language en

The image is named rhasspy/wyoming-whisper, even though its GitHub repo is wyoming-faster-whisper. docker logs whisper shows Ready once the model has loaded. tiny-int8 is small and fast but not very accurate; use a larger model when transcription quality matters.

If you already run Home Assistant with its Whisper add-on, you can point WyomingWhisperSTT at that server's host and port instead.

Development

git clone https://github.com/brienalkire/voxport.git
cd voxport
pip install -e ".[all]" pytest
python -m pytest

The tests need no network, no Whisper server and no Kokoro model: WyomingWhisperSTT is tested against a fake in-process Wyoming server. Installing .[wyoming] instead of .[all] is enough to run them and skips the 2 GB torch download.

License

MIT

Metadata

Release files for voxport 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for voxport 0.4.0
File Size Uploaded Provenance Actions
voxport-0.4.0.tar.gz 14.8 kB With provenance Details for voxport-0.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for voxport 0.4.0
File Interpreter ABI Platform Actions
voxport-0.4.0-py3-none-any.whl Python 3 none any Details for voxport-0.4.0-py3-none-any.whl

Total release size: 26.3 kB

Release files / voxport-0.4.0.tar.gz

Download URL voxport-0.4.0.tar.gz
Size 14.8 kB
Tags Source
SHA-256 checksum
How to use checksums
cc770d3c4f78d6672fb7224cd71ccaed55ed197af3cf10ec59c59d1967f809bb
BLAKE2b-256 checksum
How to use checksums
1fe5d3d0b2b012180a4ac9c413dd3a954aea4b595bb16d1588ca302261374618
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Release files / voxport-0.4.0-py3-none-any.whl

Download URL voxport-0.4.0-py3-none-any.whl
Size 11.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
76caf4a10d7509df931da80a75747c6b2ba90b6d9decadabd6d74a1657ab6b70
BLAKE2b-256 checksum
How to use checksums
7759519b051c739d5a20509638db373f75be3b2b9bd57e0834bcd92c6b3b4320
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Security for voxport 0.4.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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for voxport-0.4.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

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.

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page