语音唤醒算是语音识别领域里最基础的应用,具体的场景如 Android 手机里的 “OK, Google” 或者苹果设备里的 “Hey, Siri”。
简单来说就是在后台静默地运行着一个占用较少系统资源的服务(语音识别组件),该组件一直处于监视麦克风输入的状态,如果有检测到特定的语音输入(即唤醒词或“热词”),则激活与之绑定的某个程序“开关”。
相当于一个简化版的语音助手吧,只对某一个特定的词汇进行响应,识别后也只完成某一件指定的任务。如果说同语音助手的交互是一段持续的交流,那么语音唤醒即可作为这种连续交流的入口(打招呼)。
snowboy 是一个开源的、轻量级语音唤醒引擎,可以通过它很轻松地创建属于自己的类似“hey, Siri” 的唤醒词。它的主要特性如下:
- 高度可定制性。可自由创建和训练属于自己的唤醒词
- 始终倾听。可离线使用,无需联网,保护隐私。精确度高,低延迟
- 轻量可嵌入。耗费资源非常低(单核 700MHz 树莓派只占用 10% CPU)
- 开源跨平台。开放源代码,支持多种操作系统和硬件平台,可绑定多种编程语言
详细看了官网提供的安装配置教程(已经很久没更新,有点过于繁琐了),几番尝试之后,感觉下面的介绍算是最新也相对最简单的方法了吧。
PS:只针对 Linux 系统(包含树莓派),其他平台可参考 Github
一、获取源代码并编译
安装依赖
树莓派原生的音频设备是不支持语音输入的(无法录音),需要在网上购买一支免驱动的USB音频驱动(便携式的和 U 盘差不多),一般插上即可直接使用。
建议安装下 pulseaudio
软件,减少音频配置的步骤:
$ sudo apt-get install pulseaudio
安装 sox
软件测试录音与播放功能:
$ sudo apt-get install sox
安装完成后运行 sox -d -d
命令,对着麦克风说话,确认可以听到自己的声音。
安装其他软件依赖:
- 安装 PyAudio:
$ sudo apt-get install python3-pyaudio
- 安装 SWIG(>3.0.10):
$ sudo apt-get install swig
- 安装 ATLAS:
$ sudo apt-get install libatlas-base-dev
编译源代码
获取源代码:$ git clone https://github.com/Kitt-AI/snowboy.git
编译 Python3 绑定:$ cd snowboy/swig/Python3 && make
测试:
进入官方示例目录 snowboy/examples/Python3
并运行以下命令:
$ python3 demo.py resources/models/snowboy.umdl
( 命令中的 snowboy.umdl
文件即语音识别模型)
然后对着麦克风清晰地讲出“snowboy”,如果可以听到“滴”的声音,则安装配置成功。命令行输出如下:
PS:官方源代码使用 Python3 测试有报错,经测试需修改 snowboy/examples/Python3
目录下的 snowboydecoder.py
文件。
将第 5 行代码 from * import snowboydetect
改为 import snowboydetect
即可直接运行。
二、设置自己的唤醒词
可将包含自定义唤醒词的音频文件上传至 snowboy 官网(需要登录),以训练生成自己喜欢的语音模型。
需要上传的音频文件数量为 3 个,wav 格式。我试过直接在线录制,貌似有 Bug 。。。(也可能是我浏览器的问题)
训练完成并测试通过后,即可下载 PMDL 后缀的模型文件了。
测试
将以下文件复制到自己的项目目录下:
- 上一步中下载好的 model.pmdl 模型文件
- 之前
snowboy/swig/Python3
目录下编译好的_snowboydetect.so
库 -
snowboy/examples/Python3
目录下的demo.py
、snowboydecoder.py
、snowboydetect.py
文件以及resources
目录 - 在项目目录下执行
$ python3 demo.py model.pmdl
并使用自己的唤醒词进行测试
三、自定义响应
官方提供的示例 demo.py
文件的源代码如下:
import snowboydecoder
import sys
import signal
interrupted = False
def signal_handler(signal, frame):
global interrupted
interrupted = True
def interrupt_callback():
global interrupted
return interrupted
if len(sys.argv) == 1:
print("Error: need to specify model name")
print("Usage: python demo.py your.model")
sys.exit(-1)
model = sys.argv[1]
# capture SIGINT signal, e.g., Ctrl+C
signal.signal(signal.SIGINT, signal_handler)
detector = snowboydecoder.HotwordDetector(model, sensitivity=0.5)
print('Listening... Press Ctrl+C to exit')
# main loop
detector.start(detected_callback=snowboydecoder.play_audio_file,
interrupt_check=interrupt_callback,
sleep_time=0.03)
detector.terminate()
通过阅读代码,可以看出唤醒词识别成功以后,程序响应的具体内容由程序末尾 detector.start()
函数的 detected_callback
参数指定。
即重新绑定 detected_callback
对应的函数,可改变程序最终的响应。如:
import snowboydecoder
import sys
import signal
interrupted = False
def signal_handler(signal, frame):
global interrupted
interrupted = True
def interrupt_callback():
global interrupted
return interrupted
def detected():
print("Great! I have recognized your words.\n")
if len(sys.argv) == 1:
print("Error: need to specify model name")
print("Usage: python demo.py your.model")
sys.exit(-1)
model = sys.argv[1]
# capture SIGINT signal, e.g., Ctrl+C
signal.signal(signal.SIGINT, signal_handler)
detector = snowboydecoder.HotwordDetector(model, sensitivity=0.5)
print('Listening... Press Ctrl+C to exit')
# main loop
detector.start(detected_callback=detected,
interrupt_check=interrupt_callback,
sleep_time=0.03)
detector.terminate()
注意添加的 detected
函数。
更复杂的应用形式(如控制 LED 小灯等)也是基本上一样的思路,具体示例代码可参考官方文档。