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, FormValidationActionfrom rasa_sdk.executor import CollectingDispatcherfrom 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.
- What is the naming convention used to name the method that will a slot in a
FormValidationAction
? - What do you need to return if you want to invalidate a slot?
- Can you invalidate multiple slots at once in a validator?