2018-07-30 22:08:06 +02:00
|
|
|
"""
|
|
|
|
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
|
2018-07-30 23:18:01 +02:00
|
|
|
.. license: MIT
|
2018-07-30 22:08:06 +02:00
|
|
|
"""
|
|
|
|
|
2018-03-20 23:34:36 +01:00
|
|
|
import json
|
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
import time
|
|
|
|
|
|
|
|
from platypush.backend import Backend
|
2019-07-11 22:54:33 +02:00
|
|
|
from platypush.context import get_plugin
|
2018-03-20 23:34:36 +01:00
|
|
|
from platypush.message.event.assistant import \
|
|
|
|
ConversationStartEvent, ConversationEndEvent, \
|
|
|
|
SpeechRecognizedEvent, HotwordDetectedEvent
|
|
|
|
|
2019-07-11 22:54:33 +02:00
|
|
|
|
2018-03-20 23:34:36 +01:00
|
|
|
class AssistantSnowboyBackend(Backend):
|
2018-06-26 00:16:39 +02:00
|
|
|
"""
|
|
|
|
Backend for detecting custom voice hotwords through Snowboy. The purpose of
|
|
|
|
this component is only to detect the hotword specified in your Snowboy voice
|
|
|
|
model. If you want to trigger proper assistant conversations or custom
|
|
|
|
speech recognition, you should create a hook in your configuration on
|
|
|
|
HotwordDetectedEvent to trigger the conversation on whichever assistant
|
|
|
|
plugin you're using (Google, Alexa...)
|
|
|
|
|
|
|
|
Triggers:
|
|
|
|
|
2018-07-30 23:18:01 +02:00
|
|
|
* :class:`platypush.message.event.assistant.HotwordDetectedEvent` \
|
|
|
|
whenever the hotword has been detected
|
2018-06-26 00:16:39 +02:00
|
|
|
|
|
|
|
Requires:
|
|
|
|
|
|
|
|
* **snowboy** (``pip install snowboy``)
|
2019-07-11 22:54:33 +02:00
|
|
|
|
|
|
|
Manual installation for snowboy and its Python bindings if the command above
|
|
|
|
fails:
|
|
|
|
|
|
|
|
$ [sudo] apt-get install libatlas-base-dev swig
|
|
|
|
$ [sudo] pip install pyaudio
|
|
|
|
$ git clone https://github.com/Kitt-AI/snowboy
|
|
|
|
$ cd snowboy/swig/Python3
|
|
|
|
$ make
|
|
|
|
$ cd ../..
|
|
|
|
$ python3 setup.py build
|
|
|
|
$ [sudo] python setup.py install
|
|
|
|
|
|
|
|
You will also need a voice model for the hotword detection. You can find
|
|
|
|
some under the ``resources/models`` directory of the Snowboy repository,
|
|
|
|
or train/download other models from https://snowboy.kitt.ai.
|
2018-06-26 00:16:39 +02:00
|
|
|
"""
|
2018-03-20 23:34:36 +01:00
|
|
|
|
|
|
|
def __init__(self, voice_model_file, hotword=None, sensitivity=0.5,
|
2019-07-11 22:54:33 +02:00
|
|
|
audio_gain=1.0, assistant_plugin=None, **kwargs):
|
2018-03-20 23:34:36 +01:00
|
|
|
"""
|
2018-07-30 23:18:01 +02:00
|
|
|
:param voice_model_file: Snowboy voice model file - \
|
|
|
|
see https://snowboy.kitt.ai/
|
2018-06-26 00:16:39 +02:00
|
|
|
:type voice_model_file: str
|
|
|
|
|
|
|
|
:param hotword: Name of the hotword
|
|
|
|
:type hotword: str
|
|
|
|
|
2019-07-11 22:54:33 +02:00
|
|
|
:param sensitivity: Hotword recognition sensitivity, between 0 and 1.
|
|
|
|
Default: 0.5.
|
2018-06-26 00:16:39 +02:00
|
|
|
:type sensitivity: float
|
|
|
|
|
|
|
|
:param audio_gain: Audio gain, between 0 and 1
|
|
|
|
:type audio_gain: float
|
2019-07-11 22:54:33 +02:00
|
|
|
|
|
|
|
:param assistant_plugin: By default Snowboy fires a
|
|
|
|
:class:`platypush.message.event.assistant.HotwordDetectedEvent` event
|
|
|
|
whenever the hotword is detected. You can also pass the plugin name of
|
|
|
|
a :class:`platypush.plugins.assistant.AssistantPlugin` instance
|
|
|
|
(for example ``assistant.google.pushtotalk``). If set, then the
|
|
|
|
assistant plugin will be invoked to start a conversation.
|
|
|
|
:type assistant_plugin: str
|
2018-06-26 00:16:39 +02:00
|
|
|
"""
|
|
|
|
|
2019-07-11 22:54:33 +02:00
|
|
|
try:
|
|
|
|
import snowboydecoder
|
|
|
|
except ImportError:
|
|
|
|
import snowboy.snowboydecoder as snowboydecoder
|
2018-03-20 23:34:36 +01:00
|
|
|
|
|
|
|
super().__init__(**kwargs)
|
2019-07-11 22:54:33 +02:00
|
|
|
self.voice_model_file = os.path.abspath(os.path.expanduser(voice_model_file))
|
2018-03-20 23:34:36 +01:00
|
|
|
self.hotword = hotword
|
|
|
|
self.sensitivity = sensitivity
|
|
|
|
self.audio_gain = audio_gain
|
2019-07-11 22:54:33 +02:00
|
|
|
self.assistant_plugin = assistant_plugin
|
2018-03-20 23:34:36 +01:00
|
|
|
|
|
|
|
self.detector = snowboydecoder.HotwordDetector(
|
|
|
|
self.voice_model_file, sensitivity=self.sensitivity,
|
|
|
|
audio_gain=self.audio_gain)
|
|
|
|
|
2018-06-06 20:09:18 +02:00
|
|
|
self.logger.info('Initialized Snowboy hotword detection')
|
2018-03-20 23:34:36 +01:00
|
|
|
|
|
|
|
def hotword_detected(self):
|
2018-07-30 22:08:06 +02:00
|
|
|
"""
|
|
|
|
Callback called on hotword detection
|
|
|
|
"""
|
|
|
|
|
2018-03-20 23:34:36 +01:00
|
|
|
def callback():
|
|
|
|
self.bus.post(HotwordDetectedEvent(hotword=self.hotword))
|
2019-07-11 22:54:33 +02:00
|
|
|
|
|
|
|
if self.assistant_plugin:
|
|
|
|
# Trigger assistant conversation
|
|
|
|
get_plugin(self.assistant_plugin).start_conversation()
|
|
|
|
|
2018-03-20 23:34:36 +01:00
|
|
|
return callback
|
|
|
|
|
2019-07-11 22:54:33 +02:00
|
|
|
def on_stop(self):
|
|
|
|
if self.detector:
|
|
|
|
self.detector.terminate()
|
|
|
|
self.detector = None
|
|
|
|
|
2018-10-25 20:45:58 +02:00
|
|
|
def run(self):
|
|
|
|
super().run()
|
2018-03-20 23:34:36 +01:00
|
|
|
self.detector.start(self.hotword_detected())
|
|
|
|
|
|
|
|
|
|
|
|
# vim:sw=4:ts=4:et:
|