User-defined slots (static)¶
In Alan AI, 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 $
character followed by brackets ()
. In brackets, define the slot name 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 providing possible slot values, you can use the same rules as with patterns. You can:
List multiple alternatives separated with the
|
delimiter.Make slots optional by adding another
|
delimiter at the end of the slot.
intent('What (is|was|would be) the weather $(D yesterday|today|tomorrow|)', p => {
p.play('It is great!');
});
The list of values in user-defined slots is static: it remains intact for the whole dialog session. If you need to update the slot values during the dialog, for example, with the data obtained from an external source, use dynamic slots in patterns:
onCreateUser(p => {
p.userData.contacts = {en:"Anna|Emma|John|Mark"};
});
intent('Show details for $(CONTACT u:contacts)', p => {
p.play(`Getting contact details for ${p.CONTACT.value}`);
});
Slot values and labels¶
A slot 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 an intent with the slot is matched. This field contains the captured user’s input.
In the example below, the user’s input is displayed in the Alan AI logs and pronounced by Alan AI as a response.
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!');
});
The .label
field can be used to provide any description, identify or classify the 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 ~
character followed by the label value to the 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, labels are used 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 AI 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, that is, offset in backticks.
You can also add slot values 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!');
}
});
Slots with fuzzy matching¶
By default, to match an intent with a slot with the highest score, Alan AI requires that the user’s input contains the exact slot value. However, it is not always possible to specify all variants of values for a slot. For example, values can contain word groups with variable word order, some words in the input phrase may be replaced with synonyms or there can be values that are hard to pronounce.
To allow Alan AI to match intents with slots whose values may be less than perfect, you can use slots with fuzzy matching. In this case, Alan AI matches the intent based on the most similar alternative. Alan AI relies on the semantic meaning, even if it does not coincide exactly with what the user has said.
Warning
Slots with fuzzy matching should be used with caution, as they can lead to overly general matching.
To define a slot with fuzzy matching, add the ~
character after the slot name. As well as for other user-defined slots, you can accompany each value with a label. In this case:
The
.value
field of the slot will contain the user’s input exactly as user has said it, not the value you have defined in the script.The
.label
field of the slot can have any value and can be used, for example, to give a proper response to the user.
In the example below, the intent will be matched even if the user skips a part of the item name or names a close variant instead. And to ensure proper verbiage, the slot label is played instead of the slot value in the confirmation phrase.
intent('I want a $(ORDER~ Double Cheese Burger~Cheese Burger|Spicy Mexican Burger~Mexican Burger|Grilled Hawaiian Burger~Hawaiian Burger)', p => {
console.log(`Your choice is ${p.ORDER.value}`);
p.play(`You have ordered ${p.ORDER.label}. Is it correct?`);
});
Multiple values in slots¶
If you need to capture multiple slot values at once, you can add a slot to a pattern several times. When such an intent is matched, all pieces of data captured with the slot are collected to an array of values.
In such a case, p.SLOTNAME.value
would contain only the value captured with the first slot instance in the pattern.
To access the list of all values in the array, use the slot name followed by the underscore character, for example:
p.SLOTNAME_
.To access a specific element in the array, add the element index, for example:
p.SLOTNAME_[0].value
.
Each element in the array has its own .value
and .label
fields:
The
value
field is populated with the value obtained from the user’s input:p.SLOTNAME_[index].value
.The
label
field can contain a custom value and can be used to give more accurate responses to the user:p.SLOTNAME_[index].label
.
Let’s assume we want to provide the user with the ability to ask about the price of different pizza sizes with one command. We can add the following intent:
const SHOW_REQ = 'How much is a $(D small|medium|large) pizza';
const ALL_REQ = [
`${SHOW_REQ}`,
`${SHOW_REQ} and ${SHOW_REQ}`,
`${SHOW_REQ} and ${SHOW_REQ} and ${SHOW_REQ}`,
]
intent(ALL_REQ, p => {
console.log(JSON.stringify(p.D));
console.log(JSON.stringify(p.D_));
let resultMessage = "";
if(p.D_[0]) {
resultMessage = playSizeMessage(p.D_[0].value);
p.play(resultMessage);
}
if(p.D_[1]) {
resultMessage = playSizeMessage(p.D_[1].value);
p.play(resultMessage);
}
if(p.D_[2]) {
resultMessage = playSizeMessage(p.D_[2].value);
p.play(resultMessage);
}
})
function playSizeMessage(theSize) {
if (theSize == "small") {
return "A small pizza is 5 dollars";
}
if (theSize == "medium") {
return "A medium pizza is 10 dollars"
}
if (theSize == "large") {
return "A large pizza is 15 dollars"
}
}
Here, we use SHOW_REQ
to define a question the user will ask: How much is a $(D small|medium|large) pizza?
In ALL_REQ
, we provide all possible combinations for this question. For example, the user can ask:
How much is a small pizza?
How much is a small pizza and how much is a large pizza?
How much is a small pizza and how much is a medium pizza and how much is a large pizza?
When the user asks one of the questions above, we collect all captured values for the D
slot to an array and then play the pizza price for each element in the array with the playSizeMessage()
function.
Slot name limitations¶
Mind the following limitations for user-defined slot names:
User-defined slot names must start with a letter.
You can use the following characters in user-defined slot names:
A-Z
,a-z
,0-9
and underscore(_)
.Predefined slot names are reserved and cannot be used as user-defined slot names.
User-defined slot cannot start with one of the predefined slot names. For example,
NAMECUSTOM
will result in an error, whileCUSTOMNAME
will be a valid variant.