Previously, the order of elements in dicts in the configuration file was
not retained. The most notable consequence of this is that plugins
would be loaded in an arbitrary order, which may have led to unexpected
or inconsistent results. Now order is retained, so plugins will be
loaded in the order specified, and all is well in the world.
Now the Kaylee object handles the invalid_sentence_command as well. It
does this by having the last handler for the recognizer's 'finished'
signal. If this handler is ever run, the voice command was obviously
not wanted by any of the plugins, so the invalid_sentence_command should
be run.
Also, I fixed the UIs to work as before. It's a temporary fix!
The plugins shouldn't be in charge of running the
valid_sentence_command. They also certainly shouldn't have to manage
the history file. Both of these functions have been delegated to the
Kaylee object, by way of a 'processed' signal emitted by a plugin as
soon as it knows it will handle the voice command.
Since Kaylee now supports Python plugins that can do arbitrary things
with spoken words, the pass_words option for shell commands seems
somewhat less necessary than before. I never liked it in the first
place, because it was all-or-nothing: there was no non-hackish way to
pass the spoken words to only specific commands. If I ever see a
compelling reason for this feature to come back, it may be
re-implemented in the form of a second shell plugin that passes words to
its commands.
As part of the effort for resolving #12, I've started work on a plugin
API for Kaylee. While very much a work in progress, it will allow
Python plugins to be written, loaded from user configuration, and
hooked in to events from necessary portions of Kaylee to handle voice
commands.
Currently there is only one plugin, a partial implementation of shell
command support as existed previously. It works in that it executes
commands, but several old features are missing. Also, the GUIs are
probably broken, but I'm not worried about that at the moment.
I spelled it "fourty", which tricks the lmtool into making it much
harder to recognize the word. Now it's spelled "forty", which makes it
much easier to understand.
This makes pocketsphinx pick up way fewer false-positives of single
number-words as recognised sentences. It doesn't seem to make any
difference in anything else, but fewer false-positives is always nice.
It actually does do the things claimed in the first sentence, so don't
use the future tense.
There's no need to tell the user the details of intermediate steps in
generating the language. All the user needs to know is that it uses the
network to update the language model when it starts.
They still need work of course, since I'm a programmer and not an
artist. The new icons of course are Kaylee's parasol, and anyone who
doesn't know that needs to watch Firefly.
Commands aren't stored in a special file anymore, and Kaylee never tries
to look at that file. Therefore, there's no need for the Config object
to keep that file's path, and so the path has been removed.
Added some blank lines and wrapped some long lines to be closer to PEP 8
compliance.
Improved docstrings in NumberParser class. Added docstrings for
undocumented code and removed a TODO message that no longer applies.
Now distributions created from setup.py put the systemd unit file in the
correct location for units provided by packages. It may then be enabled
and started by the user with systemctl.
Closes #11.
Next I need to make the setup.py script install it. It's meant to be a
user service (installed to /usr/lib/systemd/user/), since Kaylee
currently does not support being run outside of a normal user account.
Also, it would be really nice to make it possible to reload the service
once it has been started. This will require some changes to Kaylee to
support synchronously reloading configuration. I understand that you
aren't supposed to reload units asynchronously, and I *really* can't
trust Kaylee to reload succinctly since reloading configuration may
require contacting a remote server until #10 is implemented.
Configuration reloading may be a separate issue from the systemd unit
file, but I'd like to see it by version 0.2.
Apparently CMU thinks it's a good idea to release a new version of a
piece of software that breaks existing APIs without even changing the
version number. I find this idea to be highly dubious at best.
Nevertheless, I have updated Kaylee to support the latest version of
pocketsphinx.
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
Its control flow was confusing before; now it's much more
straightforward. We make a string representing classes of words, split
that by a regular expression for number words, then parse each number
and build up our return string and list. It works just as well as the
previous method, is a bit shorter, and I feel that it's clearer as well.
It wasn't actually guaranteed, it turns out. I was iterating over
dictionary keys, which is done in arbitrary order. The result was that
in different executions of the program, the corpus was generated
differently, so the hashes differed, and the language had to be updated.
Sorting the keys before adding them to the list of number-words fixed
the problem.
See commands.tmp for an example. It's pretty neat, but it could still
use some work. I thought of a really clever way to parse numbers, better
than the one I came up with last night, but since I have a working
implementation now I figure I'd better commit it.
We have a new bug which causes the dictionary to be updated every time the
program starts. I hope I didn't force that to happen last night or
something, but I have a vague feeling I did.
At the same time, I moved the logic to check if the language should be
updated into the new LanguageUpdater class. The README has been updated
to reflect the fact that you no longer need to do any of this manually
ever.
Paths of important files and directories are part of the program's
configuration, no?
We're making better use of XDG paths now. Only configuration-y things
go in $XDG_CONFIG_HOME now, with cache-y and data-y things going in the
appropriate places instead of just being crammed in with configuration.
Removed a bunch of print statements that looked like they were added for
debugging, then never removed.
Reorganized GStreamer pipeline code so that all configuration is done
when the pipeline is created.
The configuration file is now properly overridden by argument parsing.
This was accomplished by loading the config file, then treating the
specified options as a namespace for the ArgumentParser. This makes
things from the config file get overridden iff they were specified on
the command line (not simply from defaults set in the ArgumentParser).
Hashes are now stored in hash.json, not hash.yaml. Also, we use the XDG
configuration directory rather than assuming we should use ~/.config/.
Maybe I should also make use of XDG data and/or cache directories.