Hey all,
we are always trying to improve the way you can build your voice applications with the Jovo Framework, and although speech recognition and natural language understanding (nlu) work very well in many cases, false matches for user input can still happen.
This is why we want to introduce a new feature proposal called Input Validation and want to hear your opinions on this topic, what is to be improved on the current design implementation and what you would like to see added to this!
Problem
We encountered some problems with false input matching internally, where validation as a feature in some form would’ve been very helpful. For example, we built an Alexa Skill that was dependent on a custom slot which was only allowed to hold four values, otherwise we wanted the skill to reprompt the user.
In another case we needed the Alexa-built-in slot “AMAZON.DE_CITY” to recognize different German cities, but noticed that sometimes it understood “Wedding” (a district of Berlin) instead of Berlin itself. We noticed this for other cities as well, on both Alexa and Google Assistant/Dialogflow.
Current Solution
Due to the lack of this feature so far, we needed to solve these problems manually.
Take the first issue for example. If we generalized this to an intent, that only accepts four car brands, we would need to check the inputs for these values manually like so:
// app.js
CarBrandIntent() {
if(['Ford', 'Mercedes', 'Ferrari', 'Mini'].indexOf(this.$inputs.car.value) === -1) {
// If input contains car brands apart from the specified ones, go to Unhandled intent
return this.toIntent('Unhandled');
}
// continue with intent
}
For the second example, a simplified manual solution would look like this:
// app.js
CityIntent() {
let city = this.$inputs.city.value;
switch(city) {
case 'Wedding': city = 'Berlin';
break;
case 'Maunheim': city = 'Mannheim';
break;
}
// continue with intent
}
Implementation Proposal
To solve these and more input matching issues, we want to introduce a new field validation
to the app configuration in config.js
.
// config.js
validation: {
ExampleIntent: {
input1: new ValidValuesValidator(['valid1', 'valid2'], 'Unhandled'),
input2: [
new IsRequiredValidator(),
{
validate() {
if(this.$inputs.input2.value === 'test') {
this.toIntent('Unhandled');
}
}
}
],
input3: function() {
// validate
}
}
}
validation
will contain pre-defined validators or your own validation functions for specified intents and inputs. Since the configuration file is written in Javascript, you can also choose to import these from other files.
The idea is to assign a number of validators to the input that is to be validated. This is possible by assigning a single validator to your input name, as well as an array or a function.
// validation
ExampleIntent: {
input1: [
// Pre-defined validators
new ValidValuesValidator(), // define values the current input is allowed to adopt
new InvalidValuesValidator(), // define values the current input is not allowed to adopt
new IsRequiredValidator(), // fails if current input is not present in this.$inputs
new ReplaceValuesValidator() // replace all values for current input with a specified one
]
}
Each validator accepts a number of parameters, depending on its functionality. For example, the ValidValuesValidator
accepts an array of strings, that it will match the input against. Another parameter will be the handler. If the validation fails, for this instance the input has a value that is not valid against the specified values, the validator will redirect the user to this handler. It can consist of an intent name and an optional state.
// validation
ExampleIntent: {
input1: [
new ValidValuesValidator(
[
'validValue1',
'validValue2'
],
'Unhandled', // handler, optionally 'STATE.handler'
)
]
}
Aside from the pre-defined validators, you can also choose to define your own validator. All you need is a validate()
function, which is the core function of all validators. The scope is the same as in your intents, so this
will have the same functionality.
// validation
ExampleIntent: {
input1: [
{
validate() {
if(this.$inputs.input1.value === 'test') {
return this.toIntent('Unhandled');
}
}
}
]
}
The same goes for assigning your own function.
// validation
ExampleIntent: {
input1: function() {
if(this.$inputs.input1.value === 'test') {
return this.toIntent('Unhandled');
}
}
}
This is just a quick overview of what we think could be achieved with this feature and how it could exist in the configuration file.
But we are eager to hear your opinions and ideas on this, so please feel free to comment on this topic!