From cb8f284edce400eaf08f8707f72fe8197528199c Mon Sep 17 00:00:00 2001 From: zoe Date: Tue, 20 Feb 2018 16:18:04 -0800 Subject: [PATCH 1/3] Add IBM Watson support --- client/stt.py | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/client/stt.py b/client/stt.py index a48696099..c954a6dfb 100644 --- a/client/stt.py +++ b/client/stt.py @@ -535,6 +535,118 @@ def is_available(cls): return diagnose.check_network_connection() +class WatsonSTT(AbstractSTTEngine): + """ + Speech-To-Text implementation which relies on the Watson Speech to Text API. + + This implementation requires a IBM Cloud user name and password to be present in + profile.yml. Please follow this tutuorial: https://console.bluemix.net/docs/services/speech-to-text/getting-started.html#gettingStarted + or select Text to Speach from https://console.bluemix.net/developer/watson/services . + This will present you with the following: + { + "speech_to_text": [ + { + "name": "speech-to-text-jasper-ne-speech-to--123456789", + "plan": "lite", + "credentials": { + "url": "https://stream.watsonplatform.net/speech-to-text/api", + "username": "••••••••••••••••••••••••••••••••••••", + "password": "••••••••••••" + } + } + ] + } + which you can past into your profile.yml: + ... + stt_engine: watson + watson-stt: + user_name: 'b9981d71-99a9-1234-some-bPASSCODEd' + password: 'supasswordT6' + """ + + SLUG = "watson" + + def __init__(self, user_name, password): + self._logger = logging.getLogger(__name__) + self.user_name = user_name + self.password = password + self._headers = {'accept': 'application/json', + 'Content-Type': 'audio/wav'} + + @classmethod + def get_config(cls): + # FIXME: Replace this as soon as we have a config module + config = {} + profile_path = jasperpath.config('profile.yml') + if os.path.exists(profile_path): + with open(profile_path, 'r') as f: + profile = yaml.safe_load(f) + if 'watson-stt' in profile: + if 'user_name' in profile['watson-stt']: + config['user_name'] = profile['watson-stt']['user_name'] + if 'password' in profile['watson-stt']: + config['password'] = profile['watson-stt']['password'] + return config + + @property + def user_name(self): + return self._user_name + + @user_name.setter + def user_name(self, value): + self._user_name = value + + @property + def password(self): + return self._password + + @password.setter + def password(self, value): + self._password = value + + @property + def headers(self): + return self._headers + + def transcribe(self, fp): + data = fp.read() + r = requests.post('https://stream.watsonplatform.net/speech-to-text/api/v1/recognize', + data=data, + auth=(self.user_name, self.password), + headers=self.headers) + text='' + try: + r.raise_for_status() + for result in r.json()['results']: + for alt in result['alternatives']: + text += alt['transcript'] + except requests.exceptions.HTTPError: + self._logger.critical('Request failed with response: %r', + r.text, + exc_info=True) + return [] + except requests.exceptions.RequestException: + self._logger.critical('Request failed.', exc_info=True) + return [] + except ValueError as e: + self._logger.critical('Cannot parse response: %s', + e.args[0]) + return [] + except KeyError: + self._logger.critical('Cannot parse response.', + exc_info=True) + return [] + else: + transcribed = [] + if text: + transcribed.append(text.upper()) + self._logger.info('Transcribed: %r', transcribed) + return transcribed + + @classmethod + def is_available(cls): + return diagnose.check_network_connection() + class WitAiSTT(AbstractSTTEngine): """ Speech-To-Text implementation which relies on the Wit.ai Speech API. From 160b9f6560d53c2e0cf823f999bba21d8918ef49 Mon Sep 17 00:00:00 2001 From: zoecarver Date: Wed, 6 Nov 2019 10:52:56 -0800 Subject: [PATCH 2/3] feat: implement bouncer --- client/conversation.py | 104 +++++++++++++++++++++++++++++++++++++++++ client/diagnose.py | 9 +++- run.command | 5 ++ run.sh | 7 +++ 4 files changed, 123 insertions(+), 2 deletions(-) create mode 100755 run.command create mode 100755 run.sh diff --git a/client/conversation.py b/client/conversation.py index 6b2fab1a0..23acf0950 100644 --- a/client/conversation.py +++ b/client/conversation.py @@ -3,6 +3,90 @@ from notifier import Notifier from brain import Brain +from subprocess import Popen, PIPE + +def bounce(): + scpt = ''' + tell application "Logic Pro X" to activate + delay 1 + tell application "System Events" + keystroke "b" using command down + delay 1 + keystroke return + end tell + ''' + args = [] + + p = Popen(['osascript', '-'] + args, stdin=PIPE, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate(scpt) + print (p.returncode, stdout, stderr) + +def record(): + scpt = ''' + tell application "Logic Pro X" to activate + delay 1 + tell application "System Events" + keystroke "r" + end tell + ''' + args = [] + + p = Popen(['osascript', '-'] + args, stdin=PIPE, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate(scpt) + print (p.returncode, stdout, stderr) + +def stop_req(): + scpt = ''' + tell application "Logic Pro X" to activate + delay 1 + tell application "System Events" + key code 49 + end tell + ''' + args = [] + + p = Popen(['osascript', '-'] + args, stdin=PIPE, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate(scpt) + print (p.returncode, stdout, stderr) + +def copy_track(): + scpt = ''' + tell application "Logic Pro X" to activate + delay 1 + tell application "System Events" + keystroke "d" using command down + end tell + ''' + args = [] + + p = Popen(['osascript', '-'] + args, stdin=PIPE, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate(scpt) + print (p.returncode, stdout, stderr) + +def bring_begin(): + scpt = ''' + tell application "System Events" + keystroke return + end tell + ''' + args = [] + + p = Popen(['osascript', '-'] + args, stdin=PIPE, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate(scpt) + print (p.returncode, stdout, stderr) + +def confirm(): + scpt = ''' + tell application "System Events" + keystroke return + end tell + ''' + args = [] + + p = Popen(['osascript', '-'] + args, stdin=PIPE, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate(scpt) + print (p.returncode, stdout, stderr) + class Conversation(object): @@ -29,6 +113,26 @@ def handleForever(self): self._logger.debug("Started listening for keyword '%s'", self.persona) threshold, transcribed = self.mic.passiveListen(self.persona) + found = (transcribed + [''])[0] + if 'BOUNCE' in found or 'BALANCE' in found: + print("BOUNCEING...") + bounce() + if 'REC' in found or 'RECORD' in found or 'START' in found: + print("RECORDING...") + record() + if 'STOP' in found or 'END' in found: + print("STOPPING...") + stop_req() + if 'DUPLICATE' in found or 'COPY' in found: + print("COPYING...") + copy_track() + if 'FRONT' in found or 'BEGINING' in found or 'FRONT' in found: + print("BRINGING BEGIN...") + bring_begin() + if 'CONFIRM' in found or 'YES' in found or 'ENTER' in found or 'CONTINUE' in found: + print("CONFIRMING...") + confirm() + self._logger.debug("Stopped listening for keyword '%s'", self.persona) diff --git a/client/diagnose.py b/client/diagnose.py index 06ed9ea2e..4dea32414 100644 --- a/client/diagnose.py +++ b/client/diagnose.py @@ -6,7 +6,6 @@ import subprocess import pkgutil import logging -import pip.req import jasperpath if sys.version_info < (3, 3): from distutils.spawn import find_executable @@ -89,6 +88,12 @@ def check_python_import(package_or_module): return found +def parse_requirements(filename): + """ load requirements from a pip requirements file """ + lineiter = (line.strip() for line in open(filename)) + return [line for line in lineiter if line and not line.startswith("#")] + + def get_pip_requirements(fname=os.path.join(jasperpath.LIB_PATH, 'requirements.txt')): """ @@ -104,7 +109,7 @@ def get_pip_requirements(fname=os.path.join(jasperpath.LIB_PATH, """ logger = logging.getLogger(__name__) if os.access(fname, os.R_OK): - reqs = list(pip.req.parse_requirements(fname)) + reqs = list(parse_requirements(fname)) logger.debug("Found %d PIP requirements in file '%s'", len(reqs), fname) return reqs diff --git a/run.command b/run.command new file mode 100755 index 000000000..9d5472c7e --- /dev/null +++ b/run.command @@ -0,0 +1,5 @@ +#!/bin/bash + +echo "Hello" + +# /usr/bin/python /Users/zoe/Developer/jasper-client/jasper.py diff --git a/run.sh b/run.sh new file mode 100755 index 000000000..8a196e3e6 --- /dev/null +++ b/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +echo "hello" + +cd /Users/zoe/Developer/jasper-client + +/usr/bin/python /Users/zoe/Developer/jasper-client/jasper.py From 5435774577fadcd5901d9fd3794ec2a01e96557c Mon Sep 17 00:00:00 2001 From: zoecarver Date: Fri, 15 Nov 2019 10:01:04 -0800 Subject: [PATCH 3/3] stash --- client/conversation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/conversation.py b/client/conversation.py index 23acf0950..9e261b2dc 100644 --- a/client/conversation.py +++ b/client/conversation.py @@ -114,6 +114,8 @@ def handleForever(self): self.persona) threshold, transcribed = self.mic.passiveListen(self.persona) found = (transcribed + [''])[0] + if 'AMOS' not in found: continue + if 'BOUNCE' in found or 'BALANCE' in found: print("BOUNCEING...") bounce()