From 051e1f7aec42dc9bed13a6caddb465ac20f8df17 Mon Sep 17 00:00:00 2001 From: schneefux Date: Sun, 11 Jan 2015 17:09:17 +0100 Subject: Added basic Julius STT engine and vocabcompiler --- client/stt.py | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'client/stt.py') diff --git a/client/stt.py b/client/stt.py index 95ed487..fc1452a 100644 --- a/client/stt.py +++ b/client/stt.py @@ -7,6 +7,8 @@ import tempfile import logging import urllib import urlparse +import re +import subprocess from abc import ABCMeta, abstractmethod import requests import yaml @@ -176,6 +178,78 @@ class PocketSphinxSTT(AbstractSTTEngine): return diagnose.check_python_import('pocketsphinx') +class JuliusSTT(AbstractSTTEngine): + """ + A very basic Speech-to-Text engine using Julius. + """ + + SLUG = 'julius' + VOCABULARY_TYPE = vocabcompiler.JuliusVocabulary + + def __init__(self, vocabulary=None, hmmdefs="/usr/share/voxforge/julius/" + + "acoustic_model_files/hmmdefs", tiedlist="/usr/share/" + + "voxforge/julius/acoustic_model_files/tiedlist"): + self._logger = logging.getLogger(__name__) + self._vocabulary = vocabulary + self._hmmdefs = hmmdefs + self._tiedlist = tiedlist + self._pattern = re.compile(r'sentence(\d+): (.+) ') + + @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 'julius' in profile: + if 'hmmdefs' in profile['julius']: + config['hmmdefs'] = profile['julius']['hmmdefs'] + if 'tiedlist' in profile['julius']: + config['tiedlist'] = profile['julius']['tiedlist'] + return config + + def transcribe(self, fp, mode=None): + cmd = ['julius', + '-quiet', + '-nolog', + '-input', 'stdin', + '-dfa', self._vocabulary.dfa_file, + '-v', self._vocabulary.dict_file, + '-h', self._hmmdefs, + '-hlist', self._tiedlist, + '-forcedict'] + cmd = [str(x) for x in cmd] + self._logger.debug('Executing: %r', cmd) + transcribed = [] + with tempfile.SpooledTemporaryFile() as out_f: + with tempfile.SpooledTemporaryFile() as err_f: + subprocess.call(cmd, stdin=fp, stdout=out_f, stderr=err_f) + out_f.seek(0) + output = out_f.read() + for line in output.splitlines(): + line = line.strip() + if line: + if line.startswith('sentence'): + print(line) + matchobj = self._pattern.search(line) + if matchobj and matchobj.groups(1): + transcribed.append(matchobj.group(2)) + self._logger.debug(line) + if not transcribed: + transcribed.append('') + self._logger.info('Transcribed: %r', transcribed) + return transcribed + + @classmethod + def is_available(cls): + return diagnose.check_executable('julius') + + class GoogleSTT(AbstractSTTEngine): """ Speech-To-Text implementation which relies on the Google Speech API. -- cgit v1.3.1 From 7475cf0b7f0076d5e6b78ee3961697f70b630ef9 Mon Sep 17 00:00:00 2001 From: schneefux Date: Mon, 12 Jan 2015 13:35:20 +0100 Subject: Julius STT error logging improved --- client/stt.py | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) (limited to 'client/stt.py') diff --git a/client/stt.py b/client/stt.py index fc1452a..c192e6a 100644 --- a/client/stt.py +++ b/client/stt.py @@ -195,6 +195,31 @@ class JuliusSTT(AbstractSTTEngine): self._tiedlist = tiedlist self._pattern = re.compile(r'sentence(\d+): (.+) ') + # Inital test run: we run this command once to log errors/warnings + cmd = ['julius', + '-input', 'stdin', + '-dfa', self._vocabulary.dfa_file, + '-v', self._vocabulary.dict_file, + '-h', self._hmmdefs, + '-hlist', self._tiedlist, + '-forcedict'] + cmd = [str(x) for x in cmd] + self._logger.debug('Executing: %r', cmd) + with tempfile.SpooledTemporaryFile() as out_f: + with tempfile.SpooledTemporaryFile() as f: + with tempfile.SpooledTemporaryFile() as err_f: + subprocess.call(cmd, stdin=f, stdout=out_f, stderr=err_f) + out_f.seek(0) + for line in out_f.read().splitlines(): + line = line.strip() + if len(line) > 7 and line[:7].upper() == 'ERROR: ': + if not line[7:].startswith('adin_'): + self._logger.error(line[7:]) + elif len(line) > 9 and line[:9].upper() == 'WARNING: ': + self._logger.warning(line[9:]) + elif len(line) > 6 and line[:6].upper() == 'STAT: ': + self._logger.debug(line[6:]) + @classmethod def get_config(cls): # FIXME: Replace this as soon as we have a config module @@ -225,21 +250,15 @@ class JuliusSTT(AbstractSTTEngine): '-forcedict'] cmd = [str(x) for x in cmd] self._logger.debug('Executing: %r', cmd) - transcribed = [] with tempfile.SpooledTemporaryFile() as out_f: with tempfile.SpooledTemporaryFile() as err_f: subprocess.call(cmd, stdin=fp, stdout=out_f, stderr=err_f) out_f.seek(0) - output = out_f.read() - for line in output.splitlines(): - line = line.strip() - if line: - if line.startswith('sentence'): - print(line) - matchobj = self._pattern.search(line) - if matchobj and matchobj.groups(1): - transcribed.append(matchobj.group(2)) - self._logger.debug(line) + results = [(int(i), text) for i, text in + self._pattern.findall(out_f.read())] + transcribed = [text for i, text in + sorted(results, key=lambda x: x[0]) + if text] if not transcribed: transcribed.append('') self._logger.info('Transcribed: %r', transcribed) -- cgit v1.3.1