Decode all ready streams in parallel

May 19, 2026 · View on GitHub

Open-source speech recognition built for developers.

Our engine is fully open-source, and you choose how to deploy models: use our CC-BY-SA licensed community models or upgrade to commercial models with premium performance. We focus on building fast, high-quality production models and providing examples that take the guesswork out of integration.

Demos

▶️ Android App

Run speech recognition natively on your phone using ONNX Runtime.

🌐 Browser (WASM)

Experience transcription directly in your browser, no server required.

Documentation

Full documentation could be found here

Our Community

Join the Kroko community to learn, share, and contribute:

  • 💬 Discord – chat with developers, ask questions, and share projects.
  • 📢 Reddit – join discussions, showcase your integrations, and follow updates.
  • 🤗 Hugging Face – explore our models, try live demos, and contribute feedback.

Table of Contents

  1. Building kroko-onnx
    1.1 Linux (x64 or arm64)
    1.2 Docker
    1.3 Python

  2. Usage Examples (WebSocket Server)
    2.1 WebSocket Server Format
        2.1.1 Input
        2.1.2 Output
        2.1.3 Output Fields

  3. Using kroko-onnx from Python
    3.1 Import and Create a Recognizer
    3.2 Parameter Reference
    3.3 Running the Recognizer on Audio Files


1. Building kroko-onnx

Linux (x64 or arm64)

git clone https://github.com/orgs/kroko-ai/kroko-onnx
cd kroko-onnx
mkdir build
cd build

# By default, it builds static libraries and uses static link and works only with Kroko free models
cmake -DCMAKE_BUILD_TYPE=Release ..

# To build it with an option to use Kroko Pro models
cmake -DCMAKE_BUILD_TYPE=Release -DKROKO_LICENSE=ON ..

make -j6

⚠️ IMPORTANT: If you build with the license option enabled (-DKROKO_LICENSE=ON), and later want to switch back to a license-free build,
you must delete the build/ directory first, or explicitly rerun cmake with -DKROKO_LICENSE=OFF to clear the CMake cache.
Otherwise, the license configuration may persist in the build.

After building, you will find the executable kroko-onnx-online-websocket-server inside the bin directory.

For GPU builds, refer to:
Sherpa-ONNX GPU Install Guide


Docker

git clone https://github.com/kroko-ai/kroko-onnx.git
cd kroko-onnx

# For Kroko free models
docker build -t kroko-onnx .

# For Kroko Pro models
docker build -t kroko-onnx --build-arg KROKO_LICENSE=ON .

After building, you will find the executable kroko-onnx-online-websocket-server and the kroko-onnx Python package installed.


Python

git clone https://github.com/kroko-ai/kroko-onnx
cd kroko-onnx

# For Kroko free models
pip install .

# For Kroko Pro models
KROKO_LICENSE=ON pip install .

After installation, you can use the kroko-onnx Python package.


macOS (Apple Silicon)

Native arm64 wheel build — no Docker, no cross-compile. Tested on Apple Silicon (M-series); Intel Macs should work with the same script as long as Homebrew is installed in /usr/local.

git clone https://github.com/kroko-ai/kroko-onnx
cd kroko-onnx

# Build both pro + free variants (default)
./build_macos.sh

# Or pick one
./build_macos.sh --variant pro
./build_macos.sh --variant free

The script auto-installs the build dependencies it needs via Homebrew: cmake, ninja, openssl@3, python@3.11. Python tooling (pybind11, wheel, delocate) is installed into a venv at /tmp/kroko-onnx-macos-build/venv.

Outputs

release_artifacts/macos/
├── kroko_onnx-<version>-1pro-cp311-cp311-macosx_<host>_arm64.whl
└── kroko_onnx-<version>-1free-cp311-cp311-macosx_<host>_arm64.whl

The wheel bundles all non-system dylibs (OpenSSL, onnxruntime) into kroko_onnx/.dylibs/ via delocate-wheel, so pip install works standalone.

⚠️ Deployment target note: the wheel's macosx_<host>_arm64 tag matches the running macOS version because Homebrew's openssl@3 dylibs are built against the host SDK. For a wheel that installs on older macOS releases, run the build on the oldest macOS you support (or use cibuildwheel + GitHub Actions macOS runners). No installer is produced on macOS — only the Python wheel.


Windows (x86_64)

Windows builds are cross-compiled from a Docker image — no Windows machine required. A single command produces both the NSIS installer (.exe) and the Python wheel (.whl), and supports two variants:

  • proKROKO_LICENSE=ON, links OpenSSL (libssl-3-x64.dll + libcrypto-3-x64.dll). Use this for paid/licensed Kroko models.
  • freeKROKO_LICENSE=OFF, no license/metrics code, no OpenSSL dependency. Use this for the open-source / community workflow.

From Linux or macOS (Docker)

git clone https://github.com/kroko-ai/kroko-onnx
cd kroko-onnx

# Build both pro + free variants (default)
./build_windows.sh

# Or pick a single variant
./build_windows.sh --variant pro
./build_windows.sh --variant free

Requires Docker (or Docker Desktop) with the linux/amd64 platform available. The first run pulls the build image and warms the FetchContent cache for openfst / onnxruntime; subsequent runs are much faster.

From a Windows host (Docker Desktop)

A .bat port of the same script:

git clone https://github.com/kroko-ai/kroko-onnx
cd kroko-onnx

build_windows.bat
build_windows.bat --variant pro
build_windows.bat --variant free

Requires Docker Desktop (WSL2 backend) and PowerShell 5+ (ships with Windows 10/11).

Outputs

release_artifacts/windows/
├── kroko-onnx-websocket-server-<version>-pro-setup.exe        # NSIS installer (pro)
├── kroko-onnx-websocket-server-<version>-free-setup.exe       # NSIS installer (free)
├── kroko_onnx-<version>-1pro-cp312-cp312-win_amd64.whl        # Python wheel (pro)
├── kroko_onnx-<version>-1free-cp312-cp312-win_amd64.whl       # Python wheel (free)
├── bin-pro/                                                    # raw artefacts (pro)
└── bin-free/                                                   # raw artefacts (free)

The installer ships the websocket-server .exe plus every runtime DLL it needs and chain-installs Microsoft's Visual C++ Redistributable. The wheel bundles all runtime DLLs via delvewheel, so pip install kroko_onnx-*.whl works standalone.

The two wheel filenames carry different PEP 425 build tags (1pro / 1free) so they can sit side-by-side on disk without colliding; install whichever variant you need:

pip install kroko_onnx-<version>-1pro-cp312-cp312-win_amd64.whl

2. Usage Examples (WebSocket Server)

./kroko-onnx-online-websocket-server --key=LICENSE_KEY --model=/path/to/model.data

Starts the server listening on the default port (6006).

./kroko-onnx-online-websocket-server --key=LICENSE_KEY --port=6007 --model=/path/to/model.data

Starts the server listening on a specified port.

./kroko-onnx-online-websocket-server --help

Shows the full list of parameters.


WebSocket Server Format

Input

  • The samples should be 16kHz, single channel, and 16-bit.
  • The WebSocket connection accepts a buffer in the following format:
    • data: float32 buffer
Python Example: Convert Audio to Float32 Buffer
samples = f.readframes(num_samples)
samples_int16 = np.frombuffer(samples, dtype=np.int16)
samples_float32 = samples_int16.astype(np.float32)
buf = samples_float32.tobytes()

Output

The result is in JSON format:

{
  "type": "partial",
  "text": "Text from the current segment",
  "segment": 0,
  "startedAt": 0.0,
  "elements": {
    "segments": [
      {
        "type": "segment",
        "text": "",
        "startedAt": 0.0,
        "segment": 0
      }
    ],
    "words": [
      {
        "type": "word",
        "text": "",
        "startedAt": 0.0,
        "segment": 0
      }
    ]
  }
}

Output Fields

Each section contains the following elements:

type – The type of the element:
  • final – the full text of the decoded segment
  • partial – the text of a not-yet-finished segment
  • segment – part of the transcript, same as the text in the main segment (for Banafo Online).
  • word – individual word
text

The transcript of the segment or individual word.

startedAt

The timestamp (in seconds, float value) indicating the beginning of the element.

Example: 1.42 = 1 second and 420 milliseconds

elements

Contains:

  • segments: array of segment objects
  • words: array of word objects

3. Using kroko-onnx from Python

Import and Create a Recognizer

import kroko_onnx

recognizer = kroko_onnx.OnlineRecognizer.from_transducer(
    model_path="path/to/model",
    key="",
    referralcode="",
    num_threads=1,
    provider="cpu",
    sample_rate=16000,
    decoding_method="modified_beam_search",
    blank_penalty=0.0,
    enable_endpoint_detection=True,
    rule1_min_trailing_silence=2.4,
    rule2_min_trailing_silence=1.2,
    rule3_min_utterance_length=20.0,
)

⚠️ Only model_path is required. All other parameters are optional.


Parameter Reference

ArgumentTypeDefaultDescription
model_pathstrRequiredPath to the Kroko model file.
keystr""License key. Required only for Pro models.
referralcodestr""Optional project referral code. Contact Kroko for revenue sharing options.
num_threadsint1Number of threads used for neural network computation.
providerstr"cpu"Execution provider. Valid values: cpu, cuda, coreml.
sample_rateint16000Sample rate of the input audio. Resampling is performed if it differs.
decoding_methodstr"modified_beam_search"Valid values: greedy_search, modified_beam_search.
blank_penaltyfloat0.0Penalty applied to the blank symbol during decoding (applied as: logits[:, 0] -= blank_penalty).
enable_endpoint_detectionboolTrueEnables endpoint detection using rule-based logic.
rule1_min_trailing_silencefloat2.4Rule 1: Minimum trailing silence (in seconds) to trigger endpoint.
rule2_min_trailing_silencefloat1.2Rule 2: Minimum trailing silence (in seconds) to trigger endpoint.
rule3_min_utterance_lengthfloat20.0Rule 3: Minimum utterance length (in seconds) to trigger endpoint.

Running the Recognizer on Audio Files

Below is a complete example of how to use the recognizer to transcribe one or more .wav files:

import numpy as np
from kroko_onnx.utils import read_wave, assert_file_exists

streams = []
total_duration = 0

for wave_filename in args.sound_files:
    assert_file_exists(wave_filename)

    samples, sample_rate = read_wave(wave_filename)
    duration = len(samples) / sample_rate
    total_duration += duration

    # Create a new stream for this audio
    s = recognizer.create_stream()

    # Send waveform data
    s.accept_waveform(sample_rate, samples)

    # Add 0.66 seconds of padding silence
    tail_paddings = np.zeros(int(0.66 * sample_rate), dtype=np.float32)
    s.accept_waveform(sample_rate, tail_paddings)

    s.input_finished()
    streams.append(s)

# Decode all ready streams in parallel
while True:
    ready_list = [s for s in streams if recognizer.is_ready(s)]
    if not ready_list:
        break
    recognizer.decode_streams(ready_list)

# Collect results
results = [recognizer.get_result(s) for s in streams]

# Print transcriptions
for i, result in enumerate(results):
    print(f"{args.sound_files[i]}: {result.text}")

🔁 You can process multiple files at once using this pattern.
📎 Each stream corresponds to one audio file.