Browse Source

Only write the strings file if necessary

Now we check a hash of the voice commands before writing the strings
file to reduce how much we write to the hard disk.  In implementing
this, I realized that some code was being duplicated in an easily
fixable way, so I created a Hasher object that keeps track of the
hash.json file.

Resolves #6
Clara Hobbs 8 years ago
parent
commit
bc07966df1
4 changed files with 69 additions and 20 deletions
  1. 37
    0
      hasher.py
  2. 22
    4
      kaylee.py
  3. 8
    15
      languageupdater.py
  4. 2
    1
      recognizer.py

+ 37
- 0
hasher.py View File

@@ -0,0 +1,37 @@
1
+# This is part of Kaylee
2
+# -- this code is licensed GPLv3
3
+# Copyright 2015-2016 Clayton G. Hobbs
4
+# Portions Copyright 2013 Jezra
5
+
6
+import json
7
+import hashlib
8
+
9
+class Hasher:
10
+    """Keep track of hashes for Kaylee"""
11
+
12
+    def __init__(self, config):
13
+        self.config = config
14
+        try:
15
+            with open(self.config.hash_file, 'r') as f:
16
+                self.hashes = json.load(f)
17
+        except IOError:
18
+            # No stored hash
19
+            self.hashes = {}
20
+
21
+    def __getitem__(self, hashname):
22
+        try:
23
+            return self.hashes[hashname]
24
+        except (KeyError, TypeError):
25
+            return None
26
+
27
+    def __setitem__(self, hashname, value):
28
+        self.hashes[hashname] = value
29
+
30
+    def get_hash_object(self):
31
+        """Returns an object to compute a new hash"""
32
+        return hashlib.sha256()
33
+
34
+    def store(self):
35
+        """Store the current hashes into a the hash file"""
36
+        with open(self.config.hash_file, 'w') as f:
37
+            json.dump(self.hashes, f)

+ 22
- 4
kaylee.py View File

@@ -11,12 +11,12 @@ import signal
11 11
 import os.path
12 12
 import subprocess
13 13
 from gi.repository import GObject, GLib
14
-import json
15 14
 
16 15
 from recognizer import Recognizer
17 16
 from config import Config
18 17
 from languageupdater import LanguageUpdater
19 18
 from numberparser import NumberParser
19
+from hasher import Hasher
20 20
 
21 21
 
22 22
 class Kaylee:
@@ -27,8 +27,6 @@ class Kaylee:
27 27
         ui_continuous_listen = False
28 28
         self.continuous_listen = False
29 29
 
30
-        self.commands = {}
31
-
32 30
         # Load configuration
33 31
         self.config = Config()
34 32
         self.options = vars(self.config.options)
@@ -37,8 +35,11 @@ class Kaylee:
37 35
         # Create number parser for later use
38 36
         self.number_parser = NumberParser()
39 37
 
38
+        # Create a hasher
39
+        self.hasher = Hasher(self.config)
40
+
40 41
         # Create the strings file
41
-        self.create_strings_file()
42
+        self.update_strings_file_if_changed()
42 43
 
43 44
         if self.options['interface']:
44 45
             if self.options['interface'] == "g":
@@ -71,6 +72,23 @@ class Kaylee:
71 72
         self.recognizer = Recognizer(self.config)
72 73
         self.recognizer.connect('finished', self.recognizer_finished)
73 74
 
75
+    def update_voice_commands_if_changed(self):
76
+        """Use hashes to test if the voice commands have changed"""
77
+        stored_hash = self.hasher['voice_commands']
78
+
79
+        # Calculate the hash the voice commands have right now
80
+        hasher = self.hasher.get_hash_object()
81
+        for voice_cmd in self.commands.keys():
82
+            hasher.update(voice_cmd.encode('utf-8'))
83
+            # Add a separator to avoid odd behavior
84
+            hasher.update('\n'.encode('utf-8'))
85
+        new_hash = hasher.hexdigest()
86
+
87
+        if new_hash != stored_hash:
88
+            self.create_strings_file()
89
+            self.hasher['voice_commands'] = new_hash
90
+            self.hasher.store()
91
+
74 92
     def create_strings_file(self):
75 93
         # Open the strings file
76 94
         with open(self.config.strings_file, 'w') as strings:

+ 8
- 15
languageupdater.py View File

@@ -3,16 +3,17 @@
3 3
 # Copyright 2015-2016 Clayton G. Hobbs
4 4
 # Portions Copyright 2013 Jezra
5 5
 
6
-import hashlib
7
-import json
8 6
 import re
9 7
 
10 8
 import requests
11 9
 
10
+from hasher import Hasher
11
+
12 12
 class LanguageUpdater:
13 13
 
14 14
     def __init__(self, config):
15 15
         self.config = config
16
+        self.hasher = Hasher(config)
16 17
 
17 18
     def update_language_if_changed(self):
18 19
         """Test if the language has changed, and if it has, update it"""
@@ -21,18 +22,11 @@ class LanguageUpdater:
21 22
             self.save_language_hash()
22 23
 
23 24
     def language_has_changed(self):
24
-        """Use SHA256 hashes to test if the language has changed"""
25
-        # Load the stored hash from the hash file
26
-        try:
27
-            with open(self.config.hash_file, 'r') as f:
28
-                hashes = json.load(f)
29
-            self.stored_hash = hashes['language']
30
-        except (IOError, KeyError, TypeError):
31
-            # No stored hash
32
-            self.stored_hash = ''
25
+        """Use hashes to test if the language has changed"""
26
+        self.stored_hash = self.hasher['language']
33 27
 
34 28
         # Calculate the hash the language file has right now
35
-        hasher = hashlib.sha256()
29
+        hasher = self.hasher.get_hash_object()
36 30
         with open(self.config.strings_file, 'rb') as sfile:
37 31
             buf = sfile.read()
38 32
             hasher.update(buf)
@@ -75,9 +69,8 @@ class LanguageUpdater:
75 69
         self._download_file(dic_url, self.config.dic_file)
76 70
 
77 71
     def save_language_hash(self):
78
-        new_hashes = {'language': self.new_hash}
79
-        with open(self.config.hash_file, 'w') as f:
80
-            json.dump(new_hashes, f)
72
+        self.hasher['language'] = self.new_hash
73
+        self.hasher.store()
81 74
 
82 75
     def _download_file(self, url, path):
83 76
         r = requests.get(url, stream=True)

+ 2
- 1
recognizer.py View File

@@ -15,7 +15,8 @@ Gst.init(None)
15 15
 
16 16
 class Recognizer(GObject.GObject):
17 17
     __gsignals__ = {
18
-        'finished' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))
18
+        'finished' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE,
19
+                      (GObject.TYPE_STRING,))
19 20
     }
20 21
 
21 22
     def __init__(self, config):

Loading…
Cancel
Save