Somewhat fancy voice command recognition software
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

kaylee.py 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #!/usr/bin/env python3
  2. # This is part of Kaylee
  3. # -- this code is licensed GPLv3
  4. # Copyright 2015-2016 Clayton G. Hobbs
  5. # Portions Copyright 2013 Jezra
  6. from __future__ import print_function
  7. import sys
  8. import signal
  9. import hashlib
  10. import os.path
  11. import subprocess
  12. from gi.repository import GObject, GLib
  13. import json
  14. from recognizer import Recognizer
  15. from config import Config
  16. from languageupdater import LanguageUpdater
  17. from numberparser import NumberParser
  18. class Kaylee:
  19. def __init__(self):
  20. self.ui = None
  21. self.options = {}
  22. ui_continuous_listen = False
  23. self.continuous_listen = False
  24. self.commands = {}
  25. # Load configuration
  26. self.config = Config()
  27. self.options = vars(self.config.options)
  28. # Create number parser for later use
  29. self.number_parser = NumberParser()
  30. # Read the commands
  31. self.read_commands()
  32. if self.options['interface']:
  33. if self.options['interface'] == "g":
  34. from gtkui import UI
  35. elif self.options['interface'] == "gt":
  36. from gtktrayui import UI
  37. else:
  38. print("no GUI defined")
  39. sys.exit()
  40. self.ui = UI(self.options, self.options['continuous'])
  41. self.ui.connect("command", self.process_command)
  42. # Can we load the icon resource?
  43. icon = self.load_resource("icon.png")
  44. if icon:
  45. self.ui.set_icon_active_asset(icon)
  46. # Can we load the icon_inactive resource?
  47. icon_inactive = self.load_resource("icon_inactive.png")
  48. if icon_inactive:
  49. self.ui.set_icon_inactive_asset(icon_inactive)
  50. if self.options['history']:
  51. self.history = []
  52. # Update the language if necessary
  53. self.language_updater = LanguageUpdater(self.config)
  54. self.language_updater.update_language_if_changed()
  55. # Create the recognizer
  56. self.recognizer = Recognizer(self.config)
  57. self.recognizer.connect('finished', self.recognizer_finished)
  58. def read_commands(self):
  59. # Read the commands file
  60. file_lines = open(self.config.command_file)
  61. strings = open(self.config.strings_file, "w")
  62. for line in file_lines:
  63. # Trim the white spaces
  64. line = line.strip()
  65. # If the line has length and the first char isn't a hash
  66. if len(line) and line[0] != "#":
  67. # This is a parsible line
  68. (key, value) = line.split(":", 1)
  69. self.commands[key.strip().lower()] = value.strip()
  70. strings.write(key.strip().replace('%d', '') + "\n")
  71. # Add number words to the corpus
  72. for word in self.number_parser.number_words:
  73. strings.write(word + "\n")
  74. # Close the strings file
  75. strings.close()
  76. def log_history(self, text):
  77. if self.options['history']:
  78. self.history.append(text)
  79. if len(self.history) > self.options['history']:
  80. # Pop off the first item
  81. self.history.pop(0)
  82. # Open and truncate the history file
  83. hfile = open(self.config.history_file, "w")
  84. for line in self.history:
  85. hfile.write(line + "\n")
  86. # Close the file
  87. hfile.close()
  88. def run_command(self, cmd):
  89. """Print the command, then run it"""
  90. print(cmd)
  91. subprocess.call(cmd, shell=True)
  92. def recognizer_finished(self, recognizer, text):
  93. t = text.lower()
  94. numt, nums = self.number_parser.parse_all_numbers(t)
  95. # Is there a matching command?
  96. if t in self.commands:
  97. # Run the valid_sentence_command if it's set
  98. if self.options['valid_sentence_command']:
  99. subprocess.call(self.options['valid_sentence_command'],
  100. shell=True)
  101. cmd = self.commands[t]
  102. # Should we be passing words?
  103. if self.options['pass_words']:
  104. cmd += " " + t
  105. self.run_command(cmd)
  106. self.log_history(text)
  107. elif numt in self.commands:
  108. # Run the valid_sentence_command if it's set
  109. if self.options['valid_sentence_command']:
  110. subprocess.call(self.options['valid_sentence_command'],
  111. shell=True)
  112. cmd = self.commands[numt]
  113. cmd = cmd.format(*nums)
  114. # Should we be passing words?
  115. if self.options['pass_words']:
  116. cmd += " " + t
  117. self.run_command(cmd)
  118. self.log_history(text)
  119. else:
  120. # Run the invalid_sentence_command if it's set
  121. if self.options['invalid_sentence_command']:
  122. subprocess.call(self.options['invalid_sentence_command'],
  123. shell=True)
  124. print("no matching command {0}".format(t))
  125. # If there is a UI and we are not continuous listen
  126. if self.ui:
  127. if not self.continuous_listen:
  128. # Stop listening
  129. self.recognizer.pause()
  130. # Let the UI know that there is a finish
  131. self.ui.finished(t)
  132. def run(self):
  133. if self.ui:
  134. self.ui.run()
  135. else:
  136. self.recognizer.listen()
  137. def quit(self):
  138. sys.exit()
  139. def process_command(self, UI, command):
  140. print(command)
  141. if command == "listen":
  142. self.recognizer.listen()
  143. elif command == "stop":
  144. self.recognizer.pause()
  145. elif command == "continuous_listen":
  146. self.continuous_listen = True
  147. self.recognizer.listen()
  148. elif command == "continuous_stop":
  149. self.continuous_listen = False
  150. self.recognizer.pause()
  151. elif command == "quit":
  152. self.quit()
  153. def load_resource(self, string):
  154. local_data = os.path.join(os.path.dirname(__file__), 'data')
  155. paths = ["/usr/share/kaylee/", "/usr/local/share/kaylee", local_data]
  156. for path in paths:
  157. resource = os.path.join(path, string)
  158. if os.path.exists(resource):
  159. return resource
  160. # If we get this far, no resource was found
  161. return False
  162. if __name__ == "__main__":
  163. # Make our kaylee object
  164. kaylee = Kaylee()
  165. # Init gobject threads
  166. GObject.threads_init()
  167. # We want a main loop
  168. main_loop = GObject.MainLoop()
  169. # Handle sigint
  170. signal.signal(signal.SIGINT, signal.SIG_DFL)
  171. # Run the kaylee
  172. kaylee.run()
  173. # Start the main loop
  174. try:
  175. main_loop.run()
  176. except:
  177. print("time to quit")
  178. main_loop.quit()
  179. sys.exit()