| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
sttserv is a low-latency Speech-To-Text (ASR) library and server written in C++. It wraps existing ML inference engines behind one backend interface, so the same capture and transcription code runs on top of different model runtimes.
Backends available today:
The original goal was Hebrew speech-to-text, but nothing in the library is language-specific — the language is a property of the model you load. The design target is to make the capture → transcription path as fast as feasible for local and embedded deployment.
sttserv/ the library + server target (public headers in sttserv/include/sttserv/) test/ GoogleTest accuracy/functionality harness (asr_test.cpp) benchmark/ GoogleBenchmark performance targets sandbox/ Python scratch space for prototyping / measurement cmake/ workspace CMake modules (CPM, output dirs, diagnostics, ...) dependencies/ vendored submodules fetched via CPM (whispercpp, sherpa-onnx, util2, ...) build.sh / build.ps1 convenience build wrappers (Linux / Windows) bench.sh ASR model accuracy+latency sweep (see Benchmarks below)
Dependencies are pulled through CPM (safe_cpm_add_package) from dependencies/. Model files and recordings live under dependencies/models/ and dependencies/recordings/ and are git-ignored.
This project uses the same CMake workspace layout as the wider drone/perception project it was borrowed from — CPM for dependencies, build.sh / build.ps1 wrappers, out-of-source builds under build/. If you have built that project, this will feel identical.
Use the wrapper. Its signature is build.sh <build_type> <library_type> <action>:
./build.sh --help
./build.sh release static configure # configure once (fetches submodules, runs CMake)
./build.sh release static build # compileWindows is the same via PowerShell:
.\build.ps1 -BuildType release -LinkType shared -Action configure
.\build.ps1 -BuildType release -LinkType shared -Action buildBuild output lands in build/<build_type>/<library_type>/.
Backends and the top-level targets are CMake options (see CMakeLists.txt). At least one backend is required — configuring with none is a fatal error. The defaults baked into build.sh are:
| Option | Default | Meaning |
|---|---|---|
| STTSERVER_BUILD_LIBRARY_BACKEND_WHISPER | ON | whisper.cpp / ggml backend (Whisper + Parakeet) |
| STTSERVER_BUILD_LIBRARY_BACKEND_SHERPA_ONNX | OFF | sherpa-onnx (ONNX Runtime) backend |
| STTSERVER_BUILD_LIBRARY | ON | build the actual server library |
| STTSERVER_BUILD_TESTS | ON (top-level) | GoogleTest harness |
| STTSERVER_BUILD_BENCHMARKS | ON (top-level) | GoogleBenchmark targets |
ggml compute backend (Vulkan / CUDA / Metal / CPU) is selected with the usual -DGGML_* flags passed through at configure time; see the commented block in build.sh for a worked CUDA + Vulkan example.
In your CMakeLists.txt:
add_subdirectory(path/to/sttserv)
target_link_libraries(your_target PRIVATE STTSERVER::SpeechToTextServer)Public headers are under sttserv/include/sttserv/ — backend.hpp (the transcription backend), audio2.hpp (capture / WAV), async_key.hpp (push-to-talk key hook), cmdline.hpp, and the exported C API in sttserver_api.h. The C API export macros (STTSERVER_EXPORTS / STTSERVER_STATIC_DEFINE) are set for you by the library target depending on shared vs static.
As a submodule the workspace-level tests and benchmarks auto-disable, so you only pull in the library.
The accuracy harness (test/asr_test.cpp) builds one run_<target> per model. From the build dir:
cd build/release/static
ninja -t targets | grep run # list the model targets
ninja run_parakeet-v3-q4-whisper-backendThe harness reads clips from dependencies/recordings/, transcribes each against a model, and verifies the output against sentences.txt. See test/run_tests.txt for the current target list.
If you have a suggestion, fork the repo and open a pull request, or open an issue tagged "enhancement".
Distributed under the MIT License. See the LICENSE file for more information.
Which ASR model to ship for a real-time voice loop. Reproduce with ./bench.sh from the workspace root (build the test targets first). Setup and full results follow.
Setup. Local box, GTX 1050 Ti (4 GB), whisper backend on Vulkan, flash-attention (--fa), GPU gid 0. The accuracy_test harness over 44 clips = 5 sentences × ~9 noise variations (quiet / mid / noisy), four speakers (anonymized). Ground truth is sentences.txt. "Pass" = a clip transcribes above the harness accuracy threshold. The three sherpa-onnx NeMo targets were not built for this run (sherpa backend off) and are excluded.
| Model | Backend | Size | Total (44) | Per-clip ms (min / med / max) | Pass | Acc p50 | Acc min |
|---|---|---|---|---|---|---|---|
| parakeet-v3 q4_k | whisper-parakeet | 397 MB | 27 s | 157 / 586 / 1460 | 37/44 | 95.1% | 37.8% |
| parakeet-v3 q8_0 | whisper-parakeet | 638 MB | 25 s | 139 / 522 / 915 | 36/44 | 95.1% | 36.2% |
| parakeet-v3 f16 | whisper-parakeet | 1.2 GB | 25 s | 146 / 510 / 900 | 36/44 | 95.1% | 36.2% |
| parakeet-v3 f32 | whisper-parakeet | 2.4 GB | 27 s | 142 / 515 / 916 | 36/44 | 95.1% | 36.2% |
| distil-whisper-large-v3.5 q5k | whisper-whisper | 513 MB | 329 s | 5850 / 6698 / 10389 | 33/44 | 95.1% | 39.5% |
| whisper-large-v3-turbo q4_k | whisper-whisper | 453 MB | 313 s | 5737 / 6650 / 9846 | 33/44 | 94.0% | 63.0% |
Winner: Parakeet TDT 0.6B v3, q4_k. Fastest tier (median 0.59 s/clip), smallest footprint (397 MB — the most headroom when it shares a 4 GB GPU with a VLM), and the best pass rate (37/44). Accuracy is flat across the parakeet quant ladder (p50 95.1% identical f32 → q4), so quantization is free here; pick by size. The two whisper-large models are ~12× slower for no accuracy gain — they only look more robust on min-accuracy because they drop fewer worst-case clips, but their latency disqualifies them for a real-time loop.
Most failing clips are the loud/noisy variations, so a denoise/filter stage in front of the ASR is the obvious idea. Three filters were measured against the same 44 clips, parakeet-q4_k, with raw as the baseline. None was assumed; every one was run through the full transcription harness.
| filter | type | Pass | acc mean | cf mean |
|---|---|---|---|---|
| raw (no filter) | — | 37/44 | 89.1% | 0.965 |
| GTCRN | neural speech-enhancement (sherpa-onnx, ONNX CPU) | 27/44 | 81.3% | 0.941 |
| SpeexDSP | spectral noise suppression | 30/44 | 87.5% | 0.945 |
| classical DSP | 300–3500 Hz band-pass + noise gate | 33/44 | 86.2% | 0.960 |
Every filter is net-negative. Raw wins. Detail:
Verdict: ship parakeet-q4 on raw audio; do not filter. If filtering is ever revisited, the band-pass + gate direction is the only one that improved noisy speech — it needs a gate that will not clamp on voiced frames. Neural whole-utterance enhancement (GTCRN) and spectral suppression (SpeexDSP) both only hurt. Do not gate on SNR; if a quality signal is wanted, see confidence below.
A per-utterance confidence (geometric mean of token probabilities) was tested as an "ask the speaker to repeat" gate. Two findings:
Verdict: token-probability confidence is not a usable accuracy filter. Keep it only as an empty/garbage guard (near-zero score or empty string → retry), never as a "was this transcript correct" signal.
Footprint matters because the ASR shares a 4 GB GPU with a VLM. Parakeet-q4 at 397 MB leaves the most KV headroom; q8_0 (638 MB) is the fallback if q4 ever misbehaves on field audio. The per-model logs from bench.sh hold transcript text and speaker labels, so they are git-ignored and never committed.
| Back | FazBrowse Home | New Git URL |