Skip to Content

Build a Webhook for a Chatbot Using Python

Create a Python script (with Flask), deploy it to SAP Business Technology Platform, and use it as a webhook to be called by an SAP Conversational AI chatbot.
You will learn
  • How to create a Python endpoint in SAP BTP, using Flask
  • How to read POST data from a chatbot
  • How to send back data to a chatbot
  • How to deploy a Python script to SAP BTP (using Cloud Foundry CLI)
  • How to connect the webhook to the chatbot
thecodesterDaniel WroblewskiJune 27, 2022
Created by
thecodester
September 22, 2021
Contributors
thecodester

Prerequisites

You will create a very simple chatbot that asks the user to pick an animal, and then have the chatbot call a webhook, which will then call an API to retrieve a “fun fact” about the animal via the cat-facts API. The webhook will also update the memory variable that keeps track of how many times the user requested a fun fact.

The point of the tutorial is to show you how the webhook reads the request data from the chatbot, and to show you the format of the data that must be returned to the chatbot.

As an added bonus, we will show how to deploy a Python script to SAP BTP. Special thanks to Yohei Fukuhara for his blog Create simple Flask REST API using Cloud Foundry.

IMPORTANT: The focus of this tutorial is the response an application (API) must return in order to work with SAP Conversational AI. The requirements for Python on SAP BTP changes from time to time – e.g., quota, runtime – so you are encouraged to check the documentation for how to deploy Python scripts: Developing Python in the Cloud Foundry Environment

  • Step 1

    Create a bot that asks the user to select an animal to get a fun fact about.

    1. Create a new bot and call it webhookdemo. Use the following values:

      Field Name Value
      1. What do you want your chatbot to do? Perform Actions
      2. Predefined Skills None
      3. Create your bot
      • Name: webhookdemo
      • Description: A bot to test creation of webhooks
      • Language: English
      4. Data Policy Non-personal and Non-vulnerable
      5. Bot Visibility Public

      Click Create Bot.

    2. In the Train tab, create an intent called ask, and add the expression I’m interested in.

      Since you define only one intent, this intent will always be triggered when the user types in a message.

    3. In the Train tab, create a restricted entity called animal and add 4 valid values: cat, horse, snail, dog.

      Restricted entity
    4. In the Build tab, create a skill called answer, and open it.

      Under Triggers, set the condition to: If @ask is-present.

      Under Requirements, specify #animal as animal.

      Expand the requirement and click New Replies – If #animal is missing, add the following text message, and then click Save and Back:

      Message
      Copy
      Type an animal and I will get you a fun fact about it.
      
      But I am only familiar with certain animals.
      
    5. Click Train at the top of the page.

    Log in to complete tutorial
  • Step 2
    1. First, open the Test tab and test the bot. No matter what you type the intent will be ask.

      Enter dog and it will recognize the animal entity, too.

      Animal
    2. Now open Chat With Your Bot.

      If you enter anything that does not match the animals, a short message is displayed and it asks you to enter an animal.

      Enter one of the animals. Now the requirement is met but you did not define a reply so the default No reply is sent.

      Skill test
    Log in to complete tutorial
  • Step 3
    1. In the file explorer, create a new folder for the project and call it chatbot-webhook.

    2. Open VS Code.

      Make sure you have installed the Microsoft extension for Python, as well as Python and the Flask and requests packages.

    3. Go to File > Add Folder to Workspace, and select the project folder.

      New file
    4. Inside the folder, create the helper files for the project

      manifest.yml

      You must change the host name below to a unique name. The rest of the tutorial assumes the host name below, but everywhere you must change it (e.g., URL to API).

      Text
      Copy
      applications:
      - name: dbw-catfacts
        memory: 128M
        command: python chatbot-webhook-test.py
      

      Procfile

      Text
      Copy
      web: python chatbot-webhook.py
      

      requirements.txt

      This file contains dependencies in our project: Flask to create endpoints and requests to call other APIs from within our app.

      Text
      Copy
      Flask
      requests
      

      runtime.txt

      Make sure to use a version currently supported by SAP BTP. At the time of the writing of this tutorial (December 2020), the version below worked.

      Text
      Copy
      python-3.x
      

      static (folder)

      Create the folder static. Download the SAP Conversational AI icon and place it in the folder.

    Your project should look like this:

    VS Code setup
    Log in to complete tutorial
  • Step 4

    Now we will write the main part of the app, which creates the endpoints.

    1. In your project, create a new file called chatbot-webhook.py.

    2. Add the following code – which adds dependencies and creates a default endpoint, which returns a nice HTML page with a cool image, so you will be able to make sure the deployment was successful.

      Python
      Copy
      from flask import Flask, request, jsonify
      import os
      import json
      import datetime
      import requests
      
      app = Flask(__name__)
      cf_port = os.getenv("PORT")
      
      # Only get method by default
      @app.route('/')
      def hello():
          return '<h1>SAP Conversational AI</h1><body>The animal facts webhook for use in SAP Conversational AI chatbots.<br><img src="static/283370-pictogram-purple.svg" width=260px></body>'
      
      if __name__ == '__main__':
      	if cf_port is None:
      		app.run(host='0.0.0.0', port=5000, debug=True)
      	else:
      		app.run(host='0.0.0.0', port=int(cf_port), debug=True)
      
      

      Save the file.

      If you want, you can test this in VS Code by running the .py file – either by right-clicking the file and choosing Run Python File in Terminal or clicking the green arrow

      Link text e.g., Destination screen
      in the upper right. You will get the following:

      VS Code test default endpoint

      You can then open a browser to the default endpoint.

      VS Code test default endpoint
    3. Add the following code for the main endpoint right after the default one – and before the if __name__ == '__main__': line.

      This endpoint takes the data from the chatbot, makes the call to the API to get the fun fact, and then returns the next message to the chatbot.

      Python
      Copy
      @app.route('/bot', methods=['POST'])
      def bot():
        # Get the request body, and determine the dog and memory
        try:
          bot_data = json.loads(request.get_data())
          animal = bot_data['conversation']['memory']['animal']['raw']
          memory = bot_data['conversation']['memory']
        except:
          animal = "dog"
          memory = json.loads("{}")
      
        # Get the fun fact
        url = "https://cat-fact.herokuapp.com/facts/random?animal_type=" + animal + "&amount=1"
        nodata = {"text" : "No data"}
      
        # In case the API does not work after 8 seconds, we return "no data"
        try:
          r = requests.get(url, timeout=8)
          fact_data = json.loads(r.content)
        except:
          fact_data = nodata
      
        # Increment the # of times this has been called
        if 'funfacts' in memory:
           memory['funfacts'] += 1
        else:
           memory['funfacts'] = 1
      
        # Return message to display (replies) and update memory
        return jsonify(
          status=200,
          replies=[
          {
            'type': 'text',
            'content': fact_data['text']
          }
          ],
          conversation={
            'memory': memory
          }
      
        )
      

      Save the file.

      You can test this by opening Postman, and calling the endpoint localhost:5000/bot (with POST method and no body).

      VS Code test bot endpoint

      Test it again but this time sending the following (raw) body, to simulate as if the chatbot were sending the request:

      JSON
      Copy
      {
        "conversation": {
          "memory": {
            "animal" : {"raw" : "snail"},
            "funfacts": 1
          }
        }
      }
      

      Now, the API call uses the animal from the body (i.e., snail) and updates the funfacts variable in the memory.

      VS Code test bot endpoint
    Log in to complete tutorial
  • Step 5

    Use the Cloud Foundry CLI to deploy the script to SAP BTP.

    You will need your SAP BTP Cloud Foundry endpoint and org name, which you can see when you open your subaccount Overview page.

    Account info
    1. Open a command prompt in the folder containing your Python project, and set the Cloud Foundry API URL.

      CLI
      Copy
      cf api https://api.cf.eu10.hana.ondemand.com
      
      CLI
    2. Log in by entering the following command and entering your credentials:

      CLI
      Copy
      cf login
      
    3. Select your CF org (if you have multiple orgs in that endpoint).

      CLI org
    4. Now push the application, and call it catfacts:

      CLI
      Copy
      cf push catfacts
      

    This should about a minute, with a lot of output in the command screen. Once finished, you should now have the application deployed. Go to your Cloud Foundry space, under Applications.

    Link text e.g., Destination screen

    If you click the app, you will get the endpoint link.

    Link text e.g., Destination screen

    And if you click the link (and open it in browser), you will be making a GET call to the default endpoint.

    Test endpoint
    Log in to complete tutorial
  • Step 6

    Now that you deployed your webhook, let’s attach it to the chatbot.

    1. In the Build tab, open the answer skill.

    2. In the Actions tab, click Add New Message Group, and then click Connect External Service > Call Webhook.

      • For the URL, enter the name of your endpoint with /bot at the end. Make sure the method is POST.

        For example, mine is: https://catfacts-quiet-klipspringer-kx.cfapps.eu10.hana.ondemand.com/bot

      • Click Save.

    3. Click Update Conversation > Edit Memory, and then set the Unset memory field to animal.

      Add webhook
    4. Click Add New Message Group.

      This message group is to display a message when the user has requested 3 or more fun facts. Our webhook is keeping track of the number of calls, and then passing the results via the memory.

      • Set the condition to If _memory.funfacts is 3.

      • Add a text message that says: WOW!! You sure like these fun facts!!

    Log in to complete tutorial
  • Step 7

    Open a conversation with the bot, by entering Hi. The message when an animal is missing is displayed.

    No animal

    Then enter an animal, and the webhook is triggered and a fun fact is displayed.

    Animal

    Enter an animal 2 more times – must be cat, dog, snail, or horse. The extra message is displayed for when the user repeatedly asks for fun facts.

    Lots of animals

    Click on the yellow i icon to see the JSON of the conversation. Scroll down and you can see that the webhook added to the memory the value for funfacts.

    Memory

    You demonstrated the way to return information to the memory from the webhook, so you kept track via a custom memory variable _memory.funfacts of how many times the current user requested a fun fact.

    You could have instead used the built-in variable _skill_occurences to keep track of how many times you executed the answer skill.

    For information on built-in variables, see Runtime Data Accessible.

    Log in to complete tutorial
  • Step 8

    What is the name of the field you created in the chatbot memory to keep track of how many times the user called the webhook?

    Log in to complete tutorial
Back to top