... | ... | @@ -42,7 +42,7 @@ Last but not least we have conversation contexts. Contexts are things you are ta |
|
|
|
|
|
So contexts basically remember what you last talked about, but they can do way more than that with it.
|
|
|
|
|
|
###What will you need?
|
|
|
### What will you need?
|
|
|
Everything related to API.ai questions is located in `be.maximvdw.qaplugin.api.*`
|
|
|
However if you are only interested in creating intents/entities and not responding to them
|
|
|
you will do with `be.maximvdw.qaplugin.api.ai.*`
|
... | ... | @@ -50,6 +50,8 @@ you will do with `be.maximvdw.qaplugin.api.ai.*` |
|
|
### Creating an AIModule
|
|
|
An AIModule is basically the same as a dynamic response for a question. But instead for a local question it is for an API.ai question. When API.ai detects your question, it will extract the parameters and return them to the QAPlugin. The plugin will then call your AIModule with that information so you can do with it whatever you want.
|
|
|
|
|
|
**General rule of thumb:** If your questions are related to each other with the same information, use the same module. Example: "name.set", "name.get"
|
|
|
|
|
|
To create a module the only thing you have to do is create a class and make it extend `be.maximvdw.qaplugin.api.AIModule`
|
|
|
|
|
|
```java
|
... | ... | @@ -93,6 +95,7 @@ Entity myTiers = new Entity("myTiersEntity") |
|
|
|
|
|
An entity consists of a entries with optional synonyms. An entry is a 'possibility' and a synonym is another way of wording that 'possibility'.
|
|
|
|
|
|
### Uploading an entity
|
|
|
You have to upload the entity before you can use it. It is recommended to do this in the constructor of the AIModule.
|
|
|
Check out:
|
|
|
https://github.com/Maximvdw/QAPlugin-module-userdata/blob/master/src/main/java/be/maximvdw/qaplugin/modules/NameGetModule.java
|
... | ... | @@ -114,3 +117,352 @@ I am using the `findEntityByName` to check if the entity already exists. If you |
|
|
|
|
|
Notice that a `FeatureNotEnabled` exception will be thrown when the user does not have his developer-access-token configured. This token is required in order for the plugin to upload the entity.
|
|
|
|
|
|
### Creating an Intent
|
|
|
As said before an Intent contains templates and a response.
|
|
|
|
|
|
#### Simple Intent without context
|
|
|
```java
|
|
|
// Question to ask for the current rank
|
|
|
Intent qCurrentRank = new Intent("QAPlugin-module-ezrankspro-rank.current")
|
|
|
// These are the possible questions
|
|
|
// Note that the API is smart to detect
|
|
|
// variations on these templates
|
|
|
.addTemplate("what rank do I have?")
|
|
|
.addTemplate("what is my current rank?")
|
|
|
.addTemplate("can you tell me my rank?")
|
|
|
.addTemplate("what is the name of my rank?")
|
|
|
.addTemplate("on what rank am I?")
|
|
|
.addResponse(new IntentResponse()
|
|
|
// The response will trigger this action
|
|
|
.withAction(this)
|
|
|
.addMessage(new IntentResponse.TextResponse()
|
|
|
// These are possible speech responses
|
|
|
// Keep in mind that you do have to replace the {rank} placeholder
|
|
|
// yourself
|
|
|
.addSpeechText("You are currently on rank {{rank}}!")
|
|
|
.addSpeechText("Your current rank is {{rank}}")
|
|
|
.addSpeechText("This is your current rank: {{rank}}")));
|
|
|
```
|
|
|
This is a simple intent without entities. It will also accepts variations of those templates (using machine learning). The response will trigger the module you define with `withAction`.
|
|
|
|
|
|
**Note:** I used {{rank}} instead of {rank} because {{ becomes {
|
|
|
|
|
|
#### Advanced intent without context
|
|
|
```java
|
|
|
Intent question = new Intent("QAPlugin-module-userdata-user.name.set")
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("My first name is ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Maxim")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name")))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("My given name is ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Maxim")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name")))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("My name is ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Maxim")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name")))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("Call me ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("John")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name")))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("You can call me ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Abraham")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name")))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("Call me ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Cloe")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name"))
|
|
|
.addPart(" from now on"))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("I am ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Maxim")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name")))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("My name is ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Erwin")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name"))
|
|
|
.addPart(" ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Vanden Bosche")
|
|
|
.withAlias("last-name")
|
|
|
.withMeta("@sys.last-name")))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("Call me ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Maxim")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name"))
|
|
|
.addPart(" ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Kaspersky")
|
|
|
.withAlias("last-name")
|
|
|
.withMeta("@sys.last-name")))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("You can call me ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Maxim")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name"))
|
|
|
.addPart(" ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Baba luga")
|
|
|
.withAlias("last-name")
|
|
|
.withMeta("@sys.last-name")))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("Call me ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Maxim")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name"))
|
|
|
.addPart(" ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Van de Wynckel")
|
|
|
.withAlias("last-name")
|
|
|
.withMeta("@sys.last-name"))
|
|
|
.addPart(" from now on"))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("I am ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Maxim")
|
|
|
.withAlias("given-name")
|
|
|
.withMeta("@sys.given-name"))
|
|
|
.addPart(" ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Van de Wynckel")
|
|
|
.withAlias("last-name")
|
|
|
.withMeta("@sys.last-name")))
|
|
|
.addResponse(new IntentResponse()
|
|
|
.withAction(this)
|
|
|
.addParameter(new IntentResponse.ResponseParameter("given-name", "$given-name")
|
|
|
.setRequired(true)
|
|
|
.withDataType("@sys.given-name")
|
|
|
.addPrompt("Didn't catch that name sorry. Say again please?")
|
|
|
.addPrompt("What is your name?")
|
|
|
.addPrompt("What's your name?")
|
|
|
.addPrompt("Say your name please"))
|
|
|
.addParameter(new IntentResponse.ResponseParameter("last-name", "$last-name")
|
|
|
.withDataType("@sys.last-name"))
|
|
|
.addMessage(new IntentResponse.TextResponse()
|
|
|
.addSpeechText("Ok, $given-name!")
|
|
|
.addSpeechText("I will try and remember that ;)")
|
|
|
.addSpeechText("I will remember that $given-name!")
|
|
|
.addSpeechText("Hi there $given-name!")));
|
|
|
```
|
|
|
This intent creates entities inside the templates. The response has two parameters, one being the given-name and the other being the last-name.
|
|
|
|
|
|
I made it so the given-name is required, so it will prompt the user if it did not detect it.
|
|
|
|
|
|
#### Advanced intent with context
|
|
|
```java
|
|
|
Intent translate = new Intent("Translate")
|
|
|
.addTemplate("can you translate something?")
|
|
|
.addTemplate("can you help me translate something?")
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("how do you translate it to ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("dutch")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true)))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("how do you say it in ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("dutch")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true)))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("translate \"")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Ik ben maxim")
|
|
|
.withMeta("@sys.any")
|
|
|
.withAlias("text")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("\" to ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("english")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true)))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("can you translate \"")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Ik ben maxim")
|
|
|
.withMeta("@sys.any")
|
|
|
.withAlias("text")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("\" from ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("english")
|
|
|
.withAlias("source")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart(" to ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("german")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("?"))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("how do you say \"")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Ik ben maxim")
|
|
|
.withMeta("@sys.any")
|
|
|
.withAlias("text")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("\" in ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("english")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("?"))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("how do you say \"")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Greetings")
|
|
|
.withMeta("@sys.any")
|
|
|
.withAlias("text")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("\" in ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("english")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("?"))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("how do you say \"")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Greetings")
|
|
|
.withMeta("@sys.any")
|
|
|
.withAlias("text")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("\" to ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("english")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("?"))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("how to translate \"")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Ik ben maxim")
|
|
|
.withMeta("@sys.any")
|
|
|
.withAlias("text")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("\" from ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("english")
|
|
|
.withAlias("source")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart(" to ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("german")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("?"))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("how do you say \'")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Ik ben maxim")
|
|
|
.withMeta("@sys.any")
|
|
|
.withAlias("text")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("\' from ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("english")
|
|
|
.withAlias("source")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart(" to ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("german")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("?"))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("how do you say \'")
|
|
|
.addPart(new IntentTemplate.TemplatePart("I love you")
|
|
|
.withMeta("@sys.any")
|
|
|
.withAlias("text")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("\' in ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("french")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("?"))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("what is \'")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Ik ben maxim")
|
|
|
.withMeta("@sys.any")
|
|
|
.withAlias("text")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("\' in ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("french")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("?"))
|
|
|
.addTemplate(new IntentTemplate()
|
|
|
.addPart("what is \"")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Bonjour")
|
|
|
.withMeta("@sys.any")
|
|
|
.withAlias("text")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("\" in ")
|
|
|
.addPart(new IntentTemplate.TemplatePart("Dutch")
|
|
|
.withAlias("target")
|
|
|
.withMeta("@sys.language")
|
|
|
.setUserDefined(true))
|
|
|
.addPart("?"))
|
|
|
.addResponse(new IntentResponse()
|
|
|
.addAffectedContext(new Context("translate", 2))
|
|
|
.withAction(this)
|
|
|
.addParameter(new IntentResponse.ResponseParameter("text", "$text.original")
|
|
|
.withDefaultValue("#translate.text")
|
|
|
.withDataType("@sys.any")
|
|
|
.setRequired(true)
|
|
|
.addPrompt("What do I need to translate?")
|
|
|
.addPrompt("What is there for me to translate?")
|
|
|
.addPrompt("Can you tell me what I have to translate?")
|
|
|
.addPrompt("Please provide the text you want translated")
|
|
|
.addPrompt("What do you want me to translate?")
|
|
|
.addPrompt("Can you tell me what is there to translate?"))
|
|
|
.addParameter(new IntentResponse.ResponseParameter("source", "$source")
|
|
|
.withDefaultValue("#translate.source")
|
|
|
.withDataType("@sys.language"))
|
|
|
.addParameter(new IntentResponse.ResponseParameter("target", "$target")
|
|
|
.withDefaultValue("#translate.target")
|
|
|
.withDataType("@sys.language")
|
|
|
.setRequired(true)
|
|
|
.addPrompt("To what language do you want me to translate it?")
|
|
|
.addPrompt("What is the language I need to translate to?")
|
|
|
.addPrompt("To what language should I translate?")
|
|
|
.addPrompt("What is the language I have to translate to?"))
|
|
|
.addMessage(new IntentResponse.TextResponse()
|
|
|
.addSpeechText("It is translated like: {{translation}}")
|
|
|
.addSpeechText("\"{{text}}\" is translated to \"{{translation}}\" in {{target}}")
|
|
|
.addSpeechText("\"{{text}}\" is translated to \"{{translation}}\"")
|
|
|
.addSpeechText("\"{{translation}}\"")
|
|
|
.addSpeechText("{{translation}}"))
|
|
|
.addMessage(new IntentResponse.TextResponse()
|
|
|
.addSpeechText("I don't know that language :S")
|
|
|
.addSpeechText("I can't find the language you want to translate to")
|
|
|
.addSpeechText("I do not know the language you want to translate to")));
|
|
|
```
|
|
|
This example contains multiple Text responses for possible error handling. Look at the code for the translator to see how this works:
|
|
|
https://github.com/Maximvdw/QAPlugin-module-translate/blob/master/src/main/java/be/maximvdw/qaplugin/modules/TranslateModule.java
|
|
|
|
|
|
Using `addAffectedContext` the paramters are saved for a lifetime of **2** questions. This means that you can fill in the parameters with a default value of your previous question using `withDefaultValue`
|
|
|
The format is: `#<contextName>.<parameterName>`
|
|
|
|
|
|
### Uploading an intent
|
|
|
You have to upload the intent before you can use it. It is recommended to do this in the constructor of the AIModule.
|
|
|
Check out:
|
|
|
https://github.com/Maximvdw/QAPlugin-module-userdata/blob/master/src/main/java/be/maximvdw/qaplugin/modules/NameGetModule.java
|
|
|
for an example.
|
|
|
|
|
|
```java
|
|
|
try {
|
|
|
// Upload the intents
|
|
|
if (QAPluginAPI.findIntentByName(myIntent.getName()) == null) {
|
|
|
if (!QAPluginAPI.uploadIntent(myIntent)) {
|
|
|
warning("Unable to upload intent!");
|
|
|
}
|
|
|
}
|
|
|
} catch (FeatureNotEnabled ex) {
|
|
|
severe("You do not have a developer access token in your QAPlugin config!");
|
|
|
}
|
|
|
```
|
|
|
I am using the `findIntentByName` to check if the intent already exists. A future feature will ensure that the intent is only uploaded upon a change.
|
|
|
|
|
|
Notice that a `FeatureNotEnabled` exception will be thrown when the user does not have his developer-access-token configured. This token is required in order for the plugin to upload the intent. |
|
|
\ No newline at end of file |