Start building your own chatbot now

Objective

After having several conversations with customers, colleagues, and partners about SAP Conversational AI, one feature always stands out: integration.

Chatbots offer a new user experience that in many ways are more efficient and effective than a human interaction and there are many statistics to support that statement. However, very often, it’s hard for a chatbot to be helpful and valuable on its own. It needs to be able to retrieve information from other systems and present consolidated data to the user.

With many developers and customers not having the resources (skills or licenses) to build a middleware application from scratch for their integration purposes, I have decided to demonstrate an integration example using SAP Cloud Platform Integration (CPI). You can read more about CPI here.

The example in this blog is inspired by the movie bot tutorial originally developed by the SAP Conversational AI team.

Disclaimer

This guide is intended for knowledge sharing purposes only. The steps presented here, including the accuracy and cleanliness of the code, security considerations, and overall steps are not to be considered best practices.

Prerequisites

You must have :

  • An SAP Cloud Platform Integration-PI account
  • Basic knowledge of SAP Cloud Platform Integration

  • A free account with SAP Conversational AI (you can sign up here)
  • Read and understood Parts 1 & 2 of the movie bot tutorial

1. Forking and configuring the bot

1.1 Forking the bot

fork-the-bot

1.2 Configuring the bot

a) Once the forking process is complete, go to settings by clicking the cog icon.

bot-settings-sap-conversational-aib) Select the “Bot webhook base URL” box and type in your CPI runtime node.

Your runtime node should look something like this:

https://<Account Short Name>-iflmap.<SSL HOST>.<Landscape Host>/http.

For example: https://l0001-iflmap.hcisbp.eu1.hana.ondemand.com/http

Make sure to enter /http at the end of the URL because we will be using an http adapter later.

bot-settings-chatbotc) On the same screen click the Build tab at the top. Select the Discover skill and scroll down to the “_memory.yes” action.

d) Click the pencil icon to edit the action block.

memory-management-chatbot-sap-conversational-aie) Make sure “/discover-movies” is added to the URL and the POST method is selected.

f) Under Authentication: select basic authentication and enter your CPI tenant’s username and password.

g) Under Headers: add the field Content-Type application/json.

h) Under Body: use the default settings.

authentification-chatbotauthentification-chatbot-headers

authentification-chatbot-body

2. Getting your MovieDB API URL and API Key

Go to link below and follow the steps:

  • 2.1 Create a MovieDB account
  • 2.2 Make sure you are logged in to your The Movie DB account
  • 2.3 Follow this link The Movie DB API and follow the steps to get your API key

It should look like this on MovieDB:

movie-db-api-settings

3. Building the integration flow

3.1 Getting started

Go to your CPI tenant.

  • a) Create an integration package or use a pre-existing one of your liking.
  • b) Create a new integration flow of type Process Integration.

You are now ready to start building your integration flow.

3.2 Building the integration flow

  • a) Start by selecting an HTTPS adapter and dragging the line from Sender to Start.
  • b) Under the connection tab, make sure that you enter/do as shown in the screenshot.
  • c) Don’t change any other adapter settings.

integration-flow-sender-sap

https-connection

4. Configuring properties

Next, we want to extract the parameters from the incoming message from Conversational AI and save the parameters as properties for use in the MovieDB query.

  • a) Open the menu on the left and click the Transformation
  • b) Open the Script dropdown menu and select JavaScript.
  • c) Add the code below and save your data.

extract-query-parameters

importClass(com.sap.gateway.ip.core.customdev.util.Message);
importClass(java.util.HashMap);


function processData(message) {
    var body = message.getBody(java.lang.String);
    var myObj = JSON.parse(body);
    var kind = myObj.conversation.memory.recording.type;
    var genreId = myObj.conversation.memory.genre.id;
    var language = myObj.conversation.language;
    var conversationId = myObj.conversation.id;

    message.setProperty("kind", kind);
    message.setProperty("genreId", genreId);
    message.setProperty("language", language);
    message.setProperty("conversationId", conversationId);

    message.setHeader("Accept","application/json");
    message.setHeader("Content-Type","application/json");

	return message;
}

5. Querying the MovieDB

  • a) Add a request reply box, a receiver box outside the integration bus, and an http adapter connecting the two (as shown in the figure below).
  • b) Configure the http adapter as shown in the screenshot.
  • c) Replace the API_KEY field with your “api_key”.
    connection-api-db-movies

Now that we receive the response in the payload (body of the message), we can use the data and store it again in properties. We can use the stored data in our final response back to the bot.

  • d) Insert a script box of type JavaScript. See the figure below for how the integration flow looks so far.
  • e) Insert the following code in it

integration-flow



importClass(com.sap.gateway.ip.core.customdev.util.Message);
importClass(java.util.HashMap);


function processData(message) {
    var body = message.getBody(java.lang.String);
    var myObj = JSON.parse(body);
    
    var i, x = "";
    
    for (i in myObj.results) {
    x += myObj.results[i];
    }
    
    var title = [myObj.results[0].title, myObj.results[1].title, myObj.results[2].title, myObj.results[3].title, myObj.results[4].title];
    var subtitle = [myObj.results[0].overview, myObj.results[1].overview, myObj.results[2].overview, myObj.results[3].overview, myObj.results[4].overview];
    var imageUrl = [myObj.results[0].poster_path, myObj.results[1].poster_path, myObj.results[2].poster_path, myObj.results[3].poster_path, myObj.results[4].poster_path];
    var buttonValue = [myObj.results[0].id, myObj.results[1].id, myObj.results[2].id, myObj.results[3].id, myObj.results[4].id];


    message.setProperty("title", title);
    message.setProperty("subtitle", subtitle);
    message.setProperty("imageUrl", imageUrl);
    message.setProperty("buttonValue", buttonValue);

	return message;
}

6. Adding a Content Modifier that contains the final payload that goes back to SAP Conversational AI

  • a) Add in a “Content Modifier”
  • b) In the message header, add in the authorization details from CAI, that would be your request token (find it in the settings of your bot’s page under token)

Note: If the number characters in the content array exceed 512, the bot shows No Reply.integration-process-receiver

  • c) Add in the code below under the Message Body tab

content-modifier


{
    "replies": [
        {
            "type": "carousel",
            "content":[
            {
              "title": "${property.title[0]}",
              "subtitle": "${property.subtitle[0]}",
              "imageUrl": "https://image.tmdb.org/t/p/w600_and_h900_bestv2${property.imageUrl[0]}",
              "buttons": [
                {
                  "title": "View More",
                  "type": "web_url",
                  "value": "https://www.themoviedb.org/${property.kind}/${property.id[0]}"
                }
              ]
            },
			{
              "title": "${property.title[1]}",
              "subtitle": "${property.subtitle[1]}",
              "imageUrl": "https://image.tmdb.org/t/p/w600_and_h900_bestv2${property.imageUrl[1]}",
              "buttons": [
                {
                  "title": "View More",
                  "type": "web_url",
                  "value": "https://www.themoviedb.org/${property.kind}/${property.id[1]}"
                }
              ]
            },
            {
              "title": "${property.title[2]}",
              "subtitle": "${property.subtitle[2]}",
              "imageUrl": "https://image.tmdb.org/t/p/w600_and_h900_bestv2${property.imageUrl[2]}",
              "buttons": [
                {
                  "title": "View More",
                  "type": "web_url",
                  "value": "https://www.themoviedb.org/${property.kind}/${property.id[2]}"
                }
              ]
            },
            {
              "title": "${property.title[3]}",
              "subtitle": "${property.subtitle[3]}",
              "imageUrl": "https://image.tmdb.org/t/p/w600_and_h900_bestv2${property.imageUrl[3]}",
              "buttons": [
                {
                  "title": "View More",
                  "type": "web_url",
                  "value": "https://www.themoviedb.org/${property.kind}/${property.id[3]}"
                }
              ]
            },
            {
              "title": "${property.title[4]}",
              "subtitle": "${property.subtitle[4]}",
              "imageUrl": "https://image.tmdb.org/t/p/w600_and_h900_bestv2${property.imageUrl[4]}",
              "buttons": [
                {
                  "title": "View More",
                  "type": "web_url",
                  "value": "https://www.themoviedb.org/${property.kind}/${property.id[4]}"
                }
              ]
            }
          ]
        }
    ]
}

(Optional) Add the following groovy script if you want to see how your payload looks like at the end of the integration flow.

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import com.sap.it.api.mapping.*;
import java.text.SimpleDateFormat;
import java.util.Calendar;


def Message processData(Message message) {

	map = message.getProperties();
	property_ENABLE_PAYLOAD_LOGGING = "TRUE";
	if (property_ENABLE_PAYLOAD_LOGGING.toUpperCase().equals("TRUE")) {
		def header = message.getHeaders() as String;
		def body = message.getBody(java.lang.String) as String;
		
		String timeStamp = new SimpleDateFormat("HH:mm:ss.SSS").format(new Date());
		String logTitle = timeStamp + " JSstep ";
		  
		def messageLog = messageLogFactory.getMessageLog(message);
		if (messageLog != null) {
			messageLog.addAttachmentAsString(logTitle, body, "text/xml");
		}
	}
	return message;
}

7. Deploying and testing your bot

webchat-movie-bot

You should be good to go now, but feel free to ask for support in the comments section below! 🤖

I’d love to hear from the community how this example can be enhanced through better code, instructions, or any other way.

If you want to follow other tutorials with our bot building platform, don’t hesitate to visit this page.

Happy bot building everyone!

Want to build your own conversational bot? Get started with SAP Conversational AI !

Follow us on
  • Anonymous

    hi
    I have done the similar configuration, my iflow is getting triggered in SAP CPI and also its completing successful and sending the response back, but i cannot see the response in my chatbot
    My chatbot is showing “No Reply” as response

    • Mohammad Alhennawi

      Hello, can you try replacing “replies” with “messages” in the final payload inside of the content modifier? like below:

      {
      “messages”: [
      “type”: “carousel”,
      “content”:[
      {…..etc.

  • Anonymous

    Hi Alhennawi,

    I am sending the structure as below according to your suggestion but still getting “No reply” in bot. Kindly help.

    {
    “messages”: [
    {
    “type”: “carousel”,
    “content”:[
    {
    “title”: “The Lion King”,
    “subtitle”: “Simba idolises his father, King Mufasa, and takes to heart his own royal destiny. But not everyone in the kingdom celebrates the new cub’s arrival. Scar, Mufasa’s brother—and former heir to the throne—has plans of his own. The battle for Pride Rock is ravaged with betrayal, tragedy and drama, ultimately resulting in Simba’s exile. With help from a curious pair of newfound friends, Simba will have to figure out how to grow up and take back what is rightfully his.”,
    “imageUrl”: “https://image.tmdb.org/t/p/w600_and_h900_bestv2/dzBtMocZuJbjLOXvrl4zGYigDzh.jpg”,
    “buttons”: [
    {
    “title”: “View More”,
    “type”: “web_url”,
    “value”: “https://www.themoviedb.org/movie/”
    }
    ]
    },
    {
    “title”: “Detective Conan: The Fist of Blue Sapphire”,
    “subtitle”: “23rd movie in the “Detective Conan” franchise.”,
    “imageUrl”: “https://image.tmdb.org/t/p/w600_and_h900_bestv2/86Y6qM8zTn3PFVfCm9J98Ph7JEB.jpg”,
    “buttons”: [
    {
    “title”: “View More”,
    “type”: “web_url”,
    “value”: “https://www.themoviedb.org/movie/”
    } etc…..

    Regards,
    Aman Raj

  • Anonymous

    Hi,

    I have tried as suggested but still getting “No Reply” in bot. Kindly help.

    Regards,
    Aman

  • Anonymous

    Hi,
    The issue resolved, it was because of some unexpected characters (“”) coming in subtitle part fro Movie DB.

    Regards,
    Aman

    • Anonymous

      Thank you for providing feedback. Also note this known issue: if the number characters in the content array exceeds 512, then the bot will show “No Reply”

      Mohammad

  • Srikanth

    Hi,

    I have developed as per the blog. But I am getting ” No Reply” as response. Even i am not able to see any messages logs in my CPI. How can we check whether request is hitting CPI or not. And where might be the issue to check in detail.

    Please suggest.

    • Anonymous

      If it’s not being shown in your CPI monitoring screen, then the request didn’t make it to CPI. My guess is that something is off with authorizations. What does your API request code say on CAI when testing the bot?

  • Srikanth

    Hi,

    Thanks for the reply.

    I am getting two errors one in Chat box and another one in the CPI.

    1. Request failed with status code 404 in the Chat box itself.
    2. In the CPI message monitoring i could see some logs ” com.sap.it.rt.adapter.http.api.exception.HttpResponseException: An internal server error occured: SyntaxError: Empty JSON string (//src/main/resources/script/script1.js#6).”

    But i am not understanding where i have done wrong.

Leave a Reply to Anonymous
Cancel Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.