Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better examples of using Intents with Adapt #42

Merged
merged 4 commits into from
Mar 14, 2018
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions _pages/introduction-developing-skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,119 @@ def stop(self):

In the above code block, the [`pass` statement](https://docs.python.org/2/reference/simple_stmts.html#the-pass-statement) is used as a placeholder; it doesn't actually have any function. However, if the **Skill** had any active functionality, the stop() method would terminate the functionality, leaving the *Skill** in a known good state.

#### Intents and regular expressions (regex)

In the examples above, we walked through how to use phrases in a `.voc` file to build an `Intent` using _entities_. In this section, we expand on how `Intents` are built, and introduce _multiple entities_, and _regular expressions_.

Throughout this section, we will be using examples from the [Date and Time Skill](https://github.com/MycroftAI/skill-date-time).

##### How .voc files are used to handle Intents

At the top of your **Skill** file, you will have a line that looks like this:

`from adapt.intent import IntentBuilder`

This tells your **Skill** to import the `IntentBuilder` class from Adapt. Adapt is an Intent-handling engine. Its job is to understand what a user Speaks to Mycroft, and to pass that information to a **Skill** for handling.

Different **Skills** require different information from the user. For example, the **Skill** to change the color of Mycroft's eyes just has one parameter - `color`. That parameter is mandatory - because you can't change the color of Mycroft's eyes without knowing what color to change them to.

Later in your **Skill** file, you will call `IntentBuilder`, with one or more parameters. The parameters can be either `required` or `optional`.

For example, here is the `@intent_handler` _decorator_ used in the [Date and Time Skill](https://github.com/MycroftAI/skill-date-time). It has three parameters; two are `required` and one is `optional`.

```python

@intent_handler(IntentBuilder("")
.require("Query")
.require("Time")
.optionally("Location")
)

```

This call is then interpreted by the Adapt Intent Parser.

Internally, Adapt uses a function called `register_entity`, and tries to register `entities` based on the parameters passed to `IntentBuilder`. There are several ways that Adapt can register `entities`.

If we were building `Intent`s manually, we would do something like this:

```python

locations = [
"Seattle",
"San Francisco",
"Tokyo"
]

for loc in locations:
engine.register_entity(loc, "Location")

```

But what if we want to support more `locations`? Or make the `location` available to the **Skill** to use as a parameter in an API call?

First, Adapt will look in `.voc` files to try and register an `Intent`. For example, in the [Date and Time Skill](https://github.com/MycroftAI/skill-date-time), in the `vocab` directory, you will see several `.voc` files. Note that they each correspond to one of the parameters passed to `Intentbuilder()`.

```bash

pi@mark_1:/opt/mycroft/skills/skill-date-time/vocab/en-us $ ls -las
total 24
4 drwxr-xr-x 2 mycroft mycroft 4096 Feb 15 14:17 .
4 drwxr-xr-x 4 mycroft mycroft 4096 Feb 15 14:17 ..
4 -rwxr-xr-x 1 mycroft mycroft 8 Feb 15 14:17 Date.voc
4 -rwxr-xr-x 1 mycroft mycroft 12 Feb 15 14:17 Display.voc
4 -rwxr-xr-x 1 mycroft mycroft 9 Feb 15 14:17 Query.voc
4 -rwxr-xr-x 1 mycroft mycroft 5 Feb 15 14:17 Time.voc

```

If we take a look inside each of these files, they contain only a single word each:

* `Date.voc` => "date"
* `Display.voc => "display"
* `Query.voc`=> "what"
* `Time.voc` => "time"

Now, remember back to `IntentBuilder` and the mandatory and optional parameters? Only `Query` and `Time` were mandatory. So if a user Spoke:

`"Hey Mycroft, **what** **time** is it?"`

then Adapt would match that **Utterance** to the [Date and Time Skill](https://github.com/MycroftAI/skill-date-time), by _registering_ the `Intent`, and within the **Skill**, this would be handled by the `handle_query_time()` function.

If the user Spoke:

`"Hey Mycroft, **display** the **time** "`

which function within the Date and Time Skill do you think would handle the **Utterance**?

_ANSWER: handle_show_time()_

But what about `Location`? There isn't a `.voc` file for `Location`, so how does Adapt register an `entity` for `Location` so that `Location` can be included in an **Utterance**, recognised as an `Intent`, and handled properly by the [Date and Time Skill](https://github.com/MycroftAI/skill-date-time)?

This is done using [regular expressions](https://docs.python.org/2/library/re.html).

In the [Date and Time Skill](https://github.com/MycroftAI/skill-date-time) directory, you will see a sub-directory called `regex`. This sub-directory follows the same file structure as the `voc` directory (eg. there will be an `en-us` directory inside), and contains a file called 'location.rx':

```bash

pi@mark_1:/opt/mycroft/skills/skill-date-time/regex/en-us $ ls -las
total 12
4 drwxr-xr-x 2 mycroft mycroft 4096 Feb 15 14:17 .
4 drwxr-xr-x 4 mycroft mycroft 4096 Feb 15 14:17 ..
4 -rwxr-xr-x 1 mycroft mycroft 28 Feb 15 14:17 location.rx

```

Inside `location.rx` is a _regular expression_:

`(at|in|for) (?P<Location>.*)`

Because a `.voc` file is not present for the `Location` parameter, Adapt will then search for an equivalent `.rx` file in the `regex` directory. Instead of being restricted to the specified words in the `.voc` file, Adapt can register `Intents` using _regular expressions_, and thus support a wider range of input from the user.

Can you think of another **Skill** where a _regular expression_ `Location` would be useful?

_ANSWER: [Weather Skill](https://github.com/MycroftAI/skill-weather)_

## Simplifying your Skill code with `intent_handler` _decorators_

Your **Skill** code can be simplified using the intent_handler() _decorator_. The major advantage in this approach is that the **Intent** is described together with the method that handles the **Intent**. This makes your code easier to read, easier to write, and errors will be easier to identify.
Expand Down