Add runner wrapper for simple use in Python programs

This commit is contained in:
Matthew D. Scholefield 2017-11-27 20:28:58 -06:00
parent cb31c79e86
commit 5a1fe8c078
3 changed files with 119 additions and 0 deletions

View File

@ -0,0 +1 @@
from .runner import PreciseRunner

View File

@ -0,0 +1,82 @@
# Python 2 + 3
# Copyright (c) 2017 Mycroft AI Inc.
import atexit
from psutil import Popen
from subprocess import PIPE
from threading import Thread
class PreciseRunner:
"""
Wrapper to use Precise
Args:
exe_file (str): Location to precise-stream executable
model (str): Location to .pb model file to use (with .pb.params)
chunk_size (int): Number of samples per prediction. Higher numbers
decrease CPU usage but increase latency
stream (BinaryIO): Binary audio stream to read 16000 Hz 1 channel int16
audio from. If not given, the microphone is used
on_prediction: callback for every new prediction
on_activation: callback for when the wake word is heard
"""
def __init__(self, exe_file, model, chunk_size=1024, stream=None,
on_prediction=lambda x: None, on_activation=lambda: None):
self.pa = None
self.stream = stream
self.exe_file = exe_file
self.model = model
self.chunk_size = chunk_size
self.thread = None
self.proc = None
self.on_prediction = on_prediction
self.on_activation = on_activation
self.running = False
self.cooldown = 0
atexit.register(self.stop)
def start(self):
"""Start listening from stream"""
if self.stream is None:
from pyaudio import PyAudio, paInt16
self.pa = PyAudio()
self.stream = self.pa.open(16000, 1, paInt16, True, frames_per_buffer=self.chunk_size)
self.proc = Popen([self.exe_file, self.model, str(self.chunk_size)], stdin=PIPE, stdout=PIPE)
self.running = True
self.thread = Thread(target=self._check_output)
self.thread.daemon = True
self.thread.start()
def stop(self):
"""Stop listening and close stream"""
if self.thread:
self.running = False
self.thread.join()
self.thread = None
if self.proc:
self.proc.kill()
self.proc = None
if self.pa:
self.pa.terminate()
self.stream.stop_stream()
self.stream = self.pa = None
def _check_output(self):
"""Continuously check Precise process output"""
while self.running:
chunk = self.stream.read(self.chunk_size)
self.proc.stdin.write(chunk)
self.proc.stdin.flush()
prob = float(self.proc.stdout.readline())
self.on_prediction(prob)
if self.cooldown > 0:
self.cooldown -= 1
elif prob > 0.5:
self.cooldown = self.chunk_size // 50
self.on_activation()

36
runner/setup.py Executable file
View File

@ -0,0 +1,36 @@
#!/usr/bin/env python3
from setuptools import setup, find_packages
setup(
name='precise-runner',
version='0.1.0',
packages=find_packages(),
install_requires=[
'pyaudio'
],
author='Matthew Scholefield',
author_email='matthew.scholefield@mycroft.ai',
description='Wrapper to use Mycroft Precise Wake Word Listener',
keywords='wakeword keyword wake word listener sound',
url='http://github.com/MycroftAI/mycroft-precise',
zip_safe=True,
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'Topic :: Text Processing :: Linguistic',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.0',
'Programming Language :: Python :: 3.1',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
],
)