Last active
November 24, 2020 09:48
-
-
Save SethBuilder/0c3e26a2aa4f7c2765ec1167b7a44bcd to your computer and use it in GitHub Desktop.
Node webhook for the Google Assistant.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const {dialogflow, Image, Carousel, BasicCard, Button, LinkOutSuggestion} = require('actions-on-google'); | |
const functions = require('firebase-functions'); | |
// Different "Intents" or "purposes" to be fullfilled | |
const WELCOME_INTENT = 'Default Welcome Intent'; | |
const TRIPS_INTENT = 'find_trips'; | |
const TRIP_INTENT = 'trip_details'; | |
// Params passed to backend by the assistant | |
const LOCATION_PARAMETER_1 = 'geo-city'; | |
const LOCATION_PARAMETER_2 = 'geo-state'; | |
const LOCATION_PARAMETER_3 = 'geo-country'; | |
const LOCATION_PARAMETER_4 = 'place-attraction'; | |
const app = dialogflow({debug: false}); | |
app.fallback((conv, input, option) => { | |
const intent = conv.intent; | |
const axios = require('axios'); | |
switch (intent) { | |
// Welcome Intent triggered right after user invokes Action | |
case WELCOME_INTENT: | |
conv.ask(`Hello there! Welcome to Adventure Meetups! Where would you like to go? `); | |
const countries_url = process.env.COUNTRIES_API_URL; | |
return axios.get(countries_url) | |
.then(response => { | |
this.data = response.data.data; | |
// list of countries to show on carousel | |
let items={}; | |
// String of countries to read out to user | |
let countries = ""; | |
this.data.forEach((item, index, array) => { | |
let obj = | |
{ | |
synonyms: [ | |
item.code, | |
], | |
title: item.name, | |
description: item.activities + "Trips", | |
image: new Image({ | |
url: item.photo, | |
alt: item.name, | |
}), | |
}; | |
items[item.name.toUpperCase()] = obj | |
if (index == 0) { | |
countries+=item.name; | |
} | |
else if (index === array.length - 1) { | |
countries+=" and "+item.name+"."; | |
} | |
else { | |
countries+=", "+item.name; | |
} | |
}); | |
// Return string | |
conv.ask(' We have trips and tours in '+countries); | |
// and carousel | |
conv.ask(new Carousel({ | |
title: 'Trips', | |
items: items | |
})); | |
}) | |
break; | |
// Trip details Intent | |
case TRIP_INTENT: | |
const trip_url = process.env.TRIP_DETAILS_API_URL+option; | |
return axios.get(trip_url) | |
.then(response => { | |
const data = response.data.data; | |
const isCountry = response.data.isCountry; | |
if(!isCountry) { | |
// Return trip details | |
conv.ask(`Alright, here are the deets for this trip.`); | |
conv.ask(new BasicCard({ | |
text: data.deets, | |
subtitle: data.category.name, | |
title: data.name, | |
buttons: new Button({ | |
title: 'Book | $'+data.budgetUsd+" per person", | |
url: data.complete_url, | |
}), | |
image: new Image({ | |
url: data.hasVideoCover ? data.inspiration.desktopThumb : data.inspiration.desktopInspiration, | |
alt: data.name, | |
}), | |
display: 'CROPPED', | |
})); | |
conv.close(new LinkOutSuggestion({ | |
name: 'Search', | |
url: 'https://www.getyourguide.com/s?partner_id=0CVLYT9', | |
})); | |
} | |
else { | |
// Return all trips in certain country (after being selected from carousel) | |
var items={}; | |
data.forEach((item) => { | |
let obj = | |
{ | |
synonyms: [ | |
item.name, | |
], | |
title: item.name, | |
description: item.deets, | |
image: new Image({ | |
url: item.hasVideoCover ? item.inspiration.desktopThumb : item.inspiration.desktopInspiration, | |
alt: item.name, | |
}), | |
}; | |
items[item.name.toUpperCase()] = obj | |
}); | |
conv.ask('I found these awesome trips for you!'); | |
conv.ask(new Carousel({ | |
title: 'Trips', | |
items: items | |
})); | |
conv.ask(` I hope you like them!`); | |
} | |
}) | |
.catch(err => { | |
conv.ask(`Albeit I'm super awesome, I'm unable to respond right now due to computer error.`); | |
}) | |
break; | |
// When user mentions random location names instaed of choosing country | |
case TRIPS_INTENT: | |
// User might mention location name(s) instead of choosing country from carousel. | |
// Backend returns all trips if it found none matching user's preference. | |
const location = conv.parameters[LOCATION_PARAMETER_1] + " " +conv.parameters[LOCATION_PARAMETER_2] + conv.parameters[LOCATION_PARAMETER_3] | |
+ " " +conv.parameters[LOCATION_PARAMETER_4]; | |
const url_call = process.env.LOCATION_SEARCH_API_URL+location; | |
return axios.get(url_call) | |
.then(response => { | |
this.data = response.data.data; | |
var items={}; | |
this.data.forEach((item) => { | |
let obj = | |
{ | |
synonyms: [ | |
item.name, | |
], | |
title: item.name, | |
description: item.deets, | |
image: new Image({ | |
url: item.hasVideoCover ? item.inspiration.desktopThumb : item.inspiration.desktopInspiration, | |
alt: item.name, | |
}), | |
}; | |
items[item.name.toUpperCase()] = obj | |
}); | |
return items; | |
}) | |
.then(items => { | |
conv.ask('I found these awesome trips for you!'); | |
conv.ask(new Carousel({ | |
title: 'Trips', | |
items: items | |
})); | |
conv.ask(` I hope you like them!`); | |
}) | |
break; | |
} | |
}); | |
exports.tripFinder = functions.https.onRequest(app); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "google-assistant-trip-finder", | |
"description": "Node.js webhook as backend for the google assistant as frontend", | |
"version": "0.0.1", | |
"author": "Seif Elmughrabi", | |
"engines": { | |
"node": "8" | |
}, | |
"dependencies": { | |
"actions-on-google": "^2.0.0", | |
"firebase-admin": "^4.2.1", | |
"firebase-functions": "1.0.0" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment