2017-10-04 06:28:44 +00:00
|
|
|
# Copyright 2017 Mycroft AI Inc.
|
2016-05-26 20:55:40 +00:00
|
|
|
#
|
2017-10-04 06:28:44 +00:00
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
2016-05-26 20:55:40 +00:00
|
|
|
#
|
2017-10-04 06:28:44 +00:00
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
2016-05-26 20:55:40 +00:00
|
|
|
#
|
2017-10-04 06:28:44 +00:00
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
2016-05-26 20:55:40 +00:00
|
|
|
#
|
2016-05-20 20:34:03 +00:00
|
|
|
import unittest
|
|
|
|
|
2016-05-28 21:28:12 +00:00
|
|
|
import speech_recognition
|
2016-05-20 14:16:01 +00:00
|
|
|
from os.path import dirname, join
|
|
|
|
from speech_recognition import WavFile, AudioData
|
2016-05-24 23:58:36 +00:00
|
|
|
|
2019-06-08 18:14:15 +00:00
|
|
|
from mycroft.client.speech.listener import (AudioConsumer, RecognizerLoop,
|
|
|
|
AUDIO_DATA, STREAM_START,
|
|
|
|
STREAM_DATA, STREAM_STOP)
|
2017-04-16 07:39:34 +00:00
|
|
|
from mycroft.stt import MycroftSTT
|
2018-02-12 20:26:15 +00:00
|
|
|
from queue import Queue
|
2016-05-20 22:15:53 +00:00
|
|
|
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
class MockRecognizer(object):
|
2016-05-25 01:27:35 +00:00
|
|
|
def __init__(self):
|
2016-05-20 14:16:01 +00:00
|
|
|
self.transcriptions = []
|
|
|
|
|
2017-04-16 07:39:34 +00:00
|
|
|
def recognize_mycroft(self, audio, key=None,
|
|
|
|
language=None, show_all=False):
|
2016-05-28 21:28:12 +00:00
|
|
|
if len(self.transcriptions) > 0:
|
|
|
|
return self.transcriptions.pop(0)
|
|
|
|
else:
|
|
|
|
raise speech_recognition.UnknownValueError()
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
def set_transcriptions(self, transcriptions):
|
2016-05-25 00:32:40 +00:00
|
|
|
self.transcriptions = transcriptions
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
class AudioConsumerTest(unittest.TestCase):
|
|
|
|
"""
|
|
|
|
AudioConsumerTest
|
|
|
|
"""
|
2016-05-20 20:34:03 +00:00
|
|
|
|
2016-05-20 14:16:01 +00:00
|
|
|
def setUp(self):
|
|
|
|
self.loop = RecognizerLoop()
|
|
|
|
self.queue = Queue()
|
|
|
|
self.recognizer = MockRecognizer()
|
|
|
|
self.consumer = AudioConsumer(
|
2017-04-16 07:39:34 +00:00
|
|
|
self.loop.state, self.queue, self.loop, MycroftSTT(),
|
2017-09-15 04:34:16 +00:00
|
|
|
self.loop.wakeup_recognizer,
|
|
|
|
self.loop.wakeword_recognizer)
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
def __create_sample_from_test_file(self, sample_name):
|
|
|
|
root_dir = dirname(dirname(dirname(__file__)))
|
2016-05-20 22:15:53 +00:00
|
|
|
filename = join(
|
2017-06-18 06:52:13 +00:00
|
|
|
root_dir, 'unittests', 'client',
|
|
|
|
'data', sample_name + '.wav')
|
2016-05-20 14:16:01 +00:00
|
|
|
wavfile = WavFile(filename)
|
|
|
|
with wavfile as source:
|
2016-05-20 22:15:53 +00:00
|
|
|
return AudioData(
|
2016-06-18 19:00:07 +00:00
|
|
|
source.stream.read(), wavfile.SAMPLE_RATE,
|
|
|
|
wavfile.SAMPLE_WIDTH)
|
2016-05-20 14:16:01 +00:00
|
|
|
|
2016-05-25 21:04:29 +00:00
|
|
|
def test_word_extraction(self):
|
|
|
|
"""
|
|
|
|
This is intended to test the extraction of the word: ``mycroft``.
|
|
|
|
The values for ``ideal_begin`` and ``ideal_end`` were found using an
|
|
|
|
audio tool like Audacity and they represent a sample value position of
|
|
|
|
the audio. ``tolerance`` is an acceptable margin error for the distance
|
|
|
|
between the ideal and actual values found by the ``WordExtractor``
|
|
|
|
"""
|
2016-06-18 19:00:07 +00:00
|
|
|
# TODO: implement WordExtractor test without relying on the listener
|
|
|
|
return
|
|
|
|
|
2016-05-25 01:27:35 +00:00
|
|
|
audio = self.__create_sample_from_test_file('weather_mycroft')
|
2019-06-08 18:14:15 +00:00
|
|
|
self.queue.put((AUDIO_DATA, audio))
|
2016-05-24 23:58:36 +00:00
|
|
|
tolerance = 4000
|
2016-05-25 21:04:29 +00:00
|
|
|
ideal_begin = 70000
|
|
|
|
ideal_end = 92000
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
monitor = {}
|
2016-05-25 01:27:35 +00:00
|
|
|
self.recognizer.set_transcriptions(["what's the weather next week"])
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
def wakeword_callback(message):
|
|
|
|
monitor['pos_begin'] = message.get('pos_begin')
|
|
|
|
monitor['pos_end'] = message.get('pos_end')
|
|
|
|
|
|
|
|
self.loop.once('recognizer_loop:wakeword', wakeword_callback)
|
2016-09-16 22:04:54 +00:00
|
|
|
self.consumer.read()
|
2016-05-20 14:16:01 +00:00
|
|
|
|
2016-05-25 21:04:29 +00:00
|
|
|
actual_begin = monitor.get('pos_begin')
|
|
|
|
self.assertIsNotNone(actual_begin)
|
|
|
|
diff = abs(actual_begin - ideal_begin)
|
2016-05-20 22:15:53 +00:00
|
|
|
self.assertTrue(
|
2016-06-18 19:00:07 +00:00
|
|
|
diff <= tolerance,
|
|
|
|
str(diff) + " is not less than " + str(tolerance))
|
2016-05-20 14:16:01 +00:00
|
|
|
|
2016-05-25 21:04:29 +00:00
|
|
|
actual_end = monitor.get('pos_end')
|
|
|
|
self.assertIsNotNone(actual_end)
|
|
|
|
diff = abs(actual_end - ideal_end)
|
2016-05-20 22:15:53 +00:00
|
|
|
self.assertTrue(
|
2016-06-18 19:00:07 +00:00
|
|
|
diff <= tolerance,
|
|
|
|
str(diff) + " is not less than " + str(tolerance))
|
2016-05-20 14:16:01 +00:00
|
|
|
|
2017-04-16 12:04:25 +00:00
|
|
|
@unittest.skip('Disabled while unittests are brought upto date')
|
2016-05-20 14:16:01 +00:00
|
|
|
def test_wakeword_in_beginning(self):
|
2019-06-10 23:04:38 +00:00
|
|
|
tag = AUDIO_DATA
|
|
|
|
data = self.__create_sample_from_test_file('weather_mycroft')
|
|
|
|
self.queue.put((tag, data))
|
2016-05-25 01:27:35 +00:00
|
|
|
self.recognizer.set_transcriptions(["what's the weather next week"])
|
2016-05-20 14:16:01 +00:00
|
|
|
monitor = {}
|
|
|
|
|
|
|
|
def callback(message):
|
|
|
|
monitor['utterances'] = message.get('utterances')
|
|
|
|
|
|
|
|
self.loop.once('recognizer_loop:utterance', callback)
|
2016-09-16 22:04:54 +00:00
|
|
|
self.consumer.read()
|
2016-05-25 01:27:35 +00:00
|
|
|
|
2016-05-20 14:16:01 +00:00
|
|
|
utterances = monitor.get('utterances')
|
|
|
|
self.assertIsNotNone(utterances)
|
|
|
|
self.assertTrue(len(utterances) == 1)
|
|
|
|
self.assertEquals("what's the weather next week", utterances[0])
|
|
|
|
|
2017-04-16 12:04:25 +00:00
|
|
|
@unittest.skip('Disabled while unittests are brought upto date')
|
2016-05-25 01:27:35 +00:00
|
|
|
def test_wakeword(self):
|
2019-06-08 18:14:15 +00:00
|
|
|
self.queue.put((AUDIO_DATA,
|
|
|
|
self.__create_sample_from_test_file('mycroft')))
|
2016-05-25 01:27:35 +00:00
|
|
|
self.recognizer.set_transcriptions(["silence"])
|
2016-05-20 14:16:01 +00:00
|
|
|
monitor = {}
|
|
|
|
|
|
|
|
def callback(message):
|
|
|
|
monitor['utterances'] = message.get('utterances')
|
|
|
|
|
|
|
|
self.loop.once('recognizer_loop:utterance', callback)
|
2016-09-16 22:04:54 +00:00
|
|
|
self.consumer.read()
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
utterances = monitor.get('utterances')
|
|
|
|
self.assertIsNotNone(utterances)
|
|
|
|
self.assertTrue(len(utterances) == 1)
|
2016-05-25 01:27:35 +00:00
|
|
|
self.assertEquals("silence", utterances[0])
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
def test_ignore_wakeword_when_sleeping(self):
|
2019-06-08 18:14:15 +00:00
|
|
|
self.queue.put((AUDIO_DATA,
|
|
|
|
self.__create_sample_from_test_file('mycroft')))
|
2016-05-25 01:27:35 +00:00
|
|
|
self.recognizer.set_transcriptions(["not detected"])
|
2016-05-20 14:16:01 +00:00
|
|
|
self.loop.sleep()
|
|
|
|
monitor = {}
|
|
|
|
|
|
|
|
def wakeword_callback(message):
|
|
|
|
monitor['wakeword'] = message.get('utterance')
|
|
|
|
|
|
|
|
self.loop.once('recognizer_loop:wakeword', wakeword_callback)
|
2016-09-16 22:04:54 +00:00
|
|
|
self.consumer.read()
|
2016-05-20 14:16:01 +00:00
|
|
|
self.assertIsNone(monitor.get('wakeword'))
|
|
|
|
self.assertTrue(self.loop.state.sleeping)
|
2016-05-25 01:27:35 +00:00
|
|
|
|
|
|
|
def test_wakeup(self):
|
2019-06-10 23:04:38 +00:00
|
|
|
tag = AUDIO_DATA
|
|
|
|
data = self.__create_sample_from_test_file('mycroft_wakeup')
|
|
|
|
self.queue.put((tag, data))
|
2016-05-25 01:27:35 +00:00
|
|
|
self.loop.sleep()
|
2016-09-16 22:04:54 +00:00
|
|
|
self.consumer.read()
|
2016-05-25 01:27:35 +00:00
|
|
|
self.assertFalse(self.loop.state.sleeping)
|
2016-05-26 20:21:08 +00:00
|
|
|
|
2017-04-16 15:42:51 +00:00
|
|
|
@unittest.skip('Disabled while unittests are brought upto date')
|
2016-06-02 18:33:39 +00:00
|
|
|
def test_stop(self):
|
2019-06-08 18:14:15 +00:00
|
|
|
self.queue.put((AUDIO_DATA,
|
|
|
|
self.__create_sample_from_test_file('mycroft')))
|
2016-09-16 22:04:54 +00:00
|
|
|
self.consumer.read()
|
2016-06-02 18:33:39 +00:00
|
|
|
|
2019-06-08 18:14:15 +00:00
|
|
|
self.queue.put((AUDIO_DATA,
|
|
|
|
self.__create_sample_from_test_file('stop')))
|
2016-06-02 18:33:39 +00:00
|
|
|
self.recognizer.set_transcriptions(["stop"])
|
|
|
|
monitor = {}
|
|
|
|
|
|
|
|
def utterance_callback(message):
|
|
|
|
monitor['utterances'] = message.get('utterances')
|
|
|
|
|
|
|
|
self.loop.once('recognizer_loop:utterance', utterance_callback)
|
2016-09-16 22:04:54 +00:00
|
|
|
self.consumer.read()
|
2016-06-02 18:33:39 +00:00
|
|
|
|
|
|
|
utterances = monitor.get('utterances')
|
|
|
|
self.assertIsNotNone(utterances)
|
|
|
|
self.assertTrue(len(utterances) == 1)
|
|
|
|
self.assertEquals("stop", utterances[0])
|
|
|
|
|
2017-04-16 15:42:51 +00:00
|
|
|
@unittest.skip('Disabled while unittests are brought upto date')
|
2016-06-02 18:33:39 +00:00
|
|
|
def test_record(self):
|
2019-06-08 18:14:15 +00:00
|
|
|
self.queue.put((AUDIO_DATA,
|
|
|
|
self.__create_sample_from_test_file('mycroft')))
|
2016-09-16 22:04:54 +00:00
|
|
|
self.consumer.read()
|
2016-06-02 18:33:39 +00:00
|
|
|
|
2019-06-08 18:14:15 +00:00
|
|
|
self.queue.put((AUDIO_DATA,
|
|
|
|
self.__create_sample_from_test_file('record')))
|
2016-06-02 18:33:39 +00:00
|
|
|
self.recognizer.set_transcriptions(["record"])
|
|
|
|
monitor = {}
|
|
|
|
|
|
|
|
def utterance_callback(message):
|
|
|
|
monitor['utterances'] = message.get('utterances')
|
|
|
|
|
|
|
|
self.loop.once('recognizer_loop:utterance', utterance_callback)
|
2016-09-16 22:04:54 +00:00
|
|
|
self.consumer.read()
|
2016-06-02 18:33:39 +00:00
|
|
|
|
|
|
|
utterances = monitor.get('utterances')
|
|
|
|
self.assertIsNotNone(utterances)
|
|
|
|
self.assertTrue(len(utterances) == 1)
|
|
|
|
self.assertEquals("record", utterances[0])
|