79 lines
2.3 KiB
Python
79 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Skeleton: load openwakeword's 'alexa' model and print scores every 80 ms.
|
|
|
|
This task validates that the model loads, the mic stream produces 1280-sample
|
|
frames, and predict() returns a non-empty score dict. Detection + beep come
|
|
in the next task.
|
|
"""
|
|
import os
|
|
os.environ.setdefault("PA_ALSA_PLUGHW", "1")
|
|
|
|
import sys
|
|
import time
|
|
|
|
import numpy as np
|
|
import sounddevice as sd
|
|
import openwakeword.utils
|
|
from openwakeword.model import Model
|
|
|
|
SAMPLE_RATE = 16_000
|
|
FRAME_SAMPLES = 1280 # 80 ms @ 16 kHz, openwakeword's expected chunk
|
|
CHANNELS = 1
|
|
DTYPE = "int16"
|
|
WAKEWORD = "alexa"
|
|
|
|
|
|
def find_usb_device() -> int:
|
|
for idx, dev in enumerate(sd.query_devices()):
|
|
name = dev["name"].lower()
|
|
if "usb" in name and dev["max_input_channels"] >= 1:
|
|
return idx
|
|
print("USB audio device not found. Devices:", file=sys.stderr)
|
|
print(sd.query_devices(), file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def main() -> int:
|
|
print("Ensuring openwakeword onnx models are downloaded (idempotent)...")
|
|
openwakeword.utils.download_models()
|
|
|
|
print("Loading openwakeword model...")
|
|
t0 = time.monotonic()
|
|
model = Model(wakeword_models=[WAKEWORD], inference_framework="onnx")
|
|
print(
|
|
f"Model loaded in {time.monotonic() - t0:.2f}s. "
|
|
f"Score keys: {list(model.models.keys())}"
|
|
)
|
|
|
|
device = find_usb_device()
|
|
print(
|
|
f"Streaming from device {device} ({sd.query_devices(device)['name']!r}). "
|
|
f"Will print {WAKEWORD} score 5x/s for ~10s, then exit."
|
|
)
|
|
|
|
start = time.monotonic()
|
|
last_print = 0.0
|
|
with sd.InputStream(
|
|
samplerate=SAMPLE_RATE,
|
|
channels=CHANNELS,
|
|
dtype=DTYPE,
|
|
device=device,
|
|
blocksize=FRAME_SAMPLES,
|
|
) as stream:
|
|
while time.monotonic() - start < 10.0:
|
|
frame, overflowed = stream.read(FRAME_SAMPLES)
|
|
if overflowed:
|
|
print("[status] input overflow", file=sys.stderr)
|
|
mono = frame[:, 0]
|
|
scores = model.predict(mono)
|
|
now = time.monotonic()
|
|
if now - last_print >= 0.2:
|
|
score = float(scores.get(WAKEWORD, 0.0))
|
|
print(f"t={now - start:4.1f}s {WAKEWORD}={score:.3f}")
|
|
last_print = now
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|