Somewhat fancy voice command recognition software
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

blather.py 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. #!/usr/bin/env python2
  2. # This is part of Kaylee
  3. # -- this code is licensed GPLv3
  4. # Copyright 2013 Jezra
  5. # Copyright 2015 Clayton G. Hobbs
  6. import sys
  7. import signal
  8. from gi.repository import GObject
  9. import os.path
  10. import subprocess
  11. from optparse import OptionParser
  12. try:
  13. import yaml
  14. except:
  15. print "YAML is not supported. ~/.config/blather/options.yaml will not function"
  16. from recognizer import Recognizer
  17. # Where are the files?
  18. conf_dir = os.path.expanduser("~/.config/blather")
  19. lang_dir = os.path.join(conf_dir, "language")
  20. command_file = os.path.join(conf_dir, "commands.conf")
  21. strings_file = os.path.join(conf_dir, "sentences.corpus")
  22. history_file = os.path.join(conf_dir, "blather.history")
  23. opt_file = os.path.join(conf_dir, "options.yaml")
  24. lang_file = os.path.join(lang_dir,'lm')
  25. dic_file = os.path.join(lang_dir,'dic')
  26. # Make the lang_dir if it doesn't exist
  27. if not os.path.exists(lang_dir):
  28. os.makedirs(lang_dir)
  29. class Blather:
  30. def __init__(self, opts):
  31. # Import the recognizer so Gst doesn't clobber our -h
  32. self.ui = None
  33. self.options = {}
  34. ui_continuous_listen = False
  35. self.continuous_listen = False
  36. self.commands = {}
  37. # Read the commands
  38. self.read_commands()
  39. # Load the options file
  40. self.load_options()
  41. # Merge the opts
  42. for k,v in opts.__dict__.items():
  43. if (not k in self.options) or opts.override:
  44. self.options[k] = v
  45. if self.options['interface'] != None:
  46. if self.options['interface'] == "g":
  47. from gtkui import UI
  48. elif self.options['interface'] == "gt":
  49. from gtktrayui import UI
  50. else:
  51. print "no GUI defined"
  52. sys.exit()
  53. self.ui = UI(args, self.options['continuous'])
  54. self.ui.connect("command", self.process_command)
  55. # Can we load the icon resource?
  56. icon = self.load_resource("icon.png")
  57. if icon:
  58. self.ui.set_icon_active_asset(icon)
  59. # Can we load the icon_inactive resource?
  60. icon_inactive = self.load_resource("icon_inactive.png")
  61. if icon_inactive:
  62. self.ui.set_icon_inactive_asset(icon_inactive)
  63. if self.options['history']:
  64. self.history = []
  65. # Create the recognizer
  66. try:
  67. self.recognizer = Recognizer(lang_file, dic_file, self.options['microphone'])
  68. except Exception, e:
  69. #no recognizer? bummer
  70. print 'error making recognizer'
  71. sys.exit()
  72. self.recognizer.connect('finished', self.recognizer_finished)
  73. print "Using Options: ", self.options
  74. def read_commands(self):
  75. # Read the commands file
  76. file_lines = open(command_file)
  77. strings = open(strings_file, "w")
  78. for line in file_lines:
  79. print line
  80. # Trim the white spaces
  81. line = line.strip()
  82. # If the line has length and the first char isn't a hash
  83. if len(line) and line[0]!="#":
  84. # This is a parsible line
  85. (key,value) = line.split(":",1)
  86. print key, value
  87. self.commands[key.strip().lower()] = value.strip()
  88. strings.write( key.strip()+"\n")
  89. # Close the strings file
  90. strings.close()
  91. def load_options(self):
  92. # Is there an opt file?
  93. try:
  94. opt_fh = open(opt_file)
  95. text = opt_fh.read()
  96. self.options = yaml.load(text)
  97. except:
  98. pass
  99. def log_history(self,text):
  100. if self.options['history']:
  101. self.history.append(text)
  102. if len(self.history) > self.options['history']:
  103. # Pop off the first item
  104. self.history.pop(0)
  105. # Open and truncate the blather history file
  106. hfile = open(history_file, "w")
  107. for line in self.history:
  108. hfile.write( line+"\n")
  109. # Close the file
  110. hfile.close()
  111. def run_command(self, cmd):
  112. '''Print the command, then run it'''
  113. print cmd
  114. subprocess.call(cmd, shell=True)
  115. def recognizer_finished(self, recognizer, text):
  116. t = text.lower()
  117. # Is there a matching command?
  118. if self.commands.has_key( t ):
  119. # Run the valid_sentence_command if there is a valid sentence command
  120. if self.options['valid_sentence_command']:
  121. subprocess.call(self.options['valid_sentence_command'], shell=True)
  122. cmd = self.commands[t]
  123. # Should we be passing words?
  124. if self.options['pass_words']:
  125. cmd += " " + t
  126. self.run_command(cmd)
  127. else:
  128. self.run_command(cmd)
  129. self.log_history(text)
  130. else:
  131. # Run the invalid_sentence_command if there is an invalid sentence command
  132. if self.options['invalid_sentence_command']:
  133. subprocess.call(self.options['invalid_sentence_command'], shell=True)
  134. print "no matching command %s" % t
  135. # If there is a UI and we are not continuous listen
  136. if self.ui:
  137. if not self.continuous_listen:
  138. # Stop listening
  139. self.recognizer.pause()
  140. # Let the UI know that there is a finish
  141. self.ui.finished(t)
  142. def run(self):
  143. if self.ui:
  144. self.ui.run()
  145. else:
  146. blather.recognizer.listen()
  147. def quit(self):
  148. sys.exit()
  149. def process_command(self, UI, command):
  150. print command
  151. if command == "listen":
  152. self.recognizer.listen()
  153. elif command == "stop":
  154. self.recognizer.pause()
  155. elif command == "continuous_listen":
  156. self.continuous_listen = True
  157. self.recognizer.listen()
  158. elif command == "continuous_stop":
  159. self.continuous_listen = False
  160. self.recognizer.pause()
  161. elif command == "quit":
  162. self.quit()
  163. def load_resource(self,string):
  164. local_data = os.path.join(os.path.dirname(__file__), 'data')
  165. paths = ["/usr/share/blather/","/usr/local/share/blather", local_data]
  166. for path in paths:
  167. resource = os.path.join(path, string)
  168. if os.path.exists( resource ):
  169. return resource
  170. # If we get this far, no resource was found
  171. return False
  172. if __name__ == "__main__":
  173. parser = OptionParser()
  174. parser.add_option("-i", "--interface", type="string", dest="interface",
  175. action='store',
  176. help="Interface to use (if any). 'g' for GTK or 'gt' for GTK system tray icon")
  177. parser.add_option("-c", "--continuous",
  178. action="store_true", dest="continuous", default=False,
  179. help="starts interface with 'continuous' listen enabled")
  180. parser.add_option("-p", "--pass-words",
  181. action="store_true", dest="pass_words", default=False,
  182. help="passes the recognized words as arguments to the shell command")
  183. parser.add_option("-o", "--override",
  184. action="store_true", dest="override", default=False,
  185. help="override config file with command line options")
  186. parser.add_option("-H", "--history", type="int",
  187. action="store", dest="history",
  188. help="number of commands to store in history file")
  189. parser.add_option("-m", "--microphone", type="int",
  190. action="store", dest="microphone", default=None,
  191. help="Audio input card to use (if other than system default)")
  192. parser.add_option("--valid-sentence-command", type="string", dest="valid_sentence_command",
  193. action='store',
  194. help="command to run when a valid sentence is detected")
  195. parser.add_option( "--invalid-sentence-command", type="string", dest="invalid_sentence_command",
  196. action='store',
  197. help="command to run when an invalid sentence is detected")
  198. (options, args) = parser.parse_args()
  199. # Make our blather object
  200. blather = Blather(options)
  201. # Init gobject threads
  202. GObject.threads_init()
  203. # We want a main loop
  204. main_loop = GObject.MainLoop()
  205. # Handle sigint
  206. signal.signal(signal.SIGINT, signal.SIG_DFL)
  207. # Run the blather
  208. blather.run()
  209. # Start the main loop
  210. try:
  211. main_loop.run()
  212. except:
  213. print "time to quit"
  214. main_loop.quit()
  215. sys.exit()