Yashi Saxena — February 3, 2022
Advanced Artificial Intelligence chatbot Guide Machine Learning NLP

This article was published as a part of the Data Science Blogathon.

Introduction

A chatbot is a computer application that interacts with the user. It can be as simple as an information-gathering chatbot or as complex as a wellness coach chatbot that tracks your meals, body weight, water intake and suggests customized exercise or diet plans.

Chatbots can be rule-based or powered by AI/ML. As the name suggests, Rule-based chatbots use a series of defined rules. These rules contain the types of problems the chatbot is familiar with and deliver answers or solutions to. However, they cannot answer questions outside of their defined rules. On the other hand, AI chatbots use machine learning to understand the context and intent of the question asked before providing an answer. These chatbots use Natural Language Programming to compose their responses to complicated questions. The more an AI chatbot is used or trained, the more they learn, and hence they can interact better with the user. Examples of AI chatbots are Alexa by Amazon, Siri by Apple, Google Assistant, etc.

This guide will cover: basic terms used in chatbot development, What is RASA, how it works, installing RASA 3. x, its important concepts, and finally building our translator bot, which will translate the user input from English to any other language. We will be using the following specifications:

RASA 3.x

Table of contents

  1. Basic terms of chatbot development
  2. What is RASA?
  3. Working of RASA
  4. Installation of RASA 3. x
  5. File structure
  6. Custom actions
  7. Slots
  8. Lookup tables
  9. Forms
  10. Translator bot
  11. Conclusion

Basic Terms of Chatbot Development

  1. Query: User’s message or user input to the chatbot.
  2. Response/Action: Chatbots reply or the action, taken by it as per the user input.
  3. Intent: The user’s primary goal or the intention behind the input or message.
  4. Entity: Any piece of important information gathered from the user input. (nouns in the user input)
Chatbot development

Referring to the simple interaction between cafe TR chatbot and the user, here blue represents the user’s query and purple represents chatbot’s query.

What is RASA?

RASA is an essential open-source machine learning framework used to build customized AI chatbots. It can be integrated with websites, Facebook, Telegram, Whatsapp, Slack, Discord, etc.

RASA has two main components: RASA NLU and RASA CORE. RASA NLU interprets the user input and extracts entities and intent with the help of various pipelines. It then converts the input into a dictionary that includes the original text, intent, and entities identified, which is then sent to RASA CORE. RASA CORE is responsible for the chatbot’s response. It selects the appropriate response as per the user input and then sends it back as a chatbot response. RASA also offers RASA X functionality which provides a Web UI and supports interactive learning.

Working of RASA

 

Working of RASA
  1. User message is sent to the interpreter, which converts the message into a dictionary having original text, the intent, and entities. This is handled by RASA NLU.
  2. The interpreter sends the message to Tracker which keeps a record of the conversation.
  3. The current state of the Tracker is sent to each policy.
  4. The policy then chooses which action has to be taken next.
  5. Action chosen is recorded in the Tracker.
  6. Chatbots Response sent as per the chosen action.

Installation of RASA 3.x in Windows

1. Install
virtual environment using pip

py -m pip install --user virtualenv

2. Create a virtual environment

py -m venv env

3. Activating
virtual environment

 .envScriptsactivate

4. Now
install RASA in the virtual environment (env)

 (env) pip install rasa

5. Now
create a new project by running:

rasa init 
RASA 3.x
Enter the path for the project, or the current directory will be used as the default path. Next, we can train the initial model after initializing it.
RASA 3.x

Now we can speak to the trained bot.

Trained bot

User ‘/stop’ to exit 

File structure

 

File Structure
  1. Actions folder contains the actions.py file, which holds the custom action code.
  2. Config.yml has pipelines, policies, and components used by the model to make predictions based on user input.
  3. Credentials.yml, this file contains the credentials for the voice & chat platforms that your Bot is using.
  4. Data folder consists of :
    1. nlu.yml: stores intent, entities, and lookup tables for the user input
    2. rules.yml: define a short conversation path that should always be followed
    3. stories.yml: contain general stories to train the model
  5. Domain.yml is the main file, represents the universe in which the model works. It lists all intents, entities, slots, responses, forms, and actions that your Bot uses and specifies a configuration for conversation sessions.
  6. Endpoints.yml contains the different endpoints your Bot can use.
  7. Models folder contains the trained models.
  8. Tests folder contains tests to evaluate that your Bot behaves as expected.

Custom Actions in RASA 3.x

A custom action can be used to execute any code. This can be used to query a database or make an API call.

To use custom actions, RASA needs to run two services parallelly, like in the translator chatbot also two terminals have to run simultaneously for the RASA to make use of custom actions. Let’s look at the code structure of custom action : 

Custom Actions

Initially, all the actions.py is a commented file, and a simple hello world custom action is present by default. Uncomment from line 10.

RASA 3.x

RASA actions are implemented as a Python class, it also provides a rasa_sdk library which makes it easy to create custom actions, but you’ll need to follow a predefined API.

class ActionHelloWorld is inheriting from rasa_sdk’s Action base class then there are two functions: name and run. The name method defines the name of the action, and it is important because this name will be used in stories, domain, and rule.yml files to identify the custom action. The run method contains the Python code that we want to run when the custom action is called in this example, name of the custom action is “action_hello_world” and it will respond with “Hello World!” when called. The run method receives data from the RASA NLU service which can be utilized in the custom actions and we can also send an appropriate response back to the user programmatically. Going more into the python code:

Rasa Actions

The run method has :

  1. Dispatcher: Responsible for sending the response back to the user
  2. Tracker: Responsible for gathering information like intent, entities, slot values, and the conversation so far.
  3. Domain: Provides access to data defined in the domain.yml file

Slots in RASA 3.x

Slots serve as your Bot’s memory; it stores the data gathered from users or data related to the outside world (e.g.: the result of an API call) in a key-value pair structure. They are defined in the domain.yml under the slots section, with their name, type, and mapping. If you want the slot value should influence the conversation, then set influence_conversation to true.

slots:
   name_sl:
      type: text
      influence_conversation: true 
      mappings:
       - types: from_entity 
          entity: user_name

In the above example, the slot name is “name_sl” and ” text ” type. It will influence the conversation; therefore, influence_conversation is set to True. Under mappings, the type is from_entity, which means that the value will be extracted from the entity defined as the user_name.

Type of slots can be text, bool, categorical, float, list and will store arbitrary values like a dictionary, lists, etc. You can also write a python code to define custom slots.

RASA uses four predefined slot mappings to map the slots with the latest user data, and you can also write a custom python code for slot mapping as per your use case.

Predefined slot mappings are :

  1. from_entity: slot value is mapped with the data extracted from the entity
  2. from_text: slot value is mapped with the last user message
  3. from_intent: slot value is mapped as per the intent defined in the domain.yml
  4. from_trigger_intent: slot value is mapped if the user activates a form with the given intent_name.

Lookup Tables in RASA 3.x

The lookup table can be defined as a list of words used to generate a particular pattern; it is written in the nlu.yml file. They are basically like a Regular Expression. They are a combination of two pipeline components:

RegexFeaturizer and RegexEntityExtractor.

Lookup tables can be used to extract entity values which a set pattern. Keep your lookup table as precise as possible to get the best results.

-lookup: color
  examples :
    - pink
    - brown
    - red
    - blue 
    - green

In the above example, a lookup table for colors is written.

Forms in RASA 3.x

Forms consist of multiple slots, in the sense that multiple slots will make a form. A form is filled by providing values for these multiple slots. It is also known as “slot filling.”

To use forms, make sure the rule policy is uncommented in the config.yml file

Forms | RASA 3.x

It is defined in the domain.yml file, under forms.

Refer to the above example having details about a form employee_form, which is taking information like name, mobile number, email, and department

Activating a form will require adding a story or rule which describes when the Bot should run the form. A form is deactivated on its own once all the slots are filled. To explicitly deactivate a form, you’ll need a story or rule that says so.

Now let’s create our Translator bot.

Translator bot

Firstly we are going to write the custom code for Translation.

actions.py :

# This files contains your custom actions which can be used to run
# custom Python code.
#
# See this guide on how to implement these action:
# https://rasa.com/docs/rasa/custom-actions
# This is a simple example of a custom action that utters "Hello World!"
from typing import Any, Text, Dict, List
from translate import Translator
from rasa_sdk import Action, Tracker
from rasa_sdk.events import SlotSet
from rasa_sdk.executor import CollectingDispatcher
#
#
class ActionTranslateToLang(Action):
#
def name(self) -> Text:
    return "action_translate_to_lang"
#
def run(self, dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
    sentence=next(tracker.get_latest_entity_values("sentence"),None)
    print('sentence entity taken',sentence)
    to_langg=next(tracker.get_latest_entity_values("to_langg"),None)
    print('to_langg entity taken',to_langg)
    if not sentence:
        print('inside if of sentence')
        msg=f"Give me a sentence to translate"
        dispatcher.utter_message(text=msg)
        sentence=next(tracker.get_latest_entity_values("sentence"),None)
        print('inside if of sentence, sentence taken',sentence)
        return []
    if not to_langg:
        print('inside if of to_langg')
        msg=f"Give me a target language"
        dispatcher.utter_message(text=msg)
        to_langg=next(tracker.get_latest_entity_values("to_langg"),None)
        print('inside if of to_langg, to_langg taken',to_langg)
        return []
    translator= Translator(from_lang="english", to_lang=to_langg)
    print('translator var set')
    translation=translator.translate(sentence)
    print('translation var set',translation)
    msg=f"translated sentence: {translation}"
    dispatcher.utter_message(text=msg)
    return []

We are using an internal python library called Translate’s method Translator. The name of the action is “action_translate_to_lang,” which is defined in the name (self) method call. In the run method, the sentence variable is used to get value from an entity called a sentence, and similarly, the to_langg variable is used to get value from the to_lang entity.

If the sentence variable is null, then the dispatcher sends a message “Give me a sentence to translate” and then the next user input is taken into the sentence variable. The same is implemented for the to_langg variable also.

A function call is defined in the translator variable.Translator(from_lang=”english” , to_lang=to_langg) , where the source language is English, and to_lang is the language into which the sentence has to be translated.

The translator variable is then used to call the function translate, with the sentence variable passed as the object. The result is stored in the translation variable. In the end, the translation variable is sent back to the user by the dispatcher as the translated sentence.

Now moving to domain.yml file

domain.yml :

Add a new intent called “translate”.

version: "3.0"
intents:
- greet
- goodbye
- affirm
- deny
- mood_great
- mood_unhappy
- bot_challenge
- translate

Define the following entities

entities:
- to_langg
- sentence

Now we add slots and map them to the entities

slots:
    to_lang:
        type: text
        influence_conversation: true
        mappings:
        - type: from_entity
        entity: to_langg
    sentence:
        type: text
        influence_conversation: true
        mappings:
        - type: from_entity
        entity: sentence

Add a response as utter_translate

utter_translate:
- text: "Great, tell me what can I translate for you!"
- text: "Glad to hear, tell me what do you want to translate"

Lastly, add actions

actions:
- action_translate_to_lang

In the domain file, we have defined the intent, entities, slots, action, and response of the Bot as utter_translate

Now moving to the nlu.yml file

nlu.yml:

Add a describe the new intent translate; you can always add more intents as per your need.

- intent: translate
examples: |
- how to say [good morning](sentence) in [spanish](to_langg)
- how to say [good evening](sentence) in [german](to_langg)
- [hello everyone](sentence) in [french](to_langg)
- [nice to meet you](sentence) in [hindi](to_langg)
- how to say [what time is it](sentence) in [hindi](to_langg) 
- translate [goodbye](sentence) in [german](to_langg)
- translate [i am sad](sentence) in [spanish](to_langg)

In this intent, value is mapped to the entity as : [value](entity)

Also, define a lookup table for languages.

- lookup: to_langg
examples: |
- german
- spanish
- hindi
- french
- dutch
- japanese

Moving to rules

rules.yml:

Define a new rule

- rule: translating
steps:
- intent: translate
- action: action_translate_to_lang

According to this rule, whenever intent translate is called, action_translate_to_lang will be called next.

Moving to stories

stories.yml:

I have added two new stories; you can always add more to make the Bot more efficient.

- story: translating 1
steps:
- intent: greet
- action: utter_greet
- intent: mood_great
- action: utter_translate
- intent: translate
entities:
- sentence: good morning
- to_langg: spanish
- action: action_translate_to_lang
- story: translating 2
steps:
- intent: greet
- action: utter_greet
- intent: mood_unhappy
- action: utter_cheer_up
- action: utter_did_that_help
- intent: affirm
- action: utter_translate
- intent: translate
entities:
- sentence: goodbye
- to_langg: german
- action: action_translate_to_lang

In the config.yml file uncomment the following pipelines:

pipeline:

# # No configuration for the NLU pipeline was provided. The following default pipeline was used to train your model.
# # If you'd like to customize it, uncomment and adjust the pipeline.
# # See https://rasa.com/docs/rasa/tuning-your-model for more information.
- 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
- name: RegexEntityExtractor
use_lookup_tables: True
# Configuration for Rasa Core.
# https://rasa.com/docs/rasa/core/policies/

Similarly, uncomment the following policies also:

policies:

# # No configuration for policies was provided. The following default policies were used to train your model.
# # If you'd like to customize them, uncomment and adjust the policies.
# # See https://rasa.com/docs/rasa/policies for more information.
- name: MemoizationPolicy
- name: RulePolicy
# - name: UnexpecTEDIntentPolicy
# max_history: 5
# epochs: 100
- name: TEDPolicy
max_history: 5
epochs: 100
constrain_similarities: true

In the endpoints.yml file, uncomment the following:

action_endpoint:
url: "http://localhost:5055/webhook"

We are done will all the changes. We’ll be using two terminals, one for running actions and another for talking to the Bot.

Now we open a terminal and activate the same virtual environment we created when installing RASA and run the custom action.

rasa run actions
Rasa run actions

If your output looks above, the actions.py file has no error and is up and running.

Now open another terminal and activate the same virtual environment we created when installing RASA and train the model.

rasa train
Rasa Train

Since I made no changes to the RASA files, it has restored the old model and saved it as a new model.

Now we are ready to talk to our Bot. run the following command after the rasa train

rasa she

Conclusion 

We have covered all the major topics for RASA chatbot development and created a translator bot. I hope this article has been an informative one. Thank you!

Note

Use https://yamlchecker.com/ to check for any yml file errors.

Use rasa shell –debug and rasa run actions –debug to debug your code.

The terminal may not support font of all languages, hence some languages may not be displayed after translation, and only [][] are seen.

RASA has a great forum to help out newbies and learn about RASA new features, do check it out: https://forum.rasa.com/

Read more on Chatbot development using RASA here.

About the author

Hey, there reader, Yashi here; I am a System Engineer at TATA CONSULTANCY SERVICES, interested in AI, ML, NLP, and Python.

Connect with me on LinkedIn: https://www.linkedin.com/in/yashi-saxena-y1009s

Images are drawn using CANVA or are file snippets. Do not re-post the images.

 

The media shown in this article is not owned by Analytics Vidhya and are used at the Author’s discretion. 

About the Author

Yashi Saxena

Our Top Authors

Download Analytics Vidhya App for the Latest blog/Article

Leave a Reply Your email address will not be published. Required fields are marked *