WhatsApp Business API | Integration with Rasa

logo_rasa_ct2x

Hi there!

In this tutorial, you will learn to enable WhatsApp communication on a simple Rasa assistant with the tyntec Conversations API. This integration allows your assistant to receive WhatsApp text messages and reply to them with ease.

You will need

Step One: Create an assistant

Let’s create artificial intelligence! This step is optional if you are starting with Rasa Open Source. Continue with step 2 if you already have your Assistant. 

  1. Create a new project with an initial model by running the following command:
$ rasa init
Welcome to Rasa! 🤖
 
To get started quickly, an initial project will be created.
If you need some help, check out the documentation at https://rasa.com/docs/rasa.
Now let's start! 👇🏽
 
? Please enter a path where the project will be created [default: current directory] ./my-great-assistant
? Path './my-great-assistant' does not exist 🧐. Create path?  Yes
Created project directory at '/home/john-doe/my-great-assistant'.
Finished creating project structure.
? Do you want to train an initial model? 💪🏽  Yes
Training an initial model...
The configuration for pipeline and policies was chosen automatically. It was written into the config file at './my-great-assistant/config.yml'.
Training NLU model...
[...]
NLU model training completed.
Training Core model...
[...]
Core model training completed.
Your Rasa model is trained and saved at '/home/john-doe/my-great-assistant/models/20210930-155824.tar.gz'.
? Do you want to speak to the trained assistant on the command line? 🤖  No 	 
Ok 👍🏼. If you want to speak to the assistant, run 'rasa shell' at any time inside the project directory.

2. Change your current working directory:

$ cd my-great-assistant

You’ve created an assistant that automatically handles interactions.

Step Two: Add a WhatsApp connector

In this step, you connect the assistant to the tyntec Conversations API with a custom channel connector. The connector can process incoming WhatsApp messages, pass them to your assistant, and reply on WhatsApp.

1. Create a file addons/tyntec.py with the following content:

import json
import logging
 
import rasa.core.channels.channel
import requests
import sanic
import sanic.response
 
 
def _compose_tyntec_send_whatsapp_text_request(apikey, from_, to, text):
    return requests.Request(
        method="POST",
        url="https://api.tyntec.com/conversations/v3/messages",
        headers={
            "Accept": "application/json",
            "apikey": apikey},
        json={
            "from": from_,
            "to": to,
            "channel": "whatsapp",
            "content": {
                "contentType": "text",
                "text": text}})
 
 
def _parse_tyntec_webhook_request(body):
    try:
        id_ = body["messageId"]
        event = body["event"]
        from_ = body["from"]
        channel = body["channel"]
        content_type = body["content"]["contentType"]
        content_text = body["content"]["text"]
    except KeyError:
        raise ValueError("body not a tyntec WhatsApp text message event")
 
    if event != "MoMessage" or channel != "whatsapp" or content_type != "text":
        raise ValueError("body not a WhatsApp text message event")
 
    return _TyntecWhatsAppTextMessage(id_, from_, content_text)
 
 
class _TyntecWhatsAppTextMessage:
    def __init__(self, id_, from_, text):
        self.id = id_
        self.from_ = from_
        self.text = text
 
 
class TyntecInputChannel(rasa.core.channels.channel.InputChannel):
    def __init__(self, waba, tyntec_apikey, requests_session=None):
        if requests_session is None:
            requests_session = requests.Session()
 
        self.requests_session = requests_session
        self.tyntec_apikey = tyntec_apikey
        self.waba = waba
 
    @classmethod
    def from_credentials(cls, credentials):
        return cls(credentials["waba"], credentials["apikey"])
 
    @classmethod
    def name(cls):
        return "tyntec"
 
    def blueprint(self, on_new_message):
        custom_webhook = sanic.Blueprint("tyntec")
 
        @custom_webhook.route("/", methods=["GET"])
        async def health(request):
            return sanic.response.json({"status": "ok"})
 
        @custom_webhook.route("/webhook", methods=["POST"])
        async def receive(request):
            try:
                text_message = _parse_tyntec_webhook_request(request.json)
            except ValueError:
                request_json = json.dumps(request.json)
                logging.warning(f"Unsupported event skipped: {request_json}")
                return sanic.response.text(f"Unsupported event skipped: {request_json}")
 
            await on_new_message(
                rasa.core.channels.channel.UserMessage(
                    text_message.text,
                    TyntecOutputChannel(self.waba, self.tyntec_apikey, self.requests_session),
                    text_message.from_,
                    input_channel=self.name(),
                    message_id=text_message.id))
 
            return sanic.response.text("OK")
 
        return custom_webhook
 
 
class TyntecOutputChannel(rasa.core.channels.channel.OutputChannel):
    def __init__(self, waba, tyntec_apikey, requests_session):
        self.requests_session = requests_session
        self.tyntec_apikey = tyntec_apikey
        self.waba = waba
 
    @classmethod
    def name(cls):
        return "tyntec"
 
    async def send_text_message(self, recipient_id, text, **kwargs):
        request = _compose_tyntec_send_whatsapp_text_request(self.tyntec_apikey, self.waba, recipient_id, text)
        prepared_request = request.prepare()
 
        response = self.requests_session.send(prepared_request)
        response.raise_for_status()

Step Three: Configure and run the assistant

Now, you will configure and run the assistant.

1. Add the following associative array entry to the credentials.yml file and replace WABA with your WABA phone number and APIKEY with your tyntec API key:

addons.tyntec.TyntecInputChannel:
  waba: "WABA"  # replace WABA with your WABA phone number
  apikey: "APIKEY"  # replace APIKEY with your tyntec API key

2.  Start the assistant:

$ rasa run

3. Create a publicly accessible URL using ngrok in another terminal:

$ path/to/ngrok http 5005

4. Copy the displayed public URL (such as https://843fc8776770.ngrok.io).

Note: This setup is suitable only for development. For production use, follow the official documentation “Deploy Your Rasa Assistant” to deploy your assistant. It includes methods such as Helm charts, deploying your Kubernetes cluster, or Docker Compose.

Step Four: Let the Conversations API know about your assistant

Let the tyntec Conversations API know where to deliver WhatsApp messages from your customers or users. You’re going to subscribe to the assistant’s webhook via an API call in Postman.

1. From the api-collection/conversations/v3 directory, import the Conversations V3.5.postman_collection.json into Postman.

2. Authorize Postman with your tyntec API key and your WABA phone number. Right-click the collection and select Edit. Then go to Variables and set the apikey variable to your tyntec API key. Also, set the whatsAppBusinessNumber variable to your WABA phone number.

3. Let's set up a webhook! Open the WhatsApp folder. Inside, open the Configurations folder and select the Configure the callback for a specific number request and change the inboundMessageUrl in the body to the assistant’s /webhooks/tyntec/webhook endpoint URL (for example, https://843fc8776770.ngrok.io/webhooks/tyntec/webhook). This request will subscribe the URL to incoming message events.

Tell Conversations API where to send your WA messages

4. Hit the Send button. You should receive a 2xx status in the response if everything is okay.

Cool! Now the Conversations API knows where to deliver WhatsApp messages from your customers.

Step Five: Test your assistant

Nothing more is needed to publish your assistant through WhatsApp. Now you can test it!

1. From your test device with WhatsApp installed, write a message to your WhatsApp Business Account Number and wait for the Rasa assistant's response.

Response from your Rasa Assistant

Cool! Your Rasa assistant can now talk with anyone on WhatsApp!

More?

Utilizing Rasa's platform you can make your assistant smarter. Look at the official Handle Business Logic tutorial and level up your assistant. For example, you may want the assistant to collect specific information such as customer phone numbers.

By overriding the TyntecOutputChannel’s methods (for example, send_image_url or send_attachment), your assistant can reply with a snappy meme using an image message or with a funny cat video using a video message. Moreover, you send replies with buttons in cooperation with WhatsApp interactive messages. Look at the documentation of the TyntecOutputChannel’s base class OutputChannel for more information about all the methods that can be overridden.

If you want to protect the assistant’s /webhooks/tyntec/webhook endpoint against unauthorized messages, you can register the webhook with a custom header containing a bearer token. Then, you check the request headers in the blueprint’s receive function before parsing the request body and throw an error response if the request does not include the token.

Once you have built an assistant that can handle the most important happy path stories, you can use a Rasa X tool to improve your assistant. It can help you to listen to your users and use those insights to improve your AI.