Karen provides methods for users to create and add their own skills to her runtime. The process is pretty simple and there are a few built-in skills that provide some examples. Let’s build a simple class that responds to the phrase “What is your name?”.

Setting up the Skill

Karen’s skills have a directory structure that must be named in a very specific way. The outline for our skill will be as follows:

-> WhoAmISkill/
   -> __init__.py
   -> vocab/
      -> en_us/
         -> whoami.intent
         -> whoami.dialog

Creating the Class

While it’s not required, the basic class can be inherited from Karen’s code base. It is important though that the minimum functions be defined in your class and return the values expected by the Karen runtime.

from karen import Skill

The minimum function definitions and return values are given below.

class WhoAmISkill(Skill):
    def __init__(self):
        self.name = "WhoAmISkill"
        # Put your class variable definitions here 

    def initialize(self):
        # Put your initialization and startup actions here
        return True

    def stop(self):
        # Put any shutdown/stopping actions here
        return True

def create_skill():
    # Put any setup actions here, but make sure to return the created class.
    return WhoAmISkill()

The initialize() method is effectively equivalent to a “start” process. It is called when the class is loaded into memory. In this method you can create timers and other in-memory object structures that will persist until the program ends. This is where you could establish the processes for things like alarm clocks or persistent connections to other services. Once a class is instantiated it is maintained in memory for the life of the program so be mindful that loading lots of data into memory could cause performance issues with the overall program.

Creating an Intent

Karen uses the Padatious library which is a Neural Network (based on the FANN model) that attempts to parse incoming text to determine intent. It attempts to correlate words and phrases as alternative ways to say the same thing in order to select the appropriate intent. As your list of skills grow this will be translated into probabilities that are passed into the skill indicating how likely Karen thinks it is that the skill she is calling is the correct one (she will only call the one skill that has the highest probability, but it will be up to the skill itself if a minimum probability is required before processing).

Creating the intent file.

An intent file is fairly simple in structure. It is a text file that contains alternate phrases in the Padatious format.

For our WhoAmISkill we’ll create a file named “WhoAmISkill/vocab/en_us/whoami.intent” that looks like the following:

what is your name
what do you call yourself
what do people call you

Adding the Intent to the Skill Manager Runtime

Once we have the intent file we can register it with Karen’s Skill Manager during our Initialize() method as follows.

class WhoAmISkill(Skill):
    def initialize():
        # Add the following line in the initialize() method
        self.register_intent_file("whoami.intent", self.handle_whoami_intent)
        return True

    def handle_whoami_intent(self, message, context=None):
        # This method gets called when an intent is matched against.
        return self.say("My name is Karen.", context=context)

Adding a Custom Skills Folder

In the startup for Karen you can specify a different Skill folder than the default. Doing this will require that all skills be located in the new skill folder (so you may want to copy any built-in skills there). The process is pretty simple, you can add this in the startup configuration as:

    "settings": { 
        "skillsFolder": "/path/to/your/skill/folder" 

This folder is where you’d put all your skills so it should be the parent folder and not a specific skill folder (e.g. “/home/lnxusr1/karen_skills” and in that folder I’d place my WhoAmISkill folder).

Read about this an other startup settings in the documentation.

Bonus Material

There are several additional functions that are available to help make your interactions more interesting.

Let’s say that instead of a single response you wanted to get a random response from a file. You can use a Dialog file for that. A dialog file is a simple text file with one possible response per line in the file. You can then read a random line from the dialog using a simple command in your Skill as follows:

# Get a random response from the dialog file
myText = self.getMessageFromDialog('whoami.dialog')  

Also, the “message” that is delivered to the intent callback is a class with at least the following components:

def handle_whoami_intent(self, message, context=None):
    # Probability as a fraction (0.0 to 1.0) from the parser
    if (message.conf == 1.0):
        self.say("Hi, I'm Karen.", context=context) 

    # Text phrase that was captured in its raw/pre-processed form

    return True

You can also register multiple intents to call different callback functions. You’ll find an example of this in the TellDateAndTimeSkill which handles two different intents (one for date questions and one for time questions). How you structure your skill is purely up to you so have fun with it.