Technical Articles
Application modernization with Google Cloud Platform: Chatbots
SAP Conversational AI: Developing and Training Chatbots
The scope of this blog is to give the architecture best practices and the code to extend, change and adapt the scope and the look and feel of your Dialogflow agent to your specific needs.
The sample code is not intended for production usage.
Sample
Prerequisite
An API endpoint has been created following the guide in part 1.
Architecture overview
As we get started, it is important to describe the architecture:
- User interacts using a web browser with a web application hosted on Google Cloud Run
- Cloud Run application uses the Dialogflow Python client library to interact with Dialogflow CX agent
- Dialogflow CX agent manages the conversation flows
- Webhooks, published in Google Cloud Function, integrate with Apigee proxy
- Google Cloud Function handles the API calls to the endpoint in Apigee.
- Apigee secures and monitors access to the SAP backend OData endpoint.
Note: The SAP backend can be hosted on GCP, on premise, or on any other cloud.
Note: Before running your agent in production, be sure to implement the
productionization best practices.
Configure Cloud Function
We start putting together our building blocks. As a first step, assuming you API proxy has been configured as described in part 1, we want to create a cloud function to act as webhook for the Dialogflow agent.
- Create a new project in GCP
- Open the Cloud Functions service
- Click on Create Function
- Add a function name sapwebhook and leave all the other parameters as default
- Check that the Trigger type is set on HTTP
- Copy the URL of your Cloud Function and save it for future use
- Click Save
Cloud function
- Expand Variables, Networking and Advanced Settings section
- Switch to the environment variables tab
- Add two runtime environment variables
Parameter | value |
---|---|
API_ENDPOINT | your api proxy endpoint |
APIKEY | your api key for the application |
Runtime variable
- Click Next
- Switch the runtime to Python 3.8
- Change the entry point name to webhook
- Edit the requirements.txt file adding the following code
# Function dependencies, for example:
# package>=version
requests==2.18.4
- Edit the main.py file adding the following code
import json
import os
import requests
def webhook(request):
url = os.getenv('API_ENDPOINT')
apikey = os.getenv('APIKEY')
request_json = request.get_json()
if request_json.get('fulfillmentInfo', None):
tag = request_json['fulfillmentInfo']['tag']
print('Tag: {}'.format(tag))
else:
return ('Unrecognized request', 404)
if tag == 'salesorder.list':
params = dict(
apikey=apikey
)
resp = requests.get(url=url, params=params)
data = resp.json() # Check the JSON Response Content documentation below
reply = {
"fulfillment_response": {
"messages": [
{
"payload": {
"richContent": [
[]
]
}
}
]
}
}
for salesorder in data['results']:
salesorderitem = {
"type": "list",
"title": salesorder['SalesOrderID'],
"subtitle": salesorder['Note'],
"event": {
"name": "salesorder.list",
"languageCode": "",
"parameters": {
"SalesOrderID": salesorder['SalesOrderID'],
"SalesOrderKey" : salesorder['SalesOrderKey']
}
}
}
reply['fulfillment_response']['messages'][0]['payload']['richContent'][0].append(salesorderitem)
reply['fulfillment_response']['messages'][0]['payload']['richContent'][0].append({"type":"divider"})
elif tag == 'salesorder.detail':
order = str(int(request_json['sessionInfo']['parameters']['ordernumber'])).zfill(10)
params = dict(
apikey=apikey,
salesorderid=order
)
resp = requests.get(url=url, params=params)
data = resp.json() # Check the JSON Response Content documentation below
if len(data['results']):
salesorder = data['results'][0]
text = 'Sales order {} total value is {} {} and it has been {} and {}'.format(salesorder['SalesOrderID'],salesorder['TotalSum'],salesorder['Currency'],salesorder['DeliveryStatusDescription'],salesorder['BillingStatusDescription'])
else:
text = 'No sales order {} is available in the system'.format(order)
reply = {
"fulfillment_response": {
"messages": [
{
"text": {
"text": [text]
}
}
]
}
}
return json.dumps(reply)
- The cloud function editor should look as below
Cloud function
- Click on Deploy and wait for the function to activate
- From the Cloud Function list click on the more options and select test function
Cloud function
- Edit the triggering event payload using the json below
{
"fulfillmentInfo": {
"tag" : "salesorder.list"
}
}
- Press the Test the function button and confirm the response as below
Cloud function – test
The setup of the cloud function is completed and the webhook is now available for consumption
Create the Dialogflow CX agent
Next step is to create and configure the Dialogflow agent. For simplification we will use an already built agent for this scope
Enable Dialogflow APIs
- Enable Dialogflow API via the Cloud Console or the Cloud Shell using
gcloud services enable dialogflow.googleapis.com
Create the Dialogflow agent
- Open Dialogflow CX portal
- Select your GCP Project from the list
GCP Project
- Press Create agent
- Name for the agent SAP Sales Order and check the Enable stackdriver logging
Create agent
- Press Create
- Dialogflow CX brings you into the agent creation developer tool. In this example we will use pre build agent.
- Open the Agent drop down on top and select View all agents
- Open the context menu of your newly created agent and select and select Restore
Restore agent
- In the restore popup select Google Cloud Storage and insert the GCS URI
gs://public-demo-assets/dialogflow/SAPSalesOrder.json
Restore agent
- Press Restore
- Your agent is imported successfully
- Open the agent
- Switch to Manage tab on the left and select Webhooks
- Select the existing webhook and change the URL with the one of your cloud function created above and press Save
Modify webhook
- Return to the agent list
- From the context menu select Copy name, it will copy the agent details that we will need in the web application app configuration
Copy agent
Deploy the web application in Cloud Run
In this final step, we will deploy a simple Cloud Run web application that will be act as a front end.
- From the shell clone the GIT repository into a folder of preference
git clone https://github.com/ivanfemia/ccai-agent-client.git
- Configure the application to run in your GCP project
cd ccai-agent-client
cp .dockerignore.SAMPLE .dockerignore
cp Dockerfile.SAMPLE Dockerfile
- Edit config.py and configure PAGE_TITLE and PAGE_H1_TITLE
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# https://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Configuration file."""
PAGE_TITLE = 'SAP Dialogflow CX'
PAGE_H1_TITLE = 'SAP Sales Order Agent'
Note: Make sure you have an empty line at the end of the file
- Configure the application environment variable
- Edit the app.yaml file providing the DIALOGFLOW_PROJECT_ID and DIALOGFLOW_AGENT_ID
Parameter | value |
---|---|
DIALOGFLOW_PROJECT_ID | your GCP project id |
DIALOGFLOW_AGENT_ID | your agent id |
Note: DIALOGFLOW_AGENT_ID is the unique identifier we copied in Dialogflow CX. In my case projects/sap-dialogflow/locations/us-central1/agents/644c170f-6543-4a7b-ab78-82736f9d05e9 the agent id is 644c170f-6543-4a7b-ab78-82736f9d05e9
- Final step deploy the web application in Cloud Run
- Build your container image using Cloud Build, by running the following
command from the directory containing the Dockerfile
export DIALOGFLOW_PROJECT_ID=**your GCP project id***
gcloud builds submit --tag gcr.io/$DIALOGFLOW_PROJECT_ID/agent
- Deploy using the following command and following the instruction on screen
gcloud run deploy --image gcr.io/$DIALOGFLOW_PROJECT_ID/agent --platform managed
Note: For more details on Building and Running a Cloud Run application refer to the official documentation
Demo execution
Open the target url from the previous step
Sample script
Use this sample script to demo the use case
- Respond to the bot greetings
Sample
- Select Recent sales orders
- The agent lists the latest 10 sales orders in SAP ES5
Sample
- Select or type one of the Sales Order number in the list
- The agent provides the delivery status and payment status
Sample
- You can loop requesting the list again or a specific Sales order
- Finally just confirm that you completed the interaction
Sample
Hi and thank you for this blog, very nice
Is apigee for connection security like cloud connector? can I use cloud connector with google to connect to odata in SAP gateway? Like this example https://blogs.sap.com/2019/11/07/google-hangout-chatbot-integration-with-s-4hana/
No, Apigee is the API Management layer to connect securely from you network to Apigee you can establish a secure VPN tunnel or considering Apigee hybrid (based on Anthos)
Cloud Connector works only with SAP Cloud Platform.
So app engine can connect to SAP Gateway odata if I dont have apigee? Thank you
yes it can