Request for skill verification and testing methodology

Hi all,
I am trying to write a skill that will talk to my bot called ciso. The work flow is as follows:
user: "hey mycroft ask ciso what is cyber security"
bot: cyber security is blabla bla

I have used the speak skill as a template and have created a skill.
#How do I test the skill? I use the pycroft.
#I am unclear about some of the code from the speak skill.
What does the below line do?
@intent_handler(IntentBuilder("").require(“ask ciso”).require(“Words”))

I am pasting the code below so that you can get the context of my question.
Pranav

from adapt.intent import IntentBuilder
from mycroft.skills.core import MycroftSkill
from mycroft.util.log import getLogger

author = ‘Pranav’

Logger: used for debug lines, like “LOGGER.debug(xyz)”. These

statements will show up in the command line when running Mycroft.

LOGGER = getLogger(name)

The logic of each skill is contained within its own class, which inherits

base methods from the MycroftSkill class with the syntax you can see below:

“class ____Skill(MycroftSkill)”

import os, base64
from mycroft import MycroftSkill, intent_handler
import requests

class AskCiso(MycroftSkill):
@intent_handler(IntentBuilder("").require(“ask ciso”).require(“Words”))
def generate_session(self):
return base64.b64encode(os.urandom(32))
def speak_back(self, message):
# Get everything after say/speak/etc. and speak it back
words = message.data.get(‘utterance’).split(message.data[‘ask ciso’])[1]
words = words.strip()
payload = {‘question’: words, ‘sessionid’: generate_session()}
r = requests.get(‘http://104.236.77.142:5001/api/v1.0/ask’, params=payload)
spt=r.json()
self.speak(spt)

def stop(self):
    pass

def create_skill():
return AskCiso()

Thanks so much for your feedback here @pranav, I’m going to tag my colleague @forslund here, who may be able to assist.

I see two questions in your post, one about testing in general, and another specific on your case.

As for testing in general, this is what I have done: I divided responsibility into back-end communication and intent handling.
For the back-end communication I use ordinary unit testing. And since the back-end i use (remember the milk) is quite stable, I don’t use mocks for testing the backend communication, I use the live interface.
For testing the intent handling (in __init__.py) I use ordinary unit testing as well, but here I mock the calls to mycroft, like self.speak_dialog().
Then I only miss testing that an utterance can hit the intent, and that parameters are passed correctly.
If you want more details, take a look at the cows list skill (https://github.com/CarstenAgerskov/skill-the-cows-lists)

Hi Carsten,
Many thanks for your response. I was asking about the mechanics of deploying my skill for testing. Sorry for being unclear with my question. I subsequently learned that I could copy my skill into the /opt/mycroft/skills folder and have it load. I have done so but the skill is not triggering.
I am appending the code and will try to attach a log.

from adapt.intent import IntentBuilder
from mycroft.skills.core import MycroftSkill
from mycroft.util.log import getLogger

author = ‘Pranav’

Logger: used for debug lines, like “LOGGER.debug(xyz)”. These

statements will show up in the command line when running Mycroft.

LOGGER = getLogger(name)

The logic of each skill is contained within its own class, which inherits

base methods from the MycroftSkill class with the syntax you can see below:

“class ____Skill(MycroftSkill)”

import os, base64
from mycroft import MycroftSkill, intent_handler
import requests

class AskCiso(MycroftSkill):
def init(self):
super(AskCiso, self).init(name=“AskCiso”)

@intent_handler(IntentBuilder("").require("ask ciso").require("Words"))

def generate_session(self):
    return base64.b64encode(os.urandom(32))
def speak_back(self, message):
    # Get everything after say/speak/etc. and speak it back
    LOGGER.debug("work routine invoked")
    words = message.data.get('utterance').split(message.data['ask ciso'])[1]
    words = words.strip()
    payload = {'question': words, 'sessionid': self.generate_session()}
    LOGGER.debug("about to look up bot")
    r = requests.get('http://104.236.77.142:5001/api/v1.0/ask', params=payload)
    spt=r.json()
    self.speak(spt)

def stop(self):
    pass

def create_skill():
return AskCiso()

The log is below.
14:28:23.042 - mycroft.skills.core:load_skill:126 - INFO - ATTEMPTING TO LOAD SKILL: skill-ask-ciso with ID 1920875901
14:28:23.052 - mycroft.skills.core:init_dialog:841 - DEBUG - No dialog loaded, /opt/mycroft/skills/skill-ask-ciso/dialog/en-us does not exist
14:28:23.068 - mycroft.skills.core:load_skill:144 - INFO - Loaded skill-ask-ciso
14:28:23.071 - SKILLS - DEBUG - {“type”: “register_vocab”, “data”: {“start”: “ask ciso”, “end”: “Speak”}, “context”: null}
14:28:23.094 - SKILLS - DEBUG - {“type”: “register_vocab”, “data”: {“regex”: “ask ciso (?P.*)”}, “context”: null}
14:28:23.105 - SKILLS - DEBUG - {“type”: “register_intent”, “data”: {“at_least_one”: [], “requires”: [[“ask ciso”, “ask ciso”], [“Words”, “Words”]], “optional”: [], “name”: “1920875901:generate_session”}, “context”: null}
14:32:22.262 - SKILLS - DEBUG - {“type”: “recognizer_loop:utterance”, “data”: {“lang”: “en-us”, “utterances”: ["“ask ciso what is cyber security”"]}, “context”: null}
14:32:22.289 - SKILLS - DEBUG - {“type”: “skill.converse.request”, “data”: {“lang”: “en-us”, “skill_id”: 1017122086, “utterances”: ["“ask ciso what is cyber security”"]}, “context”: null}
14:32:22.457 - SKILLS - DEBUG - {“type”: “-1492484506:speak_back”, “data”: {“confidence”: 0.375, “target”: null, “intent_type”: “-1492484506:speak_back”, “Words”: "what is cyber security “”, “tags”: [{“end_token”: 2, “start_token”: 1, “from_context”: false, “entities”: [{“confidence”: 1.0, “data”: [[“ask ciso”, “Speak”]], “key”: “ask ciso”, “match”: “ask ciso”}], “key”: “ask ciso”, “match”: “ask ciso”}, {“end_token”: 7, “start_token”: 3, “confidence”: 0.5, “from_context”: false, “entities”: [{“confidence”: 0.5, “data”: [["what is cyber security “”, “Words”]], “key”: "what is cyber security “”, “match”: "what is cyber security “”}], “key”: "what is cyber security “”, “match”: "what is cyber security “”}], “utterance”: ““ask ciso what is cyber security””, “Speak”: “ask ciso”}, “context”: {“target”: null}}

I guess your decorator @intent_handler should be just before speak_back(). I don’t know if you can leave IntentBuilder("") string blank, I would use IntentBuilder(“speak_back_intent”). I don’t think you can do without def initialize(self): but you don’t need stop().

And it is more convenient to use the skill container when testing:
./start-mycroft.sh skill_container /opt/mycroft/skills/yourskill
That command may be a little different on the picroft.
Good luck.

@CarstenA is correct, the @intent_handler() should be just above the definition of the method that shall handle the intent within the parentheses.

The @intent_handler(...) is a function/method decorator and basically it will auto generate some code to register the method below it as an intent handler. The typical syntax would be


    @intent_handler(IntentBuilder("").require("ask ciso").require("Words"))
    def speak_back(self, message):
      # Do speak back stuff

The above will register the speak_back as an handler for utterances which includes the vocabulary in the files SKILL_FOLDER/vocab/en-us/ask ciso.voc and SKILL_FOLDER/vocab/en-us/Words.voc

The IntentBuilder() can be passed empty strings, in this case Mycroft will automatically name the intents using class name and method name.

Initialize is not required if you use the intent_handler() decorators to setup your intents.

On picroft the equivalent to
./start-mycroft.sh skill_container /opt/mycroft/skills/yourskill
is
mycroft-skill-container /opt/mycroft/skills/yourskill

1 Like

Hi @CarstenA and @forslund
Many thanks for your comments. I have revised my code as follows and am testing it.

from adapt.intent import IntentBuilder
from mycroft.skills.core import MycroftSkill
from mycroft.util.log import getLogger

author = 'Pranav’
LOGGER = getLogger(name)
import os, base64
from mycroft import MycroftSkill, intent_handler
import requests

class AskCiso(MycroftSkill):
def init(self):
super(AskCiso, self).init(name=“AskCiso”)

def generate_session(self):
    return base64.b64encode(os.urandom(32))
@intent_handler(IntentBuilder("").require("ask ciso").require("Words"))
def speak_back(self, message):
    # Get everything after say/speak/etc. and speak it back
    LOGGER.debug("work routine invoked")
    words = message.data.get('utterance').split(message.data['ask ciso'])[1]
    words = words.strip()
    payload = {'question': words, 'sessionid': self.generate_session()}
    LOGGER.debug("about to look up bot")
    r = requests.get('http://104.236.77.142:5001/api/v1.0/ask', params=payload)
    spt=r.json()
    self.speak(spt)

def stop(self):
    pass

def create_skill():
return AskCiso()

1 Like

Hi all,
My problems continue. I am still unable to trigger my skill.
I have changed the trigger word to ciso.
My Speak.voc file has a single word ciso
pranav@ubuntu:/opt/mycroft/skills/skill-ask-ciso/vocab/en-us$ cat Speak.voc
cisopranav@ubuntu:/opt/mycroft/skills/skill-ask-ciso/vocab/en-us$

See below for my regular expression file.

pranav@ubuntu:/opt/mycroft/skills/skill-ask-ciso/regex/en-us$ cat Words.rx
ciso (?P.*)

Finally, here is the code of the skill.
Note
I have had to switch platforms to ubuntu 17.04 running under vmware. My raspberry pi is being used for other things.
Another strange issue I am facing is that I do not see any logs from mycroft. I suspect this deserves its own post. I am running mycroft under my own user who has sudo privileges.

from adapt.intent import IntentBuilder
from mycroft.skills.core import MycroftSkill
from mycroft.util.log import getLogger

author = 'Pranav’
LOGGER = getLogger(name)
import os, base64
from mycroft import MycroftSkill, intent_handler
import requests

class AskCiso(MycroftSkill):
def init(self):
super(AskCiso, self).init(name=“AskCiso”)

def generate_session(self):
    return base64.b64encode(os.urandom(32))
@intent_handler(IntentBuilder("").require("ciso").require("Words"))
def speak_back(self, message):
    # Get everything after say/speak/etc. and speak it back
    LOGGER.debug("work routine invoked")
    words = message.data.get('utterance').split(message.data['ciso'])[1]
    words = words.strip()
    payload = {'question': words, 'sessionid': self.generate_session()}
    LOGGER.debug("about to look up bot")
    r = requests.get('http://104.236.77.142:5001/api/v1.0/ask', params=payload)
    spt=r.json()
    self.speak(spt)

def create_skill():
return AskCiso()

Hi all,

I have got my skill running. I however was able to do so by directly modifying the speak skill. The problem now is that its performance is not consistent. I can see the responses of the bot in my log but I sometimes do and sometimes do not hear the bot answer. My current code is below.
Note:
I am currently testing on a ubuntu virtual machine which has its own set of challenges which I have over cum by adding my user to root so that I can access the capture devices in the guest ubuntu instance.

# Copyright 2016 Mycroft AI, Inc. # # This file is part of Mycroft Core. # # Mycroft Core is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Mycroft Core is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Mycroft Core. If not, see .

import re
from os.path import dirname, join

from adapt.intent import IntentBuilder
from mycroft import MycroftSkill, intent_handler

TODO - Localization

class SpeakSkill(MycroftSkill):

def generate_session(self):
    import os, base64

    return base64.b64encode(os.urandom(32))

def askcisobot(self,msg):
    import requests

    payload = {'question': msg, 'sessionid': self.generate_session()}
    r = requests.get('http://104.236.77.142:5001/api/v1.0/ask', params=payload)
    spt=r.json()
    rp=spt[0]
    return rp

@intent_handler(IntentBuilder("").require("Speak").require("Words"))
def speak_back(self, message):
    """
        Repeat the utterance back to the user.

        TODO: The method is very english centric and will need
              localization.
    """
    # Remove everything up to the speak keyword and repeat that
    utterance = message.data.get('utterance')
    repeat = re.sub('^.*?' + message.data['Speak'], '', utterance)

    self.speak(self.askcisobot(repeat))

def stop(self):
    pass

def create_skill():
return SpeakSkill()