This article was published as a part of the Data Science Blogathon.
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:
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.
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.
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
Now we can speak to the trained bot.
User ‘/stop’ to exit
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 :
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 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:
The run method has :
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 :
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.
To use forms, make sure the rule policy is uncommented in the config.yml file
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.
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
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
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
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!
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.
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.
how to use text file in lookup table of rasa