...
 
Commits (11)
This diff is collapsed.
import sys
import gobject
import pygtk
import gtk
class UI(gobject.GObject):
__gsignals__ = {
'command' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))
}
def __init__(self,args, continuous):
gobject.GObject.__init__(self)
self.continuous = continuous
self.statusicon = gtk.StatusIcon()
self.statusicon.set_title("Blather")
self.statusicon.set_name("Blather")
self.statusicon.set_tooltip_text("Blather - Idle")
self.statusicon.set_has_tooltip(True)
self.statusicon.connect("activate", self.continuous_toggle)
self.statusicon.connect("popup-menu", self.popup_menu)
self.menu = gtk.Menu()
self.menu_listen = gtk.MenuItem('Listen')
self.menu_continuous = gtk.CheckMenuItem('Continuous')
self.menu_quit = gtk.MenuItem('Quit')
self.menu.append(self.menu_listen)
self.menu.append(self.menu_continuous)
self.menu.append(self.menu_quit)
self.menu_listen.connect("activate", self.toggle_listen)
self.menu_continuous.connect("toggled", self.toggle_continuous)
self.menu_quit.connect("activate", self.quit)
self.menu.show_all()
def continuous_toggle(self, item):
checked = self.menu_continuous.get_active()
self.menu_continuous.set_active(not checked)
def toggle_continuous(self, item):
checked = self.menu_continuous.get_active()
self.menu_listen.set_sensitive(not checked)
if checked:
self.menu_listen.set_label("Listen")
self.emit('command', "continuous_listen")
self.statusicon.set_tooltip_text("Blather - Listening")
self.set_icon_active()
else:
self.set_icon_inactive()
self.statusicon.set_tooltip_text("Blather - Idle")
self.emit('command', "continuous_stop")
def toggle_listen(self, item):
val = self.menu_listen.get_label()
if val == "Listen":
self.emit("command", "listen")
self.menu_listen.set_label("Stop")
self.statusicon.set_tooltip_text("Blather - Listening")
else:
self.icon_inactive()
self.menu_listen.set_label("Listen")
self.emit("command", "stop")
self.statusicon.set_tooltip_text("Blather - Idle")
def popup_menu(self, item, button, time):
self.menu.popup(None, None, gtk.status_icon_position_menu, button, time, item)
def run(self):
#set the icon
self.set_icon_inactive()
if self.continuous:
self.menu_continuous.set_active(True)
self.set_icon_active()
else:
self.menu_continuous.set_active(False)
self.statusicon.set_visible(True)
def quit(self, item):
self.statusicon.set_visible(False)
self.emit("command", "quit")
def finished(self, text):
if not self.menu_continuous.get_active():
self.menu_listen.set_label("Listen")
self.statusicon.set_from_icon_name("blather_stopped")
self.statusicon.set_tooltip_text("Blather - Idle")
def set_icon_active_asset(self, i):
self.icon_active = i
def set_icon_inactive_asset(self, i):
self.icon_inactive = i
def set_icon_active(self):
self.statusicon.set_from_file( self.icon_active )
def set_icon_inactive(self):
self.statusicon.set_from_file( self.icon_inactive )
import sys, gi
gi.require_version('Gtk', '3.0')
from gi.repository import GObject, Gtk
class UI(GObject.GObject):
__gsignals__ = {
'command' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))
}
def __init__(self,args, continuous):
GObject.GObject.__init__(self)
self.continuous = continuous
self.statusicon = Gtk.StatusIcon()
self.statusicon.set_title("Blather")
self.statusicon.set_name("Blather")
self.statusicon.set_tooltip_text("Blather - Idle")
self.statusicon.set_has_tooltip(True)
self.statusicon.connect("activate", self.continuous_toggle)
self.statusicon.connect("popup-menu", self.popup_menu)
self.menu = Gtk.Menu()
self.menu_listen = Gtk.MenuItem('Listen')
self.menu_continuous = Gtk.CheckMenuItem('Continuous')
self.menu_quit = Gtk.MenuItem('Quit')
self.menu.append(self.menu_listen)
self.menu.append(self.menu_continuous)
self.menu.append(self.menu_quit)
self.menu_listen.connect("activate", self.toggle_listen)
self.menu_continuous.connect("toggled", self.toggle_continuous)
self.menu_quit.connect("activate", self.quit)
self.menu.show_all()
def continuous_toggle(self, item):
checked = self.menu_continuous.get_active()
self.menu_continuous.set_active(not checked)
def toggle_continuous(self, item):
checked = self.menu_continuous.get_active()
self.menu_listen.set_sensitive(not checked)
if checked:
self.menu_listen.set_label("Listen")
self.emit('command', "continuous_listen")
self.statusicon.set_tooltip_text("Blather - Listening")
self.set_icon_active()
else:
self.set_icon_inactive()
self.statusicon.set_tooltip_text("Blather - Idle")
self.emit('command', "continuous_stop")
def toggle_listen(self, item):
val = self.menu_listen.get_label()
if val == "Listen":
self.emit("command", "listen")
self.menu_listen.set_label("Stop")
self.statusicon.set_tooltip_text("Blather - Listening")
self.set_icon_active()
else:
self.icon_inactive()
self.menu_listen.set_label("Listen")
self.emit("command", "stop")
self.statusicon.set_tooltip_text("Blather - Idle")
def popup_menu(self, item, button, time):
self.menu.popup(None, None, None, None, button, time)
def run(self):
#set the icon
self.set_icon_inactive()
if self.continuous:
self.menu_continuous.set_active(True)
self.set_icon_active()
else:
self.menu_continuous.set_active(False)
self.statusicon.set_visible(True)
def quit(self, item):
self.statusicon.set_visible(False)
self.emit("command", "quit")
def finished(self, text):
if not self.menu_continuous.get_active():
self.menu_listen.set_label("Listen")
self.set_icon_inactive()
self.statusicon.set_tooltip_text("Blather - Idle")
def set_icon_active_asset(self, i):
self.icon_active = i
def set_icon_inactive_asset(self, i):
self.icon_inactive = i
def set_icon_active(self):
self.statusicon.set_from_file( self.icon_active )
def set_icon_inactive(self):
self.statusicon.set_from_file( self.icon_inactive )
......@@ -2,110 +2,110 @@
# -- this code is licensed GPLv3
# Copyright 2013 Jezra
import sys
import gobject
#Gtk
import pygtk
import gtk
class UI(gobject.GObject):
__gsignals__ = {
'command' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))
}
def __init__(self,args, continuous):
gobject.GObject.__init__(self)
self.continuous = continuous
#make a window
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("delete_event", self.delete_event)
#give the window a name
self.window.set_title("BlatherGtk")
self.window.set_resizable(False)
layout = gtk.VBox()
self.window.add(layout)
#make a listen/stop button
self.lsbutton = gtk.Button("Listen")
layout.add(self.lsbutton)
#make a continuous button
self.ccheckbox = gtk.CheckButton("Continuous Listen")
layout.add(self.ccheckbox)
#connect the buttons
self.lsbutton.connect("clicked",self.lsbutton_clicked)
self.ccheckbox.connect("clicked",self.ccheckbox_clicked)
#add a label to the UI to display the last command
self.label = gtk.Label()
layout.add(self.label)
#create an accellerator group for this window
accel = gtk.AccelGroup()
#add the ctrl+q to quit
accel.connect_group(gtk.keysyms.q, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, self.accel_quit )
#lock the group
accel.lock()
#add the group to the window
self.window.add_accel_group(accel)
def ccheckbox_clicked(self, widget):
checked = self.ccheckbox.get_active()
self.lsbutton.set_sensitive(not checked)
if checked:
self.lsbutton_stopped()
self.emit('command', "continuous_listen")
self.set_icon_active()
else:
self.emit('command', "continuous_stop")
self.set_icon_inactive()
def lsbutton_stopped(self):
self.lsbutton.set_label("Listen")
def lsbutton_clicked(self, button):
val = self.lsbutton.get_label()
if val == "Listen":
self.emit("command", "listen")
self.lsbutton.set_label("Stop")
#clear the label
self.label.set_text("")
self.set_icon_active()
else:
self.lsbutton_stopped()
self.emit("command", "stop")
self.set_icon_inactive()
def run(self):
#set the default icon
self.set_icon_inactive()
self.window.show_all()
if self.continuous:
self.set_icon_active()
self.ccheckbox.set_active(True)
def accel_quit(self, accel_group, acceleratable, keyval, modifier):
self.emit("command", "quit")
def delete_event(self, x, y ):
self.emit("command", "quit")
def finished(self, text):
#if the continuous isn't pressed
if not self.ccheckbox.get_active():
self.lsbutton_stopped()
self.set_icon_inactive()
self.label.set_text(text)
def set_icon_active_asset(self, i):
self.icon_active = i
def set_icon_inactive_asset(self, i):
self.icon_inactive = i
def set_icon_active(self):
gtk.window_set_default_icon_from_file(self.icon_active)
def set_icon_inactive(self):
gtk.window_set_default_icon_from_file(self.icon_inactive)
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GObject, Gtk, Gdk
class UI(GObject.GObject):
__gsignals__ = {
'command' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))
}
def __init__(self,args, continuous):
GObject.GObject.__init__(self)
self.continuous = continuous
#make a window
self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
self.window.connect("delete_event", self.delete_event)
#give the window a name
self.window.set_title("BlatherGtk")
self.window.set_resizable(False)
layout = Gtk.VBox()
self.window.add(layout)
#make a listen/stop button
self.lsbutton = Gtk.Button("Listen")
layout.add(self.lsbutton)
#make a continuous button
self.ccheckbox = Gtk.CheckButton("Continuous Listen")
layout.add(self.ccheckbox)
#connect the buttons
self.lsbutton.connect("clicked",self.lsbutton_clicked)
self.ccheckbox.connect("clicked",self.ccheckbox_clicked)
#add a label to the UI to display the last command
self.label = Gtk.Label()
layout.add(self.label)
#create an accellerator group for this window
accel = Gtk.AccelGroup()
#add the ctrl+q to quit
accel.connect(Gdk.KEY_Q, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE, self.accel_quit )
#lock the group
accel.lock()
#add the group to the window
self.window.add_accel_group(accel)
def ccheckbox_clicked(self, widget):
checked = self.ccheckbox.get_active()
self.lsbutton.set_sensitive(not checked)
if checked:
self.lsbutton_stopped()
self.emit('command', "continuous_listen")
self.set_icon_active()
else:
self.emit('command', "continuous_stop")
self.set_icon_inactive()
def lsbutton_stopped(self):
self.lsbutton.set_label("Listen")
def lsbutton_clicked(self, button):
val = self.lsbutton.get_label()
if val == "Listen":
self.emit("command", "listen")
self.lsbutton.set_label("Stop")
#clear the label
self.label.set_text("")
self.set_icon_active()
else:
self.lsbutton_stopped()
self.emit("command", "stop")
self.set_icon_inactive()
def run(self):
#set the default icon
self.set_icon_inactive()
self.window.show_all()
if self.continuous:
self.set_icon_active()
self.ccheckbox.set_active(True)
def accel_quit(self, accel_group, acceleratable, keyval, modifier):
self.emit("command", "quit")
def delete_event(self, x, y ):
self.emit("command", "quit")
def finished(self, text):
#if the continuous isn't pressed
if not self.ccheckbox.get_active():
self.lsbutton_stopped()
self.set_icon_inactive()
self.label.set_text(text)
def set_icon_active_asset(self, i):
self.icon_active = i
def set_icon_inactive_asset(self, i):
self.icon_inactive = i
def set_icon_active(self):
Gtk.Window.set_default_icon_from_file(self.icon_active)
def set_icon_inactive(self):
Gtk.Window.set_default_icon_from_file(self.icon_inactive)
......@@ -2,20 +2,24 @@
# -- this code is licensed GPLv3
# Copyright 2013 Jezra
import sys
import gobject
import gi
from gi.repository import GObject
# Qt stuff
from PySide.QtCore import Signal, Qt
from PySide.QtGui import QApplication, QWidget, QMainWindow, QVBoxLayout
from PySide.QtGui import QLabel, QPushButton, QCheckBox, QIcon, QAction
from PyQt5.QtCore import pyqtSignal, Qt
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QVBoxLayout
from PyQt5.QtWidgets import QLabel, QPushButton, QCheckBox, QAction
from PyQt5.QtGui import QIcon
class UI(gobject.GObject):
class UI(GObject.GObject):
__gsignals__ = {
'command' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))
'command' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))
}
def __init__(self,args,continuous):
self.continuous = continuous
gobject.GObject.__init__(self)
GObject.GObject.__init__(self)
#start by making our app
self.app = QApplication(args)
#make a window
......@@ -29,14 +33,14 @@ class UI(gobject.GObject):
layout = QVBoxLayout()
center.setLayout(layout)
#make a listen/stop button
self.lsbutton = QPushButton("Listen")
layout.addWidget(self.lsbutton)
self.listen_button = QPushButton("Listen")
layout.addWidget(self.listen_button)
#make a continuous button
self.ccheckbox = QCheckBox("Continuous Listen")
layout.addWidget(self.ccheckbox)
#connect the buttons
self.lsbutton.clicked.connect(self.lsbutton_clicked)
self.listen_button.clicked.connect(self.listen_button_clicked)
self.ccheckbox.clicked.connect(self.ccheckbox_clicked)
#add a label to the UI to display the last command
......@@ -56,29 +60,29 @@ class UI(gobject.GObject):
def ccheckbox_clicked(self):
checked = self.ccheckbox.isChecked()
if checked:
#disable lsbutton
self.lsbutton.setEnabled(False)
self.lsbutton_stopped()
#disable listen_button
self.listen_button.setEnabled(False)
self.listen_button_stopped()
self.emit('command', "continuous_listen")
self.set_icon_active()
else:
self.lsbutton.setEnabled(True)
self.listen_button.setEnabled(True)
self.emit('command', "continuous_stop")
self.set_icon_inactive()
def lsbutton_stopped(self):
self.lsbutton.setText("Listen")
def listen_button_stopped(self):
self.listen_button.setText("Listen")
def lsbutton_clicked(self):
val = self.lsbutton.text()
def listen_button_clicked(self):
val = self.listen_button.text()
if val == "Listen":
self.emit("command", "listen")
self.lsbutton.setText("Stop")
self.listen_button.setText("Stop")
#clear the label
self.label.setText("")
self.set_icon_active()
else:
self.lsbutton_stopped()
self.listen_button_stopped()
self.emit("command", "stop")
self.set_icon_inactive()
......@@ -95,7 +99,8 @@ class UI(gobject.GObject):
def finished(self, text):
#if the continuous isn't pressed
if not self.ccheckbox.isChecked():
self.lsbutton_stopped()
self.listen_button_stopped()
self.set_icon_inactive()
self.label.setText(text)
def set_icon(self, icon):
......
# Blather
Blather is a speech recognizer that will run commands when a user speaks preset sentences.
Blather is a speech recognizer that will run commands when a user speaks preset commands.
## Requirements
1. pocketsphinx
2. gstreamer-0.10 (and what ever plugin has pocket sphinx support)
3. gstreamer-0.10 base plugins (required for alsa)
4. pyside (only required for the Qt based UI)
5. pygtk (only required for the Gtk based UI)
6. pyyaml (only required for reading the options file)
**Note:** it may also be required to install `pocketsphinx-hmm-en-hub4wsj`
2. gstreamer-1.x (and what ever plugin has pocket sphinx support)
3. Python3
4. GI (GObject Introspection)
5. pyQt (only required for the Qt based UI)
6. curl (only required when running the language file updater)
## Usage
0. move commands.tmp to ~/.config/blather/commands.conf and fill the file with sentences and command to run
1. Run Blather.py, this will generate ~/.config/blather/sentences.corpus based on sentences in the 'commands' file
2. quit blather (there is a good chance it will just segfault)
3. go to <http://www.speech.cs.cmu.edu/tools/lmtool.html> and upload the sentences.corpus file
4. download the resulting XXXX.lm file to the ~/.config/blather/language directory and rename to file to 'lm'
5. download the resulting XXXX.dic file to the ~/.config/blather/language directory and rename to file to 'dic'
6. run Blather.py
1. Run `Blather.py -u` , this will:
* generate ~/.config/blather/sentences.corpus based on sentences in the 'commands' file
* upload the corpus file to Carnegie Melon University's Sphinx language tools
* download the lexicon and language files from CMU
2. run Blather.py
* for Qt GUI, run Blather.py -i q
* for Gtk GUI, run Blather.py -i g
* for Gtk Tray GUI, run Blather.py -i gt
* to start a UI in 'continuous' listen mode, use the -c flag
* to use a microphone other than the system default, use the -m flag
7. start talking
**Note:** to start Blather without needing to enter command line options all the time, copy options.yaml.tmp to ~/.config/blather/options.yaml and edit accordingly.
3. start talking
### Bonus
**Note:** to start Blather without needing to enter command line options all the time, copy options.conf.tmp to ~/.config/blather/options.conf and edit accordingly.
once the sentences.corpus file has been created, run the language_updater.sh script to automate the process of creating and downloading language files.
### Examples
......@@ -54,13 +48,14 @@ once the sentences.corpus file has been created, run the language_updater.sh scr
* To run a command when a valid sentence has been detected:
`./Blather.py --valid-sentence-command=/path/to/command`
**note:** this can be set in the options.yml file
**note:** this can be set in the options.conf file
* To run a command when a invalid sentence has been detected:
`./Blather.py --invalid-sentence-command=/path/to/command`
**note:** this can be set in the options.yml file
**note:** this can be set in the options.conf file
### Finding the Device Number of a USB microphone
There are a few ways to find the device number of a USB microphone.
* `cat /proc/asound/cards`
* `arecord -l`
**note:** this can be set in the options.conf file
......@@ -2,56 +2,83 @@
# -- this code is licensed GPLv3
# Copyright 2013 Jezra
import pygst
pygst.require('0.10')
import gst
import os.path
import gobject
import sys
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst
#initialize gst
Gst.init(None)
#define some global variables
this_dir = os.path.dirname( os.path.abspath(__file__) )
class Recognizer(gobject.GObject):
__gsignals__ = {
'finished' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))
}
def __init__(self, language_file, dictionary_file, src = None):
gobject.GObject.__init__(self)
self.commands = {}
if src:
audio_src = 'alsasrc device="hw:%d,0"' % (src)
else:
audio_src = 'autoaudiosrc'
#build the pipeline
cmd = audio_src+' ! audioconvert ! audioresample ! vader name=vad ! pocketsphinx name=asr ! appsink sync=false'
try:
self.pipeline=gst.parse_launch( cmd )
except Exception, e:
print e.message
print "You may need to install gstreamer0.10-pocketsphinx"
raise e
#get the Auto Speech Recognition piece
asr=self.pipeline.get_by_name('asr')
asr.connect('result', self.result)
asr.set_property('lm', language_file)
asr.set_property('dict', dictionary_file)
asr.set_property('configured', True)
#get the Voice Activity DEtectoR
self.vad = self.pipeline.get_by_name('vad')
self.vad.set_property('auto-threshold',True)
def listen(self):
self.pipeline.set_state(gst.STATE_PLAYING)
def pause(self):
self.vad.set_property('silent', True)
self.pipeline.set_state(gst.STATE_PAUSED)
def result(self, asr, text, uttid):
#emit finished
self.emit("finished", text)
class Recognizer(GObject.GObject):
__gsignals__ = {
'finished' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))
}
def __init__(self, language_file, dictionary_file, src = None):
GObject.GObject.__init__(self)
self.commands = {}
if src:
audio_src = 'alsasrc device="hw:%d,0"' % (src)
else:
audio_src = 'autoaudiosrc'
#build the pipeline
cmd = audio_src+' ! audioconvert ! audioresample ! pocketsphinx name=asr ! appsink sync=false'
try:
self.pipeline=Gst.parse_launch( cmd )
except Exception as e:
print( e)
print( "You may need to install gstreamer pocketsphinx")
raise e
'''messages come from the pipeline bus now'''
#get the pipeline bus
bus = self.pipeline.get_bus()
#hey bus, start emitting signals!
bus.add_signal_watch()
#connect messages from elements to our parser
bus.connect('message::element', self.parse_bus_element_message)
#get the Auto Speech Recognition piece
asr=self.pipeline.get_by_name('asr')
asr.set_property('lm', language_file)
asr.set_property('dict', dictionary_file)
def parse_bus_element_message(self, bus, message):
#get the message's structure
message_struct = message.get_structure()
#get the message's ... ahem ... type
message_type = message_struct.get_name()
#is this pocket sphinx?
if message_type != 'pocketsphinx':
#get outa here!
return
# is this the final decided text?
if message_struct.get_value('final'):
#hypothesis is the string we want
text = message_struct.get_value('hypothesis')
#emit finished
self.emit("finished", text)
#TODO: find a way to utilize partial matches and match confidence
def listen(self):
print("listen")
self.pipeline.set_state(Gst.State.PLAYING)
def pause(self):
self.pipeline.set_state(Gst.State.PAUSED)
def result(self, asr, text, uttid):
#emit finished
self.emit("finished", text)
#!/usr/bin/env python3
import subprocess
import sys, os.path
import re
def update_language():
#set some variables
downloader = None
sentences_file = "~/.config/blather/sentences.corpus"
abs_sentences = os.path.expanduser(sentences_file)
HOST = "www.speech.cs.cmu.edu"
URL = "/cgi-bin/tools/lmtool/run"
TARGET = HOST+URL
#make sure curl is installed
try:
output = subprocess.check_output("which curl", shell = True)
downloader = "curl"
except Exception as e:
print(e)
print("Please install `curl`")
#pffftttt we're out of here!
sys.exit()
#define the curl command to upload the corus file
cmd = "curl -s -L -F [email protected]{} -F formtype=simple {}".format(abs_sentences,TARGET)
print(cmd)
#go for it, bruh!
try:
output = subprocess.check_output(cmd, shell = True)
#decode the output, should this be utf-8?
output = output.decode('utf-8')
except Exception as e:
print(e)
print("failed to update language")
sys.exit()
print(output)
#create a regex to find the base name
namefinder = re.search(r"The base name for this set is <b>(?P<base_name>.*)<", output)
base_name = namefinder.group("base_name")
print(base_name)
#use regex to find the http path to the files we want
pathfinder = re.search(r"(http://www.speech.cs.cmu.edu/tools/product/.*/)TAR",output)
http_path = pathfinder.group(1)
#where are the files we need?
lm_remote = http_path+base_name+".lm"
dic_remote = http_path+base_name+".dic"
#do more downloading
if downloader == 'curl':
#get the lang file
cmd = "curl -s {} > ~/.config/blather/lm.tmp".format(lm_remote)
try:
output = subprocess.check_output(cmd, shell = True)
except Exception as e:
print(e)
print("Failed to download {}".format(lm_remote))
sys.exit()
cmd = "curl -s {} > ~/.config/blather/dic.tmp".format(dic_remote)
try:
output = subprocess.check_output(cmd, shell = True)
except Exception as e:
print(e)
print("Failed to download {}".format(lm_remote))
sys.exit()
# if we made it this far, mv the temp files to their proper location
cmd = "mv ~/.config/blather/dic.tmp ~/.config/blather/language/dic"
subprocess.call(cmd, shell = True)
cmd = "mv ~/.config/blather/lm.tmp ~/.config/blather/language/lm"
subprocess.call(cmd, shell = True)
continuous: True
history: None
microphone: 0
interface: q
valid_sentence_command: null
invalid_sentence_command: null
#This is a YAML file
#these options can be over-ridden by commandline arguments
continuous: false
history: null
microphone: null
interface: null
valid_sentence_command: null
invalid_sentence_command: null