Google Actions + Webhook + GoogleSheets integration - node.js

Im trying to build what I thought would be a simple call and response scenario with Google Actions. I'm trying to ask google actions a question and behind the scenes a webhook gets invoked which pulls a single value from a google sheet and the google assistant reads it out.
My programming experience is solely in SQL and even that is not strong so apologies if this is a complete shambles. I've managed to set up the google actions scenes via the gui but the webhook call is where I'm falling short. I've posted where I have got to today via a number of google searches.
I assume this is super easy but with my no coding experience I'm learning the basics in node.js, google actions together, I just wanted to get an understanding if I'm going in th right direction or if I'm completely off the mark.
UPDATE:08/03:- Where I've got to with the below is the handle gets called when the google intent happens and that seems to work fine. Then I can see in the console.log that the axios.get is reaching the API and pulling the data. So the with the conv.add I was hoping that by putting response it would take whats in the axios response and call that out as speech but it doesnt seem to work.
I think where I'm getting stuck is what do I do with the response from the axios.get to turn it into something google actions can respond in speech?
const { conversation } = require('#assistant/conversation');
const functions = require('firebase-functions');
const axios = require('axios');
const app = conversation({debug: true});
app.handle('YTDget', conv => {
axios.get ('https://sheetdb.io/api/v1/u1yid5jisv40g')
.then (response => {
console.log (response);
});
conv.add(response);
});
exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);

Related

Axios not working in AWS Lambda with Google Servers

I am currently experiencing a weird issue.
I use axios in my NodeJS Lambda (AWS) to verify a Google Recaptcha Token.
However, this request to Google via axios.post() takes forever and therefore the Lambda function gets a timeout. (10s)
At first I thought it might be the VPC or the Security Group but no, I commented out the request and sent another request via axios which works.
Only the one via Google does not work. (On my local machine it works of course).
The code I use for posting to Google:
const response = await axios.post(
`https://www.google.com/recaptcha/api/siteverify?secret=${recaptchaSecret}&response=${event.token}`
);
I have already put a try / catch block around it and no errors are printed / catched.
Looking forward to your suggestions.
Thanks.

POST request hangs (timeout) when trying to parse request body, running Koa on Firebase Cloud Functions

I'm working on a small website, serving static files using Firebase Hosting (FH) and rewriting all requests to a single function on Firebase Cloud Functions (FCF), where I'm using Koa (with koa-router) to handle the requests. However, when I try to parse the body of a POST request using koa-bodyparser, the service just hangs until it eventually times out.
The same thing occurs when using other body parsers, such as koa-body, and it seems to persist no matter where I put the parser, unless I put it after the router, in which case the problem goes away, though I still can't access the data, since it never gets a chance to be parsed(?).
The following is a stripped-down version of the code that's causing the problem:
import * as functions from 'firebase-functions'
import * as Koa from 'koa'
import * as KoaRouter from 'koa-router'
import * as KoaBodyParser from 'koa-bodyparser'
const app = new Koa()
const router = new KoaRouter()
app.use(KoaBodyParser())
router.post('/', (context) => {
// do some stuff with the data
})
app.use(router.routes())
export const serve = functions.https.onRequest(app.callback())
I'm still pretty new to all of these tools and I might be missing something completely obvious, but I can't seem to find the solution anywhere. If I'm not mistaken, FCF automatically parses requests, but Koa is unable to access that data unless it does the parsing itself, so I'd assume that something is going wrong between FCF's automatic parsing and the parser used by Koa.
I haven't been able to produce any actual errors or useful error messages, other than a Gateway Timeout (504), so I don't have much to go on and won't be able to provide you with much more than I already have.
How do I go about getting a hold of the data?
Firebase already parses the body.
https://firebase.google.com/docs/functions/http-events#read_values_from_the_request
It appears that the provided Koa body parsing middlewares don't know what to do with an "already parsed" body (ie an object vs an unparsed string), so the middleware ends up getting confused and does some sort of an infinite loop.
A solution is to use ctx.req.body because it's already parsed. :)
Koa rocks!

Making a POST request in webhook in an Actions on Google app.intent [duplicate]

This question already has an answer here:
Making an HTTP POST request from fulfillment in Dialogflow
(1 answer)
Closed 4 years ago.
We are creating an action that will take user's input and create an entity in our database (datastore).
Ideally, we would like to be able to access the user's raw input audio, but it doesn't seem that is possible.
As a work around we are going to send the speech-to-text of user's utterance to our backend services. We are using firebase cloud functions for our fulfillment and an external rest api for our crud operations.
We are trying to make a post request in a webhook to create an entity based on user's input, but when I check my logs it doesn't seem like the post request is reaching our service. I'm not able to debug what or if we are getting a response back
app.intent('favorite color', (conv, {color}) => {
const options = {
// options
};
function callback(error, response, body) {
// log response or error
}
request(options, callback);
const luckyNumber = color.length;
// Respond with the user's lucky number and end the conversation.
conv.close('This word has ' + luckyNumber + ' letters.');
});
// Set the DialogflowApp object to handle the HTTPS POST request.
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
This question is not the same as the one that it was marked as a duplicate because the solution was the account type not supporting POST requests to an external API and not the HTTP Client we were using
The Inline Editor in the Dialogflow console uses Firebase Cloud Functions, as you already know.
Unfortunately, Firebase Cloud Functions DOESN'T support external API calls in it's free plan. You may need to switch to blaze plan or deploy your fulfillment elsewhere.

Response from Webhook using NodeJS Client

I built a custom webhook as a fulfillment endpoint for a Dialogflow intent. It works fine when I respond with raw JSON, ie: {'fullfillmentText':'hi'},
but does not seem to work using the "actions-on-google" library.
The code from their website implies this should work:
app.intent('myintent', (conv) => {
conv.close('See you later!');
});
But it does not. Google Home just says my app isn't responding. It might be that as it stands my function (using Fn Project) has to return JSON and if I return JSON as a response that it isn't expecting it fails. Maybe someone can shed some light?
Edit 1:
I'm using a custom webhook using the Fn Project open source functions as a service. Demonstrating how to use the project is my purpose here so I don't want to use inline editor or Google Cloud Functions or firebase or any other default option.
Here's the rest of the code
const fdk = require('#fnproject/fdk');
const request = require('request');
const dialogflow = require('actions-on-google');
const app = dialogflow({
debug: true,
});
fdk.handle(function (input) {
app.intent('myintent', (conv) => {
conv.ask('I could not understand. Can you say that again?');
});
return {'fulfillmentText': 'response from webhook'}
});
Although you are creating the app object, which does the Intent handler processing and such, and registering a handler with it via app.intent(), you're not doing anything to "export" it so app's methods are called when the webhook is triggered. When called, it gets the body of the request and will format the JSON for the response.
If, for example, you were using Firebase functions, you would connect app to be handled through the functions with something like
exports.fulfillment = functions.https.onRequest(app);
But you're not. You're using a different framework.
The library comes with a number of frameworks that are supported out of the box, but the Fn Project isn't one of them. In theory, you can create your own Framework object which will do this for you (the "Frameworks" section of this article discusses it briefly, but doesn't go into details about how to do so).
As you surmise, it may be easiest for you to just read the JSON request and generate the JSON response yourself without using the actions-on-google library. Or you can look into a library such as multivocal to see if it would be easier to leverage its multi-framework support.

Scraping from Facebook

I have a challenge I'm running into and cannot seem to find an answer for it anywhere on the web. I'm working on a personal project; it's a Node.js application that uses the request and cheerio packages to hit an end-point and scrape some data... However, the endpoint is a Facebook page... and the display of its content is dependent upon whether the user is logged in or not.
In short, the app seeks to scrape the user's saved links, you know, all that stuff you add to your "save for later" but never actually go back to (at least in my case). The end-point, then, is htpps://www.facebook.com/saved. If, in your browser, you are logged into Facebook, clicking that link will take you where the application needs to go. However, since the application isn't technically going through the browser that has your credentials and your session saved, I'm running into a bit of an issue...
Yes, using the request module I'm able to successfully reach "a" part of Facebook, but not the one I need... My question really is: how should I begin to handle this challenge?
This is all the code I have for the app so far:
var express = require('express');
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var app = express();
app.get('/scrape', (req, res) => {
// Workspace
var url = 'https://www.facebook.com/saved';
request(url, (err, response, html) => {
if (err) console.log(err);
res.send(JSON.stringify(html));
})
})
app.listen('8081', () => {
console.log('App listening on port 8081');
})
Any input will be greatly appreciated... Currently, I'm on hold...! How could I possibly hit this end-point with credentials (safely) provided by the user so that the application could get legitimately get past authentication and reach the desired end-point?
I don't think you can accomplish that using request-cheerio module since you need to make a post request with your login information.
A headless browser is more appropriate for this kind of project if you want it to be a scraper. Try using casperJs or PhantomJs. It will give you more flexibility but it's not a node.js module so you need to make a step further if you want to incorporate it with express.
One nodeJs module I know that can let you post is Osmosis. If you can make .login(user, pw) to work then that'll be great but I don't think it can successfully login to facebook though.
API if possible would be a much nicer solution but I'm assuming you already looked it up and find nothing in there for what you are looking for.
My personal choice would be to use an RobotProcessAutomation. WinAutomation, for example, is a great tool for manipulating web and scraping. It's a whole new different approach but it can do the job well and can be implemented faster compared to programmatically coding it.

Resources