Build an open future with us.

Invest in Mycroft and become a community partner.

Specific question about intent building


#1

Not sure if this is the right place to ask such a specific question, and forgive me in advance for terminology issues in this post (both python and the Intent API are very fresh to me)

I’m working on a skill where I want to add a bunch of keywords at runtime during initialization. So, say the code is:

def initialize(self):
    self.load_data_files(dirname(__file__))
    intent = IntentBuilder('MyIntent').require(
        'MyKeyword').require('SomeOtherWords').build()

If I understand, in this example one of the entities associated with the intent is called “SomeOtherWords” (and at least one of the list of keywords that are included in the entity will be required to invoke the intent) – if I have placed a list of keywords in a file called ./vocab/en-us/SomeOtherWords.voc those keywords wind up in this entity.

What I want to do is to add additional keywords – or really all the keywords – to the entity programatically at runtime in the initialize function (I will pull them from a ZMQ message that has a list of stuff in it)

I have been reading the API docs, but haven’t yet stumbled upon the way to do it. In another post here on this board, I have seen code like

engine.register_entity(‘aword’,‘SomeOtherWords’);

but that register_entity function isn’t available on the Intent, as far as I can tell.

Sorry for being so lost - any help would be greatly appreciated.


#2

@jqh1234 I have done something similar in a skill I forked from Hasinator7, https://github.com/aussieW/nature-sound-skill. If you look at the initialize() function you will see that I have constructed an .entity file containing the names of some files in a directory and then registered the .entity file. You may be able to do something similar with SomeOtherWords.voc before invoking IntentBuilder().

 def initialize(self):
        self.register_intent_file('play.intent', self.handle_play_intent)
        self.register_intent_file('library.intent', self.handle_library_intent)
        
        with open(join(self.vocab_dir, 'sounds.entity'), 'w') as f:
            f.write('\n'.join(self.getSounds()))
        self.register_entity_file('sounds.entity')

#3

thanks! I will play around with that


#4

I’m making progress - it turns out that there’s a function on the skill that can work - it’s called register_vocabulary

So from my original example:

def initialize(self):
self.load_data_files(dirname(file))
intent = IntentBuilder(“MyIntent”).require(
“MyKeyword”).require(“SomeOtherWords”).build()

I can then:

self.register_vocabulary("aNewWord","SomeOtherWords")

and the skill indeed puts ‘aNewWord’ into an entity called SomeOtherWords – the only problem is that it’s all by itself, because the entity being used by the intent has been renamed to be prepended with a seemingly arbitrary 8 character prefix (all capital letters), maybe to create a sort of pseudo-namespace for the skill – so that all the words in that came from the file SomeOtherWords.voc are actually put into an entity called, for instance: “DEFGABCDSomeOtherWords” - I saw that by looking at the debug log entries in /var/log/mycroft-skills.log

so… I tried hardcoding that entity name in my function call:

self.register_vocabulary("aNewWord","DEFGABCDSomeOtherWords")

and it works! the word ‘aNewWord’ is included in the list that came from the file SomeOtherWords.voc and the skill behaves just as I want it to with respect to ‘aNewWord’

But that’s a complete hack - I have no idea where the 8 character prefix came from - it seems to be persistent across reboots, but there has to be a better way to do it than copying it out of the debug log. Does that prefix mean anything to anyone, and if so, is there a way to get it inside the code so that I can be sure it will always be correct?


#5

I looked into this, and it seems there was a bug introduced last week that caused the behavior you’re seeing. @forslund Does it sound like this could be caused from the change that prepended the skill identifier to vocab? As a reference, the desktop launcher skill uses dynamic vocabulary with Adapt (but is, like yours, broken since this update).

You can, however, still use Padatious with a .entity file like aussieW mentioned. To do this your skill would look something like:

init.py:

from os.path import join
from mycroft import MycroftSkill, intent_file_handler


class DogSkill(MycroftSkill):
    def initialize(self):
        dogs = ['german shepherd', 'husky', 'labrador']  # This could be from an API
        with open(join(self.vocab_dir, 'dog_breed.entity'), 'w') as f:
            f.write('\n'.join(dogs))
        self.register_entity_file('dog_breed.entity')

    @intent_file_handler('dog.height.intent')
    def handle_dog_height(self, message):
        self.speak_dialog('dog.height.is', {'breed': message.data['breed'], 'height': '2.0'})

vocab/en-us/dog.height.intent:

How tall is {dog_breed}?
What's the height of {dog_breed}?

.gitignore:

/vocab/*/dog_breed.entity
settings.json
*.pyc

Let me know if this helps.
- Matthew


#6

Ah yes, seem to have missed this case in the update. will be fixing.


#7

I’ve pushed a fix to https://github.com/MycroftAI/mycroft-core/pull/1434 should be included shortly. Many thanks for reporting the issue.


#8

Thanks! I’ll have a closer look and at some point get the latest API code