Skip to content
This repository was archived by the owner on Dec 31, 2020. It is now read-only.

Commit e9b4c38

Browse files
committed
Edits for Facebook bot
Custom version from conversation-simple with following modification: 1- Ready to integrate with Facebook messenger. 2- Maintain webhook conversation context per user. 3- Method to handle conversation from browser URL with text tag. 4- Click the tab icon will hide JSON tab instead of increasing it. 5- Edit in the conversation.js to convert Arabic numbers into English numbers.
1 parent 1172838 commit e9b4c38

File tree

10 files changed

+220
-27
lines changed

10 files changed

+220
-27
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
WORKSPACE_ID=<workspace-id>
33
CONVERSATION_USERNAME=<conversation-username>
44
CONVERSATION_PASSWORD=<conversation-password>
5+
FACEBOOK_VERIFY=<facebook-verify>
6+
FACEBOOK_TOKEN=<facebook-token>
7+
GET_ACTIVE=OFF

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
# Conversation Sample Application [![Build Status](https://travis-ci.org/watson-developer-cloud/conversation-simple.svg?branch=master)](http://travis-ci.org/watson-developer-cloud/conversation-simple) [![codecov.io](https://codecov.io/github/watson-developer-cloud/conversation-simple/coverage.svg?branch=master)](https://codecov.io/github/watson-developer-cloud/conversation-simple?branch=master)
22

3-
This Node.js app demonstrates the Conversation service in a simple chat interface simulating a cognitive car dashboard.
3+
This Node.js app demonstrates the Conversation service in a simple chat interface simulating a cognitive car dashboard.<br/>
4+
This is **custom version from conversation-simple** with following modification:<br/>
5+
1- Ready to integrate with Facebook messenger.<br/>
6+
2- Maintain webhook conversation context per user.<br/>
7+
3- Method to handle conversation from browser URL with text tag.<br/>
8+
(the method created to make testing easier, the default status for method is not activate until you activate it from .env variable)<br/>
9+
4- Click the tab icon will hide JSON tab instead of increasing it.<br/>
10+
5- Edit in the conversation.js to convert Arabic numbers into English numbers. (For Watson To Match)<br/>
11+
**For more about changes check section Facebook Integration**
12+
413

514
![Demo](readme_images/demo.gif)
615

@@ -202,6 +211,7 @@ Full license text is available in [LICENSE](LICENSE).
202211
## Contributing
203212

204213
See [CONTRIBUTING](CONTRIBUTING.md).
214+
This custom version forked by Barqawiz
205215

206216
## Open Source @ IBM
207217

app.js

Lines changed: 152 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,18 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
16+
/** Forked version by Barqawiz **/
1717
'use strict';
1818

1919
var express = require('express'); // app server
20+
var request = require('request');//Http requests
2021
var bodyParser = require('body-parser'); // parser for post requests
2122
var Conversation = require('watson-developer-cloud/conversation/v1'); // watson sdk
2223

2324
var app = express();
24-
25+
/*contextCash: save context through conversation when come from facebook or
26+
any third party messanger, working on enhanced version that clear context after x time*/
27+
var contextCash = {}
2528
// Bootstrap application settings
2629
app.use(express.static('./public')); // load UI from public folder
2730
app.use(bodyParser.json());
@@ -30,13 +33,43 @@ app.use(bodyParser.json());
3033
var conversation = new Conversation({
3134
// If unspecified here, the CONVERSATION_USERNAME and CONVERSATION_PASSWORD env properties will be checked
3235
// After that, the SDK will fall back to the bluemix-provided VCAP_SERVICES environment property
33-
//'username': process.env.CONVERSATION_USERNAME,
34-
//'password': process.env.CONVERSATION_PASSWORD,
36+
'username': process.env.CONVERSATION_USERNAME,
37+
'password': process.env.CONVERSATION_PASSWORD,
3538
'version_date': '2017-05-26'
3639
});
3740

41+
//Endpoint to handle bot request
42+
app.get('/api/bot', function(req, res) {
43+
44+
var user_text = req.param('text') || '<empty>'
45+
var workspace = process.env.WORKSPACE_ID || '<workspace-id>';
46+
if (!workspace || workspace === '<workspace-id>' || user_text === '<empty>' || process.env.GET_ACTIVE === 'OFF') {
47+
return "";
48+
}
49+
50+
user_text = { text: user_text.toString("utf8") }
51+
var payload = {
52+
workspace_id: workspace,
53+
context: req.body.context || {},
54+
input: user_text || {}
55+
};
56+
57+
// Send the input to the conversation service
58+
conversation.message(payload, function(err, data) {
59+
if (err) {
60+
return res.status(err.code || 500).json(err);
61+
}
62+
if (data.output && data.output.text) {
63+
return data.output.text[0]
64+
} else {
65+
return "";
66+
}
67+
68+
});
69+
});
3870
// Endpoint to be call from the client side
3971
app.post('/api/message', function(req, res) {
72+
4073
var workspace = process.env.WORKSPACE_ID || '<workspace-id>';
4174
if (!workspace || workspace === '<workspace-id>') {
4275
return res.json({
@@ -45,6 +78,7 @@ app.post('/api/message', function(req, res) {
4578
}
4679
});
4780
}
81+
4882
var payload = {
4983
workspace_id: workspace,
5084
context: req.body.context || {},
@@ -56,7 +90,9 @@ app.post('/api/message', function(req, res) {
5690
if (err) {
5791
return res.status(err.code || 500).json(err);
5892
}
93+
5994
return res.json(updateMessage(payload, data));
95+
6096
});
6197
});
6298

@@ -92,4 +128,116 @@ function updateMessage(input, response) {
92128
return response;
93129
}
94130

131+
//THIRD PARTY
132+
// Subscribing the webhook
133+
app.get('/webhook/', function (req, res) {
134+
if (req.query['hub.verify_token'] === process.env.FACEBOOK_VERIFY) {
135+
res.send(req.query['hub.challenge']);
136+
}
137+
res.send('Error, wrong validation token');
138+
})
139+
140+
// Incoming messages reach this end point //
141+
app.post('/webhook', (req, res) => {
142+
console.log('**webhook invoced')
143+
// Parse the request body from the POST
144+
let body = req.body;
145+
// Check the webhook event is from a Page subscription
146+
if (body.object === 'page') {
147+
// Iterate over each entry - there may be multiple if batched
148+
body.entry.forEach(function(entry) {
149+
150+
// Gets the body of the webhook event
151+
let webhook_event = entry.messaging[0];
152+
//console.log(webhook_event);
153+
154+
// Get the sender PSID
155+
let sender_psid = webhook_event.sender.id;
156+
//console.log('Sender PSID: ' + sender_psid);
157+
158+
// Check if the event is a message or postback and
159+
// pass the event to the appropriate handler function
160+
if (webhook_event.message) {
161+
let ctx = {}
162+
ctx = contextCash[sender_psid] || ctx
163+
164+
handleMessage(sender_psid, webhook_event.message, ctx);
165+
} else if (webhook_event.postback) {
166+
console.log('postback request in webhook')
167+
}
168+
169+
});
170+
// Return a '200 OK' response to all events
171+
res.status(200).send('EVENT_RECEIVED');
172+
173+
} else {
174+
// Return a '404 Not Found' if event is not from a page subscription
175+
res.sendStatus(404);
176+
}
177+
178+
});
179+
180+
function handleMessage(sender_psid, received_message, contx) {
181+
182+
// Check if the message contains text
183+
if (received_message.text) {
184+
console.log("inside check")
185+
186+
let workspace = process.env.WORKSPACE_ID;
187+
let text = { text: "'"+received_message.text+"'" }
188+
let payload = {
189+
workspace_id: workspace,
190+
context: contx || {},
191+
input: text || {}
192+
};
193+
194+
// Send the input to the conversation service
195+
conversation.message(payload, function(err, data) {
196+
if (err) {
197+
return res.status(err.code || 500).json(err);
198+
}
199+
200+
if (data.output && data.output.text) {
201+
202+
let response = {
203+
"text": "'"+data.output.text[0]+"'"
204+
}
205+
callFacebookAPI(sender_psid, response);
206+
//cash last context with the user
207+
contextCash[sender_psid] = data.context
208+
} else {
209+
console.log("***response is empty: ***")
210+
return;
211+
}
212+
213+
});
214+
}
215+
216+
217+
}
218+
219+
function callFacebookAPI(sender_psid, response) {
220+
// Construct the message body
221+
let request_body = {
222+
"recipient": {
223+
"id": sender_psid
224+
},
225+
"message": response
226+
}
227+
228+
// Send the HTTP request to the Messenger Platform
229+
request({
230+
"uri": "https://graph.facebook.com/v2.6/me/messages",
231+
"qs": { "access_token": process.env.FACEBOOK_TOKEN },
232+
"method": "POST",
233+
"json": request_body
234+
}, (err, res, body) => {
235+
if (!err) {
236+
console.log('message sent!')
237+
} else {
238+
console.error("Unable to send message:" + err);
239+
}
240+
});
241+
}
242+
95243
module.exports = app;

manifest.yml

100755100644
Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
---
2-
declared-services:
3-
my-conversation-service:
4-
label: conversation
5-
plan: free
62
applications:
7-
- name: conversation-simple
8-
command: npm start
9-
path: .
10-
memory: 256M
11-
instances: 1
12-
services:
13-
- my-conversation-service
14-
env:
15-
NPM_CONFIG_PRODUCTION: false
3+
- name: conversation-simple
4+
random-route: true
5+
memory: 256M

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
"body-parser": "^1.18.2",
2323
"dotenv": "^2.0.0",
2424
"express": "^4.16.1",
25-
"watson-developer-cloud": "^2.40.0"
25+
"watson-developer-cloud": "^2.40.0",
26+
"jsonwebtoken": "^7.1.9",
27+
"request": "^2.73.0"
2628
},
2729
"devDependencies": {
2830
"babel-eslint": "^6.0.4",
@@ -35,7 +37,7 @@
3537
"supertest": "^1.2.0"
3638
},
3739
"engines": {
38-
"node": ">= 6.9.x",
39-
"npm": "> 3.10.x"
40+
"node": "6.*",
41+
"npm": "3.*"
4042
}
4143
}

public/css/app.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ div {
7272
padding: 0.9375rem 0 0.625rem 0;
7373
margin: auto;
7474
text-align: left;
75-
max-width: 25rem;
75+
max-width: 50rem;
7676
min-width: 9.375rem;
7777
}
7878

@@ -265,6 +265,10 @@ input:-moz-placeholder {
265265
min-width: initial;
266266
}
267267

268+
#payload-column.hidden {
269+
visibility: hidden;
270+
}
271+
268272
#payload-column .header-text, #payload-column #payload-initial-message {
269273
font-family: Helvetica Neue for IBM, Helvetica Neue, Helvetica, Arial, sans-serif;
270274
font-size: 1.125rem;

public/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
</head>
1313
<body>
1414
<div id="view-change-button" class="button" onclick="PayloadPanel.togglePanel(event, this)">
15-
<img class="option full" src="../img/Chat Button.png">
16-
<img class="option not-full" src="../img/Code Button.png">
15+
<img class="option full" src="../img/Code Button.png">
16+
<img class="option not-full" src="../img/Chat Button.png">
1717
</div>
1818
<div id="contentParent" class="responsive-columns-wrapper">
1919
<div id="chat-column-holder" class="responsive-column content-column">

public/js/common.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,25 @@ var Common = (function() {
7878
}
7979
}
8080
}());
81+
/*
82+
function _arabicNumberToEng(value) {
83+
var newValue="";
84+
for (var i=0;i<value.length;i +)
85+
{
86+
var ch=value.charCodeAt(i);
87+
if (ch>=1776 && ch<=1785) // For Persian digits.
88+
{
89+
var newChar=ch-1728;
90+
newValue=newValue String.fromCharCode(newChar);
91+
}
92+
else if(ch>=1632 && ch<=1641) // For Arabic digits.
93+
{
94+
var newChar=ch-1584;
95+
newValue=newValue String.fromCharCode(newChar);
96+
}
97+
else
98+
newValue=newValue String.fromCharCode(ch);
99+
}
100+
101+
return newValue;
102+
}*/

public/js/conversation.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,24 @@ var ConversationPanel = (function() {
218218
}
219219

220220
// Send the user message
221-
Api.sendRequest(inputBox.value, context);
221+
value = inputBox.value
222+
value = arabicToEn(value)
223+
Api.sendRequest(value, context);
222224

223225
// Clear input box for further messages
224226
inputBox.value = '';
225227
Common.fireEvent(inputBox, 'input');
226228
}
227229
}
230+
231+
function arabicToEn(value) {
232+
var enValue="";
233+
for (var i=0;i<value.length;i++)
234+
{
235+
var ch=value.charCodeAt(i);
236+
enValue+=(ch>=1632 && ch<=1641) ?String.fromCharCode(ch-1584):String.fromCharCode(ch);
237+
}
238+
return enValue;
239+
}
240+
228241
}());

public/js/payload.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
var PayloadPanel = (function() {
77
var settings = {
88
selectors: {
9+
//chat-column-holder
910
payloadColumn: '#payload-column',
1011
payloadInitial: '#payload-initial-message',
1112
payloadRequest: '#payload-request',
@@ -36,10 +37,10 @@ var PayloadPanel = (function() {
3637
var payloadColumn = document.querySelector(settings.selectors.payloadColumn);
3738
if (element.classList.contains('full')) {
3839
element.classList.remove('full');
39-
payloadColumn.classList.remove('full');
40+
payloadColumn.classList.remove('hidden');
4041
} else {
4142
element.classList.add('full');
42-
payloadColumn.classList.add('full');
43+
payloadColumn.classList.add('hidden');
4344
}
4445
}
4546

0 commit comments

Comments
 (0)