Form Validation

Users will sometimes give us information that is invalid. That's why Rasa allows you to validate data before it is stored in a slot.

Video


Code

You can validate slot values by writing a special type of custom action. The custom action that handles the validation in the video is shown below.

from typing import Text, List, Any, Dict
from rasa_sdk import Tracker, FormValidationAction
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.types import DomainDict
def clean_name(name):
return "".join([c for c in name if c.isalpha()])
class ValidateNameForm(FormValidationAction):
def name(self) -> Text:
return "validate_name_form"
def validate_first_name(
self,
slot_value: Any,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: DomainDict,
) -> Dict[Text, Any]:
"""Validate `first_name` value."""
# If the name is super short, it might be wrong.
name = clean_name(slot_value)
if len(name) == 0:
dispatcher.utter_message(text="That must've been a typo.")
return {"first_name": None}
return {"first_name": name}
def validate_last_name(
self,
slot_value: Any,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: DomainDict,
) -> Dict[Text, Any]:
"""Validate `last_name` value."""
# If the name is super short, it might be wrong.
name = clean_name(slot_value)
if len(name) == 0:
dispatcher.utter_message(text="That must've been a typo.")
return {"last_name": None}
first_name = tracker.get_slot("first_name")
if len(first_name) + len(name) < 3:
dispatcher.utter_message(text="That's a very short name. We fear a typo. Restarting!")
return {"first_name": None, "last_name": None}
return {"last_name": name}

The ValidateNameForm class implements the validation methods for the slots in the name_form. Note the naming conventions that are used in the class.

  • The name-method returns the name of the validator and it uses the

validate_<formname> naming convention.

  • There are two methods that check for slot values and they also adhere

to a naming convention validate_<slotname>. These methods will only check the slotnames for the name_form-form because these methods are part of a FormValidationAction.

If you want to invalidate a slot you need to return a dictionary that sets a name of a slot to None. It's usually a good idea to attach a user message when this happen so you can let the user know that something went wrong.

if len(slot_value) <= 2:
dispatcher.utter_message(text=f"That's a very short name. I'm assuming you mis-spelled.")
return {"first_name": None}
else:
return {"first_name": slot_value}

Protip

You can totally add a print-statement to the custom action if that helps you debug the custom action. In production you'll want to likely remove the print statement but it's highly recommended when you're just starting out.

Links

Exercises

Try to answer the following questions to test your knowledge.

  1. What is the naming convention used to name the method that will a slot in a FormValidationAction?
  2. What do you need to return if you want to invalidate a slot?
  3. Can you invalidate multiple slots at once in a validator?

2016-2022 © Rasa.