Browse Source

Update language automatically on startup

We now have a hash.yaml file which contains a SHA256 hash of
sentences.corpus.  If this differs from the hash the file calculated
when Kaylee sarts, the language is updated and the new hash is stored in
hash.yaml.
Clara Hobbs 8 years ago
parent
commit
900a3d8d2f
2 changed files with 70 additions and 28 deletions
  1. 66
    24
      blather.py
  2. 4
    4
      recognizer.py

+ 66
- 24
blather.py View File

@@ -5,16 +5,18 @@
5 5
 # Copyright 2013 Jezra
6 6
 # Copyright 2015 Clayton G. Hobbs
7 7
 
8
+from __future__ import print_function
8 9
 import sys
9 10
 import signal
10
-from gi.repository import GObject
11
+import hashlib
11 12
 import os.path
12 13
 import subprocess
13 14
 from optparse import OptionParser
15
+from gi.repository import GObject
14 16
 try:
15 17
     import yaml
16 18
 except:
17
-    print "YAML is not supported. ~/.config/blather/options.yaml will not function"
19
+    print("YAML is not supported; unable to use config file")
18 20
 
19 21
 from recognizer import Recognizer
20 22
 
@@ -25,8 +27,9 @@ command_file = os.path.join(conf_dir, "commands.conf")
25 27
 strings_file = os.path.join(conf_dir, "sentences.corpus")
26 28
 history_file = os.path.join(conf_dir, "blather.history")
27 29
 opt_file = os.path.join(conf_dir, "options.yaml")
28
-lang_file = os.path.join(lang_dir,'lm')
29
-dic_file = os.path.join(lang_dir,'dic')
30
+hash_file = os.path.join(conf_dir, "hash.yaml")
31
+lang_file = os.path.join(lang_dir, 'lm')
32
+dic_file = os.path.join(lang_dir, 'dic')
30 33
 # Make the lang_dir if it doesn't exist
31 34
 if not os.path.exists(lang_dir):
32 35
     os.makedirs(lang_dir)
@@ -34,7 +37,6 @@ if not os.path.exists(lang_dir):
34 37
 class Blather:
35 38
 
36 39
     def __init__(self, opts):
37
-        # Import the recognizer so Gst doesn't clobber our -h
38 40
         self.ui = None
39 41
         self.options = {}
40 42
         ui_continuous_listen = False
@@ -48,8 +50,8 @@ class Blather:
48 50
         # Load the options file
49 51
         self.load_options()
50 52
 
51
-        # Merge the opts
52
-        for k,v in opts.__dict__.items():
53
+        # Merge the options with the ones provided by command-line arguments
54
+        for k, v in opts.__dict__.items():
53 55
             if (not k in self.options) or opts.override:
54 56
                 self.options[k] = v
55 57
 
@@ -59,7 +61,7 @@ class Blather:
59 61
             elif self.options['interface'] == "gt":
60 62
                 from gtktrayui import UI
61 63
             else:
62
-                print "no GUI defined"
64
+                print("no GUI defined")
63 65
                 sys.exit()
64 66
 
65 67
             self.ui = UI(args, self.options['continuous'])
@@ -76,47 +78,51 @@ class Blather:
76 78
         if self.options['history']:
77 79
             self.history = []
78 80
 
81
+        # Update the language if necessary
82
+        self.update_language()
83
+
79 84
         # Create the recognizer
80 85
         try:
81 86
             self.recognizer = Recognizer(lang_file, dic_file, self.options['microphone'])
82
-        except Exception, e:
83
-            #no recognizer? bummer
84
-            print 'error making recognizer'
87
+        except Exception as e:
88
+            # No recognizer? bummer
89
+            print('error making recognizer')
85 90
             sys.exit()
86 91
 
87 92
         self.recognizer.connect('finished', self.recognizer_finished)
88 93
 
89
-        print "Using Options: ", self.options
94
+        print("Using Options: ", self.options)
90 95
 
91 96
     def read_commands(self):
92 97
         # Read the commands file
93 98
         file_lines = open(command_file)
94 99
         strings = open(strings_file, "w")
95 100
         for line in file_lines:
96
-            print line
101
+            print(line)
97 102
             # Trim the white spaces
98 103
             line = line.strip()
99 104
             # If the line has length and the first char isn't a hash
100 105
             if len(line) and line[0]!="#":
101 106
                 # This is a parsible line
102
-                (key,value) = line.split(":",1)
103
-                print key, value
107
+                (key, value) = line.split(":", 1)
108
+                print(key, value)
104 109
                 self.commands[key.strip().lower()] = value.strip()
105 110
                 strings.write( key.strip()+"\n")
106 111
         # Close the strings file
107 112
         strings.close()
108 113
 
109 114
     def load_options(self):
115
+        """If possible, load options from the options.yaml file"""
110 116
         # Is there an opt file?
111 117
         try:
112 118
             opt_fh = open(opt_file)
113 119
             text = opt_fh.read()
114 120
             self.options = yaml.load(text)
115 121
         except:
122
+            # Do nothing if the options file cannot be loaded
116 123
             pass
117 124
 
118
-
119
-    def log_history(self,text):
125
+    def log_history(self, text):
120 126
         if self.options['history']:
121 127
             self.history.append(text)
122 128
             if len(self.history) > self.options['history']:
@@ -130,9 +136,45 @@ class Blather:
130 136
             # Close the file
131 137
             hfile.close()
132 138
 
139
+    def update_language(self):
140
+        """Update the language if its hash has changed"""
141
+        try:
142
+            # Load the stored hash from the hash file
143
+            try:
144
+                with open(hash_file, 'r') as f:
145
+                    text = f.read()
146
+                    hashes = yaml.load(text)
147
+                stored_hash = hashes['language']
148
+            except (IOError, KeyError, TypeError):
149
+                # No stored hash
150
+                stored_hash = ''
151
+
152
+            # Calculate the hash the language file has right now
153
+            hasher = hashlib.sha256()
154
+            with open(strings_file, 'rb') as sfile:
155
+                buf = sfile.read()
156
+                hasher.update(buf)
157
+            new_hash = hasher.hexdigest()
158
+
159
+            # If the hashes differ
160
+            if stored_hash != new_hash:
161
+                # Update the language
162
+                # FIXME: Do this with Python, not Bash
163
+                self.run_command('./language_updater.sh')
164
+                # Store the new hash
165
+                new_hashes = {'language': new_hash}
166
+                with open(hash_file, 'w') as f:
167
+                    f.write(yaml.dump(new_hashes))
168
+        except Exception as e:
169
+            # Do nothing if the hash file cannot be loaded
170
+            # FIXME: This is kind of bad; maybe YAML should be mandatory.
171
+            print('error updating language')
172
+            print(e)
173
+            pass
174
+
133 175
     def run_command(self, cmd):
134
-        '''Print the command, then run it'''
135
-        print cmd
176
+        """Print the command, then run it"""
177
+        print(cmd)
136 178
         subprocess.call(cmd, shell=True)
137 179
 
138 180
     def recognizer_finished(self, recognizer, text):
@@ -154,7 +196,7 @@ class Blather:
154 196
             # Run the invalid_sentence_command if there is an invalid sentence command
155 197
             if self.options['invalid_sentence_command']:
156 198
                 subprocess.call(self.options['invalid_sentence_command'], shell=True)
157
-            print "no matching command %s" % t
199
+            print("no matching command {0}".format(t))
158 200
         # If there is a UI and we are not continuous listen
159 201
         if self.ui:
160 202
             if not self.continuous_listen:
@@ -173,7 +215,7 @@ class Blather:
173 215
         sys.exit()
174 216
 
175 217
     def process_command(self, UI, command):
176
-        print command
218
+        print(command)
177 219
         if command == "listen":
178 220
             self.recognizer.listen()
179 221
         elif command == "stop":
@@ -187,9 +229,9 @@ class Blather:
187 229
         elif command == "quit":
188 230
             self.quit()
189 231
 
190
-    def load_resource(self,string):
232
+    def load_resource(self, string):
191 233
         local_data = os.path.join(os.path.dirname(__file__), 'data')
192
-        paths = ["/usr/share/blather/","/usr/local/share/blather", local_data]
234
+        paths = ["/usr/share/blather/", "/usr/local/share/blather", local_data]
193 235
         for path in paths:
194 236
             resource = os.path.join(path, string)
195 237
             if os.path.exists( resource ):
@@ -247,7 +289,7 @@ if __name__ == "__main__":
247 289
     try:
248 290
         main_loop.run()
249 291
     except:
250
-        print "time to quit"
292
+        print("time to quit")
251 293
         main_loop.quit()
252 294
         sys.exit()
253 295
 

+ 4
- 4
recognizer.py View File

@@ -32,9 +32,9 @@ class Recognizer(GObject.GObject):
32 32
         cmd = audio_src+' ! audioconvert ! audioresample ! pocketsphinx name=asr ! appsink sync=false'
33 33
         try:
34 34
             self.pipeline=Gst.parse_launch( cmd )
35
-        except Exception, e:
36
-            print e.message
37
-            print "You may need to install gstreamer1.0-pocketsphinx"
35
+        except Exception as e:
36
+            print(e.message)
37
+            print("You may need to install gstreamer1.0-pocketsphinx")
38 38
             raise e
39 39
 
40 40
         bus = self.pipeline.get_bus()
@@ -63,4 +63,4 @@ class Recognizer(GObject.GObject):
63 63
         # If we have a final command, send it for processing
64 64
         command = msg_struct.get_string('hypothesis')
65 65
         if command != '' and msg_struct.get_boolean('final')[1]:
66
-	    self.emit("finished", command)
66
+            self.emit("finished", command)

Loading…
Cancel
Save