From f9e217766fe79a8035b7a49a9632e5eb009e1d9b Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Sun, 20 Nov 2016 02:38:21 -0800 Subject: [PATCH 01/15] Trying support for Windows speech recognition engine --- modules/speech_recognition/wsr.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 modules/speech_recognition/wsr.py diff --git a/modules/speech_recognition/wsr.py b/modules/speech_recognition/wsr.py new file mode 100644 index 0000000..c32aaf0 --- /dev/null +++ b/modules/speech_recognition/wsr.py @@ -0,0 +1,24 @@ +import logging +logger = logging.getLogger(__name__) + +#class Recognizer: +# pass + +# response = speech.input("Say something, please.") +# speech.say("You said " + response) + +# def callback(phrase, listener): +# if phrase == "goodbye": +# listener.stoplistening() +# speech.say(phrase) +# +# listener = speech.listenforanything(callback) +# while listener.islistening(): +# time.sleep(.5) +#listener.stoplistening() +#speech.listenfor(words, lambda phrase, listener: None) + +# import speech +# https://pypi.python.org/pypi/speech/0.5.2 +# req: pywin32 +# https://sourceforge.net/projects/pywin32/files/pywin32 \ No newline at end of file From 065e0b11d2bfa044ce7cf00af30a1075bda57f63 Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Sat, 26 Nov 2016 17:37:35 -0800 Subject: [PATCH 02/15] Create HACKING file to collect ideas from codebase --- HACKING.rst | 6 ++++++ run.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 HACKING.rst diff --git a/HACKING.rst b/HACKING.rst new file mode 100644 index 0000000..61ac4e4 --- /dev/null +++ b/HACKING.rst @@ -0,0 +1,6 @@ +## Speech Recognizer + + +Generate an fsg file from jsgf + + ```sphinx_jsgf2fsg < conf.jsgf_file > conf.fsg_file``` \ No newline at end of file diff --git a/run.py b/run.py index 6e8f5a8..3ffd7a9 100755 --- a/run.py +++ b/run.py @@ -162,7 +162,7 @@ def process_command(self, command): conf.dic_file = os.path.join(conf.cache_dir, 'dic') conf.lang_file = os.path.join(conf.cache_dir, 'lm') conf.fsg_file = None #os.path.join(conf.cache_dir, 'fsg') - # sphinx_jsgf2fsg < conf.jsgf_file > conf.fsg_file + l = LanguageUpdater(conf) l.update_language() From 357b7ceb86b8316becc99871f4ce98aac94e40d8 Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Sat, 26 Nov 2016 17:39:05 -0800 Subject: [PATCH 03/15] Use metavars in command processing; add simple debug option --- run.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/run.py b/run.py index 3ffd7a9..8057106 100755 --- a/run.py +++ b/run.py @@ -36,7 +36,7 @@ def _parser(args): parser.add_argument("-H", "--history", type=int, action="store", dest="history", - help="Number of commands to store in history file") + help="Number of commands to store in history file", metavar="HISTORY_SIZE") parser.add_argument("-m", "--microphone", type=int, action="store", dest="microphone", default=None, @@ -44,15 +44,19 @@ def _parser(args): parser.add_argument("--valid-sentence-command", type=str, dest="valid_sentence_command", action='store', - help="Command to run when a valid sentence is detected") + help="Command to run when a valid sentence is detected", metavar="COMMAND_PATH") parser.add_argument("--invalid-sentence-command", type=str, dest="invalid_sentence_command", action='store', - help="Command to run when an invalid sentence is detected") + help="Command to run when an invalid sentence is detected", metavar="COMMAND_PATH") parser.add_argument("-M", "--mind", type=str, dest="mind_dir", action='store', - help="Path to mind to use for assistant") + help="Path to mind to use for assistant", metavar="MIND_DIR") + + parser.add_argument("-d", "--debug", + action='store_true', dest="debug", default=False, + help="Enable debug-level logging") return parser.parse_args(args) @@ -146,6 +150,8 @@ def process_command(self, command): # use `Config` to load mind configuration # command-line overrides config file args = _parser(sys.argv[1:]) + if args.debug: + logging.root.setLevel(logging.DEBUG) logger.debug("Arguments: {args}".format(args=args)) From 761a9efe14a5db11f8e9d02ab34f330dca537ae0 Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Sat, 26 Nov 2016 17:41:18 -0800 Subject: [PATCH 04/15] Remove number processing and history logging --- run.py | 49 ++----------------------------------------------- 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/run.py b/run.py index 8057106..12cb5a2 100755 --- a/run.py +++ b/run.py @@ -64,7 +64,7 @@ def _parser(args): def recognizer_finished(a, recognizer, text): logger.debug("Agent: {}, Recognier: {}, Text: {}".format(a, recognizer, text)) t = text.lower() - #numt, nums = self.number_parser.parse_all_numbers(t) + # Is There A Matching Command? if t in a.config.commands: # Run The 'valid_sentence_command' If It's Set @@ -81,22 +81,7 @@ def recognizer_finished(a, recognizer, text): cmd += " " + t print("\x1b[32m< ! >\x1b[0m {0}".format(t)) run_command(a, cmd) - log_history(a, text) - #elif numt in self.commands: - # # Run 'valid_sentence_command' Set - # os.system('clear') - # print("Open Assistant: \x1b[32mListening\x1b[0m") - # if self.config.options['valid_sentence_command']: - # subprocess.call(self.config.options['valid_sentence_command'], - # shell=True) - # cmd = self.commands[numt] - # cmd = cmd.format(*nums) - # # Should We Be Passing Words? - # if self.config.options['pass_words']: - # cmd += " " + t - # print("\x1b[32m< ! >\x1b[0m {0}".format(t)) - # self.run_command(cmd) - # self.log_history(text) + else: # Run The Invalid_sentence_command If It's Set if a.config.options['invalid_sentence_command']: @@ -105,19 +90,6 @@ def recognizer_finished(a, recognizer, text): print("\x1b[31m< ? >\x1b[0m {0}".format(t)) -def log_history(a, text): - if a.config.options['history']: - a.history.append(text) - if len(a.history) > a.config.options['history']: - # Pop Off First Item - a.history.pop(0) - - # Open And Truncate History File - with open(a.config.history_file, 'w') as hfile: - for line in a.history: - hfile.write(line + '\n') - - def run_command(a, cmd): """PRINT COMMAND AND RUN""" print("\x1b[32m< ! >\x1b[0m", cmd) @@ -125,23 +97,6 @@ def run_command(a, cmd): subprocess.call(cmd, shell=True) recognizer.listen() - -def process_command(self, command): - print(command) - if command == "listen": - self.recognizer.listen() - elif command == "stop": - self.recognizer.pause() - elif command == "continuous_listen": - self.continuous_listen = True - self.recognizer.listen() - elif command == "continuous_stop": - self.continuous_listen = False - self.recognizer.pause() - elif command == "quit": - self.quit() - - if __name__ == '__main__': From ba8e49d5b58d0de26e1edfd8b94a4bccce6257c0 Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Sat, 26 Nov 2016 18:04:26 -0800 Subject: [PATCH 05/15] =?UTF-8?q?Commands=20isn=E2=80=99t=20used=20in=20th?= =?UTF-8?q?e=20recognizer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/speech_recognition/gst.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/speech_recognition/gst.py b/modules/speech_recognition/gst.py index 2e5af4e..dd56fcb 100644 --- a/modules/speech_recognition/gst.py +++ b/modules/speech_recognition/gst.py @@ -17,7 +17,6 @@ class Recognizer(GObject.GObject): def __init__(self, config): GObject.GObject.__init__(self) - self.commands = {} logger.debug("Initializing Recognizer") logger.debug(config) logger.debug(config.options) From 54acf15694b82486b5fd0d15e9e4b6f06b9662e4 Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Sat, 26 Nov 2016 18:30:33 -0800 Subject: [PATCH 06/15] Remove hashing/updated references from language module --- modules/language/__init__.py | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/modules/language/__init__.py b/modules/language/__init__.py index 155163b..fced252 100644 --- a/modules/language/__init__.py +++ b/modules/language/__init__.py @@ -7,10 +7,6 @@ import requests -#from .hasher import Hasher - - -NET_TEST_SERVER = "http://www.speech.cs.cmu.edu" class LanguageUpdater: """ @@ -25,33 +21,6 @@ class LanguageUpdater: def __init__(self, config): self.config = config self.create_strings_file() - - #self.hasher = Hasher(config) - - # def update_language_if_changed(self): - # """TEST IF THE LANGUAGE HAS CHANGED""" - # if self.language_has_changed(): - # """TEST NET CONNECTION AND UPDATE IF CONNECTED""" - # try: - # response=urllib.request.urlopen(NET_TEST_SERVER,timeout=1) - # print ("OpenAssistant: \x1b[32mNetwork Connection Established\x1b[0m") - # self.update_language() - # self.save_language_hash() - # except urllib.error.URLError as e: pass - # print ("OpenAssistant: \x1b[31mNo Network Connection\x1b[0m") - # - # def language_has_changed(self): - # """Use hashes to test if the language has changed""" - # self.stored_hash = self.hasher['language'] - # - # # CALCULATE LANGUAGE FILE HASH - # hasher = self.hasher.get_hash_object() - # with open(self.config.strings_file, 'rb') as sfile: - # buf = sfile.read() - # hasher.update(buf) - # self.new_hash = hasher.hexdigest() - # - # return self.new_hash != self.stored_hash def create_strings_file(self): @@ -100,9 +69,6 @@ def update_language(self): self._download_file(lm_url, self.config.lang_file) self._download_file(dic_url, self.config.dic_file) - # def save_language_hash(self): - # self.hasher['language'] = self.new_hash - # self.hasher.store() def _download_file(self, url, path): r = requests.get(url, stream=True) From 4510351eae34d8840730bfbb69631b2218c06011 Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Sat, 3 Dec 2016 01:45:36 -0800 Subject: [PATCH 07/15] Split LanguageUpdater into helper functions --- modules/language/__init__.py | 125 ++++++++++++++---------------- modules/speech_recognition/gst.py | 2 +- run.py | 29 +++++-- 3 files changed, 81 insertions(+), 75 deletions(-) diff --git a/modules/language/__init__.py b/modules/language/__init__.py index fced252..8096900 100644 --- a/modules/language/__init__.py +++ b/modules/language/__init__.py @@ -1,3 +1,12 @@ +""" +Handles updating the language using the online lmtool. + +This class provides methods to check if the corpus has changed, and to +update the language to match the new corpus using the lmtool. This allows +us to automatically update the language if the corpus has changed, saving +the user from having to do this manually. +""" + import logging logger = logging.getLogger(__name__) @@ -8,71 +17,55 @@ import requests -class LanguageUpdater: - """ - Handles updating the language using the online lmtool. - - This class provides methods to check if the corpus has changed, and to - update the language to match the new corpus using the lmtool. This allows - us to automatically update the language if the corpus has changed, saving - the user from having to do this manually. - """ - - def __init__(self, config): - self.config = config - self.create_strings_file() +def create_strings_file(path, source={}): + # Open Strings File + with open(path, 'w+') as strings: + # Add Command Words To The Corpus + for cmd in sorted(source.keys()): + strings.write(cmd.strip().replace('%d', '') + "\n") - def create_strings_file(self): - # Open Strings File - with open(self.config.strings_file, 'w') as strings: - # Add Command Words To The Corpus - for voice_cmd in sorted(self.config.commands.keys()): - strings.write(voice_cmd.strip().replace('%d', '') + "\n") - - - def update_language(self): - """Update the language using the online lmtool""" - logger.debug("\x1b[32mUpdating Language\x1b[0m") - - host = 'http://www.speech.cs.cmu.edu' - url = host + '/cgi-bin/tools/lmtool/run' - - # SUBMIT THE CORPUS TO THE LMTOOL - response_text = "" - with open(self.config.strings_file, 'rb') as corpus: - files = {'corpus': corpus} - values = {'formtype': 'simple'} - - r = requests.post(url, files=files, data=values) - response_text = r.text - - # PARSE RESPONSE TO GET URLS OF THE FILES WE NEED - path_re = r'.*Index of (.*?).*' - number_re = r'.*TAR([0-9]*?)\.tgz.*' - for line in response_text.split('\n'): - # ERROR RESPONSE - if "[_ERRO_]" in line: - return 1 - # IF WE FOUND THE DIRECTORY, KEEP IT AND DON'T BREAK - if re.search(path_re, line): - path = host + re.sub(path_re, r'\1', line) - # IF WE FOUND THE NUMBER, KEEP IT AND BREAK - elif re.search(number_re, line): - number = re.sub(number_re, r'\1', line) - break - - lm_url = path + '/' + number + '.lm' - dic_url = path + '/' + number + '.dic' - - if self.config.lang_file is not None: - self._download_file(lm_url, self.config.lang_file) - self._download_file(dic_url, self.config.dic_file) - - - def _download_file(self, url, path): - r = requests.get(url, stream=True) - if r.status_code == 200: - with open(path, 'wb') as f: - for chunk in r: - f.write(chunk) \ No newline at end of file +def create_sphinx_files(source, lm_path, dic_path): + """Update the language using the online lmtool""" + logger.debug("\x1b[32mUpdating Language\x1b[0m") + + host = 'http://www.speech.cs.cmu.edu' + url = host + '/cgi-bin/tools/lmtool/run' + + # SUBMIT THE CORPUS TO THE LMTOOL + response_text = "" + with open(source, 'rb') as corpus: + files = {'corpus': corpus} + values = {'formtype': 'simple'} + + r = requests.post(url, files=files, data=values) + response_text = r.text + + # PARSE RESPONSE TO GET URLS OF THE FILES WE NEED + path_re = r'.*Index of (.*?).*' + number_re = r'.*TAR([0-9]*?)\.tgz.*' + for line in response_text.split('\n'): + # ERROR RESPONSE + if "[_ERRO_]" in line: + return 1 + # IF WE FOUND THE DIRECTORY, KEEP IT AND DON'T BREAK + if re.search(path_re, line): + path = host + re.sub(path_re, r'\1', line) + # IF WE FOUND THE NUMBER, KEEP IT AND BREAK + elif re.search(number_re, line): + number = re.sub(number_re, r'\1', line) + break + + lm_url = path + '/' + number + '.lm' + dic_url = path + '/' + number + '.dic' + + _download_file(lm_url, lm_path) + _download_file(dic_url, dic_path) + + +def _download_file(url, dest): + r = requests.get(url, stream=True) + if r.status_code == 200: + with open(dest, 'wb') as f: + for chunk in r: + f.write(chunk) \ No newline at end of file diff --git a/modules/speech_recognition/gst.py b/modules/speech_recognition/gst.py index dd56fcb..24651d1 100644 --- a/modules/speech_recognition/gst.py +++ b/modules/speech_recognition/gst.py @@ -36,7 +36,7 @@ def __init__(self, config): ' ! audioresample' + ' ! pocketsphinx {}'.format(' '.join([ '{}={}'.format(opt, val) for opt, val in [ - ('lm', config.lang_file), + ('lm', config.lm_file), ('dict', config.dic_file), ('fsg', config.fsg_file) ] if val is not None diff --git a/run.py b/run.py index 12cb5a2..9622ba3 100755 --- a/run.py +++ b/run.py @@ -18,9 +18,9 @@ from core import Config, Assistant -from modules.language import LanguageUpdater +from modules.language import create_strings_file, create_sphinx_files from modules.speech_recognition.gst import Recognizer -#from core.numbers import NumberParser + def _parser(args): parser = ArgumentParser() @@ -114,33 +114,46 @@ def run_command(a, cmd): # - # Further patching to ease transition.. + # Pre-Configuration # # Configure Language logger.debug("Configuring Module: Language") + + # Language Paths conf.strings_file = os.path.join(conf.cache_dir, "sentences.corpus") conf.dic_file = os.path.join(conf.cache_dir, 'dic') - conf.lang_file = os.path.join(conf.cache_dir, 'lm') + conf.lm_file = os.path.join(conf.cache_dir, 'lm') conf.fsg_file = None #os.path.join(conf.cache_dir, 'fsg') - l = LanguageUpdater(conf) - l.update_language() + # Generate Language Files + create_strings_file(conf.strings_file, conf.commands) + create_sphinx_files(conf.strings_file, conf.lm_file, conf.dic_file) # Configure Recognizer logger.debug("Configuring Module: Speech Recognition") recognizer = Recognizer(conf) # - # End patching + # End Pre-Configuration # # A configured Assistant a = Assistant(config=conf) + + # + # Post-Configuration + # + recognizer.connect('finished', lambda rec, txt, agent=a: recognizer_finished(agent, rec, txt)) - + + # + # End Post-Configuration + # + + # # Questionable dependencies From 53f471445a2456921ee1364d261a24824f12d5e1 Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Sat, 3 Dec 2016 02:50:47 -0800 Subject: [PATCH 08/15] More debugging; pass recognition to valid/invalid commands; pocketsphinx recognizer options out of config --- core/util/config.py | 15 +++++++++------ modules/speech_recognition/gst.py | 22 +++++++++------------- run.py | 19 ++++++++----------- 3 files changed, 26 insertions(+), 30 deletions(-) diff --git a/core/util/config.py b/core/util/config.py index 33a9cf6..79af58d 100644 --- a/core/util/config.py +++ b/core/util/config.py @@ -21,13 +21,16 @@ def __init__(self, path=None, **opts): # CACHE FILES self.history_file = os.path.join(self.cache_dir, "history") - self.hash_file = os.path.join(self.cache_dir, "hash.json") self._make_dir(self.conf_dir) self._make_dir(self.cache_dir) self.options = self._read_options_file() - self.commands = self._read_commands_file() + self.options.update(opts) + logger.info("Options: {}".format(self.options)) + + self.commands = self._read_commands_file() + logger.info("Command Count: {}".format(len(self.commands))) def _make_dir(self, directory): @@ -37,21 +40,21 @@ def _make_dir(self, directory): def _read_options_file(self): try: + logger.debug("Reading options from {}".format(self.opt_file)) with open(self.opt_file, 'r') as f: _options = json.load(f) return _options except FileNotFoundError: - # MAKE AN EMPTY OPTIONS NAMESPACE - logger.warn("Error loading options file: {path}".format(path=self.opt_file)) + logger.warn("Error reading options file: {path}".format(path=self.opt_file)) return {} def _read_commands_file(self): try: + logger.debug("Reading commands from {}".format(self.cmd_file)) with open(self.cmd_file, 'r') as f: _cmds = json.load(f) return _cmds except FileNotFoundError: - # MAKE AN EMPTY OPTIONS NAMESPACE - logger.warn("Error loading commands file: {path}".format(path=self.cmd_file)) + logger.warn("Error reading commands file: {path}".format(path=self.cmd_file)) return {} \ No newline at end of file diff --git a/modules/speech_recognition/gst.py b/modules/speech_recognition/gst.py index 24651d1..8401bc3 100644 --- a/modules/speech_recognition/gst.py +++ b/modules/speech_recognition/gst.py @@ -15,19 +15,12 @@ class Recognizer(GObject.GObject): (GObject.TYPE_STRING,)) } - def __init__(self, config): + def __init__(self, mic=None, dic_file=None, lm_file=None, fsg_file=None): GObject.GObject.__init__(self) logger.debug("Initializing Recognizer") - logger.debug(config) - logger.debug(config.options) # Configure Audio Source - src = config.options['microphone'] - if src: - #audio_src = 'alsasrc device="hw:{0},0"'.format(src) - audio_src = 'autoaudiosrc device="hw:{0},0"'.format(src) - else: - audio_src = 'autoaudiosrc' + audio_src = 'autoaudiosrc' + ('' if mic is None else ' device="hw:{0},0"'.format(mic)) # Build Pipeline cmd = ( @@ -36,9 +29,9 @@ def __init__(self, config): ' ! audioresample' + ' ! pocketsphinx {}'.format(' '.join([ '{}={}'.format(opt, val) for opt, val in [ - ('lm', config.lm_file), - ('dict', config.dic_file), - ('fsg', config.fsg_file) + ('dict', dic_file), + ('lm', lm_file), + ('fsg', fsg_file) ] if val is not None ])) + ' ! appsink sync=false' @@ -58,9 +51,11 @@ def __init__(self, config): bus.connect('message::element', self.result) def listen(self): + logger.debug("\x1b[32mListening\x1b[0m") self.pipeline.set_state(Gst.State.PLAYING) def pause(self): + logger.debug("\x1b[31mPaused\x1b[0m") self.pipeline.set_state(Gst.State.PAUSED) def result(self, bus, msg): @@ -73,4 +68,5 @@ def result(self, bus, msg): # If We Have A Final Command, Send It For Processing command = msg_struct.get_string('hypothesis') if command != '' and msg_struct.get_boolean('final')[1]: - self.emit("finished", command) \ No newline at end of file + logger.debug("Heard: {}".format(command)) + self.emit("finished", command) diff --git a/run.py b/run.py index 9622ba3..f09cfe2 100755 --- a/run.py +++ b/run.py @@ -43,11 +43,11 @@ def _parser(args): help="Audio input card to use (if other than system default)") parser.add_argument("--valid-sentence-command", type=str, - dest="valid_sentence_command", action='store', + dest="valid_sentence_command", action='store', default=None, help="Command to run when a valid sentence is detected", metavar="COMMAND_PATH") parser.add_argument("--invalid-sentence-command", type=str, - dest="invalid_sentence_command", action='store', + dest="invalid_sentence_command", action='store', default=None, help="Command to run when an invalid sentence is detected", metavar="COMMAND_PATH") parser.add_argument("-M", "--mind", type=str, @@ -69,24 +69,21 @@ def recognizer_finished(a, recognizer, text): if t in a.config.commands: # Run The 'valid_sentence_command' If It's Set os.system('clear') - print("Open Assistant: \x1b[32mListening\x1b[0m") if a.config.options['valid_sentence_command']: - subprocess.call(a.config.options['valid_sentence_command'], - shell=True) + subprocess.call([a.config.options['valid_sentence_command'], text]) cmd = a.config.commands[t] # Should We Be Passing Words? - os.system('clear') - print("Open Assistant: \x1b[32mListening\x1b[0m") + #os.system('clear') if a.config.options['pass_words']: cmd += " " + t - print("\x1b[32m< ! >\x1b[0m {0}".format(t)) + print("\x1b[32m< ? >\x1b[0m {0}".format(t)) run_command(a, cmd) else: # Run The Invalid_sentence_command If It's Set + logger.debug("Unrecognized command: {}".format(t)) if a.config.options['invalid_sentence_command']: - subprocess.call(a.config.options['invalid_sentence_command'], - shell=True) + subprocess.call([a.config.options['invalid_sentence_command'], text]) print("\x1b[31m< ? >\x1b[0m {0}".format(t)) @@ -132,7 +129,7 @@ def run_command(a, cmd): # Configure Recognizer logger.debug("Configuring Module: Speech Recognition") - recognizer = Recognizer(conf) + recognizer = Recognizer(args.microphone, dic_file=conf.dic_file, lm_file=conf.lm_file) # # End Pre-Configuration From a8e7c4bfc9bd2f151f21526a125b4bc88ada9f86 Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Sat, 3 Dec 2016 03:40:18 -0800 Subject: [PATCH 09/15] Prototype database for commands/prompts --- core/util/db.py | 47 ++++++++++++++++++++++++++++++++++++ modules/language/__init__.py | 2 +- run.py | 17 ++++++++++--- 3 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 core/util/db.py diff --git a/core/util/db.py b/core/util/db.py new file mode 100644 index 0000000..e68f569 --- /dev/null +++ b/core/util/db.py @@ -0,0 +1,47 @@ +import sqlite3 +import json + +#from importlib import reload + + +class DB: + def __init__(self, path=None): + self.path = ":memory:" if path is None else path + self.db = sqlite3.connect(self.path) + + def create_schema(self): + self.db.execute("CREATE TABLE IF NOT EXISTS Prompt (Prompt TEXT)") + self.db.execute("CREATE TABLE IF NOT EXISTS Command (Command TEXT)") + self.db.execute("CREATE TABLE IF NOT EXISTS PromptCommand (PromptID INT, CommandID INT)") + self.db.commit() + + def add_action(self, prompt, command): + p = self.db.execute("SELECT rowid FROM Prompt WHERE Prompt = ?", (prompt,)).fetchone() + if p is None: + prompt_id = self.db.execute("INSERT INTO Prompt (Prompt) VALUES (?)", (prompt,)).lastrowid + else: + prompt_id = p[0] + + c = self.db.execute("SELECT Command FROM Command WHERE Command = ?", (command,)).fetchone() + if c is None: + command_id = self.db.execute("INSERT INTO Command (Command) VALUES (?)", (command,)).lastrowid + else: + command_id = c[0] + + action_id = self.db.execute("SELECT PromptID, CommandID FROM PromptCommand WHERE PromptID=? AND CommandID=?", (prompt_id, command_id)).fetchone() + if action_id is None: + self.db.execute("INSERT INTO PromptCommand (PromptID, CommandID) VALUES (?, ?)", (prompt_id, command_id)) + + self.db.commit() + + def get_action(self, prompt): + action = self.db.execute("SELECT Command FROM Command INNER JOIN PromptCommand ON PromptCommand.CommandID = Command.rowid INNER JOIN Prompt ON Prompt.rowid = PromptCommand.rowid WHERE Prompt = ?", (prompt,)).fetchone() + if action is not None: + return action[0] + + def get_prompts(self): + for prompt in self.db.execute("SELECT Prompt FROM Prompt"): + yield prompt[0] + + def load_commands(self, path): + pass \ No newline at end of file diff --git a/modules/language/__init__.py b/modules/language/__init__.py index 8096900..4ea8e88 100644 --- a/modules/language/__init__.py +++ b/modules/language/__init__.py @@ -21,7 +21,7 @@ def create_strings_file(path, source={}): # Open Strings File with open(path, 'w+') as strings: # Add Command Words To The Corpus - for cmd in sorted(source.keys()): + for cmd in source: strings.write(cmd.strip().replace('%d', '') + "\n") diff --git a/run.py b/run.py index f09cfe2..16cf612 100755 --- a/run.py +++ b/run.py @@ -21,6 +21,8 @@ from modules.language import create_strings_file, create_sphinx_files from modules.speech_recognition.gst import Recognizer +from core.util.db import DB + def _parser(args): parser = ArgumentParser() @@ -65,13 +67,14 @@ def recognizer_finished(a, recognizer, text): logger.debug("Agent: {}, Recognier: {}, Text: {}".format(a, recognizer, text)) t = text.lower() + cmd = a.db.get_action(t) + # Is There A Matching Command? - if t in a.config.commands: + if cmd is not None: # Run The 'valid_sentence_command' If It's Set os.system('clear') if a.config.options['valid_sentence_command']: subprocess.call([a.config.options['valid_sentence_command'], text]) - cmd = a.config.commands[t] # Should We Be Passing Words? #os.system('clear') if a.config.options['pass_words']: @@ -106,8 +109,13 @@ def run_command(a, cmd): logging.root.setLevel(logging.DEBUG) logger.debug("Arguments: {args}".format(args=args)) - conf = Config(path=args.mind_dir, **vars(args)) + + db = DB(os.path.join(conf.conf_dir, "db")) + db.create_schema() + for prompt, command in conf.commands.items(): + print("Adding {} -> {}".format(prompt, command)) + db.add_action(prompt, command) # @@ -124,7 +132,7 @@ def run_command(a, cmd): conf.fsg_file = None #os.path.join(conf.cache_dir, 'fsg') # Generate Language Files - create_strings_file(conf.strings_file, conf.commands) + create_strings_file(conf.strings_file, db.get_prompts()) # conf.commands) create_sphinx_files(conf.strings_file, conf.lm_file, conf.dic_file) # Configure Recognizer @@ -138,6 +146,7 @@ def run_command(a, cmd): # A configured Assistant a = Assistant(config=conf) + a.db = db # From 6a32f450a9ea9fa42d993780dd07868257574020 Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Fri, 9 Dec 2016 11:44:03 -0800 Subject: [PATCH 10/15] =?UTF-8?q?More=20general=20auto=20detect=20syntax?= =?UTF-8?q?=20=E2=80=94=20works=20on=20Ubuntu=20and=20macOS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.sh b/run.sh index 9e7f9ba..3cc130f 100755 --- a/run.sh +++ b/run.sh @@ -15,7 +15,7 @@ export KEYPRESS="xvkbd -xsendevent -secure -text" export TERMINAL="tmux new-window " # Use system speech synthesizer on macOS -if [[ "uname" == "Darwin" ]] +if [ "$(uname)" = "Darwin" ] then export VOICE="say" else From 7a303e62ff813bfefa788e456b522ed3b605b951 Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Sun, 18 Dec 2016 22:44:21 -0800 Subject: [PATCH 11/15] The database is in cache for now --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index 16cf612..7612d75 100755 --- a/run.py +++ b/run.py @@ -111,7 +111,7 @@ def run_command(a, cmd): conf = Config(path=args.mind_dir, **vars(args)) - db = DB(os.path.join(conf.conf_dir, "db")) + db = DB(os.path.join(conf.cache_dir, "db")) db.create_schema() for prompt, command in conf.commands.items(): print("Adding {} -> {}".format(prompt, command)) From ca7a7fc12951293819fe64ca292c4276ab40c89c Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Thu, 5 Jan 2017 13:33:51 -0800 Subject: [PATCH 12/15] Command line switch for updating language files --- run.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/run.py b/run.py index 7612d75..3b676cb 100755 --- a/run.py +++ b/run.py @@ -59,6 +59,10 @@ def _parser(args): parser.add_argument("-d", "--debug", action='store_true', dest="debug", default=False, help="Enable debug-level logging") + + parser.add_argument("-u", "--update", + action='store_true', dest="update", default=False, + help="Update language files online") return parser.parse_args(args) @@ -132,8 +136,9 @@ def run_command(a, cmd): conf.fsg_file = None #os.path.join(conf.cache_dir, 'fsg') # Generate Language Files - create_strings_file(conf.strings_file, db.get_prompts()) # conf.commands) - create_sphinx_files(conf.strings_file, conf.lm_file, conf.dic_file) + if args.update: + create_strings_file(conf.strings_file, db.get_prompts()) # conf.commands) + create_sphinx_files(conf.strings_file, conf.lm_file, conf.dic_file) # Configure Recognizer logger.debug("Configuring Module: Speech Recognition") From ee08b9d0b5ffa7bdec1f42b042f5afefae0c9b9f Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Thu, 15 Mar 2018 16:52:51 -0700 Subject: [PATCH 13/15] Trying to reestablish a baseline (commenting out some partial features for future cleanup). It's kind of a mess, but it's a start --- core/util/config.py | 13 +- modules/language/__init__.py | 212 +++++++++++++++++++++--------- modules/speech_recognition/gst.py | 22 +++- run.py | 163 +++++++++++++++-------- 4 files changed, 284 insertions(+), 126 deletions(-) diff --git a/core/util/config.py b/core/util/config.py index 79af58d..3d961e8 100644 --- a/core/util/config.py +++ b/core/util/config.py @@ -10,7 +10,7 @@ class Config: def __init__(self, path=None, **opts): logger.info("Loading Mind: {path}".format(path=path)) - + # DIRECTORIES self.cache_dir = os.path.join(path, 'cache') self.conf_dir = os.path.join(path, 'conf') @@ -21,15 +21,16 @@ def __init__(self, path=None, **opts): # CACHE FILES self.history_file = os.path.join(self.cache_dir, "history") + self.hash_file = os.path.join(self.cache_dir, "hash.json") self._make_dir(self.conf_dir) self._make_dir(self.cache_dir) - + self.options = self._read_options_file() self.options.update(opts) logger.info("Options: {}".format(self.options)) - - self.commands = self._read_commands_file() + + self.commands = self._read_commands_file() logger.info("Command Count: {}".format(len(self.commands))) @@ -45,6 +46,7 @@ def _read_options_file(self): _options = json.load(f) return _options except FileNotFoundError: + # MAKE AN EMPTY OPTIONS NAMESPACE logger.warn("Error reading options file: {path}".format(path=self.opt_file)) return {} @@ -56,5 +58,6 @@ def _read_commands_file(self): _cmds = json.load(f) return _cmds except FileNotFoundError: + # MAKE AN EMPTY COMMANDS NAMESPACE logger.warn("Error reading commands file: {path}".format(path=self.cmd_file)) - return {} \ No newline at end of file + return {} diff --git a/modules/language/__init__.py b/modules/language/__init__.py index 4ea8e88..b4c7a79 100644 --- a/modules/language/__init__.py +++ b/modules/language/__init__.py @@ -1,12 +1,3 @@ -""" -Handles updating the language using the online lmtool. - -This class provides methods to check if the corpus has changed, and to -update the language to match the new corpus using the lmtool. This allows -us to automatically update the language if the corpus has changed, saving -the user from having to do this manually. -""" - import logging logger = logging.getLogger(__name__) @@ -16,56 +7,153 @@ import requests - -def create_strings_file(path, source={}): - # Open Strings File - with open(path, 'w+') as strings: - # Add Command Words To The Corpus - for cmd in source: - strings.write(cmd.strip().replace('%d', '') + "\n") - - -def create_sphinx_files(source, lm_path, dic_path): - """Update the language using the online lmtool""" - logger.debug("\x1b[32mUpdating Language\x1b[0m") - - host = 'http://www.speech.cs.cmu.edu' - url = host + '/cgi-bin/tools/lmtool/run' - - # SUBMIT THE CORPUS TO THE LMTOOL - response_text = "" - with open(source, 'rb') as corpus: - files = {'corpus': corpus} - values = {'formtype': 'simple'} - - r = requests.post(url, files=files, data=values) - response_text = r.text - - # PARSE RESPONSE TO GET URLS OF THE FILES WE NEED - path_re = r'.*Index of (.*?).*' - number_re = r'.*TAR([0-9]*?)\.tgz.*' - for line in response_text.split('\n'): - # ERROR RESPONSE - if "[_ERRO_]" in line: - return 1 - # IF WE FOUND THE DIRECTORY, KEEP IT AND DON'T BREAK - if re.search(path_re, line): - path = host + re.sub(path_re, r'\1', line) - # IF WE FOUND THE NUMBER, KEEP IT AND BREAK - elif re.search(number_re, line): - number = re.sub(number_re, r'\1', line) - break - - lm_url = path + '/' + number + '.lm' - dic_url = path + '/' + number + '.dic' - - _download_file(lm_url, lm_path) - _download_file(dic_url, dic_path) - - -def _download_file(url, dest): - r = requests.get(url, stream=True) - if r.status_code == 200: - with open(dest, 'wb') as f: - for chunk in r: - f.write(chunk) \ No newline at end of file +#from .hasher import Hasher + +NET_TEST_SERVER = "http://www.speech.cs.cmu.edu" + + +class LanguageUpdater: + """ + Handles updating the language using the online lmtool. + + This class provides methods to check if the corpus has changed, and to + update the language to match the new corpus using the lmtool. This allows + us to automatically update the language if the corpus has changed, saving + the user from having to do this manually. + """ + + def __init__(self, config): + self.config = config + self.create_strings_file() + + #self.hasher = Hasher(config) + + # def update_language_if_changed(self): + # """TEST IF THE LANGUAGE HAS CHANGED""" + # if self.language_has_changed(): + # """TEST NET CONNECTION AND UPDATE IF CONNECTED""" + # try: + # response=urllib.request.urlopen(NET_TEST_SERVER,timeout=1) + # print ("OpenAssistant: \x1b[32mNetwork Connection Established\x1b[0m") + # self.update_language() + # self.save_language_hash() + # except urllib.error.URLError as e: pass + # print ("OpenAssistant: \x1b[31mNo Network Connection\x1b[0m") + # + # def language_has_changed(self): + # """Use hashes to test if the language has changed""" + # self.stored_hash = self.hasher['language'] + # + # # CALCULATE LANGUAGE FILE HASH + # hasher = self.hasher.get_hash_object() + # with open(self.config.strings_file, 'rb') as sfile: + # buf = sfile.read() + # hasher.update(buf) + # self.new_hash = hasher.hexdigest() + # + # return self.new_hash != self.stored_hash + + + # def create_strings_file(path, source={}): + def create_strings_file(self): + # Open Strings File + # with open(path, 'w+') as strings: + with open(self.config.strings_file, 'w') as strings: + # Add Command Words To The Corpus + # for cmd in source: + # strings.write(cmd.strip().replace('%d', '') + "\n") + for voice_cmd in sorted(self.config.commands.keys()): + strings.write(voice_cmd.strip().replace('%d', '') + "\n") + + # def create_sphinx_files(source, lm_path, dic_path): + # """Update the language using the online lmtool""" + # logger.debug("\x1b[32mUpdating Language\x1b[0m") + # + # host = 'http://www.speech.cs.cmu.edu' + # url = host + '/cgi-bin/tools/lmtool/run' + # + # # SUBMIT THE CORPUS TO THE LMTOOL + # response_text = "" + # with open(source, 'rb') as corpus: + # files = {'corpus': corpus} + # values = {'formtype': 'simple'} + # + # r = requests.post(url, files=files, data=values) + # response_text = r.text + # + # # PARSE RESPONSE TO GET URLS OF THE FILES WE NEED + # path_re = r'.*Index of (.*?).*' + # number_re = r'.*TAR([0-9]*?)\.tgz.*' + # for line in response_text.split('\n'): + # # ERROR RESPONSE + # if "[_ERRO_]" in line: + # return 1 + # # IF WE FOUND THE DIRECTORY, KEEP IT AND DON'T BREAK + # if re.search(path_re, line): + # path = host + re.sub(path_re, r'\1', line) + # # IF WE FOUND THE NUMBER, KEEP IT AND BREAK + # elif re.search(number_re, line): + # number = re.sub(number_re, r'\1', line) + # break + # + # lm_url = path + '/' + number + '.lm' + # dic_url = path + '/' + number + '.dic' + # + # _download_file(lm_url, lm_path) + # _download_file(dic_url, dic_path) + + def update_language(self): + """Update the language using the online lmtool""" + logger.debug("\x1b[32mUpdating Language\x1b[0m") + + host = 'http://www.speech.cs.cmu.edu' + url = host + '/cgi-bin/tools/lmtool/run' + + # SUBMIT THE CORPUS TO THE LMTOOL + response_text = "" + with open(self.config.strings_file, 'rb') as corpus: + files = {'corpus': corpus} + values = {'formtype': 'simple'} + + r = requests.post(url, files=files, data=values) + response_text = r.text + + # PARSE RESPONSE TO GET URLS OF THE FILES WE NEED + path_re = r'.*Index of (.*?).*' + number_re = r'.*TAR([0-9]*?)\.tgz.*' + for line in response_text.split('\n'): + # ERROR RESPONSE + if "[_ERRO_]" in line: + return 1 + # IF WE FOUND THE DIRECTORY, KEEP IT AND DON'T BREAK + if re.search(path_re, line): + path = host + re.sub(path_re, r'\1', line) + # IF WE FOUND THE NUMBER, KEEP IT AND BREAK + elif re.search(number_re, line): + number = re.sub(number_re, r'\1', line) + break + + lm_url = path + '/' + number + '.lm' + dic_url = path + '/' + number + '.dic' + + if self.config.lang_file is not None: + self._download_file(lm_url, self.config.lang_file) + self._download_file(dic_url, self.config.dic_file) + + # def save_language_hash(self): + # self.hasher['language'] = self.new_hash + # self.hasher.store() + + def _download_file(self, url, path): + r = requests.get(url, stream=True) + if r.status_code == 200: + with open(path, 'wb') as f: + for chunk in r: + f.write(chunk) + + # def _download_file(url, dest): + # r = requests.get(url, stream=True) + # if r.status_code == 200: + # with open(dest, 'wb') as f: + # for chunk in r: + # f.write(chunk) diff --git a/modules/speech_recognition/gst.py b/modules/speech_recognition/gst.py index 8401bc3..e232fa7 100644 --- a/modules/speech_recognition/gst.py +++ b/modules/speech_recognition/gst.py @@ -15,12 +15,21 @@ class Recognizer(GObject.GObject): (GObject.TYPE_STRING,)) } - def __init__(self, mic=None, dic_file=None, lm_file=None, fsg_file=None): + # def __init__(self, mic=None, dic_file=None, lm_file=None, fsg_file=None): + def __init__(self, config): GObject.GObject.__init__(self) logger.debug("Initializing Recognizer") + self.commands = {} + logger.debug(config) + logger.debug(config.options) # Configure Audio Source - audio_src = 'autoaudiosrc' + ('' if mic is None else ' device="hw:{0},0"'.format(mic)) + src = config.options['microphone'] + if src is not None: + #audio_src = 'alsasrc device="hw:{0},0"'.format(src) + audio_src = 'autoaudiosrc device="hw:{0},0"'.format(src) + else: + audio_src = 'autoaudiosrc' # Build Pipeline cmd = ( @@ -29,15 +38,16 @@ def __init__(self, mic=None, dic_file=None, lm_file=None, fsg_file=None): ' ! audioresample' + ' ! pocketsphinx {}'.format(' '.join([ '{}={}'.format(opt, val) for opt, val in [ - ('dict', dic_file), - ('lm', lm_file), - ('fsg', fsg_file) + ('lm', config.lang_file), + ('dict', config.dic_file), + ('fsg', config.fsg_file), + ('hmm', config.hmm_path), ] if val is not None ])) + ' ! appsink sync=false' ) logger.debug(cmd) - + try: self.pipeline = Gst.parse_launch(cmd) except Exception as e: diff --git a/run.py b/run.py index 3b676cb..5b9e64b 100755 --- a/run.py +++ b/run.py @@ -4,25 +4,16 @@ import logging logging.basicConfig(level=logging.CRITICAL) -logger = logging.getLogger(__name__) +logger = logging.getLogger(__name__) -from argparse import ArgumentParser, Namespace import os import signal import sys import subprocess -from gi.repository import GObject - -from core import Config, Assistant - -from modules.language import create_strings_file, create_sphinx_files -from modules.speech_recognition.gst import Recognizer - -from core.util.db import DB - +from argparse import ArgumentParser, Namespace def _parser(args): parser = ArgumentParser() @@ -33,12 +24,11 @@ def _parser(args): parser.add_argument("-p", "--pass-words", action="store_true", dest="pass_words", default=False, - help="Pass the recognized words as arguments to the shell" + - " command") + help="Pass the recognized words as arguments to the shell command") parser.add_argument("-H", "--history", type=int, action="store", dest="history", - help="Number of commands to store in history file", metavar="HISTORY_SIZE") + help="Number of commands to store in history file") parser.add_argument("-m", "--microphone", type=int, action="store", dest="microphone", default=None, @@ -46,20 +36,20 @@ def _parser(args): parser.add_argument("--valid-sentence-command", type=str, dest="valid_sentence_command", action='store', default=None, - help="Command to run when a valid sentence is detected", metavar="COMMAND_PATH") + help="Command to run when a valid sentence is detected") parser.add_argument("--invalid-sentence-command", type=str, dest="invalid_sentence_command", action='store', default=None, - help="Command to run when an invalid sentence is detected", metavar="COMMAND_PATH") - + help="Command to run when an invalid sentence is detected") + parser.add_argument("-M", "--mind", type=str, dest="mind_dir", action='store', - help="Path to mind to use for assistant", metavar="MIND_DIR") - + help="Path to mind to use for assistant") + parser.add_argument("-d", "--debug", action='store_true', dest="debug", default=False, help="Enable debug-level logging") - + parser.add_argument("-u", "--update", action='store_true', dest="update", default=False, help="Update language files online") @@ -70,21 +60,38 @@ def _parser(args): def recognizer_finished(a, recognizer, text): logger.debug("Agent: {}, Recognier: {}, Text: {}".format(a, recognizer, text)) t = text.lower() - - cmd = a.db.get_action(t) - + + # cmd = a.db.get_action(t) + + # # Is There A Matching Command? + # if cmd is not None: + # # Run The 'valid_sentence_command' If It's Set + # os.system('clear') + # if a.config.options['valid_sentence_command']: + # subprocess.call([a.config.options['valid_sentence_command'], text]) + # # Should We Be Passing Words? + # #os.system('clear') + # if a.config.options['pass_words']: + # cmd += " " + t + # print("\x1b[32m< ? >\x1b[0m {0}".format(t)) + # run_command(a, cmd) + # Is There A Matching Command? - if cmd is not None: + if t in a.config.commands: # Run The 'valid_sentence_command' If It's Set os.system('clear') + print("Open Assistant: \x1b[32mListening\x1b[0m") if a.config.options['valid_sentence_command']: - subprocess.call([a.config.options['valid_sentence_command'], text]) + subprocess.call([a.config.options['valid_sentence_command'], text], shell=True) + cmd = a.config.commands[t] # Should We Be Passing Words? - #os.system('clear') + os.system('clear') + print("Open Assistant: \x1b[32mListening\x1b[0m") if a.config.options['pass_words']: cmd += " " + t - print("\x1b[32m< ? >\x1b[0m {0}".format(t)) + print("\x1b[32m< ! >\x1b[0m {0}".format(t)) run_command(a, cmd) + log_history(a, text) else: # Run The Invalid_sentence_command If It's Set @@ -92,7 +99,19 @@ def recognizer_finished(a, recognizer, text): if a.config.options['invalid_sentence_command']: subprocess.call([a.config.options['invalid_sentence_command'], text]) print("\x1b[31m< ? >\x1b[0m {0}".format(t)) - + + +def log_history(a, text): + if a.config.options['history']: + a.history.append(text) + if len(a.history) > a.config.options['history']: + # Pop Off First Item + a.history.pop(0) + + # Open And Truncate History File + with open(a.config.history_file, 'w') as hfile: + for line in a.history: + hfile.write(line + '\n') def run_command(a, cmd): """PRINT COMMAND AND RUN""" @@ -102,9 +121,28 @@ def run_command(a, cmd): recognizer.listen() +def process_command(self, command): + print(command) + if command == "listen": + self.recognizer.listen() + elif command == "stop": + self.recognizer.pause() + elif command == "continuous_listen": + self.continuous_listen = True + self.recognizer.listen() + elif command == "continuous_stop": + self.continuous_listen = False + self.recognizer.pause() + elif command == "quit": + self.quit() + if __name__ == '__main__': - + + from gi.repository import GObject + + from core import Config, Assistant + # Parse command-line options, # use `Config` to load mind configuration # command-line overrides config file @@ -115,57 +153,77 @@ def run_command(a, cmd): conf = Config(path=args.mind_dir, **vars(args)) - db = DB(os.path.join(conf.cache_dir, "db")) - db.create_schema() - for prompt, command in conf.commands.items(): - print("Adding {} -> {}".format(prompt, command)) - db.add_action(prompt, command) - - + + # Database Prototyping + # from core.util.db import DB + # db = DB(os.path.join(conf.cache_dir, "db")) + # db.create_schema() + # for prompt, command in conf.commands.items(): + # print("Adding {} -> {}".format(prompt, command)) + # db.add_action(prompt, command) + + + # # Pre-Configuration # - + # Configure Language logger.debug("Configuring Module: Language") # Language Paths conf.strings_file = os.path.join(conf.cache_dir, "sentences.corpus") conf.dic_file = os.path.join(conf.cache_dir, 'dic') - conf.lm_file = os.path.join(conf.cache_dir, 'lm') + # conf.lm_file = os.path.join(conf.cache_dir, 'lm') + conf.lang_file = os.path.join(conf.cache_dir, 'lm') + #XXX: hard coding this for now, sorry :( + conf.hmm_path = "/usr/local/share/pocketsphinx/model/en-us/en-us" conf.fsg_file = None #os.path.join(conf.cache_dir, 'fsg') + # Generate Language Files if args.update: - create_strings_file(conf.strings_file, db.get_prompts()) # conf.commands) - create_sphinx_files(conf.strings_file, conf.lm_file, conf.dic_file) - + from modules.language import LanguageUpdater + + # create_strings_file(conf.strings_file, db.get_prompts()) # conf.commands) + # create_sphinx_files(conf.strings_file, conf.lm_file, conf.dic_file) + + l = LanguageUpdater(conf) + l.update_language() + + + + + # Configure Recognizer logger.debug("Configuring Module: Speech Recognition") - recognizer = Recognizer(args.microphone, dic_file=conf.dic_file, lm_file=conf.lm_file) + from modules.speech_recognition.gst import Recognizer + + # recognizer = Recognizer(args.microphone, dic_file=conf.dic_file, lm_file=conf.lm_file) + recognizer = Recognizer(conf) # # End Pre-Configuration # - + # A configured Assistant a = Assistant(config=conf) - a.db = db - - + # a.db = db + + # # Post-Configuration # - + recognizer.connect('finished', lambda rec, txt, agent=a: recognizer_finished(agent, rec, txt)) - + # # End Post-Configuration # - - - + + + # # Questionable dependencies # @@ -186,7 +244,7 @@ def run_command(a, cmd): # could supplant GObject features #a.run() recognizer.listen() - + # Start Main Loop try: @@ -196,4 +254,3 @@ def run_command(a, cmd): print(e) main_loop.quit() sys.exit() - From 01ffcc1f327aa76ed0a9e0f23502578bc1808aae Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Thu, 15 Mar 2018 16:54:57 -0700 Subject: [PATCH 14/15] Latest README from vavrek/openassistant --- README.rst | 54 ++++++++---------------------------------------------- 1 file changed, 8 insertions(+), 46 deletions(-) diff --git a/README.rst b/README.rst index 93ba201..5b33805 100755 --- a/README.rst +++ b/README.rst @@ -1,14 +1,14 @@ Open Assistant ============= -Open Assistant is an evolving open source artificial intelligence agent able +Open Assistant is an evolving open source artificial intelligence agent able to interact in basic conversation and automate an increasing number of tasks. -Maintained by the `Open Assistant `__ -working group lead by `Andrew Vavrek `__, this software -is an extension of `Blather `__ -by `Jezra `__, `Kaylee `__ -by `Clayton G. Hobbs `__, and includes work +Maintained by the `Open Assistant `__ +working group lead by `Andrew Vavrek `__, this software +is an extension of `Blather `__ +by `Jezra `__, `Kaylee `__ +by `Clayton G. Hobbs `__, and includes work done by `Jonathan Kulp `__. @@ -30,15 +30,12 @@ Useful Tools * aplay - console audio player * plaympeg - console mp3 player * projectm - visualizations responsive to sound -* wmctrl - window manager control. opening, closing, resize, switch windows. +* wmctrl - window manager control. opening, closing, resize, switch windows. * xdotool - command line x automation tool * xvkbd - virtual keyboard for x -Running OpenAssistant +Running Open Assistant --------------------- -* The latest documentation can be found on our wiki at http://openassistant.org/wiki/ - -* Install dependencies and tools. Please see http://openassistant.org/wiki/doku.php?id=installation * Download and unpack the latest ``openassistant-master.zip`` package. @@ -54,41 +51,6 @@ Running OpenAssistant * To change assistant commands and language, edit ``conf/commands.json``. Exit and relaunch ``run.sh``. -* For usage instructions, check out the `Open Assistant Wiki `_. - -* For help, you can receive support in the `Open Assistant Forum `_. - - -Next Steps ----------- - -* Port Open Assistant to multiple Linux distributions, beginning with Ubuntu - -* Enable dynamic voice and instant name changes via spoken commands - -* Configure syntax and actions via spoken commands - -* Install internal language model translation - -* Improve speech recognition and synthesis - -* Long-term memory & machine learning - -* Web scraping & information analysis - -* Establish multiple default 'personalities' and plug-in functions - -* Port Open Assistant to all operating systems and devices - -* Galactic Exploration! - - -Join Us! --------- - -Join our development working group at: http://www.openassistant.org -Developers: here's a quick start guide: http://openassistant.org/wiki/doku.php?id=developers - Open Assistant Fork ================== From bead2008498ceb3c9b06617040dff363b94b4fb4 Mon Sep 17 00:00:00 2001 From: Joshua Short Date: Thu, 15 Mar 2018 20:25:46 -0700 Subject: [PATCH 15/15] Updating with github-generated python ignore template --- .gitignore | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 4910b1a..513e4b4 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,13 @@ +# OA files +mind/**/cache + +# Byte-compiled / optimized / DLL files __pycache__/ -*.pyc -.idea/ +*.py[cod] +*$py.class + +# C extensions +*.so # Distribution / packaging .Python @@ -16,8 +23,82 @@ lib64/ parts/ sdist/ var/ +wheels/ *.egg-info/ .installed.cfg *.egg -mind/**/cache \ No newline at end of file +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/