Rasa Quizbot - Setting Up Responses (Part 1)
Rasa can be a bit daunting to develop with at first. As a developer, you need to learn where the different parts of the chatbot go and how they relate. In this article, we’ll build a quiz chatbot using Rasa. The chatbot will help students practice their addition skills, so we’ll call it Addy. It will take the user’s name, allow them to choose a quiz difficulty, give them their quiz results, and send results to a learning record store using xAPI for an instructor to review. Below is a diagram of how the chatbot will work. Along the way, we’ll get experience with a number of Rasa’s features.
This article assumes you have a rasa environment set up and starter project created by using rasa init. If you don’t have these yet, no worries. Check out this article that introduces Rasa and how to set up a development environment. As you work through the article, if you get stuck, you can review the source code for this part of the project.
First we need to clean up the files from the starter project rasa init generated. Do the following:
Remove from domain.yml
Intents: mood_great, mood_unhappy, bot_challenge
utter_cheer_up
utter_did_that_help
utter_happy
utter_iamabot
Remove from stories.yml
sad path 1
sad path 2
Remove mood_great and utter_happy from the happy path story
Remove from nlu.yml
mood_great
mood_unhappy
bot_challenge
Remove from rules.yml
bot_challenge
With that out of the way, we’ll get started by adding the responses Addy will give to users. These responses live in the domain.yml file. Noticed that we changed utter_greet and utter_goodbye to match our bot’s purpose a bit better. Update the domain.yml file with the utterances below.
responses:
utter_greet:
- text: "Hey, I'm Addy! I'm here to help you practice addition."
utter_purpose:
- text: "I offer quizzes that can help you practice your skills."
utter_name:
- text: "Before we get started, could you tell me your name?"
utter_quiz_level:
- text: "Thanks. What level quiz would you like to take - beginner or advanced?"
utter_quiz_finished:
- text: "Great! You've answered all the questions."
utter_quiz_retake:
- text: "Would you like to take another quiz?"
utter_goodbye:
- text: "Bye. Come back any time to practice."
Now we’ll move over to the stories.yml file. We need to update happy path. Change the happy path to reflect the new utterances we added. Notice that the utterances are in the same order as were listed in domain.yml. You don’t have to keep the order consistent across files, but it can help you manage and work with dialogue when you keep the parts of the conversation in a consistent order across files. It also helps you find specific dialogue when you arrange things in order of your expected conversation flow.
stories:
- story: happy path
steps:
- intent: greet
- action: utter_greet
- action: utter_purpose
- action: utter_name
- action: utter_quiz_level
- action: utter_quiz_finished
- action: utter_quiz_retake
- action: utter_goodbye
So far, our chatbot just responds with information. If we were to run our bot, a user would say hi and then Addy would rattle off all the responses we’ve prepared. That’s not very interesting for our user. Let’s add in a bit of interactivity with a simple form. We’ll collect the user’s name and then use that name in a response.
In domain.yml, we need to add a forms section. Rasa forms collect information from the user and save that information into slots. This allows a bot to use the information later in utterances or even to change the conversation path. Our first form will be name_form, and it will save the user’s name to the slot name. The from_text setting means the bot should expect to capture a text value from the user’s response.
forms:
name_form:
required_slots:
name:
- type: from_text
Even though we included the slot name in our form, we haven’t actually defined it yet. In domain.yml, we still need to create a slots section. In this section, we define the settings for the slot. Our name slot will receive a text value, so we use TextSlot. Rasa has several other slot types you can use. The RasaDocs have a list of these and the different settings they require. In this case, we can’t provide an initial_value because we don’t know the user’s name. Also, the user’s name doesn’t have any bearing on the rest of the conversation, so influence_conversation is false. This attribute will be especially important when we are working with stories later.
slots:
name:
type: rasa.shared.core.slots.TextSlot
initial_value: null
auto_fill: true
influence_conversation: false
To prompt the user to tell their name, we need to set up a response. The name of this response is important. The keyword “ask” indicates that the utterance is part of a form. What comes after ask, in this case “name”, references the slot the form fills. These have to match. By following this naming scheme, Rasa will know to use the utterance when the form starts and tries to collect this slot value.
Our utterance is almost right, but we need to add “ask” to the utterance name.
utter_ask_name:
- text: "Before we get started, could you tell me your name?"
Now that we have set up the form and the value it will fill, we should use that value in our conversation. In the domain.yml file, modify utter_quiz_types and utter_quiz_finished to use the person’s name by calling the slot value in brackets.
utter_quiz_level:
- text: "Thanks, {name}. What level quiz would you like to take - beginner or advanced?"
utter_quiz_finished:
- text: "Great, {name}! You've answered all the questions in the quiz."
The last thing we need to do is add our form to the happy path story in stories.yml. We will replace action: utter_name with the following three lines:
- action: name_form
- active_loop: name_form
- active_loop: null
So our happy path should look like this. The active loop references the life of the form – from the time name_form starts until it no longer has slots to ask about.
stories:
- story: happy path
steps:
- intent: greet
- action: utter_greet
- action: utter_purpose
- action: name_form
- active_loop: name_form
- active_loop: null
- action: utter_quiz_level
- action: utter_quiz_finished
- action: utter_quiz_retake
- action: utter_goodbye
Before we start our model, we need to set up the configuration. Uncomment the settings in config.yml, except the UnexpecTEDIntentPolicy.
language: en
pipeline:
- name: WhitespaceTokenizer
- name: RegexFeaturizer
- name: LexicalSyntacticFeaturizer
- name: CountVectorsFeaturizer
- name: CountVectorsFeaturizer
analyzer: char_wb
min_ngram: 1
max_ngram: 4
- name: DIETClassifier
epochs: 100
constrain_similarities: true
- name: EntitySynonymMapper
- name: ResponseSelector
epochs: 100
constrain_similarities: true
- name: FallbackClassifier
threshold: 0.3
ambiguity_threshold: 0.1
policies:
- name: MemoizationPolicy
- name: RulePolicy
- name: TEDPolicy
max_history: 5
epochs: 100
constrain_similarities: true
Now, type rasa train to build the bot’s model. It may take a long time, especially since this is the first time. Once Rasa finishes the training, type “rasa shell.” You will be able to chat with the bot.
The bot’s not very capable now. Nonetheless, you can see all the utterances we’ve created so far. Also, Addy captures and uses the user’s name. Great stuff!
We’ve built one form. However, Addy still needs more forms to fulfill its purpose as a quiz bot – a quiz 1 form, a quiz 2 form, and a retake quiz form.
Project Code: Addy Quizbot - Step 2
If you’d like to practice the skills in this article more, try to add a form that asks the user to provide their email.
Continue on to the next article to take a deep dive into forms and to continue developing our Addy chatbot.