Skip to main content

wyoming-bench

Benchmark servers that speak the Wyoming protocol:

  • TTS — text-to-speech servers, via the non-streaming (synthesize) and streaming (synthesize-start / synthesize-chunk / synthesize-stop) synthesis paths. Reports latency and throughput.
  • STT — speech-to-text (ASR) servers, via the non-streaming and streaming (transcript-start / transcript-chunk / transcript-stop) transcription paths. Reports speed and word-level accuracy.
  • gen-corpus — synthesize a test corpus from a TTS server to feed the STT benchmark (a realistic TTS→STT round-trip).
  • info — query a server's advertised services (describe/info), so you can see whether it speaks TTS, STT, or both, and whether it supports streaming.

Before benchmarking, sends a describe to confirm the server advertises the service being benchmarked. A server that answers but lacks it (e.g. an STT server for a TTS benchmark) is skipped with a notice instead of timing out on every round. Servers that do not answer describe at all are benchmarked as before. The same describe response also reports whether the server advertises streaming support: when it does not, streaming mode is skipped immediately with a notice (no behavioral probe, no per-round timeout). A server that advertises streaming — or does not report it at all — is probed once to confirm before the streaming rounds run.

Every measurement uses a fresh TCP connection, so results are isolated per round. Statistics (min / mean / median / p95 / max) are aggregated across rounds.

Vibe Warning

This project was vibe coded with Qwen 3.8 27B and the Zed Agent on local hardware.

Install

pipx install wyoming-bench

Usage

# TTS: one server, both modes, default texts (one per 1..4 sentences)
wyoming-bench tts 10.100.1.20:10210

# TTS: multiple servers, streaming only, 5 rounds
wyoming-bench tts a:10700 b:10700 --mode streaming --rounds 5

# TTS: specific voice from a JSON config
wyoming-bench tts a:10700 \
    --config '{"voice": {"name": "en_US-lessac-medium"}, "text_format": "text"}'

# TTS: verbose per-measurement output, extra chunk delay for streaming
wyoming-bench tts a:10700 --mode streaming --chunk-delay 0.2 -v

# STT: one server, both modes, over a corpus of paired recordings
wyoming-bench stt 10.100.1.20:10700 --corpus ./samples

# STT: multiple servers, accuracy + speed comparison, 3 rounds
wyoming-bench stt a:10700 b:10700 --corpus ./samples --rounds 3

# STT: streaming only, pace audio-chunk writes at 0.1s (simulated real-time)
wyoming-bench stt a:10700 --mode streaming --corpus ./samples --chunk-delay 0.1 -v

# Generate a corpus from a TTS server, then benchmark an STT server on it
wyoming-bench gen-corpus tts:10210 --out ./tts-samples \
    --texts "The quick brown fox jumps over the lazy dog."
wyoming-bench stt asr:10700 --corpus ./tts-samples

# Inspect what a server offers before benchmarking it
wyoming-bench info 10.100.1.20:10700

TTS metrics

Metric Meaning
TTFT Time to first audio byte (from when the request is sent).
Total Total wall time until the final audio-stop event.
RTF Total time divided by the duration of the returned audio (lower is better; < 1 means faster than real time).
Audio Returned audio duration and byte count.

In streaming mode the text is split into sentences (via the sentence-stream heuristics, which hold abbreviations such as Mr. and U.S. together) and sent one sentence per synthesize-chunk event, so servers that buffer until a certain boundary are exercised the way an LLM-driven pipeline would drive them. --chunk-delay paces those writes.

STT metrics

Speed:

Metric Meaning
Total Wall time until the final transcript result.
TTFT Time to the first transcript-chunk (streaming mode only).
RTF Total time divided by the duration of the input audio (lower is better; < 1 means faster than real time).

Accuracy (word-level by default, character-level as a bonus):

Metric Meaning
WER Pooled word error rate: (substitutions + insertions + deletions) over total reference words across all samples.
CER Pooled character error rate (over total reference characters).
SAR Sentence accuracy: the fraction of samples whose normalized transcript exactly matches the reference.
S / I / D Total substitution / insertion / deletion word counts.

Reference and hypothesis text are normalized before comparison (lowercased, punctuation stripped, whitespace collapsed).

By default the bench appends --trailing-silence (0.5s) of silence to the end of each recording before sending it. Streaming (online) ASR models commit words incrementally and need a little trailing context to finalize their last words; without it they tend to drop the final one or two, which inflates WER. RTF is still computed on the original recording length, so the padding does not speed up the timing. Set --trailing-silence 0 to send recordings exactly as stored.

Corpus format (STT)

--corpus DIR points at a directory of .wav recordings paired with .txt transcripts that share the same stem:

samples/
  data_01.wav   +   data_01.txt
  data_02.wav   +   data_02.txt
  ...
  • data_01.txt holds the reference transcript for data_01.wav.
  • Files without a matching counterpart are skipped with a warning.
  • The WAV is sent to the server as-is (its sample rate / width / channels are read from the header). Record the corpus in the format the ASR server expects — typically 16 kHz, 16-bit, mono.

Generating a test corpus from a TTS server

Prefer not to record audio? gen-corpus synthesizes text with a TTS server and saves each sample as a .wav plus the source text as its .txt reference. A TTS→STT round-trip then yields a realistic word-error-rate measurement:

wyoming-bench gen-corpus tts:10210 --out ./tts-samples \
    --config '{"voice": "en_US-lessac-medium"}'
wyoming-bench stt asr:10700 --corpus ./tts-samples

The WAV is saved in whatever format the TTS server emits — make sure that format is acceptable to the STT server (most resample internally, but check yours).

Options

All subcommands take the server(s) as positional arguments (SERVER is HOST or HOST:PORT, repeatable). tts, stt, and gen-corpus share these flags (in addition to their own):

Flag Description Default
--rounds N Timed measurement rounds per sample per mode. 3
--warmup N Untimed warmup runs per mode. 1
--mode {non_streaming,streaming,both} Path(s) to exercise. both
--probe-timeout SEC Per-event timeout for one-off probes (streaming capability, describe preflight). 8
--timeout SEC Connect and per-event read timeout. 60
-v, --verbose Print one line per measurement. off

TTS-specific flags:

Flag Description Default
--texts TEXT [TEXT ...] Text samples to synthesize. built-in 1–4 sentence set
--texts-file FILE One text sample per line.
--texts-dir DIR Directory of .txt files, one text sample per file.
--config JSON {"voice": "name"} or {"voice": {"name","language","speaker"}, "text_format": "text"}. {}
--chunk-delay SEC Seconds to wait between synthesize-chunk writes (streaming). 0
--unique / --no-unique Append a random nonce to each text to defeat server-side synthesis caching (cold-cache timings). on

STT-specific flags:

Flag Description Default
--corpus DIR Directory of paired .wav/.txt samples (required).
--config JSON Transcribe JSON, e.g. {"name": "model", "language": "en"} (fields: name, language, context, vad_sensitivity, transcript_names, transcript_terms). {}
--chunk-samples N Samples per audio-chunk when sending audio. 1024
--chunk-delay SEC Seconds to wait between audio-chunk writes (streaming). 0
--trailing-silence SEC Seconds of silence appended to each recording before transcription (helps streaming/online models finalize their last words; RTF still uses the original length). 0.5

gen-corpus-specific flags:

Flag Description Default
--out DIR Output directory for the corpus (created if missing, required).
--mode {non_streaming,streaming} TTS synthesis path to use. non_streaming
--texts TEXT [TEXT ...] Text to synthesize. built-in 1–4 sentence set
--texts-file FILE One text sample per line.
--texts-dir DIR Directory of .txt files, one text sample per file.
--config JSON Voice/format JSON (same as tts). {}
--prefix PFX File name prefix (sample_01.wav, …). sample
--overwrite Overwrite existing files. off
--probe-timeout SEC Per-event timeout for the one-off describe preflight. 8
--timeout SEC Connect and per-event read timeout. 60

info-specific flags:

Flag Description Default
--timeout SEC Timeout for the describe exchange. 5

A bare HOST uses port 10700 (the Wyoming default).

Exit codes

0 — at least one measurement succeeded. 1 — every measurement on every server failed (or a server was skipped / no info response). 130 — interrupted.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wyoming_bench-2026.9.1.tar.gz (45.9 kB view details)

Uploaded Source

Built Distribution

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

wyoming_bench-2026.9.1-py3-none-any.whl (36.0 kB view details)

Uploaded Python 3

File details

Details for the file wyoming_bench-2026.9.1.tar.gz.

File metadata

  • Download URL: wyoming_bench-2026.9.1.tar.gz
  • Upload date:
  • Size: 45.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for wyoming_bench-2026.9.1.tar.gz
Algorithm Hash digest
SHA256 9e6f5d6eefd467af1da1a8d8d191983c00c726b8627d07fee07f2cde1b9ec5ad
MD5 06c609550844c73c98a36eb9ee10526a
BLAKE2b-256 eee4b317f6f2fd2da558a1126e6a98389b6052b24f786ba120115488f989beb2

See more details on using hashes here.

Provenance

The following attestation bundles were made for wyoming_bench-2026.9.1.tar.gz:

Publisher: publish-pypi.yml on mill1000/wyoming-bench

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file wyoming_bench-2026.9.1-py3-none-any.whl.

File metadata

File hashes

Hashes for wyoming_bench-2026.9.1-py3-none-any.whl
Algorithm Hash digest
SHA256 03d6322ae41417cfc618d7a6df096cf4b252f7e1009405ce9939ec8b3dc9a9b1
MD5 2edced4f755405898711e26fb9383a99
BLAKE2b-256 e35b2be035f8def9a241a701306a88c7feb054ae116af118289a31550fe9f4ad

See more details on using hashes here.

Provenance

The following attestation bundles were made for wyoming_bench-2026.9.1-py3-none-any.whl:

Publisher: publish-pypi.yml on mill1000/wyoming-bench

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

2026.9.2

2 files

This release

2026.9.1 This release

2 files

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