Asking for a Name
Note: This is material for Rasa 2.x. The syntax has updated slightly in Rasa 3.0 so we recommend new users to check the new course found here.
In this lesson we'll expand our understanding of forms by writing one that's highly customised. We will make a dynamic form that will also generate buttons on our behalf.
Video
Install
If you don't have it installed already, be sure that you install Rasa X first. You can install it locally via pip.
pip install rasa-x --extra-index-url https://pypi.rasa.com/simple
If you appreciate more guidance, we've also gotten installation videos for Rasa X.
Windows Installation
MacOS Installation
Ubuntu Installation
Code
Most of the magic of this demo is handled in the actions.py
file. Primarily
we're using the required_slots
method to indicate which slots are required
at a given point in the form.
async def required_slots( self, slots_mapped_in_domain: List[Text], dispatcher: "CollectingDispatcher", tracker: "Tracker", domain: "DomainDict",) -> Optional[List[Text]]: first_name = tracker.slots.get("first_name") if first_name is not None: if first_name not in names: return ["name_spelled_correctly"] + slots_mapped_in_domain return slots_mapped_in_domain
The idea here is that if we see a name that doesn't appear in our predefined name list that
we'll add another required slot. This required slot will allow us to double-check if the user
spelled their name correctly. The way we ask for this slot is defined in our domain.yml
file.
responses: utter_ask_name_spelled_correctly: - buttons: - payload: /affirm title: Yes - payload: /deny title: No text: Is {first_name} spelled correctly?
The payload of the buttons carry an intent. The buttons can either trigger the affirm
or deny
intent. These intents can then be extracted by our custom code
and be picked up by our validators.
def extract_name_spelled_correctly( self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict) -> Dict[Text, Any]: # Explained in more detail on our docs. # https://rasa.com/docs/rasa/forms#custom-slot-mappings intent = tracker.get_intent_of_latest_message() return {"name_spelled_correctly": intent == "affirm"}
def validate_name_spelled_correctly( self, slot_value: Any, dispatcher: CollectingDispatcher, tracker: Tracker, domain: DomainDict,) -> Dict[Text, Any]: """Validate `first_name` value.""" if tracker.get_slot("name_spelled_correctly"): return { "first_name": tracker.get_slot("first_name"), "name_spelled_correctly": True } return {"first_name": None, "name_spelled_correctly": None}
Here's the great trick: by dynamically adding a slot value we're able able to invalidate
the first_name
slot if the user indicates that they'd like to see a correction.
Links
Exercises
Try to answer the following questions to test your knowledge.
- You can generate buttons by defining it as a response in the
domain.yml
file. How can you configure a response to trigger an intent? - When buttons are generated for the user, does that mean they cannot speak to the assistant anymore?
- What does it mean when a form validator has a method called
extract_<slot_name>
? What are these methods meant for?