Overriding skills

Hi everyone,

I have been working on a skill that is supposed to work before other skills. For example: if we want mycroft to act as a teacher (or just an authority figure), we would say something like “teacher mode” and if the person says something like “Hey mycroft dude give me the time” Mycroft would first say “that’s not a respectful way to speak to a teacher” and then answer.

Here is a better step by step to see how it’s supposed to work:

  1. Activate the mode (with an intent like “teacher mode”).
    2 Ask something (it is not meant to be used as a get_response() it should be triggered by “Hey Mycroft”).
  2. Since the mode is active, Mycroft analyzes the request (that’s the part where it should say “that’s not respectful”).
  3. It should then send the request for the other skills that are concerned (time, weather…)

So far it works for simple queries (fallback-query) but other skills (like weather, date, spelling…) override it and I was wondering if there was a way to make sure Mycroft goes first to my skill and there we could send the request with the message bus?

1 Like

You can override the converse() method. This can look at all utterances, choose whether to handle them and whether to pass them onto the normal intent handling process.

The Timer Skill uses this to stop the beeping when a timer has expired.

make_active() is also useful here.

Would this handle the situation you are looking at?

I have the same issue.
I still don’t understand what to change and where.
When is the converse() method used and what should I change in it?

So an example Skill might look like this

class PoliteSkill(MycroftSkill):
    def __init__(self):
        super().__init__()
        impolite_utterances = 0

    def initialize(self):
        self.add_event("recognizer_loop:wakeword", self.make_active)

    def converse(self, utterances):
        utt = utterances[0]
        if self.voc_match(utt, "RudeWords"):
            impolite_utterances += 1
            if impolite_utterances < 3:
                self.speak_dialog("that.is.not.respectful")
            else:
                self.speak_dialog("you.have.detention")
            return True
        else:
            return False

    def stop(self):
        pass

def create_skill():
    return PoliteSkill()

You can see in converse() when a rude word is detected, we speak some dialog and then return True. This “consumes” the phrase so Mycroft doesn’t process it any further. Else if no rude word is found then we return False so Mycroft should pass this onto the normal intent handling process.

Thank You, but I still don’t understand how the program knows to call the skill.

Look at this Say "Please" and "Thank you" to mycroft. There is a skill for good manners. The skill check all uttrance for good manners and say thank you.

Yeah good addition, I’ve thrown this up on Github as a proper Skill:

The converse method will be called if the Skill has been active within the last 5 minutes. So as Jarbas has done, you can register a function to be called based on an event such as a message in the recognizer_loop. I’ve set it to call self.make_active() anytime the wake word is detected (which means this won’t trigger if you type a command into the CLI.

To implement the “teacher_mode” you can add an intent to add / remove the event trigger based on this.

In the polite-skill it shows how to use the converse() method.
When you use it, how do you know if the skills intent is triggered if you don’t use the intent_handler method?

Thank You

In this example there is no intent that can be triggered. It processes every utterance that Mycroft receives and chooses whether to act or not. I did just realise that the self.log.debug didn’t make sense where it was, so have shifted that. This would then indicate in your logs which path the converse method took.

Is that what you mean?

You can also include intent handlers in the same Skill and they would be triggered in the same way as any other intent.

That Is not what I meant. I want my skill to be triggered for some words and then sometimes to continue to the regular skill.
The problem is, how do I make sure that my skill handler is triggered before the other skills?

Thank You

Can you give some examples of how you would hope it would work?

What are example phrases that the user would say, and how should they each be handled?

My skill is adding a voice identification to Mycroft. So I copied every phrase that I want to be handled from the skills and I want my skill to start every time a phrase is said (like an intent handler) and then go to the regular skill.
The question is how do I add the converse() method with the intent handler together?

Thank You

Would something like the following work:

def converse(self, utterances):
    utt = utterances[0]
    # check my.phrases.voc to find matches with spoken utterance
    if self.voc_match(utt, "my.phrases"):
        # mock the standard message object to pass it to a standard intent handler
        mock_message = {'data': {'utterance': utt}}
        self.my_intent_handler(mock_message)

        # if you don't really need an intent handler you can just pass the utterance
        self.my_function(utt)

        return True # consume the utterance
    else:
        return False # pass to normal intent handling process

def my_intent_handler(self, message):
    ...

def my_function(self, utt):
    ...

If it’s over matching things it shouldn’t then you could steal the voc_match_exact function from the Playback Control Skill.

I tried this and sometimes the skill is called and sometimes it isnt.
I cant figure out why.
Does anyone know?

Thank You

Does this mean this skill is sometimes successfully loaded and sometimes fails or that sometimes the intent is succesful and sometime not?

I have two skills with the same intent phrase. One of them has a converse() method so it should always run first.
The problem is that both of the skills run. one each time (I think randomly).
Mycroft doesnt show that there was an error.

Thank You

Does anyone know?
Thank You