npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

wakeword-web

v0.1.0

Published

Browser-side wake word detection using ONNX models (openWakeWord compatible)

Downloads

19

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