Entities
Learn how to access entities and configure dynamic entities using Jovo.
Introduction
Entities are variable elements of an intent that can be defined in a model and retrieved by a platform or NLU integration.
For example, a user saying "my name is max" could result in a MyNameIsIntent
with the entity name
being filled with max
. Here is what the corresponding $input
object could look like:
{ type: 'INTENT', intent: 'MyNameIsIntent', entities: { name: { value: 'max', }, }, }
Depending on if the information is coming from a platform directly, or from an NLU integration, the entities
can either be found in the root of the $input
object or inside an nlu
property. Jovo offers a convenience property this.$entities
to access entities:
this.$entities.entityName // Example someHandler() { // ... const name = this.$entities.name!.value; // Result: max }
There are also two additional sections with examples for accessing entities:
- Slot filling shows how to collect entity values by delegating to subcomponents
- Entity validation shows how entity values can be checked using the
@Handle
decorator
Usually, entities and their entity types are defined in the Jovo Model. Learn more about entity types here.
{ "entityTypes": { "myCityEntityType": { "values": ["Berlin", "New York"] } } // ... }
The downside of this is that the trained models are static and can't be dynamically updated, e.g. by using data from an API call. Jovo offers a concept called dynamic entities to update entity values during runtime.
Access Entities
You can access the complete object of entities with this.$entities
, and a specific entity by its name, this.$entities.entityName
.
this.$entities.entityName // Example someHandler() { // ... const color = this.$entities.color!.value; }
Each entity is an object that contains the following information:
{ value: 'entityValue', resolved: 'mappedEntityValue', id: 'entityValueId', native: { /* ... */ } }
value
: The (raw) value retrieved from the user input.resolved
: If the entity value was a synonym, the "main" value of the language model will be provided here. If there is no resolved value, this will default tovalue
.id
: Some platforms and NLUs provide the possibility to add IDs to their entity values. If there is no ID available, theid
will be the same asresolved
.native
: For platforms that support additional entity features, the raw entity data of the API response will be stored here.
For example, if we have a city
entity type in our model that includes the following for New York
:
"myCityEntityType": { "values": [ { "value": "New York", "id": "nyc", "synonyms": [ "New York City", "NYC", "n. y. c." ] } ] }
If a user said something like I live in new york
, the values would be the following:
{ value: 'new york', resolved: 'New York', id: 'nyc', }
In general, we recommend using the resolved
property because the value
can be ambiguous and might even include typos on text-based platforms.
Slot Filling
Often, it is necessary to capture multiple entity values for a specific task. For example, a table reservation at a restaurant might need the following:
numberOfPeople
: The amount of seats to be reservedtime
: For when the reservation should be made
The process of retrieving these values is also called slot filling. Learn more in this introduction to dialogue management.
We recommend retrieving and validating entities in designated components. The example below includes the following:
- A
ReservationComponent
that is responsible for handling everything related to reservations. - It imports a
CollectReservationDataComponent
and adds it as subcomponent. - A
global
handler that reacts to aReservationIntent
(for example, if a user says "I want to make a reservation"). - This handler then uses
$delegate
to let theCollectReservationDataComponent
handle the slot filling. - If the
CollectReservationDataComponent
resolves withsuccess
, themakeReservation
handler will be called.
// src/components/ReservationComponent.ts import { Component, BaseComponent, Handle } from '@jovotech/framework'; import { CollectReservationDataComponent } from './CollectReservationDataComponent'; @Component({ components: [CollectReservationDataComponent], }) class ReservationComponent extends BaseComponent { @Handle({ global: true, intents: ['ReservationIntent'], }) collectReservationData() { return this.$delegate(CollectReservationDataComponent, { resolve: { success: this.makeReservation, // ... }, }); } makeReservation(data) { // ... } }
The CollectReservationDataComponent
could include the following:
- It prompts the user for data input in the
START
handler. - It has handlers for each intent that are used to collect and validate entities for this task.
- It then uses
$resolve
to send the data back to theReservationComponent
.
A simple example could be just a single entity that needs to be collected. Here, the $resolve
could be called right in the collectNumberOfPeople
handler:
// src/components/CollectReservationDataComponent.ts import { Component, BaseComponent, Intents } from '@jovotech/framework'; @Component() class CollectReservationDataComponent extends BaseComponent { START() { return this.$send('How many people should we expect?'); } @Intents(['NumberIntent']) collectNumberOfPeople() { if (this.$entities.$number) { return this.$resolve('success', this.$entities.$number.resolved); } // ... } }
If you need to collect more data, it is advisable to store all collected entities in the component data and then manually check if all slots are filled. A few more examples for this can be found in the entity validation section.
If all data is collected, you could call a success
handler. If not, you could prompt for additional entities.
// src/components/CollectReservationDataComponent.ts import { Component, BaseComponent, Intents } from '@jovotech/framework'; @Component() class CollectReservationDataComponent extends BaseComponent { START() { return this.$send('How many people should we expect?'); } @Intents(['NumberIntent']) collectNumberOfPeople() { this.$component.$data.numberOfPeople = this.$entities.$number!.resolved; // ... } success() { return this.$resolve('success', this.$component.$data); } }
You can access the data in the makeReservation
handler of the ReservationComponent
:
// src/components/ReservationComponent.ts import { Component, BaseComponent } from '@jovotech/framework'; import { CollectReservationDataComponent } from './CollectReservationDataComponent'; @Component({ components: [CollectReservationDataComponent], }) class ReservationComponent extends BaseComponent { // ... makeReservation(data) { // ... } }
Entity Validation
You can use the if
property of the @Handle
decorator to check if certain entities are set or have a specific value.
For example, if a ReservationDataIntent
allows the user to fill multiple slots at once ("for 3 people at 6pm"), you can make sure if the entity values are set like this:
// This handler is used if all entities are filled successfully @Handle({ intents: ['ReservationDataIntent'], if: (jovo) => jovo.$entities.numberOfPeople && jovo.$entities.time }) confirmReservation() { // ... } // This handler is used to prompt for a missing entity @Handle({ intents: ['ReservationDataIntent'], if: (jovo) => jovo.$entities.numberOfPeople === undefined }) askForNumberOfPeople() { return this.$send('For how many people would you like to reserve a table?'); }
For readability, you can also take a look at imported decorators.
Dynamic Entities
Dynamic entities offer the ability to dynamically add values (e.g. from an API call) to entity types during runtime. Currently, this feature is supported by the following platforms and NLU services: Alexa, Google Assistant, Snips NLU.
You can add dynamic entities to the listen
property:
{ message: 'Which type of pizza do you like?', listen: { entities: { /* ... */ } } }
This will set listen
to true
and add dynamic entities to all platforms/NLUs that support that feature.
{ entities: { mode: 'REPLACE', // default types: { PizzaType: { values: [ { value: 'peperoni', synonyms: [ 'salami' ], // optional id: 'someId', // optional }, ], }, }, }, }
The following modes are supported:
REPLACE
: Only uses the new entitiesMERGE
: Supplements the new entities with existing onesCLEAR
: Deletes the dynamic entities