From 474627c477ea1d754b8d7249e694173fc65db91e Mon Sep 17 00:00:00 2001 From: schneefux Date: Thu, 27 Nov 2014 22:56:36 +0100 Subject: Added AT&T Speech-to-Text engine --- client/stt.py | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/client/stt.py b/client/stt.py index 0ae7871..afe5944 100644 --- a/client/stt.py +++ b/client/stt.py @@ -250,6 +250,102 @@ class GoogleSTT(AbstractSTTEngine): return diagnose.check_network_connection() +class ATandTSTT(AbstractSTTEngine): + + SLUG = "att" + + def __init__(self, app_key, app_secret): + self._logger = logging.getLogger(__name__) + self._token = None + self.app_key = app_key + self.app_secret = app_secret + + @classmethod + def get_config(cls): + # FIXME: Replace this as soon as we have a config module + config = {} + # HMM dir + # Try to get hmm_dir from 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 'att-stt' in profile: + if 'app_key' in profile['att-stt']: + config['app_key'] = profile['att-stt']['app_key'] + if 'app_secret' in profile['att-stt']: + config['app_secret'] = profile['att-stt']['app_secret'] + return config + + @property + def token(self): + if not self._token: + headers = {'content-type': 'application/x-www-form-urlencoded', + 'accept': 'application/json'} + payload = {'client_id': self.app_key, + 'client_secret': self.app_secret, + 'scope': 'SPEECH', + 'grant_type': 'client_credentials'} + r = requests.post('https://api.att.com/oauth/token', + data=payload, + headers=headers) + self._token = r.json()['access_token'] + return self._token + + def transcribe(self, fp): + data = fp.read() + r = self._get_response(data) + if r.status_code == requests.codes['unauthorized']: + # Request token invalid, retry once with a new token + self._logger.warning('OAuth access token invalid, generating a ' + + 'new one and retrying...') + self._token = None + r = self._get_response(data) + try: + r.raise_for_status() + 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 [] + else: + try: + recognition = r.json()['Recognition'] + if recognition['Status'] != 'OK': + raise ValueError(recognition['Status']) + results = [(x['Hypothesis'], x['Confidence']) + for x in recognition['NBest']] + except ValueError as e: + self._logger.debug('Recognition failed with status: %s', + e.args[0]) + return [] + except KeyError: + self._logger.critical('Cannot parse response.', + exc_info=True) + return [] + else: + results = [x[0].upper() for x in sorted(results, + key=lambda x: x[1], + reverse=True)] + self._logger.info('Recognized: %r', results) + return results + + def _get_response(self, data): + headers = {'authorization': 'Bearer %s' % self.token, + 'accept': 'application/json', + 'content-type': 'audio/wav'} + return requests.post('https://api.att.com/speech/v3/speechToText', + data=data, + headers=headers) + + @classmethod + def is_available(cls): + return diagnose.check_network_connection() + + def get_engine_by_slug(slug=None): """ Returns: -- cgit v1.3.1 From e06bdaa546b66d90d2346e588810d2490e7731aa Mon Sep 17 00:00:00 2001 From: schneefux Date: Thu, 27 Nov 2014 23:01:31 +0100 Subject: Replace wront comment --- client/stt.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/stt.py b/client/stt.py index afe5944..4316b53 100644 --- a/client/stt.py +++ b/client/stt.py @@ -264,8 +264,7 @@ class ATandTSTT(AbstractSTTEngine): def get_config(cls): # FIXME: Replace this as soon as we have a config module config = {} - # HMM dir - # Try to get hmm_dir from config + # Try to get AT&T app_key/app_secret from config profile_path = jasperpath.config('profile.yml') if os.path.exists(profile_path): with open(profile_path, 'r') as f: -- cgit v1.3.1 From 37a381a0becb024437c04dee7687329325a0b2a3 Mon Sep 17 00:00:00 2001 From: schneefux Date: Thu, 27 Nov 2014 23:07:47 +0100 Subject: Add a detailed docstring to ATandTSTT engine class --- client/stt.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/client/stt.py b/client/stt.py index 4316b53..fa960ce 100644 --- a/client/stt.py +++ b/client/stt.py @@ -251,6 +251,19 @@ class GoogleSTT(AbstractSTTEngine): class ATandTSTT(AbstractSTTEngine): + """ + Speech-To-Text implementation which relies on the AT&T Speech API. + + This implementation requires an AT&T app_key/app_secret to be present in + profile.yml. Please sign up at http://developer.att.com/apis/speech and + create a new app. You can then take the app_key/app_secret and put it into + your profile.yml: + ... + stt_engine: att + att-stt: + app_key: 4xxzd6abcdefghijklmnopqrstuvwxyz + app_secret: 6o5jgiabcdefghijklmnopqrstuvwxyz + """ SLUG = "att" -- cgit v1.3.1 From ce7b8488c1483bea06cf345b7ca1e4ad11cc0281 Mon Sep 17 00:00:00 2001 From: schneefux Date: Tue, 2 Dec 2014 13:54:57 +0100 Subject: Rename AT&T STT engine class to AttSTT --- client/stt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/stt.py b/client/stt.py index fa960ce..fc874f2 100644 --- a/client/stt.py +++ b/client/stt.py @@ -250,7 +250,7 @@ class GoogleSTT(AbstractSTTEngine): return diagnose.check_network_connection() -class ATandTSTT(AbstractSTTEngine): +class AttSTT(AbstractSTTEngine): """ Speech-To-Text implementation which relies on the AT&T Speech API. -- cgit v1.3.1