RASA - Creating forms
Tags: rasa, chatbot, nlp, ai
Published: 2021-03-11 17:38:48

## Forms
Forms are useful when an assistant needs to collect information from the user. For example, when a user wants to subscribe to a newsletter, the assistant must ask for their email address.
A form is a specific kind of custom action that contains the logic to loop over a set of required slots and ask the user for this information.

To use forms, you need to make sure that the **Rule Policy** is added to your policy configuration.

```yml
# config.yml
# ... previous content ...
policies:
- name: RulePolicy
```

The policy configuration is located in `config.yml`.
If you leave `policies` empty, the `RulePolicy` will be added automatically.

We will create a **newsletter_form**, that will be used to collect an **email** address from the user and **frequency** how often to send emails.

```yml
# domain.yml
# ... previous content ...
forms:
  newsletter_form:
    email:
      - type: from_text
    frequency:
      - type: from_text
```
Here we are creating a form named **newsletter_form**. This name is also the name of the action which we will use in stories to handle form executions.
Then we are saying that slots named **email** and **frequency** will be filled **from_text**.
But what is a slot? Let's learn about slots next.

## <a name="slots"></a> Slots
Slots are our chatbot's memory. They act as a key-value store which can be used to store information the user provided (e.g their email address) as well as information gathered about the outside world (e.g. the result of a database query).

Slots are defined in the slots section in our domain with their name, type and if and how they should influence the assistant's behavior.
The following example defines slots with name **email** and **frequency**, both having type **text**.
```yml
# domain.yml
# ... previous content ...
slots:
  email:
    type: text
    influence_conversation: false
  frequency:
    type: text
    influence_conversation: false
```
We are also saying that those slots don't influence the conversation with the `influence_conversation` property.
The way the slot influences the conversation will depend on its slot type. Here, the slot type is **text**, but there are other types like **bool**, **categorical**, **float**, **list**, **any** or you can even create your own slot type.

You can learn more about slot types in the [documentation](https://rasa.com/docs/rasa/domain#slot-types).
You can learn more about slots in the [documentation](https://rasa.com/docs/rasa/domain#slots) or in [my next article](https://dev.to/petr7555/rasa-slots-in-detail-3e85).

## Creating new intents
We need to create a new intent that will mean that a user wants to subscribe to a newsletter.
```yml
# data/nlu.yml
# ... previous content ...
  - intent: subscribe
    examples: |
      - I want to get the newsletter
      - Can you send me the newsletter?
      - Can you sign me up for the newsletter?
      - I want to subscribe to a newsletter.
```
We also need intents informing the chatbot about our email and how often we would like to receive emails.
```yml
# data/nlu.yml
# ... previous content ...
  - intent: inform_email
    examples: |
      - My email is example@example.com
      - random@example.com
      - Please send it to anything@example.com
      - Email is something@example.com

  - intent: inform_frequency
    examples: |
      - every week
      - once a week
      - twice per month
      - as ofter as possible
      - once a month
```
Don't forget to add these new intents to your `domain.yml` file
```yml
# domain.yml
# ... previous content ...
intents:
  - greet
  - mood_great
  - subscribe
  - inform_email
  - inform_frequency
```

## Responses
Now we need to add three new responses. First one will be chatbot asking about user's email address, second one will ask the frequency and the third one will be chatbot confirming the subscription.
```yml
# domain.yml
# ... previous content ...
responses:
  # ... previous responses ...
  utter_ask_email:
    - text: What is your email address?
  utter_ask_frequency:
    - text: How often do you want to receive emails from me?
  utter_subscribed:
    - text: You're all set! Check your inbox at {email} to confirm your subscription.
            You will receive emails {frequency}.
```
Notice that we are using the value of **email** and **frequency** slots in our response by putting the name of the slot in curly brackets.
Naming of **utter_ask_email** and **utter_ask_frequency** is important.
Once the form action gets called for the first time, the form gets activated and will prompt the user for the next required slot value. It does this by looking for a response called `utter_ask_<form_name>_<slot_name>` or `utter_ask_<slot_name>` if the former isn't found.

You can learn more about this in the [documentation](https://rasa.com/docs/rasa/forms#defining-a-form).

## Stories
Now, in order to connect users' intents with chatbot's responses, we have to write a story.
```yml
# data/stories.yml
# ... previous content ...
  - story: greet and subscribe
    steps:
      - intent: greet
      - action: utter_greet
      - intent: subscribe
      - action: newsletter_form
      - active_loop: newsletter_form
      - active_loop: null
      - action: utter_subscribed
```
First, user and chatbot exchange greetings.
Then, if user expresses the intent **subscribe**, **newsletter_form** is run by calling action of the same name: `- action: newsletter_form`. 
The `active_loop: newsletter_form` step indicates there is currently an active form.

A form will automatically deactivate itself once all required slots are filled (both email and frequency). You can describe your assistant's behavior for the end of a form with a rule or a story (we will learn about rules later on). If you don't add an applicable story or rule, the assistant will automatically listen for the next user message after the form is finished. But since we want to inform the user about the subscription details, we say that after the form is no longer active (`- active_loop: null`), an action **utter_subscribed** should follow. 

> `active_loop: null` step indicates that no form should be active before the subsequent steps are taken

You can learn more about form events in the [documentation](https://rasa.com/docs/rasa/stories#form-events).

Now run `rasa train && rasa shell` and try chatting with the chatbot.

![Chat session](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rrq0agkkv53gpogy10wm.png)

## Entities
On the image above you will notice that the chatbot considers the email to be our whole sentece informing him about our email, not just the email address itself.
To fix this, we will create an email entity.
Entities are structured pieces of information inside a user message. You can think of them as of keywords.
For entity extraction to work, we need to annotate those entities in our training data.
```yml
# data/nlu.yml
# ... previous content ...
  - intent: inform_email
    examples: |
      - My email is [example@example.com](email)
      - [random@example.com](email)
      - Please send it to [anything@example.com](email)
      - Email is [something@example.com](email)
```
We put the value of entity inside square brackets and follow it by the entity name in parentheses. The name of the entity is independent of our form slots.

Previously, we defined that slot **email** will be filled **from_text**. We will change this to **from_entity** now.

```yml
# domain.yml
# ... previous content ...
forms:
  newsletter_form:
    email:
      - type: from_entity
        entity: email
    frequency:
      - type: from_text
```
Below **type** key we specify from which entity the slot should be filled. In our case, it will be filled from entity **email**.

We also need to add all our entities to the `domain.yml` file.
```yml
# domain.yml
# ... previous content ...
entities:
  - email
```

You can learn more about entities in the [documentation](https://rasa.com/docs/rasa/nlu-training-data#entities).

Now, when you run `rasa train && rasa shell`, you can see that the chatbot finds the email in your answer.

![Chat session with email entity](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uo7e93hhywdm1vxg8rzm.png)

You can learn more about forms in the documentation [here](https://rasa.com/docs/rasa/forms) and [here](https://rasa.com/docs/rasa/training-data-format#forms).

In the next chapter, we will look at how we can test our form and replace some of our stories by rules.

Repository for this tutorial:
{% github petr7555/rasa-dev-tutorial no-readme %}

You can checkout the state of the repository at the end of this tutorial by running:
```bash
git clone --branch 03-creating-forms git@github.com:petr7555/rasa-dev-tutorial.git
```