Documentation

Powered by Algolia

Slots

When constructing intents in the voice script, you can use slots. A slot is essentially a variable in the user utterance that allows Alan to identify and retrieve important information from the user input. Slots and slot values can be used to differentiate the logic in the conversation flow and give meaningful responses to the user.

Alan offers the following slot types:

  • User-defines slots allow you to list all possible values that the user can say when giving a voice command.
  • Predefined slots allow you to get specific pieces of information from user utterances, for example, the user location, time, numbers and so on.

User-defined slots

In Alan, you can create custom, or user-defined slots. User-defined slots list expected possibilities (words or phrases) that the user can say when giving a command. To define a slot, use the $ sign followed by brackets (). In brackets, define the name of the slot followed by its possible value.

In the example below, we define the D slot with the today value.

intent('what is the weather $(D today)', p => {
    p.play('It is great!');
});

When defining possible slot values, you can use the same principles as with patterns. You can:

intent('what (is|was|would be) the weather $(D yesterday|today|tomorrow|)', p => {
    p.play('It is great!');
});

Slot values and labels

A slot in Alan is an object that has a set of predefined fields and methods. All slot types have the following fields:

  • .value
  • .label

The .value field is filled automatically when a command with the slot is matched. In this case, the user input is added to the .value field.

In the example below, the user input is both printed in the Info logs section in the Alan Studio and said by Alan.

intent('what (is|was|would be) the weather $(D yesterday|today|tomorrow|)', p => {
    console.log(p.D.value);
    p.play(p.D.value);
    p.play('It is great!');
});

You can use slot labels to provide some description or characteristic for slot values. Unlike slot values, labels do not necessarily need to be unique.

To use a label, you need to define it first. Add the ~ sign followed by the label value to a slot value.

intent('what (is|was|would be) the weather $(D yesterday~past|today~now|tomorrow~future|)', p => {
    console.log('Value:', p.D.value);
    console.log('Label:', p.D.label);
    p.play('It is great!');
});

In the example below, we use labels to adjust the logic of intents and provide more accurate responses to the user. Now if the user says What was the weather yesterday, the slot .value will be yesterday and the .label will be past. Alan will give a response defined for the past label.

intent('what (is|was|would be) the weather $(D yesterday~past|last day~past|today~now|now~now|tomorrow~future|next day~future|)', p => {
    console.log('Value:', p.D.value);
    console.log('Label:', p.D.label);
    switch (p.D.label) {
        case 'past':
            p.play('It was terrible!');
            break;
        case 'future':
            p.play('I hope it will be fine.');
            break;
        case 'now':
        default:
            p.play('It is great!');
    }
});

Slot values in responses

You can use slots in patterns for response functions: play and reply. Use the standard JavaScript syntax for "template strings", with right back-tick quotation marks. You can also add slots to the string line.

intent('what (is|was|would be) the weather $(D yesterday~past|last day~past|today~now|now~now|tomorrow~future|next day~future|)', p => {
    console.log('Value:', p.D.value);
    console.log('Label:', p.D.label);
    switch (p.D.label) {
        case 'past':
            p.play(`The weather ${p.D.value} was terrible!`);
            break;
        case 'future':
            p.play(`I hope that the weather ${p.D.value} will be fine.`);
            break;
        case 'now':
        default:
            p.play('The weather ' + p.D.value + ' is great!');
    }
});

Regular expressions

You can use regular expressions in patterns. To do this, you need to add * sign to the slot name. This will signal Alan that this slot contains RegEx.

For example, if you want to match the I want $(FLAVOUR) ice cream command, but you don’t know all possible flavours in advance, you can use the following expression:

const regIce = "\\w+";

intent(`I want $(FLAVOUR* ${regIce}) ice cream`, p => {
    p.play(p.FLAVOUR.value);
});

If you need to use special characters in RegEx, you should escape them with \. Such characters are: \, '.

You can use regular expressions of any complexity. In the example below, the intent will match all combinations of six letters and any number of digits going after the incident word. This will help if you need your users to input some uncommon abbreviations.

let letters_reg = "([A-Za-z]{1}\\s?){6}";
let num_reg = "(\\d+\\s?)+";
let reg = letters_reg+num_reg;

intent(`incident $(INCIDENT* ${reg})`, p => {
    p.play(`${p.INCIDENT.value}`);
});

RegEx is best when it is unique. You should try to use words surrounding RegEx in the intent; in this case, matching will be more precise.

Getting any user input

It is possible to use greedy RegEx that will match any user input. One of the possible use cases for this functionality is to gather user feedback.

In the example below, any user message is saved to the COMPLAINT slot value and played back to the user.

intent('I want to open a complaint. $(COMPLAINT* (.*))', p => {
    p.play(`Your complaint has been registered. You've said: ${p.COMPLAINT.value}`);
});

Slots with fuzzy matching

By default, to match some intent with a slot, Alan requires that the user input contains the exact slot value. However, you sometimes cannot specify all possible variants of the user input in the slot. For example, a slot may contain groups of words in which the word order may differ, some words in the input phrase may be replaced with synonyms or there may be some values that are hard to pronounce, like a list of units.

To allow Alan match intents with slots whose values may be less than 100% perfect, you can use slots with fuzzy matching. In such slots, Alan matches the intent based on the most similar alternative. That is, Alan relies on the semantic meaning, even if it is not close to what the user has said.

To define a slot with fuzzy matching, you need to add the ~ sign after the slot name and provide a label for each value. For slots with fuzzy matching, the .value field will contain the user input exactly as user has said it, not the value you have defiined in the script. And the .label field can be used to give a proper response to the user.

Slots with fuzzy matching should be used with caution, as they can lead to overly general matching.

For example, let's assume you want to receive feedback on the following question: How likely are you to use our company products again? To the intent, you add a slot with four values, each of which gets a rating from 1 to 4 in the label field. There are many different variants how users can say very likely, for example:

  • very likely
  • super likely
  • extremely likely
  • massively likely

To make sure such intent is matched, you need to either cover all possible variants using alternatives with the same label (as in the end you are interested in the numerical grouped value for statistics) or you can use slot with fuzzy matching.

intent('$(RATING~ very unlikely~1|unlikely~2|likely~3|very likely~4)', p => {
    p.play(`Your input is ${p.RATING.value}`);
    p.play(`The rating that you are giving is ${p.RATING.label}`);
});

In the example above, all listed inputs (super likely, extremely likely and so on) and other phrases similar to them will be matched as semantically they are close to very likely.

Predefined slots

You can use predefined slots to let Alan identify and retrieve some common types of data from the user input. Alan offers the following types of predefined slots:

Slot type Short description
DATE Matches a correct date in the user input, for example, today, March 3rd or two days ago
TIME Matches time information in the user input, for example, 10:00 AM
NUMBER Matches cardinal numbers in the user input, for example, 3 or 25
ORDINAL Matches ordinal numbers in the user input, for example, first or 22nd
LOC Matches a location in the user input, for example, a city, district or address
NAME Matches a name, surname or both in the user input, for example, John Doe

DATE

The DATE slot matches the user input when it can be represented as a correct date. For example, the DATE slot can match user inputs like today, last friday, tomorrow, yesterday, March 3rd, 2 days ago and so on.

intent(`what is $(DATE)`, p => {
    console.log(p.DATE.moment);
    p.play(`${p.DATE.value} is a date`);
    p.play(`Its ${p.DATE.moment.format("dddd, MMMM Do YYYY")}`);
});

Each DATE slot contains two special fields:

  • moment: date object from the moment.js library
  • luxon: the luxon date object

You can call all available methods for date formatting or any kind of calculations on dates. These two objects already use the date in the user timezone which is also always available in p.timeZone.

intent(`what is (my|) timezone`, p => {
    p.play(`Your current timezone is ${p.timeZone}`);
});

TIME

The TIME slot matches time information in the user input. If the user inputs time, the corresponding TIME slot value will be interpreted as time, and the slot is filled with time data.

intent(`I will come at $(TIME)`, p => {
    p.play(`Ok, we are waiting for you at ${p.TIME.value}`);
});

You can use the special .time field of the TIME object to get the number of seconds from midnight.

intent(`How many seconds went till $(TIME)`, p => {
    p.play(`${p.TIME.time} seconds passed from midnight till ${p.TIME.value}`);
});

NUMBER

The NUMBER slot matches any cardinal number, for example 5, three, 256, one million. The .value field will contain the user input and the .number field will contain a numerical representation of this input.

intent('I want to order $(NUMBER) items', p => {
    console.log('User input:', p.NUMBER.value);
    console.log('Parsed number:', p.NUMBER.number);
    p.play(`You have ordered ${p.NUMBER.number} items`);
});

ORDINAL

You can use the ORDINAL slot to get ordinal numbers like fist, second, 21st, 3rd. Its .value field will contain the user input and .number field will contain a numerical representation of this input.

const LIST = ["Anna", "Michael", "Lisa", "Alex"]

intent (`Who is the $(ORDINAL) in the list?`, p => {
    let member = LIST[p.ORDINAL.number - 1];
    p.play(`${member} is the ${p.ORDINAL.value} in the list`);
})

LOC

The LOC slot interprets the user input as a location. It can be a city, district, or full address string. For example, Washington, 36 West Bedford and so on.

intent(`Navigate me to $(LOC)`, p => {
    p.play(`OK! Calculating a route to ${p.LOC.value}.`);
});

NAME

The NAME slot interprets the user input as a person. It can be a name, surname, or both. So Alan, Turing, and Alan Turing all can be matched using this slot.

intent('show contact details for $(NAME)', p => {
    p.play(`Getting contact details for ${p.NAME.value}`);
});

Accessing data in predefined slots

To access data captured by predefined slots, you can use system names of these slots or specify custom names. For example, to get the number of tickets captured with the NUMBER slot, you can use the p.NUMBER.value variable:

intent('I need $(NUMBER) tickets', p => {
    p.play(`You have ordered ${p.NUMBER.value} tickets. Is it correct?`);
});

Alternatively, you can specify a custom name for the predefined NUMBER slot and access the captured number using this custom name:

intent('I need $(TICKETNUM NUMBER) tickets', p => {
    p.play(`You have ordered ${p.TICKETNUM.value} tickets. Is it correct?`);
});