I have a skill that needs a prompt using messagebus. When I receive this prompt I need my skill to read json contents from a file and asks the user a question. However it appears once the contents have been read, the skill reloads and I’m unable to capture the users response. Is there a way to pause reloading the skill or can I read contents from the file as soon as the skill reloads? My directory structure is as follows:
skills/my-skill
|_/json-files
|_json_file
My json file is read as follows:
class MySkill(MycroftSkill):
def __init__(self):
MySkill.__init__(self)
self.json_data = {}
self.json_file = join(self.root_dir, 'json_files/json_file')
def initialize(self):
self.add_event('json', self.json_data)
def handler_json(self, message):
self.get_data()
self.ask_questions()
def get_data(self):
if os.stat(self.json_file ).st_size == 0:
return False
else:
with open(self.questions_file) as f:
json_data = json.load(f)
self.json_data = json_data
self.json_data = True
def ask_questions(self):
response = self.get_response("You have new questions")
if response == "yes":
#read self.json_data
else:
#pass
My skill recieves a prompt with:
python3 -m mycroft.messagebus.send ‘json’
All help is appreciated thank you!
Hi Santiago,
It looks like your event handler isn’t registered correctly.
self.add_event('json', self.json_data)
Here the second argument is the handler callback so presumably should be self.handler_json
in this instance.
If you haven’t found them yet the Skill will be generating logs at /var/log/mycroft/skills.log which are also visible in the CLI. You can generate your own logs too. Find out more in our docs:
https://mycroft-ai.gitbook.io/docs/skill-development/introduction/logging
There are a few other little typo’s that might be tripping up the Skill, eg self.questions_file
doesn’t exist and the if / else block needs something in it other than comments.
As a side note, I’d suggest using a more specific message type. Instead of json
it would be better as skill.myskill.json
. We do this to keep each Skills messages in their own namespace. You could easily see someone else doing something with JSON messages which have nothing to do with your Skill but they’d both be issuing json
messages.
Here’s a working example with the above incorporated:
import json
import os
from os.path import join
from mycroft import MycroftSkill, intent_handler
class JsonSkill(MycroftSkill):
def __init__(self):
super().__init__(name="JsonSkill")
self.json_data = {}
self.json_file = join(self.root_dir, 'json_files/json_file')
def initialize(self):
self.add_event('skill.jsonskill.json', self.handler_json)
def handler_json(self, message):
self.get_data()
self.ask_questions()
def get_data(self):
if os.stat(self.json_file ).st_size == 0:
return False
else:
with open(self.json_file) as f:
json_data = json.load(f)
self.json_data = json_data
self.json_data = True
def ask_questions(self):
response = self.get_response("new.questions")
if response == "yes":
self.log.info("YES")
else:
self.log.info("NO")
def create_skill():
return JsonSkill()
Edit: small note, I moved the dialog for get_response
into locale/en-us/new-questions.dialog
1 Like
Mycroft has an auto-reload feature reloading the skill if a file in it gets updated. It’s probably this that happens.
You can turn this off completely by setting the self.reload_skill flag to false in initialize, in your case:
def initialize(self):
self.reload_skill = False
self.add_event('json', self.json_data)
But you should consider an alternative location for the json file.
1 Like
Hi!
Just realised I have those typos in my question which I apologise for.
-
self.add_event('json', self.json_data)
should most definitely be self.add_event('json', self.handler_json)
-
self.questions_file
should be self.json_file
-
The comments in the if/else block are there to illustrate what’s supposed to happen not actually what I have in my code. However, I’ll keep in mind this is confusing when reading, appreciate the feedback and will definitely not repeat this again!
Moving dialogue into locale/en-us/ certainly looks a lot cleaner and I’ll also implement this as well as changing the prompt to use skill.myskill.json to keep it within the skill namespace!
I was wondering if there was a way to match utterances from a user to an intent file. For example using something like:
def ask_questions(self):
response = self.get_response("new.questions")
if response in yes.intent: <-----------------SOMETHING LIKE THIS
self.log.info("YES")
else:
self.log.info("NO")
Responding to intents with an intent handler seems easy enough but within a block like that, I’m not so sure. Thank you very much for your help and bearing with my typos!
In relation to switching of auto reload, this is what I’m looking for. Thank you very much!
As for moving the location of the json file, I’ve been trying to figure out where else to put it but its a little confusing as to where mycroft is picking up files. Can you suggest where else I can store this file?
A few things I should have mentioned for this:
-
For Yes / No questions in particular we have a built-in method for this: ask_yesno(dialog)
-
translate("yes")
will return the phrase “yes” in the users set language if the translation exists. So better to use this than attempting to match against the string “yes” directly.
-
voc_match(response, "yes")
returns a boolean on whether “yes” (translated into the users language) is in the response
string
As for file location:
self.file_system.path
should be assigned to your Skills dedicated directory. By default this is ~/.mycroft/skills/YourSkillName
1 Like