Dynamic slots¶
The dynamic slots concept is similar to regular user-defined slots. You can add them to patterns to capture important pieces of data from the user’s input. However, regular user-defined slots are static. After the dialog model for your AI assistant has been built, their values cannot be updated.
Dynamic slots, instead, are adaptive. Use them if you need to update values on a more frequent basis, for example, get them from your database, with an API call or alter them based on what the user has said. Whenever the values for dynamic slots are updated, Alan AI rebuilds the dialog model at runtime, without restarting the dialog session, which makes the user’s experience more flexible and personalized.
Consider the following example:
intent('Show $(FAVORITE flannel shirt|fleece jacket|softshell pants)', p => {
p.play(`Opening the ${p.FAVORITE.value} page`);
});
Here, the favorites list remains static and cannot be altered after the dialog model has been built. If we replace it with a dynamic slot, it will be possible to alter the favorites list in runtime. The user will be able to add a new item to the list with the first command and then give the second command to access the added item immediately.
onCreateUser(p => {
p.userData.favorites = {en: "flannel shirt|fleece jacket|softshell pants"};
});
intent('Add $(ITEM* .+) to favorites', p => {
p.userData.favorites.en += '|' + p.ITEM.value;
console.log(p.userData.favorites.en);
p.play(`${p.ITEM.value} is added`);
});
intent('Show $(FAVORITE u:favorites)', p => {
p.play(`Opening the ${p.FAVORITE.value} page`);
});
For more details on this example, see Updating dynamic slot values with voice and text commands.
Defining dynamic slots¶
You can define dynamic slots in different ways:
With the
project
global object if dynamic slots must be accessible globally at the project level.With the
userData
object if dynamic slots must be accessible within the user dialog session.With
visualState
if values of dynamic slots are passed from the client app.
Defining dynamic slots at the project level¶
A dynamic slot defined at the project level can be accessed by all users interacting with the AI assistant. Use this type of dynamic slots to work with generic data that must be available to all app users.
To define a dynamic slot at the project level, save the values of the dynamic slot to the project global object. To add such a dynamic slot to patterns, specify the $
sign followed by brackets ()
.
In brackets, specify the slot name followed by p:variablename
.
In the example below, values of a dynamic slot are saved to the project.movies
variable when the onCreateProject callback is invoked, and $(MOVIE p:movies)
is added to the pattern.
Note
Note that values in the project
object are stored in the language key: en
. Always follow this pattern to be able to properly update the dynamic slot values later when needed. For details, see Updating dynamic slot values with voice and text commands.
onCreateProject(() => {
project.movies = {en: "Sergio|Valley Girl|All Day and a Night|The Half of It"};
});
intent('When is $(MOVIE p:movies) on?', p => {
p.play(`Let me check the showtime for ${p.MOVIE.value}`);
});
Defining dynamic slots at the dialog session level¶
A dynamic slot defined at the dialog session level can be accessed only by the user interacting with the AI assistant during the current dialog session. Use this type of dynamic slots to work with user-specific and user-sensitive information, for example, to handle the data that differs depending on the user logged in to the system.
Values of such dynamic slots exist only while the dialog session is running. After the session ends or the user reconnects to the app in another session, all data stored in such dynamic slots is removed.
To define a dynamic slot at the dialog session level, save the values of the dynamic slot to the userData object. To add such a dynamic slot to patterns, specify the $
sign followed by brackets ()
.
In brackets, specify the slot name followed by u:variablename
.
In the example below, values of a dynamic slot are saved to the p.userData.contacts
variable when the onCreateUser callback is invoked, and $(CONTACT u:contacts)
is added to the pattern.
Note
Note that values in the userData
object are stored in the language key: en
. Always follow this pattern to be able to properly update the dynamic slot values later when needed. For details, see Updating dynamic slot values with voice commands.
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}`);
});
Passing dynamic slot values from the app¶
You can define dynamic slots with the help of the visual object. This type of dynamic slots can be helpful if you need to handle data sent from the app to the dialog script. In this case, you can pass the necessary data in the visual
object, access this data through the keys of the passed object and save it to a dynamic slot.
To add such a dynamic slot to patterns, specify the $
sign followed by brackets ()
. In brackets, specify the dynamic slot name followed by v:variablename
.
Let’s assume you need to pass menu items from the app to the dialog script to use them in a dynamic slot. You can send the item list to the dialog script with the setVisualState() method. In the script, you can join the passed values, save the result to p.visual.menu
when the onVisualState callback is invoked, and add $(ITEM v:menu)
to the pattern.
onVisualState((p, s) => {
if (s.values) {
p.visual.menu = { en: ""};
p.visual.menu.en = s.values.join('|');
}
});
intent('Give me a $(ITEM~ v:menu)', p => {
p.play(`Adding one ${p.ITEM.value} to your order`);
});
Note
Note that values in the visual
object are stored in the language key: en
. Always follow this pattern to be able to properly update the dynamic slot values later when needed. For details, see Updating dynamic slot values with voice and text commands.
Updating dynamic slot values with voice and text commands¶
You can not only get dynamic slots values from external sources, but also alter them with voice and text commands. In the example below, the shopping list is extended when the user gives a command to add a specific item. The resulting string of slot values is then logged to the console.
onCreateUser(p => {
p.userData.shopping = {en: "coffee|sugar|honey"};
});
intent('Do I need $(SHOP~ u:shopping)?', p => {
p.play(`${p.SHOP} is in the shopping list`);
});
intent('Add $(ITEM* .+)', p => {
p.userData.shopping.en += '|' + p.ITEM.value;
p.play(`${p.ITEM.value} is added`);
console.log(p.userData.shopping.en);
});
Note
Dynamic slot values are saved by language keys, for example: {en: "coffee|sugar|honey"}
, where en
denotes the current AI assistant language. When you update the values list, make sure you save data in the language key as shown in the example above.
Capturing several values with dynamic slots¶
You can add the same dynamic slot to the pattern several times, just like regular user-defined slots. When such an intent is matched, all pieces of data captured with this dynamic slot are collected to an array of values.
To access the list of all values in the array, use the dynamic slot name followed by the underscore character, for example:
p.SLOTNAME_
.To access a specific element in the array, specify the element index, for example:
p.SLOTNAME_[0].value
.
Let’s say you want the user to filter the list of products by brand. You can add the following command to the script:
onCreateProject(() => {
project.BRANDS = {en: "Apple|Asus|Microsoft|Samsung"};
});
intent('Show me $(B p:BRANDS) (and|or|) $(B p:BRANDS|) (and|or|) $(B p:BRANDS|)', p => {
p.play('Getting the products list');
});
As in regular slots, in dynamic slots each element in the array has its own .value
and .label
fields:
The
value
field is populated with values obtained from the user’s input. To access thevalue
field, refer to it in the following way:p.SLOTNAME_[index].value
. In the example above, to access the value of the first element in the brands array, usep.B_[0].value
.The
label
field can contain custom values and can be used to give more accurate responses to the user. To access thelabel
field, refer to it in the following way:p.SLOTNAME_[index].label
. In the example below, to access the label of the first element in the brands array, usep.B_[0].label
.
onCreateProject(() => {
project.BRANDS = {en:"Apple~ios|Asus~android|Microsoft~win|Samsung~android"};
});
intent('Show me $(B p:BRANDS) (and|or|) $(B p:BRANDS|) (and|or|) $(B p:BRANDS|)', p => {
p.play('Getting the products list');
console.log(p.B_[0].label);
console.log(p.B_[0].value);
});
Defining dynamic slots with a short form¶
To define dynamic slots, you can use a short form, without the name preceding the slot variable, for example:
$(p:ITEM)
$(u:ITEM)
$(v:ITEM)
You can refer to the value captured with such a dynamic slot through the slot name: p.ITEM
and p.ITEM.value
.
Warning
When working with short forms, save patterns with dynamic slots to a variable and use it for the command pattern. Short forms added directly to the command pattern are not supported at the moment.
In the example below, the p:ORIGIN
dynamic slot is used to capture the movie origin:
onCreateProject(p => {
project.ORIGIN = {en:"Italian|American|French|German"};
});
const REQUEST = [
"(Do you have|Find|Show me|I'm looking for) (the|) (best|top rated|popular|good) $(p:ORIGIN) movies, (please|)",
"What are (the|) (best|top rated|popular|good) $(p:ORIGIN) movies?",
];
intent(REQUEST, p => {
p.play(`Here is the list of top rated ${p.ORIGIN.value} movies`);
});
Making dynamic slots optional¶
As well as regular user-defined slots, dynamic slots can be optional. To mark a dynamic slot as optional, add the vertical bar |
at the end of it. Both regular dynamic slots and dynamic slots defined with a short form can be made optional.
onCreateProject(p => {
project.ORIGIN = {en:"Italian~Italy|American~U.S.|French~France|German~Germany"};
});
const REQUEST = [
"(Do you have|Find|Show me|I'm looking for) (the|) (best|top rated|popular|good) $(p:ORIGIN|) movies, (please|)",
"What are (the|) (best|top rated|popular|good) $(p:ORIGIN|) movies?",
];
intent(REQUEST, p => {
let pattern = "Here is a list of top rated movies";
if (p.ORIGIN && p.ORIGIN.value) {
pattern += ` from ${p.ORIGIN.label}`;
}
p.play(pattern);
});
Using fuzzy matching with dynamic slots¶
You can enable fuzzy matching for dynamic slots. Fuzzy matching can be used both with regular dynamic slots:
onCreateProject(p => {
project.DRINKS = {en:"kentucky bourbon ale~kentucky bourbon ale|imperial lager beer~imperial lager beer|peche stout beer~peche stout beer|amber lager beer~amber lager beer"};
});
intent('Get me $(BEER~ p:DRINKS)', p => {
p.play(`Sure, here is your ${p.BEER.label}`);
});
and dynamic slots defined with a short form:
onCreateProject(p=> {
project.DRINKS = {en:"kentucky bourbon ale~kentucky bourbon ale|imperial lager beer~imperial lager beer|peche stout beer~peche stout beer|amber lager beer~amber lager beer"};
});
const REQUEST = [
'Get me $(~ p:DRINKS), (please|)',
'Is $(~ p:DRINKS) on the menu?'
];
intent(REQUEST, p => {
p.play(`Sure, here is your ${p.DRINKS.label}`);
});
See also¶
Tutorial: Using dynamic slots in patterns
dynamic entities oncreateproject() oncreateuser() oncleanupuser() onvisualstate()