Browse Source

Ported to new pocketsphinx and pygi

Gotta keep that stuff up-to-date, yo.  Pocketsphinx changed so it needs
GStreamer 1.0, and that required rewriting everything to use GObject
Introspection instead of the old, static Python bindings for GObject.
Clayton G. Hobbs 8 years ago
parent
commit
a6e27df2cc
6 changed files with 513 additions and 505 deletions
  1. 1
    0
      .gitignore
  2. 224
    224
      Blather.py
  3. 96
    98
      GtkTrayUI.py
  4. 106
    108
      GtkUI.py
  5. 31
    28
      README.md
  6. 55
    47
      Recognizer.py

+ 1
- 0
.gitignore View File

@@ -0,0 +1 @@
1
+*.pyc

+ 224
- 224
Blather.py View File

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

+ 96
- 98
GtkTrayUI.py View File

@@ -1,99 +1,97 @@
1 1
 import sys
2
-import gobject
3
-
4
-import pygtk
5
-import gtk
6
-
7
-class UI(gobject.GObject):
8
-	__gsignals__ = {
9
-		'command' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))
10
-	}
11
-
12
-	def __init__(self,args, continuous):
13
-		gobject.GObject.__init__(self)
14
-		self.continuous = continuous
15
-
16
-		self.statusicon = gtk.StatusIcon()
17
-		self.statusicon.set_title("Blather")
18
-		self.statusicon.set_name("Blather")
19
-		self.statusicon.set_tooltip_text("Blather - Idle")
20
-		self.statusicon.set_has_tooltip(True)
21
-		self.statusicon.connect("activate", self.continuous_toggle)
22
-		self.statusicon.connect("popup-menu", self.popup_menu)
23
-
24
-		self.menu = gtk.Menu()
25
-		self.menu_listen = gtk.MenuItem('Listen')
26
-		self.menu_continuous = gtk.CheckMenuItem('Continuous')
27
-		self.menu_quit = gtk.MenuItem('Quit')
28
-		self.menu.append(self.menu_listen)
29
-		self.menu.append(self.menu_continuous)
30
-		self.menu.append(self.menu_quit)
31
-		self.menu_listen.connect("activate", self.toggle_listen)
32
-		self.menu_continuous.connect("toggled", self.toggle_continuous)
33
-		self.menu_quit.connect("activate", self.quit)
34
-		self.menu.show_all()
35
-
36
-	def continuous_toggle(self, item):
37
-		checked = self.menu_continuous.get_active()
38
-		self.menu_continuous.set_active(not checked)
39
-
40
-	def toggle_continuous(self, item):
41
-		checked = self.menu_continuous.get_active()
42
-		self.menu_listen.set_sensitive(not checked)
43
-		if checked:
44
-			self.menu_listen.set_label("Listen")
45
-			self.emit('command', "continuous_listen")
46
-			self.statusicon.set_tooltip_text("Blather - Listening")
47
-			self.set_icon_active()
48
-		else:
49
-			self.set_icon_inactive()
50
-			self.statusicon.set_tooltip_text("Blather - Idle")
51
-			self.emit('command', "continuous_stop")
52
-
53
-	def toggle_listen(self, item):
54
-		val = self.menu_listen.get_label()
55
-		if val == "Listen":
56
-			self.emit("command", "listen")
57
-			self.menu_listen.set_label("Stop")
58
-			self.statusicon.set_tooltip_text("Blather - Listening")
59
-		else:
60
-			self.icon_inactive()
61
-			self.menu_listen.set_label("Listen")
62
-			self.emit("command", "stop")
63
-			self.statusicon.set_tooltip_text("Blather - Idle")
64
-
65
-	def popup_menu(self, item, button, time):
66
-		self.menu.popup(None, None, gtk.status_icon_position_menu, button, time, item)
67
-
68
-	def run(self):
69
-		#set the icon
70
-		self.set_icon_inactive()
71
-		if self.continuous:
72
-			self.menu_continuous.set_active(True)
73
-			self.set_icon_active()
74
-		else:
75
-			self.menu_continuous.set_active(False)
76
-		self.statusicon.set_visible(True)
77
-
78
-	def quit(self, item):
79
-		self.statusicon.set_visible(False)
80
-		self.emit("command", "quit")
81
-
82
-	def finished(self, text):
83
-		if not self.menu_continuous.get_active():
84
-			self.menu_listen.set_label("Listen")
85
-			self.statusicon.set_from_icon_name("blather_stopped")
86
-			self.statusicon.set_tooltip_text("Blather - Idle")
87
-
88
-	def set_icon_active_asset(self, i):
89
-		self.icon_active = i
90
-
91
-	def set_icon_inactive_asset(self, i):
92
-		self.icon_inactive = i
93
-
94
-	def set_icon_active(self):
95
-		self.statusicon.set_from_file( self.icon_active )
96
-
97
-	def set_icon_inactive(self):
98
-		self.statusicon.set_from_file( self.icon_inactive )
99
-
2
+from gi.repository import GObject
3
+# Gtk
4
+from gi.repository import Gtk, Gdk
5
+
6
+class UI(GObject.GObject):
7
+    __gsignals__ = {
8
+        'command' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))
9
+    }
10
+
11
+    def __init__(self, args, continuous):
12
+        GObject.GObject.__init__(self)
13
+        self.continuous = continuous
14
+
15
+        self.statusicon = Gtk.StatusIcon()
16
+        self.statusicon.set_title("Blather")
17
+        self.statusicon.set_name("Blather")
18
+        self.statusicon.set_tooltip_text("Blather - Idle")
19
+        self.statusicon.set_has_tooltip(True)
20
+        self.statusicon.connect("activate", self.continuous_toggle)
21
+        self.statusicon.connect("popup-menu", self.popup_menu)
22
+
23
+        self.menu = Gtk.Menu()
24
+        self.menu_listen = Gtk.MenuItem('Listen')
25
+        self.menu_continuous = Gtk.CheckMenuItem('Continuous')
26
+        self.menu_quit = Gtk.MenuItem('Quit')
27
+        self.menu.append(self.menu_listen)
28
+        self.menu.append(self.menu_continuous)
29
+        self.menu.append(self.menu_quit)
30
+        self.menu_listen.connect("activate", self.toggle_listen)
31
+        self.menu_continuous.connect("toggled", self.toggle_continuous)
32
+        self.menu_quit.connect("activate", self.quit)
33
+        self.menu.show_all()
34
+
35
+    def continuous_toggle(self, item):
36
+        checked = self.menu_continuous.get_active()
37
+        self.menu_continuous.set_active(not checked)
38
+
39
+    def toggle_continuous(self, item):
40
+        checked = self.menu_continuous.get_active()
41
+        self.menu_listen.set_sensitive(not checked)
42
+        if checked:
43
+            self.menu_listen.set_label("Listen")
44
+            self.emit('command', "continuous_listen")
45
+            self.statusicon.set_tooltip_text("Blather - Listening")
46
+            self.set_icon_active()
47
+        else:
48
+            self.set_icon_inactive()
49
+            self.statusicon.set_tooltip_text("Blather - Idle")
50
+            self.emit('command', "continuous_stop")
51
+
52
+    def toggle_listen(self, item):
53
+        val = self.menu_listen.get_label()
54
+        if val == "Listen":
55
+            self.emit("command", "listen")
56
+            self.menu_listen.set_label("Stop")
57
+            self.statusicon.set_tooltip_text("Blather - Listening")
58
+        else:
59
+            self.icon_inactive()
60
+            self.menu_listen.set_label("Listen")
61
+            self.emit("command", "stop")
62
+            self.statusicon.set_tooltip_text("Blather - Idle")
63
+
64
+    def popup_menu(self, item, button, time):
65
+        self.menu.popup(None, None, Gtk.StatusIcon.position_menu, item, button, time)
66
+
67
+    def run(self):
68
+        # Set the icon
69
+        self.set_icon_inactive()
70
+        if self.continuous:
71
+            self.menu_continuous.set_active(True)
72
+            self.set_icon_active()
73
+        else:
74
+            self.menu_continuous.set_active(False)
75
+        self.statusicon.set_visible(True)
76
+
77
+    def quit(self, item):
78
+        self.statusicon.set_visible(False)
79
+        self.emit("command", "quit")
80
+
81
+    def finished(self, text):
82
+        if not self.menu_continuous.get_active():
83
+            self.menu_listen.set_label("Listen")
84
+            self.statusicon.set_from_icon_name("blather_stopped")
85
+            self.statusicon.set_tooltip_text("Blather - Idle")
86
+
87
+    def set_icon_active_asset(self, i):
88
+        self.icon_active = i
89
+
90
+    def set_icon_inactive_asset(self, i):
91
+        self.icon_inactive = i
92
+
93
+    def set_icon_active(self):
94
+        self.statusicon.set_from_file(self.icon_active)
95
+
96
+    def set_icon_inactive(self):
97
+        self.statusicon.set_from_file(self.icon_inactive)

+ 106
- 108
GtkUI.py View File

@@ -1,111 +1,109 @@
1
-#This is part of Blather
1
+# This is part of Blather
2 2
 # -- this code is licensed GPLv3
3 3
 # Copyright 2013 Jezra
4 4
 import sys
5
-import gobject
6
-#Gtk
7
-import pygtk
8
-import gtk
9
-
10
-class UI(gobject.GObject):
11
-	__gsignals__ = {
12
-		'command' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))
13
-	}
14
-
15
-	def __init__(self,args, continuous):
16
-		gobject.GObject.__init__(self)
17
-		self.continuous = continuous
18
-		#make a window
19
-		self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
20
-		self.window.connect("delete_event", self.delete_event)
21
-		#give the window a name
22
-		self.window.set_title("BlatherGtk")
23
-		self.window.set_resizable(False)
24
-
25
-		layout = gtk.VBox()
26
-		self.window.add(layout)
27
-		#make a listen/stop button
28
-		self.lsbutton = gtk.Button("Listen")
29
-		layout.add(self.lsbutton)
30
-		#make a continuous button
31
-		self.ccheckbox = gtk.CheckButton("Continuous Listen")
32
-		layout.add(self.ccheckbox)
33
-
34
-		#connect the buttons
35
-		self.lsbutton.connect("clicked",self.lsbutton_clicked)
36
-		self.ccheckbox.connect("clicked",self.ccheckbox_clicked)
37
-
38
-		#add a label to the UI to display the last command
39
-		self.label = gtk.Label()
40
-		layout.add(self.label)
41
-
42
-		#create an accellerator group for this window
43
-		accel = gtk.AccelGroup()
44
-		#add the ctrl+q to quit
45
-		accel.connect_group(gtk.keysyms.q, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, self.accel_quit )
46
-		#lock the group
47
-		accel.lock()
48
-		#add the group to the window
49
-		self.window.add_accel_group(accel)
50
-
51
-	def ccheckbox_clicked(self, widget):
52
-		checked = self.ccheckbox.get_active()
53
-		self.lsbutton.set_sensitive(not checked)
54
-		if checked:
55
-			self.lsbutton_stopped()
56
-			self.emit('command', "continuous_listen")
57
-			self.set_icon_active()
58
-		else:
59
-			self.emit('command', "continuous_stop")
60
-			self.set_icon_inactive()
61
-
62
-	def lsbutton_stopped(self):
63
-		self.lsbutton.set_label("Listen")
64
-
65
-	def lsbutton_clicked(self, button):
66
-		val = self.lsbutton.get_label()
67
-		if val == "Listen":
68
-			self.emit("command", "listen")
69
-			self.lsbutton.set_label("Stop")
70
-			#clear the label
71
-			self.label.set_text("")
72
-			self.set_icon_active()
73
-		else:
74
-			self.lsbutton_stopped()
75
-			self.emit("command", "stop")
76
-			self.set_icon_inactive()
77
-
78
-	def run(self):
79
-		#set the default icon
80
-		self.set_icon_inactive()
81
-		self.window.show_all()
82
-		if self.continuous:
83
-			self.set_icon_active()
84
-			self.ccheckbox.set_active(True)
85
-
86
-	def accel_quit(self, accel_group, acceleratable, keyval, modifier):
87
-		self.emit("command", "quit")
88
-
89
-	def delete_event(self, x, y ):
90
-		self.emit("command", "quit")
91
-
92
-	def finished(self, text):
93
-		#if the continuous isn't pressed
94
-		if not self.ccheckbox.get_active():
95
-			self.lsbutton_stopped()
96
-			self.set_icon_inactive()
97
-		self.label.set_text(text)
98
-
99
-	def set_icon_active_asset(self, i):
100
-		self.icon_active = i
101
-
102
-	def set_icon_inactive_asset(self, i):
103
-		self.icon_inactive = i
104
-
105
-	def set_icon_active(self):
106
-		gtk.window_set_default_icon_from_file(self.icon_active)
107
-
108
-	def set_icon_inactive(self):
109
-		gtk.window_set_default_icon_from_file(self.icon_inactive)
110
-
111
-
5
+from gi.repository import GObject
6
+# Gtk
7
+from gi.repository import Gtk, Gdk
8
+
9
+class UI(GObject.GObject):
10
+    __gsignals__ = {
11
+        'command' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))
12
+    }
13
+
14
+    def __init__(self,args, continuous):
15
+        GObject.GObject.__init__(self)
16
+        self.continuous = continuous
17
+        # Make a window
18
+        self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
19
+        self.window.connect("delete_event", self.delete_event)
20
+        # Give the window a name
21
+        self.window.set_title("BlatherGtk")
22
+        self.window.set_resizable(False)
23
+
24
+        layout = Gtk.VBox()
25
+        self.window.add(layout)
26
+        # Make a listen/stop button
27
+        self.lsbutton = Gtk.Button("Listen")
28
+        layout.add(self.lsbutton)
29
+        # Make a continuous button
30
+        self.ccheckbox = Gtk.CheckButton("Continuous Listen")
31
+        layout.add(self.ccheckbox)
32
+
33
+        # Connect the buttons
34
+        self.lsbutton.connect("clicked",self.lsbutton_clicked)
35
+        self.ccheckbox.connect("clicked",self.ccheckbox_clicked)
36
+
37
+        # Add a label to the UI to display the last command
38
+        self.label = Gtk.Label()
39
+        layout.add(self.label)
40
+
41
+        # Create an accellerator group for this window
42
+        accel = Gtk.AccelGroup()
43
+        # Add the ctrl+q to quit
44
+        accel.connect(Gdk.keyval_from_name('q'), Gdk.ModifierType.CONTROL_MASK,
45
+                Gtk.AccelFlags.VISIBLE, self.accel_quit)
46
+        # Lock the group
47
+        accel.lock()
48
+        # Add the group to the window
49
+        self.window.add_accel_group(accel)
50
+
51
+    def ccheckbox_clicked(self, widget):
52
+        checked = self.ccheckbox.get_active()
53
+        self.lsbutton.set_sensitive(not checked)
54
+        if checked:
55
+            self.lsbutton_stopped()
56
+            self.emit('command', "continuous_listen")
57
+            self.set_icon_active()
58
+        else:
59
+            self.emit('command', "continuous_stop")
60
+            self.set_icon_inactive()
61
+
62
+    def lsbutton_stopped(self):
63
+        self.lsbutton.set_label("Listen")
64
+
65
+    def lsbutton_clicked(self, button):
66
+        val = self.lsbutton.get_label()
67
+        if val == "Listen":
68
+            self.emit("command", "listen")
69
+            self.lsbutton.set_label("Stop")
70
+            # Clear the label
71
+            self.label.set_text("")
72
+            self.set_icon_active()
73
+        else:
74
+            self.lsbutton_stopped()
75
+            self.emit("command", "stop")
76
+            self.set_icon_inactive()
77
+
78
+    def run(self):
79
+        # Set the default icon
80
+        self.set_icon_inactive()
81
+        self.window.show_all()
82
+        if self.continuous:
83
+            self.set_icon_active()
84
+            self.ccheckbox.set_active(True)
85
+
86
+    def accel_quit(self, accel_group, acceleratable, keyval, modifier):
87
+        self.emit("command", "quit")
88
+
89
+    def delete_event(self, x, y):
90
+        self.emit("command", "quit")
91
+
92
+    def finished(self, text):
93
+        # If the continuous isn't pressed
94
+        if not self.ccheckbox.get_active():
95
+            self.lsbutton_stopped()
96
+            self.set_icon_inactive()
97
+        self.label.set_text(text)
98
+
99
+    def set_icon_active_asset(self, i):
100
+        self.icon_active = i
101
+
102
+    def set_icon_inactive_asset(self, i):
103
+        self.icon_inactive = i
104
+
105
+    def set_icon_active(self):
106
+        Gtk.Window.set_default_icon_from_file(self.icon_active)
107
+
108
+    def set_icon_inactive(self):
109
+        Gtk.Window.set_default_icon_from_file(self.icon_inactive)

+ 31
- 28
README.md View File

@@ -1,61 +1,64 @@
1
-# Blather
1
+# Kaylee
2 2
 
3
-Blather is a speech recognizer that will run commands when a user speaks preset sentences.
3
+Kaylee is a somewhat fancy speech recognizer that will run commands and perform
4
+other functions when a user speaks loosely preset sentences.  It is based on
5
+[Blather](https://gitlab.com/jezra/blather) by [Jezra](http://www.jezra.net/),
6
+but adds a lot of features that go beyond the original purpose of Blather.
4 7
 
5 8
 ## Requirements
6 9
 
7 10
 1. pocketsphinx
8
-2. gstreamer-0.10 (and what ever plugin has pocket sphinx support)
9
-3. gstreamer-0.10 base plugins (required for alsa)
11
+2. gstreamer-1.0 (and what ever plugin has pocket sphinx support)
12
+3. gstreamer-1.0 base plugins (required for alsa)
10 13
 4. pyside (only required for the Qt based UI)
11 14
 5. pygtk (only required for the Gtk based UI)
12
-6. pyyaml (only required for reading the options file)  
15
+6. pyyaml (only required for reading the options file)
13 16
 
14 17
 **Note:** it may also be required to install `pocketsphinx-hmm-en-hub4wsj`
15 18
 
16 19
 
17 20
 ## Usage
18 21
 
19
-0. move commands.tmp to ~/.config/blather/commands.conf and fill the file with sentences and command to run
22
+0. Move commands.tmp to ~/.config/blather/commands.conf and fill the file with sentences and command to run
20 23
 1. Run Blather.py, this will generate ~/.config/blather/sentences.corpus based on sentences in the 'commands' file
21
-2. quit blather (there is a good chance it will just segfault)
22
-3. go to <http://www.speech.cs.cmu.edu/tools/lmtool.html> and upload the sentences.corpus file
23
-4. download the resulting XXXX.lm file to the ~/.config/blather/language directory and rename to file to 'lm'
24
-5. download the resulting XXXX.dic file to the ~/.config/blather/language directory and rename to file to 'dic'
25
-6. run Blather.py
26
-    * for Qt GUI, run Blather.py -i q
27
-    * for Gtk GUI, run Blather.py -i g
28
-    * to start a UI in 'continuous' listen mode, use the -c flag
29
-    * to use a microphone other than the system default, use the -m flag
30
-7. start talking
24
+2. Quit blather (there is a good chance it will just segfault)
25
+3. Go to <http://www.speech.cs.cmu.edu/tools/lmtool.html> and upload the sentences.corpus file
26
+4. Download the resulting XXXX.lm file to the ~/.config/blather/language directory and rename to file to 'lm'
27
+5. Download the resulting XXXX.dic file to the ~/.config/blather/language directory and rename to file to 'dic'
28
+6. Run Blather.py
29
+    * For Qt GUI, run Blather.py -i q
30
+    * For Gtk GUI, run Blather.py -i g
31
+    * To start a UI in 'continuous' listen mode, use the -c flag
32
+    * To use a microphone other than the system default, use the -m flag
33
+7. Start talking
31 34
 
32 35
 **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.
33 36
 
34 37
 ### Bonus
35 38
 
36
-once the sentences.corpus file has been created, run the language_updater.sh script to automate the process of creating and downloading language files.
39
+Once the sentences.corpus file has been created, run the language_updater.sh script to automate the process of creating and downloading language files.
37 40
 
38 41
 ### Examples
39 42
 
40
-* To run blather with the GTK UI and start in continuous listen mode:  
43
+* To run blather with the GTK UI and start in continuous listen mode:
41 44
 `./Blather.py -i g -c`
42 45
 
43
-* To run blather with no UI and using a USB microphone recognized and device 2:  
46
+* To run blather with no UI and using a USB microphone recognized and device 2:
44 47
 `./Blather.py -m 2`
45 48
 
46
-* To have blather pass the matched sentence to the executing command:  
47
- `./Blather.py -p`  
49
+* To have blather pass the matched sentence to the executing command:
50
+ `./Blather.py -p`
48 51
 
49
- 	**explanation:** if the commands.conf contains:  
50
- **good morning world : example_command.sh**   
51
- then 3 arguments, 'good', 'morning', and 'world' would get passed to example_command.sh as  
52
+ 	**explanation:** if the commands.conf contains:
53
+ **good morning world : example_command.sh**
54
+ then 3 arguments, 'good', 'morning', and 'world' would get passed to example_command.sh as
52 55
  `example_command.sh good morning world`
53 56
 
54
-* To run a command when a valid sentence has been detected:   
55
-	`./Blather.py --valid-sentence-command=/path/to/command`  
57
+* To run a command when a valid sentence has been detected:
58
+	`./Blather.py --valid-sentence-command=/path/to/command`
56 59
 	**note:** this can be set in the options.yml file
57
-* To run a command when a invalid sentence has been detected:   
58
-	`./Blather.py --invalid-sentence-command=/path/to/command`  
60
+* To run a command when a invalid sentence has been detected:
61
+	`./Blather.py --invalid-sentence-command=/path/to/command`
59 62
 	**note:** this can be set in the options.yml file
60 63
 
61 64
 ### Finding the Device Number of a USB microphone

+ 55
- 47
Recognizer.py View File

@@ -1,57 +1,65 @@
1
-#This is part of Blather
1
+# This is part of Blather
2 2
 # -- this code is licensed GPLv3
3 3
 # Copyright 2013 Jezra
4 4
 
5
-import pygst
6
-pygst.require('0.10')
7
-import gst
5
+import gi
6
+gi.require_version('Gst', '1.0')
7
+from gi.repository import GObject, Gst
8
+GObject.threads_init()
9
+Gst.init(None)
8 10
 import os.path
9
-import gobject
10 11
 import sys
11 12
 
12
-#define some global variables
13
+# Define some global variables
13 14
 this_dir = os.path.dirname( os.path.abspath(__file__) )
14 15
 
15 16
 
16
-class Recognizer(gobject.GObject):
17
-	__gsignals__ = {
18
-		'finished' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))
19
-	}
20
-	def __init__(self, language_file, dictionary_file, src = None):
21
-		gobject.GObject.__init__(self)
22
-		self.commands = {}
23
-		if src:
24
-			audio_src = 'alsasrc device="hw:%d,0"' % (src)
25
-		else:
26
-			audio_src = 'autoaudiosrc'
27
-
28
-		#build the pipeline
29
-		cmd = audio_src+' ! audioconvert ! audioresample ! vader name=vad ! pocketsphinx name=asr ! appsink sync=false'
30
-		try:
31
-			self.pipeline=gst.parse_launch( cmd )
32
-		except Exception, e:
33
-			print e.message
34
-			print "You may need to install gstreamer0.10-pocketsphinx"
35
-			raise e
36
-
37
-		#get the Auto Speech Recognition piece
38
-		asr=self.pipeline.get_by_name('asr')
39
-		asr.connect('result', self.result)
40
-		asr.set_property('lm', language_file)
41
-		asr.set_property('dict', dictionary_file)
42
-		asr.set_property('configured', True)
43
-		#get the Voice Activity DEtectoR
44
-		self.vad = self.pipeline.get_by_name('vad')
45
-		self.vad.set_property('auto-threshold',True)
46
-
47
-	def listen(self):
48
-		self.pipeline.set_state(gst.STATE_PLAYING)
49
-
50
-	def pause(self):
51
-		self.vad.set_property('silent', True)
52
-		self.pipeline.set_state(gst.STATE_PAUSED)
53
-
54
-	def result(self, asr, text, uttid):
55
-		#emit finished
56
-		self.emit("finished", text)
17
+class Recognizer(GObject.GObject):
18
+    __gsignals__ = {
19
+        'finished' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))
20
+    }
57 21
 
22
+    def __init__(self, language_file, dictionary_file, src = None):
23
+        GObject.GObject.__init__(self)
24
+        self.commands = {}
25
+        if src:
26
+            audio_src = 'alsasrc device="hw:%d,0"' % (src)
27
+        else:
28
+            audio_src = 'autoaudiosrc'
29
+
30
+        # Build the pipeline
31
+        cmd = audio_src+' ! audioconvert ! audioresample ! pocketsphinx name=asr ! appsink sync=false'
32
+        try:
33
+            self.pipeline=Gst.parse_launch( cmd )
34
+        except Exception, e:
35
+            print e.message
36
+            print "You may need to install gstreamer1.0-pocketsphinx"
37
+            raise e
38
+
39
+        bus = self.pipeline.get_bus()
40
+        bus.add_signal_watch()
41
+
42
+        # Get the Auto Speech Recognition piece
43
+        asr=self.pipeline.get_by_name('asr')
44
+        bus.connect('message::element', self.result)
45
+        asr.set_property('lm', language_file)
46
+        asr.set_property('dict', dictionary_file)
47
+        asr.set_property('configured', True)
48
+
49
+    def listen(self):
50
+        self.pipeline.set_state(Gst.State.PLAYING)
51
+
52
+    def pause(self):
53
+        self.pipeline.set_state(Gst.State.PAUSED)
54
+
55
+    def result(self, bus, msg):
56
+        msg_struct = msg.get_structure()
57
+        # Ignore messages that aren't from pocketsphinx
58
+        msgtype = msg_struct.get_name()
59
+        if msgtype != 'pocketsphinx':
60
+            return
61
+
62
+        # If we have a final command, send it for processing
63
+        command = msg_struct.get_string('hypothesis')
64
+        if command != '' and msg_struct.get_boolean('final')[1]:
65
+	    self.emit("finished", command)

Loading…
Cancel
Save