Skip to content

Instantly share code, notes, and snippets.

@d6y
Created March 29, 2018 07:09
Show Gist options
  • Save d6y/4d3d26e8e8934be7641c7fbda4776a03 to your computer and use it in GitHub Desktop.
Save d6y/4d3d26e8e8934be7641c7fbda4776a03 to your computer and use it in GitHub Desktop.
'use strict';
const admin = require('firebase-admin');
admin.initializeApp();
const functions = require('firebase-functions'); // Cloud Functions for Firebase library
const DialogflowApp = require('actions-on-google').DialogflowApp; // Google Assistant helper library
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
if (request.body.queryResult) {
processV2Request(request, response);
} else {
console.log('Invalid Request');
return response.status(400).end('Invalid Webhook Request (expecting v2 webhook request)');
}
});
/*
* Function to handle v2 webhook requests from Dialogflow
*/
function processV2Request (request, response) {
// An action is a string used to identify what needs to be done in fulfillment
let action = (request.body.queryResult.action) ? request.body.queryResult.action : 'default';
// Parameters are any entites that Dialogflow has extracted from the request.
let parameters = request.body.queryResult.parameters || {}; // https://dialogflow.com/docs/actions-and-parameters
// Contexts are objects used to track and store conversation state
let inputContexts = request.body.queryResult.contexts; // https://dialogflow.com/docs/contexts
// Get the request source (Google Assistant, Slack, API, etc)
let requestSource = (request.body.originalDetectIntentRequest) ? request.body.originalDetectIntentRequest.source : undefined;
// Get the session ID to differentiate calls from different users
let session = (request.body.session) ? request.body.session : undefined;
// Create handlers for Dialogflow actions as well as a 'default' handler
const actionHandlers = {
// The default welcome intent has been matched, welcome the user (https://dialogflow.com/docs/events#default_welcome_intent)
'input.welcome': () => {
sendResponse('Hello, Welcome to Brighton Tide. Try asking for the next low tide.'); // Send simple response to user
},
// The default fallback intent has been matched, try to recover (https://dialogflow.com/docs/intents#fallback_intents)
'input.unknown': () => {
// Use the Actions on Google lib to respond to Google requests; for other requests use JSON
sendResponse('I\'m having trouble understanding. Try asking for the next low tide.'); // Send simple response to user
},
'next-low': () => {
var db = admin.firestore();
const now = new Date();
const nowUtc = now.getTime();
const sameDay = (tide, date) => date.toISOString().substr(0, 10) === tide.date;
function express(tide, now) {
if (sameDay(tide, now)) {
return `There's a ${tide.height} metre low at ${tide.time12}.`
} else {
return `There's a ${tide.height} metre low at ${tide.time12} on ${tide.dow}.`
}
}
db.collection('tide-times')
.where('instant', '>=', nowUtc)
.where('highOrLow', '=', 'low')
.orderBy('instant', 'asc')
.limit(1)
.get().then((snapshot) => {
if (snapshot._size === 0) {
console.log('No tides', nowUtc);
sendResponse('Sorry, I can\'t find any tide times.');
} else {
snapshot.forEach((doc) => {
var tide = doc.data();
var replyText = express(tide, now);
sendResponse(replyText);
});
}
})
.catch((err) => {
console.log('Error getting documents', err);
sendResponse('Sorry, something went wrong. Maybe try again later.');
});
},
// Default handler for unknown or undefined actions
'default': () => {
let responseToUser = {
//fulfillmentMessages: richResponsesV2, // Optional, uncomment to enable
//outputContexts: [{ 'name': `${session}/contexts/weather`, 'lifespanCount': 2, 'parameters': {'city': 'Rome'} }], // Optional, uncomment to enable
fulfillmentText: 'Sorry, I didn\'t understand that. You can ask for the next low tide.' // displayed response
};
sendResponse(responseToUser);
}
};
// If undefined or unknown action use the default handler
if (!actionHandlers[action]) {
action = 'default';
}
// Run the proper handler function to handle the request from Dialogflow
actionHandlers[action]();
// Function to send correctly formatted responses to Dialogflow which are then sent to the user
function sendResponse (responseToUser) {
// if the response is a string send it as a response to the user
if (typeof responseToUser === 'string') {
let responseJson = {fulfillmentText: responseToUser}; // displayed response
console.log('Text Response to Dialogflow: ' + JSON.stringify(responseJson));
response.json(responseJson); // Send response to Dialogflow
} else {
// If the response to the user includes rich responses or contexts send them to Dialogflow
let responseJson = {};
// Define the text response
responseJson.fulfillmentText = responseToUser.fulfillmentText;
// Optional: add rich messages for integrations (https://dialogflow.com/docs/rich-messages)
if (responseToUser.fulfillmentMessages) {
responseJson.fulfillmentMessages = responseToUser.fulfillmentMessages;
}
// Optional: add contexts (https://dialogflow.com/docs/contexts)
if (responseToUser.outputContexts) {
responseJson.outputContexts = responseToUser.outputContexts;
}
// Send the response to Dialogflow
console.log('Response to Dialogflow: ' + JSON.stringify(responseJson));
response.json(responseJson);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment