-
Notifications
You must be signed in to change notification settings - Fork 12
6) Your first skill
Prerequisites: If you haven't already, check out our Introduction to Skill development.
We have created an empty skill for you which we have called "Blank Skill" which you can find here.
It is from this skill that we will base our work.
Here is the architecture of the skill that we will explain.
Not all of these files are necessary.
This folder is not essential for the proper functioning of the skill.
It will contain files used by the "Store" tab of the server's GUI.
We still advise you to fill it in before publishing your skill.
This folder will contain all the images you want users to see when they select your skill in the "Store" tab of the server's GUI.
It is important that you name them as follows: "1.jpg", "2.jpg", "3.jpg" ...
We recommend that your images are all the same size.
Your images will appear as a carousel (here in red).
This file is essential for your skill to be offered to NOVA users.
Here is an example of content:
{
"worksOffline" : true, // This attribute is used to inform if the skill works offline.
"description" : { // This attribute is used to describe the skill. It will be displayed in the language set by the user in the "Settings" tab of the server.
"fr-FR": "Cette compétence est vraiment incroyable, elle vous permettra de ...",
"en-US": "This skill is really amazing, it will allow you to..."
},
"language": [ // This attribute is used to inform users which languages your skill is compatible with.
"fr-FR",
"en-US",
"es-ES",
"it-IT",
"de-DE"
]
}
Usually, for a GitHub user to understand the usefulness of your skill, you are asked to provide a screenshot of your skill in action.
This screenshot can be seen in the "README" file (here in red).
This image represents the application icon visible in the store.
This image will be present in large in the skill store, behind "nova-icon.png", here in red.
This folder will contain all the files useful for your skill.
You will find examples below.
This folder contains other folders, one folder per language.
You will be able to define the means of giving instructions to NOVA (triggers), and the way in which it will respond to you.
This file contains in this example, the instruction sentences and their answers in French.
This file contains in this example, the instruction sentences and their answers in French.
You will notice that the utterance variables are represented by the sign {myVariableName} and that the response variables are represented by the sign %myVariableName%.
If the extraction of variables from utterances does not go well, you can try to specify the maximum number of words they can contain like this: {myVariableName|2} In this case, the variable cannot contain more than two words.
This text comprehension works without learning, which is a good thing, since we don't have enough data, but its operation requires you to fill in all the ways to trigger your actions. It might be redundant, but usually we only have about ten different ways to request an action, and it's fully customizable, you can even put funny things 😁.
If you want to know more about text recognition, I invite you to look at it repo.
{
"name": "Random", // The name of your skill.
"data": [
{
"intent": "Random.dice", // The name of the intent
"utterances": [ // The ways to trigger it
"Lance un dé",
"Jette un dé"
],
"answers": [ // The answers
"Le dé est tomber sur %result%.",
"%result%"
]
},
{
"intent": "Random.between", // The name of the intent
"utterances": [ // The ways to trigger it
"Donne-moi un chiffre entre {first|1} et {last|1}",
"Donne-moi un nombre entre {first|1} et {last|1}",
"Donne-moi un chiffre aléatoire entre {first|1} et {last|1}",
"Donne-moi un nombre aléatoire entre {first|1} et {last|1}",
"Donne-moi un chiffre au hasard entre {first|1} et {last|1}",
"Donne-moi un nombre au hasard entre {first|1} et {last|1}",
"Donnez-moi un chiffre entre {first|1} et {last|1}",
"Donnez-moi un nombre entre {first|1} et {last|1}",
"Donnez-moi un chiffre aléatoire entre {first|1} et {last|1}",
"Donnez-moi un nombre aléatoire entre {first|1} et {last|1}",
"Donnez-moi un chiffre au hasard entre {first|1} et {last|1}",
"Donnez-moi un nombre au hasard entre {first|1} et {last|1}",
"Donne-moi un chiffre compris entre {first|1} et {last|1}",
"Donne-moi un nombre compris entre {first|1} et {last|1}",
"Donne-moi un chiffre aléatoire compris entre {first|1} et {last|1}",
"Donne-moi un nombre aléatoire compris entre {first|1} et {last|1}",
"Donne-moi un chiffre au hasard compris entre {first|1} et {last|1}",
"Donne-moi un nombre au hasard compris entre {first|1} et {last|1}",
"Donnez-moi un chiffre compris entre {first|1} et {last|1}",
"Donnez-moi un nombre compris entre {first|1} et {last|1}",
"Donnez-moi un chiffre aléatoire compris entre {first|1} et {last|1}",
"Donnez-moi un nombre aléatoire compris entre {first|1} et {last|1}",
"Donnez-moi un chiffre au hasard compris entre {first|1} et {last|1}",
"Donnez-moi un nombre au hasard compris entre {first|1} et {last|1}"
],
"answers": [ // The answers
"%result%"
]
}
]
}
...
...
This folder contains all the CSS files you want to use on the NOVA client GUI.
The file names don't matter.
This folder contains all the images you want to use on the NOVA client GUI.
This folder contains all the javascript files you want to use on the NOVA client GUI.
The file names don't matter.
This file will be executed by the server of a NOVA client.
Among other things, you can add code that will transfer socket calls from the client to the NOVA server and vice versa.
This file will be executed by the server of NOVA.
In the following example, we define actions linked to previous utterances.
const LIBRARIES = {
Skill: require("../../../Libraries/Skill")
};
class Random extends LIBRARIES.Skill{
constructor(_main, _settings) {
super(_main, _settings);
const SELF = this;
this.Main.Manager.addAction("Random.dice", function(_intent, _socket){
_intent.Variables.result = SELF.Random(1, 6);
_intent.answer(_socket);
});
this.Main.Manager.addAction("Random.between", function(_intent, _socket){
_intent.Variables.result = SELF.Random(_intent.Variables.first, _intent.Variables.last);
_intent.answer(_socket);
});
}
Random(_first_number, _last_number){
const SMALLER = _first_number < _last_number ? _first_number : _last_number;
const BIGGER = _last_number > _first_number ? _last_number : _first_number;
return Math.floor(Math.random() * (BIGGER - (SMALLER - 1))) + SMALLER;
}
}
module.exports = Random;
This file will contain the user-editable settings for your skill.
{
"Settings": {
"serverIP": "http://192.168.1.12",
"serverPort": "32400",
"token": "abcdefghijklmnopqrstuvwxyz"
}
}
This file is initialized by the "npm init" command.
It contains some info like the list of dependencies of your project.
Do you need more information?
Feel free to ask us questions on Discord.
This documentation is very inspired by that of the Alice project, another very interesting assistant project 😀
(Psycho, if you want a drink, I'm available 😅)