ソースを参照

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年前
コミット
a6e27df2cc
6個のファイルの変更513行の追加505行の削除
  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 ファイルの表示

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

+ 224
- 224
Blather.py ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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)

読み込み中…
キャンセル
保存