From 18913d6fecc43aeecfd5b617030e9cd3e840ef08 Mon Sep 17 00:00:00 2001 From: Scott Gasch Date: Wed, 5 May 2021 08:04:08 -0700 Subject: [PATCH] Working on voice command logic. --- listen.py | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100755 listen.py diff --git a/listen.py b/listen.py new file mode 100755 index 0000000..11a4db3 --- /dev/null +++ b/listen.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 + +import os +import struct +from datetime import datetime +from threading import Thread + +import numpy as np +import pvporcupine +import pyaudio +import soundfile +import speech_recognition as sr + +class HotwordListener(object): + def __init__(self, + command_queue, + keyword_paths, + sensitivities, + input_device_index=None, + library_path=pvporcupine.LIBRARY_PATH, + model_path=pvporcupine.MODEL_PATH): + super(HotwordListener, self).__init__() + self._queue = command_queue + self._library_path = library_path + self._model_path = model_path + self._keyword_paths = keyword_paths + self._sensitivities = sensitivities + self._input_device_index = input_device_index + + def listen_forever(self): + keywords = list() + for x in self._keyword_paths: + keywords.append(os.path.basename(x).replace('.ppn', '').split('_')[0]) + + porcupine = None + pa = None + audio_stream = None + try: + porcupine = pvporcupine.create( + library_path=self._library_path, + model_path=self._model_path, + keyword_paths=self._keyword_paths, + sensitivities=self._sensitivities) + recognizer = sr.Recognizer() + pa = pyaudio.PyAudio() + + audio_stream = pa.open( + rate=porcupine.sample_rate, + channels=1, + format=pyaudio.paInt16, + input=True, + frames_per_buffer=porcupine.frame_length, + input_device_index=self._input_device_index) + + print('Listening {') + for keyword, sensitivity in zip(keywords, self._sensitivities): + print(' %s (%.2f)' % (keyword, sensitivity)) + print('}') + + while True: + raw = audio_stream.read(porcupine.frame_length, exception_on_overflow=False) + pcm = struct.unpack_from("h" * porcupine.frame_length, raw) + result = porcupine.process(pcm) + if result >= 0: + os.system('/usr/bin/aplay /var/www/kiosk/attention.wav') + print('[%s] >>>>>>>>>>>>> Detected wakeword %s' % ( + str(datetime.now()), keywords[result]) + ) + print('>>>>>>>>>>>>>>> Listening for command now...') + raw = bytearray() + for i in range(0, int(porcupine.sample_rate / porcupine.frame_length * 4)): + raw += audio_stream.read(porcupine.frame_length, + exception_on_overflow=False) + print(f'>>>>>>>>>>>>>> Recognizing command... {len(raw)} bytes') + speech = sr.AudioData( + frame_data = bytes(raw), + sample_rate = porcupine.sample_rate, + sample_width = 2, # 16 bits + ) + try: + command = recognizer.recognize_google(speech) + print('[%s] >>>>>>>>>>>>> Google says command was %s' % ( + str(datetime.now()), command) + ) + except Exception: + command = 'weather' + self._queue.put(command) + + except Exception as e: + print(e) + print('Stopping ...') + + except KeyboardInterrupt: + print('Stopping ...') + + finally: + if porcupine is not None: + porcupine.delete() + + if audio_stream is not None: + audio_stream.close() + + if pa is not None: + pa.terminate() + + @classmethod + def show_audio_devices(cls): + fields = ('index', 'name', 'defaultSampleRate', 'maxInputChannels') + pa = pyaudio.PyAudio() + for i in range(pa.get_device_count()): + info = pa.get_device_info_by_index(i) + print(', '.join("'%s': '%s'" % (k, str(info[k])) for k in fields)) + pa.terminate() + + +def main(): + keyword_paths = [pvporcupine.KEYWORD_PATHS[x] for x in ["blueberry", "bumblebee"]] + sensitivities = [0.85, 0.95] + HotwordListener( + keyword_paths, + sensitivities, + ).listen_forever() + +if __name__ == '__main__': + main() -- 2.45.2