Technical Articles
The simplest connection between Node.js app and SAP Conversational AI
Hi All,
I am writing this blog to describe the simplest way to use SAP Conversational AI with Node.js application on SAP Cloud Platform Cloud Foundry.
Links
- Official Express installation guide
- SAP Tutorial “Create a Basic Node.js App”
- How to deploy Node.js application into SAP Cloud Platform CF
- GItHub Repository
- Chat-bot
Environment
Local PC
- Ubuntu18.04.01 LTS on VMWare Workstation
- cf CLI 6.43.0
- node.js 11.10.1
- npm 6.7.0
Cloud Foundry
- Nodejs Buildpack version 1.6.40
- CF Trial (Europe – Frankfurt)
Prerequisites
- space is created on Cloud Foundry environment
- cf CLI is installed on Local PC(see the official page for the installation)
- Node.js is installed on Local PC(see another article)
Steps
1. Node.js development
1.1. Setup Node.js on Local PC
Create a directory.
mkdir chat_test
cd chat_test
1.2. Setup npm
Initialize npm. After “npm init” command, I answered like this.
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (chat_test) chat-test
version: (1.0.0)
description:
entry point: (index.js) app.js
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /home/i348221/Apps/node/chat_test/package.json:
{
"name": "chat-test",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this OK? (yes) yes
1.3. Install express and body-parser
Install express and body-parser via npm.
npm install --save express body-parser
1.4. Change package.json
Change package.json file for startup registration on SAP Cloud Platform. I changed “scripts” -> “start” part.
{
"name": "chat-test",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.18.3",
"express": "^4.16.4"
}
}
Now the directory is like this.
$ ls -al
total 32
drwxr-xr-x 3 i348221 i348221 4096 Mar 7 19:24 .
drwxr-xr-x 6 i348221 i348221 4096 Mar 7 18:00 ..
drwxr-xr-x 51 i348221 i348221 4096 Mar 7 19:24 node_modules
-rw-r--r-- 1 i348221 i348221 283 Mar 7 19:24 package.json
-rw-r--r-- 1 i348221 i348221 13929 Mar 7 19:24 package-lock.json
1.5. Main program “app.js”
Create app.js in the same directory.
tourch app.js
Contents of “app.js”.
I prepared for “get” and “post” method, though I don’t use “get” method. It is just test purpose.
// Import modules
const express = require('express')
const bodyParser = require('body-parser');
const app = express()
app.use(bodyParser.json());
const port = process.env.PORT || 3000;;
// Get method
app.get('/', (req, res) => res.send('Hello World! for GET'))
// Post method
app.post('/', function(req, res) {
console.log('Start [POST] method to / ');
console.log(req.body)
console.log(`Request from user: ${req.body.conversation.memory['user']}`)
// Response Body
res.json({
replies: [
{
type: 'text',
content: `Hello ${req.body.conversation.memory['user']}`
}
],
conversation: {
memory: {
'result': 'OK',
}
}
});
});
// Listen
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
1.6. Test Node.js application
For verifying the “app.js” on local PC, run “app.js”.
$ node app.js
Example app listening on port 3000!
I used POSTMAN for the test.
The result of “get” method.
The one of “post” method. Don’t forget about request
Headers and Body.
The “post” Request Body. Most of data is unnecessary.
{
"action_id": "5149f96e-b2c5-4e30-96ec-c587ae978d52",
"conversation": {
"id": "test-1530310812548",
"memory": {
"user": "Homer"
},
"language": "en",
"skill": "foo",
"skill_occurences": 2
},
"nlp": {
"act": "assert",
"language": "en",
"processing_language": "en",
"sentiment": "neutral",
"source": "This is a sample message.",
"status": 200,
"timestamp": "2018-06-29T22:00:50.591367+00:00",
"type": null,
"uuid": "c1bc4e40-ca14-4ce2-bc18-700433b001d9",
"version": "2.12.0"
}
}
After sending a request, I can see logs via terminal.
I exported POSTMAN.
2. Deploy Node.js app to SAP CP
2.1. Create manifest.yaml
For deployment to SAP Cloud Foundry, manifest.yaml is necessary.
touch manifest.yaml
The file content is like this.
---
applications:
- name: chat-test
random-route: true
memory: 128M
2.2. Deploy the app to SAP CP Cloud Foundry
Login SAP CP Cloud Foundry via CF cli.
cf login
Now deploy the app! Application name is from “manifest.yaml”.
cf push
3. SAP Conversational AI
3.1. Create chatbot
I created a simple chatbot, which doesn’t have any intents and skills.
I used “fallback” skill for the connection with Node.js.
This is the action of “fallback” skill and just send POST request without authentication. Don’t forget about Header “Content-Type” is “application/json”.
3.2. Check the connection
Now check the connection.
I can see logs via CF cli.
cf logs chat-test --recent
Here is the logs.
2019-03-07T23:47:57.60-0800 [APP/PROC/WEB/0] OUT Start [POST] method to /
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT { nlp:
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT { uuid: '1d8ca70e-f889-4ce4-a643-20b330ed7522',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT intents: [],
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT entities: {},
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT language: 'en',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT processing_language: 'en',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT version: '1902.2.0',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT timestamp: '2019-03-08T07:47:57.074401+00:00',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT status: 200,
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT source: 'HI',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT act: 'assert',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT type: 'desc:desc',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT sentiment: 'vpositive' },
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT action_id: '78538f72-0fe9-4d64-89a9-631d76862bc1',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT conversation:
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT { id: 'test-1552031274266',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT conversation_id: 'test-1552031274266',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT warning: 'The conversation_id field will be depreciated on January 1st 2018! Switch to using the id field instead',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT language: 'en',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT memory: { user: 'Test' },
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT skill_stack: [],
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT skill: 'fallback',
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT skill_occurences: 1,
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT participant_data: {} } }
2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT Request from user: Test
2019-03-07T23:47:57.61-0800 [RTR/3] OUT chat-test-friendly-platypus.cfapps.eu10.hana.ondemand.com - [2019-03-08T07:47:57.558+0000] "POST / HTTP/1.1" 200 647 94 "-" "axios/0.18.0" "-" "10.0.139.6:61027" x_forwarded_for:"-" x_forwarded_proto:"https" vcap_request_id:"6f2d89a0-5bdf-45c1-6250-9a7358b5f059" response_time:0.056351563 app_id:"610382d3-8749-44eb-b29e-d40787a15fbb" app_index:"0" x_correlationid:"-" x_b3_traceid:"acc413c482b12ac1" x_b3_spanid:"acc413c482b12ac1" x_b3_parentspanid:"-"
2019-03-07T23:47:57.61-0800 [RTR/3] OUT
Thanks for this great tutorial. I learned a lot. I just have a question. How will this work out if we are to add an app router for the node js?
I have no idea with App Router. Why do you like to add App Router?
It's to secure the endpoint with authentication once deployed to the cloud. I can't seem to make the post call work when I added it.
How about checking OAuth token on Node.js.
Though I don't know how to do with Node.js, I achieved the validation on Java with SAP Cloud SDK.