../_images/ari-icon.png

Trigger custom behaviours from the chatbot#

In this section, you will learn what are RASA’s custom actions and how to use them eg trigger intents from the chatbot.

To have an overview of RASA and how it is used on your robot, please first have a look at Dialogue management and Create, translate or update a chatbot.

Custom actions#

Custom actions are Python functions that you can define to add custom behavior and logic to your chatbot. Custom actions allow you to go beyond simple predefined responses and enable your chatbot to perform actions, like executing some ROS code, connecting to the Web to fetch some information, or interact with databases or external APIs.

In this tutorial, we will see how to extend the robot chatbot to emit a custom robot’s Intents, ie a custom action that publishes on a ROS topic.

To create you own custom action, two steps must be followed:

  1. name your action in the domain.yml corresponding to your chatbot (for instance, see the actions: section of the chitchat domain.yml, located in $HOME/.pal/chatbots-enabled/en_GB/chitchat/domain.yml). This action can then be used in your chatbot like any other RASA action.

  2. create a new python script in $HOME/.pal/chatbots-enabled/common/actions, called <action name>.py (for instance if the action is named action_get_ip, the script must be named action_get_ip.py)

Your new action is now available. However, do not forget to retrain your chatbot as explained here.

You can use the default actions available in $HOME/.pal/chatbots-enabled/common/actions as example.

Important

Use the tr function (from rasa_actions_server.helpers import tr) to translate any text to the target language. You will need to add the required string(s) to each language actions_i8n.yml (for instance, here for en_GB: $HOME/.pal/chatbots-enabled/en_GB/actions_i8n.yml).

Example: recognising a bring command#

Let’s define a custom action bring_object to ask the robot to bring us an object. We want the user to ask the robot to ‘bring us’ various items, and this should be translated into an intent on the robot’s /intents topic.

To do so, we first need to define the RASA intent bring_object in your chatbot’s nlu.yml and domain.yml files, then implement the custom action as a Python script, and finally link the RASA intent to our custom action. By doing so, RASA will call our custom action everytime the bring_object intent is detected in the user’s speech:

RASA intentdefinition:bring_object domain.ymlnlu.yml RASAcustom action action_bring_object.py publishes robot BRING intenton ROS topic /intents rules.yml connect RASA intentto custom action

To define the RASA intent bring_object in your chatbot’s nlu.yml file and provide a few examples (check here how to create the training data for RASA), open your chatbot’s nlu.yml file and add the following code:

Note

If you have not yet created your own chatbot, you can also modify directly the provided $HOME/.pal/chatbots-enabled/<your language>/basic_commands/nlu.yml.

Note however that the content of this file might be overwritten when you update your robot!

Alternatively, copy the folder $HOME/.pal/chatbots-enabled/<your language>/basic_commands/ to e.g. $HOME/.pal/chatbots-enabled/<your language>/my_chatbot/ and work from there.

version: "3.1"

nlu:
- intent: bring_object
  examples: |
    - bring the [ball](object)
    - bring [me](goal) the [cylinder](object)
    - bring the [cube](object) [here](goal)
    - bring the [box](object) to [me](goal)
    - bring [here](goal) the [sphere](object)

As we want to define a custom action for such intent, we only need to add the name of the action that we are going to implement in domain.yml. Open and edit this file (found next to nlu.yml):

version: "3.1"
language: "en_GB"

intents:
- bring_object

entities:
- goal
- object

actions:
- action_bring_object

Note

If you are editing an existing domain.yml, add the fields to existing ones. For instance, the final domain.yml file might look like:

version: "3.1"
language: "en_GB"

intents:
- present_content
- bring_object

entities:
- object
- goal

actions:
- action_present_content
- action_bring_object

Next, we create a new action called action_bring_object.py that will process the user input. It will extract the entities goal and object and build the response to send to the user.

This Python class must implement a run() method that processes the user output from RASA. It takes as input the tracker from which we extract the entities, and the language that determines whether a translation is needed. For that reason, the class uses a method tr defined in the script helpers that maps English sentences to its translations defined in the actions_i8n.yml file.

Create the file $HOME/.pal/chatbots-enabled/common/actions/action_bring_object and copy-paste this code:

 1 #!/usr/bin/env python3
 2# -*- coding: utf-8 -*-
 3
 4import json
 5import time
 6import rospy
 7from hri_actions_msgs.msg import Intent
 8
 9from rasa_actions_server.helpers import tr
10
11
12# the name of the class does not matter as long as the file contains *exactly*
13# one class with a run() method.
14class ActionBringObject:
15
16    def __init__(self):
17        self.intent_pub = rospy.Publisher("/intents", Intent, queue_size=10)
18
19    def run(self, tracker, language):
20
21        intent_msg = Intent()
22        intent_msg.intent = intent_msg.BRING_OBJECT
23        intent_msg.source = intent_msg.UNKNOWN_AGENT
24        intent_msg.modality = intent_msg.MODALITY_SPEECH
25        intent_msg.priority = 128
26
27        entities = {
28            e["entity"]: e["value"] for e in tracker["latest_message"]["entities"]
29        }
30
31        if "object" not in entities:
32            return {
33                "events": [],
34                "responses": [
35                    {
36                        "text": tr(
37                            "Sorry, I did not understand what object do you want me to bring",
38                            language,
39                        )
40                    }
41                ],
42            }
43
44        if "goal" not in entities:
45            entities["goal"] = "here"  # implicit assumed goal
46
47        intent_msg.data = json.dumps(
48            {"object": entities["object"], "goal": entities["goal"]}
49        )
50
51        self.intent_pub.publish(intent_msg)
52        rospy.loginfo(
53            "Intent to bring the object <%s> to <%s> extracted from RASA and published to /intents"
54            % (entities["object"], entities["goal"])
55        )
56
57        return {"events": [], "responses": [{"text": ""}]}

Note

In this example, we publish a ROS intent on the /intents topic. You can modify this example to perform any other action, like fetching online resources, connect to a database, etc.

Next, we can ‘connect’ our RASA intent to the custom action. Open rules.yml (found alongside nlu.yml and domain.yml) and add the following rule:

version: "3.1"

rules:
- rule: bring object
  steps:
  - intent: bring_object
  - action: action_bring_object

Finally, we can re-train the chatbot, and test that our custom action work: simply follow the steps Step 2: Train the new RASA model and Step 3: Test your chatbot.

Try to ask the robot to bring you something: if everything went well, you should see a new intent published on the /intents topic.

If nothing appears, keep an eye on the log of the chatbot pal_chatbot_wrapper: you will likey find the reason for the error there.

See also#