Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

ovos-ww-verifier-plugin-speaker

An OVOS wake word verifier plugin. It accepts voice commands only from enrolled household members.

After a wake word engine detects an activation, this verifier extracts a speaker embedding from the captured audio. It compares the embedding against enrolled profiles. The plugin silently drops activations from unrecognized speakers.

Use case

Alice and Bob live together and use OVOS at home. They enroll their voices once. A guest's "Hey Mycroft" still triggers the wake word detector, but the speaker verifier rejects it before any intent is processed. Commands from Alice and Bob go through normally.

Privacy note

The plugin stores speaker profiles as fixed-length numeric vectors (embeddings) in a local JSON file at ~/.local/share/ovos_speaker_verifier/profiles.json. It keeps no audio after embedding extraction. You cannot reverse an embedding back into audio.

Install

pip install ovos-ww-verifier-plugin-speaker

Enroll household members

ovos-speaker-enroll Alice clip1.wav clip2.wav clip3.wav
ovos-speaker-enroll Bob morning_command.wav evening_command.wav

More clips (5 to 30 s total per person) give a more robust profile.

OVOS configuration

ovos-dinkum-listener (>= 0.6.0) loads wake-word verifiers from listener.ww_verifiers. Each key is a verifier plugin's entry-point name. Its value is that plugin's config. Add this to ~/.config/mycroft/mycroft.conf (or the OpenVoiceOS equivalent):

{
  "listener": {
    "ww_verifiers": {
      "ovos-ww-verifier-speaker": {
        "model": "wespeaker-resnet34",
        "threshold": 0.45,
        "fail_open": true
      }
    }
  }
}

Installing the plugin enables it. The listener runs every installed verifier whose config does not set "enabled": false. With no entry in ww_verifiers, the plugin still loads with its defaults. Because fail_open defaults to true, it accepts everything until you enroll at least one profile. Enroll first, then tune the threshold. To install the plugin without activating it, set "enabled": false:

{"listener": {"ww_verifiers": {"ovos-ww-verifier-speaker": {"enabled": false}}}}

What happens on a wake word

The listener runs the verifier inside wake-word detection, on the audio window that triggered the engine. The outcome decides what reaches the bus:

speaker profiles enrolled fail_open recognizer_loop:wakeword recognizer_loop:record_begin
enrolled member yes any emitted emitted
anyone else yes any suppressed suppressed
anyone none true emitted emitted
anyone none false suppressed suppressed

A rejected speaker suppresses the wake-word event itself, not only the recording, so nothing downstream sees the activation. Each decision is one INFO line in the listener log naming the matched or best-matching profile, the cosine score and the threshold applied.

This is the flow proven on a real ovos-dinkum-listener voice loop with ovos-ww-plugin-precise-onnx and its default hey_mycroft model: two synthetic voices both trigger precise-onnx on "hey mycroft, what time is it"; with voice A enrolled and fail_open false, A's clip produces both events (score 0.78 at threshold 0.45) and voice B's clip produces neither (score 0.09). To repeat it, enroll two clips of one voice, set the configuration above with "fail_open": false, start the listener, and speak the wake word as the enrolled voice and as another voice.

Configuration keys

Key Type Default Description
model str "wespeaker-resnet34" speakeronnx model alias or .onnx path
threshold float 0.45 Cosine similarity acceptance threshold
fail_open bool true Accept all activations when no profiles enrolled
profiles_path str ~/.local/share/ovos_speaker_verifier/profiles.json Override profile storage path
per_profile_thresholds dict {} Per-name threshold overrides, e.g. {"Alice": 0.5}
sample_rate int 16000 PCM sample rate of audio chunks passed to verify()
sample_width int 2 PCM sample width in bytes (2 = 16-bit)
channels int 1 PCM channel count

Supported models

The model key accepts any alias from speakeronnx's registry (models are downloaded from HuggingFace on first use and cached):

Alias Architecture
wespeaker-resnet34 (default) WeSpeaker ResNet34 r-vector
wespeaker-ecapa512 WeSpeaker ECAPA-TDNN-512
wespeaker-resnet293 WeSpeaker ResNet293 (large)
campplus WeSpeaker CAM++
campplus-zh-en CAM++ (zh/en)
eres2net ERes2Net
titanet-small NVIDIA TitaNet-Small
titanet-large NVIDIA TitaNet-Large
redimnet-b2 ReDimNet-B2

Threshold tuning

The acceptance threshold is model-specific. It does not transfer between models. Cosine-similarity scales differ widely across architectures. In our tests the same enrolled-vs-guest pair scored ~0.95 / 0.89 on titanet-small, but ~0.17 / 0.14 on campplus. The default 0.45 is calibrated for the default wespeaker-resnet34. If you change model, you must re-tune threshold.

To pick a value, enroll a speaker. Then compare verify() scores for genuine and guest clips, and choose a threshold that sits between them (tests/test_ovoscope_models_e2e.py calibrates this per model automatically). For a given model, lower the threshold for noisier or distant-microphone setups. Raise it for stricter security.

Python API

from ovos_ww_verifier_plugin_speaker import SpeakerVerifier

v = SpeakerVerifier(config={"threshold": 0.45, "fail_open": False})
v.enroll("Alice", ["alice1.wav", "alice2.wav"])

# In wake word callback:
accepted = v.verify(pcm_bytes)  # True if Alice spoke

Testing

pip install -e ".[test]"
pytest tests/test_unit.py tests/test_ovoscope_e2e.py   # fast, offline
  • test_unit.py: verifier policy logic (enrollment, thresholds, fail-open).
  • test_ovoscope_e2e.py: drives the verifier through a real listener (ovoscope.MiniVoiceLoop) and asserts a rejected speaker suppresses recognizer_loop:record_begin on the bus. It is fast and needs no model download.
  • test_e2e.py / test_ovoscope_models_e2e.py: real-model tests over every speakeronnx model. They read the committed synthetic-voice fixtures under tests/fixtures/ (two enrolment clips and one verify clip of voice A, one guest clip of voice B) and confirm only the enrolled speaker triggers the wake word. They download the models on first run and never skip. Regenerate the fixtures with python tests/generate_fixtures.py, which needs edge-tts and ffmpeg.

Dependencies

  • speakeronnx (onnxruntime + numpy + huggingface_hub)
  • ovos-plugin-manager

Credits

Developed by TigreGótico for OpenVoiceOS.

NGI0 Commons Fund

This project was funded through the NGI0 Commons Fund, a fund established by NLnet with financial support from the European Commission's Next Generation Internet programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 101135429.


License

Apache-2.0, see LICENSE

Metadata

Release files for ovos-ww-verifier-plugin-speaker 0.0.4a3

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

Source distribution (sdist)

Source distribution for ovos-ww-verifier-plugin-speaker 0.0.4a3
File Size Uploaded Provenance
ovos_ww_verifier_plugin_speaker-0.0.4a3.tar.gz 23.3 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for ovos-ww-verifier-plugin-speaker 0.0.4a3
File Interpreter ABI Platform
ovos_ww_verifier_plugin_speaker-0.0.4a3-py3-none-any.whl Python 3 none any Details

Total release size: 47.4 kB

Release files / ovos_ww_verifier_plugin_speaker-0.0.4a3.tar.gz

Download URL ovos_ww_verifier_plugin_speaker-0.0.4a3.tar.gz
Size 23.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8ab6920d10f55f624efa0f050704ede1e1b7a8234890598798fd7815dd87d9e9
BLAKE2b-256 checksum
How to use checksums
db4a9d99cfa3e896538c2553170b01f331c5e796b0ad9a8aa28c69bdd2e843ba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / ovos_ww_verifier_plugin_speaker-0.0.4a3-py3-none-any.whl

Download URL ovos_ww_verifier_plugin_speaker-0.0.4a3-py3-none-any.whl
Size 24.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f3e9b450595415f8e859207b98d875d177c8f27d3641e01d55c5782c9f04d0c0
BLAKE2b-256 checksum
How to use checksums
a7f80f4504b595ec2c85df6ffa29f07a1b49c8f690659f6e6b0c85a69baa8525
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Security for ovos-ww-verifier-plugin-speaker 0.0.4a3

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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.

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