Offline Voice Commands on Linux with Python and ONNX

August 2026 · Linux · Python · Keyword spotting

For a robot, kiosk, media controller, or industrial tool with a fixed command set, full speech recognition is often unnecessary. A compact multi-keyword model can call local Python functions immediately and keep audio off the network.

Architecture

microphone → 16 kHz PCM → Mel features → ONNX model
          → detection filters → command callback → local action

The model only decides which configured keyword was heard. Your application remains responsible for permissions, business logic, and safe action execution.

Install the runtime

sudo apt install python3-venv portaudio19-dev
git clone https://github.com/voicute/onnx-wakeword.git
cd onnx-wakeword
python3 -m venv .venv
source .venv/bin/activate
pip install onnxruntime numpy pyaudio

Test the audio device

python python/mic_test.py --list-devices

Confirm the intended input is visible before debugging the model. USB microphones can change device indexes after reboot, so production code should select a stable device name where possible.

Connect detections to actions

from python.wakeword_engine import WakeWordEngine

def on_command(word, probability, info):
    actions = {
        "lights on": turn_lights_on,
        "lights off": turn_lights_off,
        "next": show_next_item,
        "stop": stop_current_job,
    }
    action = actions.get(word)
    if action:
        action()

engine = WakeWordEngine()
engine.load("models/model_info.json", "models/melspectrogram.onnx")
engine.start(on_command)

Do not pass recognized text to a shell

Map known model labels to predeclared functions. Avoid building shell commands from callback strings, and require confirmation for deletion, door control, payments, or safety-related machinery.

Service deployment

Once the foreground microphone test works, wrap the process as a systemd service with a dedicated unprivileged user. Give it access only to the microphone and devices it actually controls. Log detections and errors, but do not retain raw audio unless users explicitly opt in.

Raspberry Pi note

The Python path is suitable for 64-bit ARM when ONNX Runtime is available. The repository also contains a TFLite inference script for 32-bit Raspberry Pi. A dedicated Pi guide should include real Pi OS installation and timing results before making performance claims.

Disclosure: Voicute develops the model generator and maintains the open-source inference examples used in this guide.
Create a multi-command model