I am trying to retrieve the location of user in Dialogfow. Following docs and blogs, this is what I have written in index.js file of fulfilment.
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
const {Permission} = require('actions-on-google');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
//const agent = new dialogflow();
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
const requestPermission = (agent) => {
//agent.add("Locaation access!");
//agent.add(new Permission({permissions:'NAME', context:''}));
agent.requestSource = agent.ACTIONS_ON_GOOGLE;
const conv = agent.conv();
conv.ask(new Permission({
context: '',
permissions: 'DEVICE_PRECISE_LOCATION',
}));
console.log(conv);
agent.add(conv);
agent.add("Apple");
};
const userInfo = (agent) => {
if(agent.isPermissionGranted()){
const address = agent.getDeviceLocation().address;
if (address){
agent.add("You are at ${address}");
}
else{
agent.add("Cannot locate you");
}
}
else{
agent.add("Cannot locate you");
}
};
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
intentMap.set('request_permission',requestPermission);
intentMap.set('user_info', userInfo);
// intentMap.set('your intent name here', yourFunctionHandler);
// intentMap.set('your intent name here', googleAssistantHandler);
agent.handleRequest(intentMap);
});
EDIT
This is JSON response I get.
Raw API response:
{
"responseId": "RESPONSE-ID",
"queryResult": {
"queryText": "locate",
"action": "request_permission",
"parameters": {},
"allRequiredParamsPresent": true,
"fulfillmentMessages": [
{
"platform": "ACTIONS_ON_GOOGLE",
"simpleResponses": {
"simpleResponses": [
{
"textToSpeech": "Apple",
"displayText": "Apple"
}
]
}
}
],
"webhookPayload": {
"google": {
"systemIntent": {
"intent": "actions.intent.PERMISSION",
"data": {
"optContext": "",
"#type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
"permissions": [
"DEVICE_PRECISE_LOCATION"
]
}
},
"expectUserResponse": true
}
},
"intent": {
"name": "projects/MY_PROJECT_NAME",
"displayName": "request_permission"
},
"intentDetectionConfidence": 1,
"diagnosticInfo": {
"webhook_latency_ms": 3564
},
"languageCode": "en"
},
"webhookStatus": {
"message": "Webhook execution successful"
}
}
Fulfillment request:
{
"responseId": "RESPONSE-ID",
"queryResult": {
"queryText": "locate",
"action": "request_permission",
"parameters": {},
"allRequiredParamsPresent": true,
"fulfillmentMessages": [
{
"text": {
"text": [
""
]
}
}
],
"intent": {
"name": "PROJECT-NAME",
"displayName": "request_permission"
},
"intentDetectionConfidence": 1,
"languageCode": "en"
},
"originalDetectIntentRequest": {
"payload": {}
},
"session": "SESSION-ID"
}
Fulfillment response:
illmentMessages": [
{
"platform": "ACTIONS_ON_GOOGLE",
"simpleResponses": {
"simpleResponses": [
{
"textToSpeech": "Apple",
"displayText": "Apple"
}
]
}
}
],
"payload": {
"google": {
"expectUserResponse": true,
"systemIntent": {
"intent": "actions.intent.PERMISSION",
"data": {
"#type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
"optContext": "",
"permissions": [
"DEVICE_PRECISE_LOCATION"
]
}
}
}
},
"outputContexts": []
}
This response is correct I think. But nothing is added on screen. It shows this on screen,
There are not any errors in console as well. But I am not getting anything when I try the agent.
In raw response, the action.intent.PERMISSION is present but why it is not added or agent asked for yes/no?
The location permissions only work if you're using Actions on Google with the Google Assistant. You also need to test it using the Actions on Google simulator - click where it says "See how it works in Google Assistant".
It doesn't work with the other Dialogflow integrations (such as Facebook or Slack) and won't work with the Dialogflow simulator (the simulator on the right hand side of the page).
Related
I am unable to send a custom payload back to dialogflow from my nodejs webhook code for SLACK platform.
const {WebhookClient, Payload, Platforms, Suggestion} = require('dialogflow-fulfillment');
let payloadObj = new Payload(Platforms.SLACK, questionStringToSend);
agent.add(payloadObj);
Here, questionStringToSend is the JSON payload that i want to send.
Any help would be appreciated.
Structure of my JSON is below:
{
"blocks":[
{
"type":"section",
"text":{
"type":"mrkdwn",
"text":"How do you rate the company?"
}
},
{
"type":"actions",
"elements":[
{
"type":"button",
"text":{
"type":"plain_text",
"text":0
},
"value":0
},
{
"type":"button",
"text":{
"type":"plain_text",
"text":1
},
"value":1
}
]
}
]
}
While sending a response from webhook the format of json is very important Link.
Custom payload response is a json file which has a specific structure and if the structure isn't followed we won't get the expected response.
So the json file can be edited as follows:
{
"fulfillmentMessages": [
{
"payload": {
"slack": {
"attachments": [
{"blocks":[
{
"type":"section",
"text":{
"type":"mrkdwn",
"text":"How do you rate the company?"
}
},
{
"type":"actions",
"elements":[
{
"type":"button",
"text":{
"type":"plain_text",
"text":"0"
},
"value":"0",
"action_id": "button"
},
{
"type":"button",
"text":{
"type":"plain_text",
"text":"1"
},
"value":"1"
}
]
}
]
}
]
}
}
}
]
}
try this
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "How do you rate the company?"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "0"
},
"value": "0"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "1"
},
"value": "1"
}
]
}
]
}
I am writing an Alexa dialog with intent confirmation. When confirmation is denied I want to restart the same dialog again by delegating to this very dialog. I am proceeding like described in this stack overflow question. As described in the solution to this question I do the delegation when the dialogState is still IN_PROGRESS. In my case Alexa always responds with the not very meaningful message There was a problem with the requested skill's response. No error message in the application log.
My skill model and the lambda code are as follows:
{
"interactionModel": {
"languageModel": {
"invocationName": "hello",
"intents": [
{
"name": "UserIntent",
"slots": [
{
"name": "UserName",
"type": "AMAZON.FirstName",
"samples": [
"My name is {UserName}",
"I am {UserName}",
"{UserName}"
]
}
],
"samples": [
"My name is {UserName}",
"I am {UserName}"
]
}
],
"types": []
},
"dialog": {
"delegationStrategy": "SKILL_RESPONSE",
"intents": [
{
"name": "UserIntent",
"confirmationRequired": true,
"prompts": {
"confirmation": "Confirm.Intent.UserName"
},
"slots": [
{
"name": "UserName",
"type": "AMAZON.FirstName",
"confirmationRequired": false,
"elicitationRequired": true,
"prompts": {
"elicitation": "Elicit.Slot.UserName"
}
}
]
}
]
},
"prompts": [
{
"id": "Elicit.Slot.UserName",
"variations": [
{
"type": "PlainText",
"value": "What is your name?"
}
]
},
{
"id": "Confirm.Intent.UserName",
"variations": [
{
"type": "PlainText",
"value": "You are {UserName}. Is this right?"
}
]
}
]
}
}
const DeniedUserIntentHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' &&
request.intent.name === 'UserIntent' &&
request.dialogState === 'IN_PROGRESS' &&
request.intent.confirmationStatus === 'DENIED';
},
async handle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
const currentIntent = request.intent;
const userName = Alexa.getSlotValue(handlerInput.requestEnvelope, 'UserName');
console.log(`DeniedUserIntentHandler:
request.dialogState=${request.dialogState}, request.intent.confirmationStatus=${request.intent.confirmationStatus}, userName=${userName}`);
return handlerInput.responseBuilder
.speak('Username was not confirmed. Please try again.')
.addDelegateDirective({
name: 'UserIntent',
confirmationStatus: 'NONE',
slots: {}
})
.getResponse();
}
};
What I am missing?
You did not specified whether you DeniedUserIntentHandler get triggered or not. if the error is generated inside DeniedUserIntentHandler then it is due to the wrong format of Delegate Directive.
your return response should be like :
return handlerInput.responseBuilder
.speak('Username was not confirmed. Please try again.')
.addDelegateDirective({
"type": "Dialog.Delegate",
"updatedIntent": {
name:"UserIntent",
confirmationStatus:"NONE",
slots: {
UserName: {
name:"UserName",
confirmationStatus:"NONE",
source:"USER"
}
}
}
})
.getResponse();
The reason you are deleting the intent's previous state because you want your intent action to start from beginning.
You can also use your code like this: reference https://forums.developer.amazon.com/questions/92334/answering-no-to-intent-confirmation.html?childToView=206243#comment-206243
currentIntent.confirmationStatus = "NONE";
Object.keys(currentIntent.slots).forEach(
(slotName) => {
var slot = intent.slots[slotName];
delete slot.value;
slot.confirmationStatus = "NONE";
}
);
var delegatedirective = {"type": "Dialog.Delegate",
"updatedIntent": currentIntent};
The problem you are facing now is real one. This issue is also mentioned in amazon forum.
However you can achieve similar behavior with slight modification. Activate slot value confirmation for UserName and remove confirmation for UserIntent.
Your interaction model would be similar like below:
{
"interactionModel": {
"languageModel": {
"invocationName": "demo app",
"intents": [
{
"name": "UserIntent",
"slots": [
{
"name": "UserName",
"type": "AMAZON.FirstName",
"samples": [
"My name is {UserName}",
"I am {UserName}",
"{UserName}"
]
}
],
"samples": [
"My name is {UserName}",
"I am {UserName}"
]
},
{
"name": "AMAZON.NavigateHomeIntent",
"samples": []
}
],
"types": []
},
"dialog": {
"intents": [
{
"name": "UserIntent",
"delegationStrategy": "SKILL_RESPONSE",
"confirmationRequired": false,
"prompts": {},
"slots": [
{
"name": "UserName",
"type": "AMAZON.FirstName",
"confirmationRequired": true,
"elicitationRequired": true,
"prompts": {
"confirmation": "Confirm.Slot.247378890994.1277345498514",
"elicitation": "Elicit.Slot.UserName"
}
}
]
}
],
"delegationStrategy": "ALWAYS"
},
"prompts": [
{
"id": "Elicit.Slot.UserName",
"variations": [
{
"type": "PlainText",
"value": "What is your name?"
}
]
},
{
"id": "Confirm.Slot.247378890994.1277345498514",
"variations": [
{
"type": "PlainText",
"value": "your name is {UserName} , right ?"
}
]
}
]
}
}
you can add this single code handler:
const UserIntenStartedHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' &&
request.intent.name === 'UserIntent';
},
async handle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
const currentIntent = Alexa.getIntentName(handlerInput.requestEnvelope);
const slot = Alexa.getSlot(handlerInput.requestEnvelope, 'UserName');
if (slot.confirmationStatus !== 'CONFIRMED') {
return handlerInput.responseBuilder
.addDelegateDirective(request.intent)
.getResponse();
} else {
return handlerInput.responseBuilder
.speak('your Final name is ' + slot.value + '. cheers')
.withShouldEndSession(true)
.getResponse();
}
}
};
Thanks to the reply of #tahiat I was able to figure out my original problem. In the updated intent the slots object must contain the intent's slots (without a value). But his first code snippet contains an error. Ether use
.addDirective({
"type": "Dialog.Delegate",
"updatedIntent": {
name:"UserIntent",
...
}
})
or use
.addDelegateDirective({
name:"UserIntent",
...
})
since addDelegateDirective expects an intent as a parameter.
But now I am facing another problem. I use confirmation in my dialog. When I go back to the initial state of UserIntent after confirmation was denied I never get prompted with the confirmation message. This is because request.intent.confirmationStatus keeps its value, which is 'DENIED', although I have reset it in updateIntent to 'NONE'.
I have a custom payload message carousel as one of my intents response in Dialogflow. It looks like this.
{
"facebook": {
"attachment": {
"type": "template",
"payload": {
"template_type": "generic",
"elements": [
{
"title": "Welcome!",
"subtitle": "We have the right hat for everyone.We have the right hat for everyone.We have the right hat for everyone.",
"imageUrl": "https://www.stepforwardmichigan.org/wp-content/uploads/2017/03/step-foward-fb-1200x628-house.jpg",
"buttons": [
{
"postback": "https://f1948e04.ngrok.io",
"text": "View Website"
},
{
"text": "Start Chatting",
"postback": "PAYLOAD EXAMPLE"
}
]
},
{
"title": "Welcome!",
"imageUrl": "https://www.stepforwardmichigan.org/wp-content/uploads/2017/03/step-foward-fb-1200x628-house.jpg",
"subtitle": "We have the right hat for everyone.We have the right hat for everyone.We have the right hat for everyone.",
"buttons": [
{
"postback": "https://f1948e04.ngrok.io",
"text": "View Website"
},
{
"text": "Start Chatting",
"postback": "PAYLOAD EXAMPLE"
}
]
}
]
}
}
}
}
I use the following code inside my node.js webhook to handle messages.
function handleCardMessages(messages, sender) {
let elements = [];
for (var m = 0; m < messages.length; m++) {
let message = messages[m];
let buttons = [];
for (var b = 0; b < message.card.buttons.length; b++) {
let isLink = (message.card.buttons[b].postback.substring(0, 4) === 'http');
let button;
if (isLink) {
button = {
"type": "web_url",
"title": message.card.buttons[b].text,
"url": message.card.buttons[b].postback
}
} else {
button = {
"type": "postback",
"title": message.card.buttons[b].text,
"payload": message.card.buttons[b].postback
}
}
buttons.push(button);
}
let element = {
"title": message.card.title,
"image_url":message.card.imageUri,
"subtitle": message.card.subtitle,
"buttons": buttons
};
elements.push(element);
}
sendGenericMessage(sender, elements);
}
function sendGenericMessage(recipientId, elements) {
var messageData = {
recipient: {
id: recipientId
},
message: {
attachment: {
type: "template",
payload: {
template_type: "generic",
elements: elements
}
}
}
};
callSendAPI(messageData);
}
function callSendAPI(messageData) {
request({
uri: 'https://graph.facebook.com/v3.2/me/messages',
qs: {
access_token: config.FB_PAGE_TOKEN
},
method: 'POST',
json: messageData
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
var recipientId = body.recipient_id;
var messageId = body.message_id;
if (messageId) {
console.log("Successfully sent message with id %s to recipient %s",
messageId, recipientId);
} else {
console.log("Successfully called Send API for recipient %s",
recipientId);
}
} else {
console.error("Failed calling Send API", response.statusCode, response.statusMessage, body.error);
}
});
}
So, everytime the intent is called. Dialogflow is supposed to post the custom payload message to the user's messenger app. But, i don't know why the message is not being posted.
If I use Dialogflow's quickreply/card messages response option under it's facebook messenger response option. Everything works fine. But, if i want to send a quickreply/card message using custom payload, the message is not displayed in the user's messenger when the intent is called. Logs looks fine. Don't know what i am doing wrong. Help will be appreciated.
hi here is how it should be formated like if your are using a custom webhook
{
"fulfillmentMessages": [
{
"payload": {
"facebook": {
"attachment": {
"type": "template",
"payload": {
"template_type":"generic",
"elements":[
{
"title":"Welcome!",
"image_url":"https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png",
"subtitle":"We have the right hat for everyone.",
"default_action":{
"type":"web_url",
"url":"https://www.google.com/",
"webview_height_ratio":"tall"
},
"buttons":[
{
"type":"web_url",
"url":"https://www.google.com/",
"title":"View Website"
},
{
"type":"postback",
"title":"Start Chatting",
"payload":"DEVELOPER_DEFINED_PAYLOAD"
}
]
},
{
"title":"Welcome!",
"image_url":"https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png",
"subtitle":"We have the right hat for everyone.",
"default_action":{
"type":"web_url",
"url":"https://www.google.com/",
"webview_height_ratio":"tall"
},
"buttons":[
{
"type":"web_url",
"url":"https://www.google.com/",
"title":"View Website"
},
{
"type":"postback",
"title":"Start Chatting",
"payload":"DEVELOPER_DEFINED_PAYLOAD"
}
]
}
]}
}
}
}
}
]
}
if you want to use the build in one it should be like this
from other answer in here
{
"facebook": {
"attachment": {
"type": "template",
"payload": {
"template_type": "generic",
"elements": [
{
"title": "Welcome!",
"image_url": "https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png",
"subtitle": "We have the right hat for everyone.",
"default_action": {
"type": "web_url",
"url": "https://commons.wikimedia.org/wiki/File:Example.png",
"messenger_extensions": false,
"webview_height_ratio": "tall",
"fallback_url": "https://website.com/"
},
"buttons": [
{
"type": "web_url",
"url": "https://commons.wikimedia.org/wiki/File:Example.png",
"title": "View Website"
},
{
"type": "postback",
"title": "Start Chatting",
"payload": "DEVELOPER_DEFINED_PAYLOAD"
}
]
}
]
}
}
}
}
I want to send custom parameters to the webhook. According to the documentation I set it under "payload" parameter. But I don't see values I set on response object.
https://dialogflow.com/docs/reference/api-v2/rpc/google.cloud.dialogflow.v2#google.cloud.dialogflow.v2.QueryParameters
Here is my code
function detectIntent(query, sessionId, contextData, callback) {
let projectId = config.get('projectId');
let languageCode = 'en-US';
let sessionPath = sessionClient.sessionPath(projectId, sessionId);
const request = {
session: sessionPath,
queryInput: {
text: {
text: query,
languageCode: languageCode,
}
},
queryParams: {
contexts: [
contextData
],
payload: { foo: "bar" }
},
};
sessionClient
.detectIntent(request)
.then(responses => {
const result = responses[0].queryResult;
callback(null, result);
})
.catch(err => {
callback(err, null);
});
}
Here is the response I'm getting
{
"fulfillmentMessages": [
{
"platform": "PLATFORM_UNSPECIFIED",
"text": {
"text": [
""
]
},
"message": "text"
}
],
"outputContexts": [
{
"name": "projects/ddddd-102d1/agent/sessions/blvy6skjngu4kvt/contexts/blvy6skjngu4kvu",
"lifespanCount": 2,
"parameters": {
"fields": {
"msisdn": {
"stringValue": "773959698",
"kind": "stringValue"
}
}
}
},
{
"name": "projects/ddddd-102d1/agent/sessions/blvy6skjngu4kvt/contexts/actionshow_card-followup",
"lifespanCount": 2,
"parameters": null
}
],
"queryText": "internet slow",
"speechRecognitionConfidence": 0,
"action": "action.show_card",
"parameters": {
"fields": {}
},
"allRequiredParamsPresent": true,
"fulfillmentText": "",
"webhookSource": "",
"webhookPayload": null,
"intent": {
"inputContextNames": [],
"events": [],
"trainingPhrases": [],
"outputContexts": [],
"parameters": [],
"messages": [],
"defaultResponsePlatforms": [],
"followupIntentInfo": [],
"name": "projects/ddddd-102d1/agent/intents/e378b17a-d899-4e69-8dfd-4b938b0222a5",
"displayName": "action.show_card",
"priority": 0,
"isFallback": false,
"webhookState": "WEBHOOK_STATE_UNSPECIFIED",
"action": "",
"resetContexts": false,
"rootFollowupIntentName": "",
"parentFollowupIntentName": "",
"mlDisabled": false
},
"intentDetectionConfidence": 1,
"diagnosticInfo": {
"fields": {
"webhook_latency_ms": {
"numberValue": 161,
"kind": "numberValue"
}
}
},
"languageCode": "en-us"
}
I tried with formatting the payload json by doing structjson.jsonToStructProto({foo: 'bar'}) as mention in following link
Send parameters to webhook on dialogflow sdk v2
but no success.
I have done a tutorial how to setup a Facebook chatbot for a fanpage.
It works perfect and we also can change the keyword and the message that pops up in case a user types exact the keyword.
Now the only thing is, we do not figure out, how to add multiple keywords with answers.
var express = require('express')
var bodyParser = require('body-parser')
var request = require('request')
var app = express()
app.set('port', (process.env.PORT || 5000))
// Process application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: false}))
// Process application/json
app.use(bodyParser.json())
// Index route
app.get('/', function (req, res) {
res.send('Hello world, I am a chat bot')
})
// for Facebook verification
app.get('/webhook/', function (req, res) {
if (req.query['hub.verify_token'] === 'token') {
res.send(req.query['hub.challenge'])
}
res.send('Error, wrong token')
})
// Spin up the server
app.listen(app.get('port'), function() {
console.log('running on port', app.get('port'))
})
// API End Point -
app.post('/webhook/', function (req, res) {
messaging_events = req.body.entry[0].messaging
for (i = 0; i < messaging_events.length; i++) {
event = req.body.entry[0].messaging[i]
sender = event.sender.id
if (event.message && event.message.text) {
text = event.message.text
if (text === 'hi') {
sendGenericMessage(sender)
continue
}
sendTextMessage(sender, "parrot: " + text.substring(0, 200))
}
if (event.postback) {
text = JSON.stringify(event.postback)
sendTextMessage(sender, "Postback received: "+text.substring(0, 200), token)
continue
}
}
res.sendStatus(200)
})
var token = " enter token here"
// function to echo back messages
function sendTextMessage(sender, text) {
messageData = {
text:text
}
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
// Send an test message back as two cards.
function sendGenericMessage(sender) {
messageData = {
"attachment": {
"type": "template",
"payload": {
"template_type": "generic",
"elements": [{
"title": "title 1",
"subtitle": "subtitle",
"image_url": "url of image",
"buttons": [{
"type": "web_url",
"url": "https://www.facebook.com/",
"title": "Facebook"
}, {
"type": "web_url",
"url": "https://www.reddit.com",
"title": "Reddit"
},{
"type": "web_url",
"url": "https://twitter.com/",
"title": "Twitter"
}],
}, {
"title": "Title 2 ",
"subtitle": "Subtitle",
"image_url": "imgurl",
"buttons": [{
"type": "postback",
"title": "title",
"payload": "payload",
},{
"type": "postback",
"title": "title",
"payload": "payload",
}, {
"type": "postback",
"title": "title",
"payload": "payload",
}],
}, {
"title": "title",
"subtitle": "subtitle",
"image_url": "http://www.google.com",
"buttons": [{
"type": "postback",
"title": "title",
"payload": "payload",
},{
"type": "postback",
"title": "title",
"payload": "payload",
}, {
"type": "postback",
"title": "title",
"payload": "payload",
}],
}]
}
}
}
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
Do you mean to say - You need to handle multiple keywords for same answer? If that is the case, then facebook sends the message as text on webhook. You need to catch it and send message back to facebook accordingly.
As in the code you've sent, [if (text === 'hi')], you need sample messages(hi in this case) to be stored in system and map the answer.