Jane, Part three: "Plug Me In..."

As I'm designing this virtual assistant thing, I'm realizing that I want to use a plugin architecture. I want to easily separate the varied functions (whether it be what resources get connected, like Google Calendar, Weather, etc., input and output, storage, logging, etc.) from the core processing functions of the assistant. So basically, I want the core to include taking in a text version of the input, figuring out what to do with it, then sending it out. Everything else, how the input comes in (such as speech-to-text), how it goes out (console, text-to-speech, etc.) as well as what resources it uses (GCal, weather, etc.) to all be atomized into plugins of some sort.

In case you didn't know - I do have a Ph.D., but it's not in computer science, so this sort of fairly advanced software design is something I've learned over time. So I don't have a handy "oh, yeah, I learned this thing in school" kind of inner resource to grab. So I'm basically making this up as I go along, and hopefully learning a ton as I try things.

The three options I was thinking of were as follows:

  • A lightweight protocol, based on the idea of passing signals between functions
  • Using one of the more heavyweight plugin packages available for Python.
  • Rolling my own

The advantage of the latter, using a plugin package, is that it has a lot of built in features, like registering plugins, making it easy to build a plugin, etc. That said, there isn't really a super-well developed, super standard one people use. Yapsy seems to be the one that's closest. I found this overview of plugin systems useful, but of the group mentioned there, yapsy seemed the best developed.

I'm rolling my own stuff for so much of this project, and the idea of rolling my own plugin system seems unwise, even though I've seen varied examples of simple plugin management systems people have built themselves.

Pelican, the static site generator that is running this website, and that I have become increasingly familiar with, uses a lightweight plugin system based on the first concept. It uses a package called 'blinker'. I really like the flexibility of this idea, and it's fairly straightforward to implement a plugin with blinker.

Pelican has a set of signals defined, and then plugins can use those signals. So here's an example for jane:

from blinker import signal

command_init = signal('command_init')

Some inner function would have:

from jane import signals

signals.command_init.send(command)

Then the plugin would have something like:

from jane import signals

def test_resource(command):
    print(f"Here we go! {command}")

def register():
    signals.command_init.connect(test_resource)

The one challenge is that it's not clear blinker is still an active project. It's been a while since a new release was made to PyPI, although the last commit was only 21 days ago. But there are some big projects that use blinker (not just Pelican, but Flask as well as others,) so it's unlikely to go away anytime soon.

links

social