naptrap
Local, text-defined wake word detection in PyTorch. Type a keyword, give naptrap a short audio clip, and it tells you whether the keyword was spoken. New wake words need no recordings or training.
from naptrap import load_model, load_wav
model = load_model("phonmatchnet") # downloads the model on first use
result = model.detect(load_wav("clip.wav"), "hey computer")
print(result.score) # keyword-match probability, 0-1
print(result.accepted) # score >= the model's calibrated threshold
The first model is an independently trained PhonMatchNet (Lee & Cho, Interspeech 2023) for English. Inference runs on the CPU with PyTorch as the only heavy dependency. There is no TensorFlow, NumPy, torchaudio or NLTK, and no cloud API.
Install
pip install "naptrap[hub]"
Python 3.9+ and PyTorch 1.13+ are required. If you want a CPU-only or
CUDA-specific PyTorch build, install it first; see
pytorch.org. The hub extra adds
huggingface_hub for automatic model downloads. Without it, pip install naptrap works with model directories you download yourself.
Models
load_model("phonmatchnet") fetches three Hugging Face repositories (about
6 MB in total), pinned to revision v1, and caches them locally:
| Repository | Role | License |
|---|---|---|
androiddrew/naptrap-phonmatchnet-en |
keyword matcher | Apache-2.0 |
androiddrew/google-speech-embedding-pytorch |
frozen audio encoder | Apache-2.0 |
androiddrew/g2p-en-decoder-pytorch |
frozen keyword text encoder | Apache-2.0 |
To work offline, download them once and pass the directories:
hf download androiddrew/naptrap-phonmatchnet-en --revision v1 --local-dir models/phonmatchnet
hf download androiddrew/google-speech-embedding-pytorch --revision v1 --local-dir models/google
hf download androiddrew/g2p-en-decoder-pytorch --revision v1 --local-dir models/g2p
model = load_model("phonmatchnet", model_dir="models/phonmatchnet",
google_dir="models/google", g2p_dir="models/g2p")
Every weight file is checked against the SHA-256 recorded in its config.json.
The keyword model also pins the exact encoders it was trained with.
Usage
Audio
detect() scores one mono 16 kHz clip of 0.5–2 seconds, given as a 1-D
float32 tensor or array with values in [-1, 1]. load_wav() reads 16-bit PCM
WAV files using only the standard library. Convert other files first:
ffmpeg -i input.m4a -ac 1 -ar 16000 -sample_fmt s16 clip.wav
naptrap does not resample, trim or rescale audio for you.
Reusing a keyword
Converting the keyword text is cheap, but if you score many clips against the same keyword you can do it once:
wake = model.keyword("hey computer")
for clip in clips:
if model.detect(clip, wake).accepted:
...
Keywords are English words; accents and punctuation are removed. Spell out numbers ("route sixty six").
Operating points and thresholds
model.thresholds # {0.01: 0.7149..., 0.1: 0.0025...}
model.detect(clip, "hey computer", far=0.1) # more sensitive
Each threshold was fitted on held-out development speakers to target a
per-clip false-accept rate (FAR) of 1% or 10%. These targets do not hold on
other audio. On phonetically confusable phrases, the 1% threshold accepted
31% of negatives. For a real product, record some positive and negative clips
in your setting and choose your own threshold on result.score. See the
model card for
the evaluation.
Command line
naptrap detect clip.wav "hey computer"
naptrap detect clip.wav "hey computer" --far 0.1 --model-dir models/phonmatchnet \
--google-dir models/google --g2p-dir models/g2p
The command prints the prediction as JSON. It exits with 0 if the keyword was
accepted, 1 if it was rejected and 2 on error. python -m naptrap works the
same way.
Precomputed features
model.predict({"keyword_mel": ..., "google": ..., "text": ...}) scores
features you computed yourself: [T, 40], [T/8, 96] and [P, 256] float32.
The encoders are exposed as naptrap.GoogleSpeechEmbedding and
naptrap.G2PTextEncoder.
Limitations
- Single clips, not a streaming listener (yet). To watch a microphone you must window the audio yourself, e.g. 1.5 s windows every 0.25 s, and add your own debouncing.
- English only, trained on read audiobook speech (LibriSpeech). Expect lower accuracy with noise, far-field microphones, accents or children.
- No speaker verification. Anyone saying the keyword triggers it.
- Similar-sounding phrases are often confused.
- CPU inference is the supported path; other devices have not been validated.
- Not for security or safety-critical use.
Adding model families
Backends implement keyword(), detect() and predict(), and return a
Prediction. Register a loader under a new name:
from naptrap import register_model, load_model
register_model("my-model", MyModel.from_pretrained)
model = load_model("my-model", model_dir="...")
Development
pip install -e ".[test]"
pytest
# Also run the real-model tests against downloaded model directories:
NAPTRAP_TEST_MODELS=path/to/models pytest
NAPTRAP_TEST_MODELS must point at a directory holding the three model
repositories in subdirectories named naptrap-phonmatchnet-en,
google-speech-embedding-pytorch and g2p-en-decoder-pytorch.
License and attribution
naptrap is licensed under the Apache License 2.0. The network follows the PhonMatchNet design and NCSOFT's BSD-3-Clause reference code (see NOTICE and licenses/). The PhonMatchNet weights were trained independently. naptrap is not affiliated with or endorsed by NCSOFT or the PhonMatchNet authors. See THIRD_PARTY_NOTICES.md for every component.
If naptrap's PhonMatchNet model is useful in your research, please cite:
@inproceedings{lee23phonmatchnet,
title = {PhonMatchNet: Phoneme-Guided Zero-Shot Keyword Spotting for User-Defined Keywords},
author = {Lee, Yong-Hyeok and Cho, Namhyun},
booktitle = {Proc. INTERSPEECH 2023},
pages = {3964--3968},
year = {2023}
}
Metadata
Release files for naptrap 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| naptrap-0.1.0.tar.gz | 28.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| naptrap-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 53.6 kB
Release files / naptrap-0.1.0.tar.gz
| Download URL | naptrap-0.1.0.tar.gz |
|---|---|
| Size | 28.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d458c0999441710ea3d67622f7ef3c782c75a07624d44ecaacedfb93685ccb6d
|
|
BLAKE2b-256 checksum How to use checksums |
7302f32e8515c47f30688f191f35e594b74d1a70e176de57addddff950f73f3b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / naptrap-0.1.0-py3-none-any.whl
| Download URL | naptrap-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8dc2a77ff212a40d7fe4b57bb79961870c16a3b123571a87c346ca96cfc63e52
|
|
BLAKE2b-256 checksum How to use checksums |
d3707c0d678b0e60eaad6712685172a4b943a1d37ba50b2e6bcc39de870329aa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|