wakeword-web
v0.1.0
Published
Browser-side wake word detection using ONNX models (openWakeWord compatible)
Downloads
19
Maintainers
Readme
wakeword-web
浏览器端唤醒词检测库,基于 openWakeWord ONNX 模型,零服务端依赖。
特性
- 纯浏览器推理,麦克风 → mel 特征 → embedding → 分类器全链路
- AudioWorklet 采集,无丢帧
- 滑动窗口 embedding 缓冲,检测延迟 ~1.3s(积累 16 帧后)
- 命中冷却机制,防止同一次说话重复触发
- 同时提供原生 Class API 和 React Hook
安装
npm install wakeword-web onnxruntime-web使用
原生 JS(任意框架)
import { WakeWordDetector } from 'wakeword-web';
const detector = new WakeWordDetector({
melModelUrl: '/models/melspectrogram.onnx',
embModelUrl: '/models/embedding_model.onnx',
clfModelUrl: '/models/xiaozhi_voxcpm.onnx',
threshold: 0.5, // 可选,默认 0.5
cooldown: 500, // 可选,命中后冷却 ms,默认 500
onDetected: (score) => console.log('唤醒词命中!score =', score),
onScore: (score) => console.log('实时分数:', score), // 可选
});
// 开始(会请求麦克风权限,需用户手势触发)
await detector.start();
// 停止(模型缓存保留,下次 start() 无需重新加载)
detector.stop();
// 彻底释放(含模型)
detector.dispose();React Hook
import { useWakeWord } from 'wakeword-web';
import { useCallback } from 'react';
function App() {
const onDetected = useCallback((score) => {
console.log('唤醒!', score);
}, []);
const { listening, score, start, stop } = useWakeWord({
melModelUrl: '/models/melspectrogram.onnx',
embModelUrl: '/models/embedding_model.onnx',
clfModelUrl: '/models/xiaozhi_voxcpm.onnx',
onDetected,
});
return (
<div>
<button onClick={listening ? stop : start}>
{listening ? 'Stop' : 'Start'}
</button>
<p>Score: {score?.toFixed(4) ?? '--'}</p>
{score >= 0.5 && <p style={{ color: 'green' }}>命中!</p>}
</div>
);
}模型文件
将以下三个文件放到项目 public/models/ 目录:
| 文件 | 说明 |
|------|------|
| melspectrogram.onnx | mel 特征提取,输入 [1, 32000],输出 [1, 1, 197, 32] |
| embedding_model.onnx | embedding 提取,输入 [1, 76, 32, 1],输出 [1, 1, 1, 96] |
| xiaozhi_voxcpm.onnx(或其他唤醒词)| 分类器,输入 [1, 16, 96],输出 score |
模型来自 livekit-wakeword 项目,与 openWakeWord Python 版本完全兼容。
onnxruntime-web WASM 配置
ort 默认从 CDN 加载 WASM 文件。如需离线或自定义路径:
import * as ort from 'onnxruntime-web';
ort.env.wasm.wasmPaths = '/ort-wasm/'; // 指向本地 wasm 目录外部音频流(不使用麦克风)
适合 LiveKit / WebRTC / 任意自定义音频源场景。
import { WakeWordDetector } from 'wakeword-web';
const detector = new WakeWordDetector({
melModelUrl: '/models/melspectrogram.onnx',
embModelUrl: '/models/embedding_model.onnx',
clfModelUrl: '/models/xiaozhi_voxcpm.onnx',
onDetected: (score) => console.log('唤醒!', score),
});
// 单独加载模型(不请求麦克风)
await detector.loadModels();
// 推送音频数据(Float32Array,16kHz,单声道,值域 [-1, 1],块大小任意)
detector.processAudio(float32Samples);
// 释放
detector.dispose();LiveKit 场景示例:
await detector.loadModels();
room.on('audioData', (int16Samples) => {
// LiveKit 通常提供 Int16Array,需转为 Float32
const f32 = new Float32Array(int16Samples.length);
for (let i = 0; i < int16Samples.length; i++) {
f32[i] = int16Samples[i] / 32768;
}
detector.processAudio(f32);
});
processAudio()内部按 80ms(1280 样本)帧滚动缓冲,与麦克风模式推理完全一致。
使用前必须先调用loadModels()或start()。
两种模式对比
| | 麦克风模式 start() | 外部音频模式 processAudio() |
|---|---|---|
| 音频来源 | 浏览器麦克风(getUserMedia) | 任意外部数据 |
| 权限需求 | 需要麦克风权限 | 无 |
| 适用场景 | 独立唤醒词检测 | LiveKit / WebRTC / 自定义管道 |
| 帧处理 | AudioWorklet 自动推送 | 手动调用 processAudio() |
| 推理流程 | 完全一致 | 完全一致 |
构建
npm install
npm run build # 输出到 dist/License
MIT
