How to test http request on Dialogflow Fulfillment with the Inline Editor - dialogflow-es

I am testing Dialogflow Fulfillment with the Inline Editor.
What I am trying to do is a http request using que 'request' library.
Here is the code I am using:
const requesthttp = require('request');
requesthttp('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY', { json: true }, (err, res, body) => {
if (err) { return console.log(err); }
console.log(body.url);
console.log(body.explanation);
});
But It returns me an error of not found.
I also noticed an alert on my Dialogflow with the following message:
"Billing account not configured. External network is not accessible and quotas are severely limited. Configure billing account to remove these restrictions."
So... Probably I can't test this piece of code without configuring a billing account.
My question is... Is there a url that I can use to test this code?
Or the only way for me to test this code is configuring a billing account and paying for it?
Thanks in advance

There are a number of approaches to testing your code.
If you want to continue to use Dialogflow's Inline Editor, you will need to setup Firebase to use a payment plan. However, the Blaze plan is "pay as you go" after a basic level of use. This level of use should be sufficient to cover most testing (and even very light production) uses of the service without imposing a charge. Once your Action has been approved, you're able to receive credits for the Google Cloud Platform, which can be applied to this use in case you go over the minimum level.
You can also use Firebase Cloud Functions, which the Inline Editor is based on, and your own local editor. One advantage of this is that you can serve the function locally, which has many of the same features as deploying it, but doesn't have the URL restriction (it is your own machine, after all). You can use a tool such as ngrok to create a secure tunnel to your your machine during testing. Once you have tested, you can deploy this to Firebase with a paid plan.
You can, of course, choose to use any other hosting method you wish. Google and Dialogflow allow you to run your fulfillment webhook on any server, as long as that server can provide an HTTPS connection using a valid, non-self-signed, certificate. If you're using node.js, you can continue to use these libraries. If you wish to use another language, you will need to be able to parse and return JSON, but otherwise you have no restrictions.

There are a lot of ways to create your own server like using NodeJS client with Express.JS which you can expose to the internet using NGROK as webhook for fulfilment.
Develop a webhook. You can use different client libraries in NodeJS (AoG Client or Dialogflow Client) or in Python (Flask-Assistant or Dialogflow Client) or can create your own just using JSON request/response with Dialogflow and Action-on-Google.
Once the webhook is ready, run it locally and expose to the internet using NGROK.
Start with following code for Actions-on-Google with Express.JS
'use strict';
const {dialogflow} = require('actions-on-google');
const express = require('express');
const bodyParser = require('body-parser');
const app = dialogflow();
app.intent('Default Welcome Intent', conv => {
conv.ask('Hi, Welcome to Assistant by Express JS ');
});
express().use(bodyParser.json(), app).listen(8080);

Since DF uses firebase cloud functions you can use https as in nodejs. But requesting domains outside of the google/firebase universe will require the paid version of firebase.
const https = require('https');
return new Promise((resolve, reject) => {
const hostname = info.hostname;
const pathname = info.pathname;
let data = '';
const request = https.get(`https://${hostname}${pathname}`, (res) => {
res.on('data', (d) => {
data += d;
});
res.on('end', resolve);
});
request.on('error', reject);
});

Related

Firebase test auth cloud functions locally

exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => {
console.log(user.uid);
console.log(user.email);
console.log(user.displayName);
});
exports.getUserInfo = functions.https.onCall(async (data, context) => {
// get array of user IDs and returns information (from Users collection)
const userIDs = data.userIDs;
const result = [];
const querySnapData = await admin.firestore().collection("Users").get();
querySnapData.forEach((ele) => {
if (userIDs.indexOf(ele.id) !== -1 && ele.id !== context.auth.uid) {
result.push(ele.data());
}
});
return { res: result };
});
I've got these two functions in my project - one is callable function and the other one is auth trigger functions.
So in my client app, I run
firebase.functions().useFunctionsEmulator('http://localhost:5001');
let getUserInfo = functions.httpsCallable('getUserInfo');
getUserInfo({userIDs: data}).then(res => doSomething);
And to run the cloud functions locally
firebase emulators:start
But it says
functions[sendWelcomeEmail]: function ignored because the auth emulator does not exist or is not running.
So in the client App, getUserInfo works pretty well but can't trigger onCreate.
But I was not able to find any document about auth emulator.
Any link/article/video or answer is appreciated.
The Firebase Emulator Suite currently Cloud Firestore, Realtime Database, Cloud Functions, and Cloud Pub/Sub. It does not yet emulate Firebase Authentication APIs. So any auth calls you make will be executed against the real project that is associated with the emulators.
This also means that your functions.auth.user().onCreate((user) => { Cloud Function will not be triggered in the emulators at the moment. You'll have to deploy it to the servers to test this trigger.
To learn when an auth emulator is available, I recommend keeping an eye on Firebase's release notes, and on the main documentation page for the emulator suite that lists the supported products. You can also follow along more closely on Github, either in the commits, or in this feature request.
firebase recently released the Authentication Emulator, you can check it via the release notes here: https://firebase.google.com/support/releases#october_26_2020, and further guide here: https://firebase.google.com/docs/emulator-suite/connect_auth
So as #Franek van Puffelen wrote above, it is not done yet.
Was able to test auth functions locally like below.
function sendWelcomeEmail(user) {
console.log(user.uid);
console.log(user.email);
console.log(user.displayName);
}
exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => sendWelcomeEmail(user));

How can I deploy a discord.js bot to Cloud Functions?

I want to deploy a Discord bot running on discord.js to Firebase Cloud Functions but I can't get the bot to run in Firebase. If I use nodemon it runs perfectly but if I use firebase deploy it will not start the bot.
Here is my current code:
const functions = require('firebase-functions');
require('dotenv').config();
const token = process.env.TOKEN
const Discord = require('discord.js')
const Client = new Discord.Client();
Client.on('ready', () => {
Client.channels.find(x => x.name === 'main-cannel').send('bot is deployed')
Client.user.setGame(`The Cult | ${Client.guilds.size} servers`)
Console.log('test')
});
Client.login(token);
//is is not working but de basic
//export.App = functions.... {Client}
exports.app = functions.https.onRequest((request, response) => {
response.send("Test");
});
This may not be the best combination of google cloud platform services, since cloud functions where not designed with this in mind. You can just host your Discord bot on a compute engine machine.
If you want to use the dynamic scaling have a look at Discord Microservice Bots where DasWolke describes what microservices are. Hey also included his javascript code to split up the different services for Discord.
What you can do on Google cloud platform specifically, is creating a VM with the Gateway running. This needs to run 24/7 and should be lightweight. You can use an f1-micro (which is free) for this though google recommends a g1-small for the task.
The gateway should filter the events you are looking for (because Discord sends a lot of events and you don't need most) and send the data to cloud function or cloud run (you can send the data via pub/sub). In my experience, a cloud run has much shorter startup times so I went with that.
Inside your function, you receive the data do with it what you want. If you want something in Discord (send a message, manage channels, ...) you can use SnowTransfer for that. SnowTransfer just calls the rest API on discord.
Put client.login(token) into where response.send("Test"); is. This will prompt your bot's code to execute upon an HTTP request.
In https://us-central1-<your project ID>.cloudfunctions.net/app, replace <your project ID> with your project's ID.
If Firebase Hosting gives you the URL example-123.web.app, your project ID is example-123. You can also get your project ID through the console: open the Firebase console, select your project, click the settings icon, go to "Project settings," and its ID is on the second line of the table.
For this to work, you have to move your token straight into the code. You can't use a shell file like .env.
In the end, your code will be:
const functions = require('firebase-functions');
const token = 'whatever the token is';
const Discord = require('discord.js')
const Client = new Discord.Client();
Client.on('ready', () => {
Client.channels.find(x => x.name === 'main-cannel').send('bot is deployed')
Client.user.setGame(`The Cult | ${Client.guilds.size} servers`)
Console.log('test')
});
exports.app = functions.https.onRequest((request, response) => {
response.send("Test"); // Do not delete this! Your request will time out if you do.
Client.login(token);
});
As Gabber235 noted, this is probably not the best Google Cloud Platform service to use for this, and you should probably use Compute Engine.

Implementing isRequestFromAssistant in Node.js on actions-on-google project fulfillment

I am having trouble implementing the isRequestFromAssistant method to verify requests to my fulfillment webhook. Using Node.js, I instantiate the following variables at the start of my index.js file:
const App = require('actions-on-google').ApiAiApp;
const app = new App({ request, response });
I then use "app" with the .ask and .tell and other methods throughout my functions.
The code I see in the docs for implementing isRequestFromAssistant is:
const app = new ActionsSdkApp({request, response});
app.isRequestFromAssistant('my-project-id')
.then(() => {
app.ask('Hey there, thanks for stopping by!');
})
.catch(err => {
response.status(400).send();
});
If I leave out the first line and use my existing app variable, created with the .ApiAi method instead of the .ActionsSdkApp method, it doesn't work. If I create a new variable App1 and app1 using the .ActionsSdkApp method and change the above code to be app1.isRequestFromAssistant, it also doesn't work. I have tried other variations with no luck.
When I say it doesn't work, I mean I receive a 500 Internal Server Error when I call it. I am hosting it with NGROK currently. I am still a beginner with Node.js, although I have managed to get the other 700 lines of code working just fine, learning mostly from Google searches and reading these forums.
You have a few things going on here which, individually or separately, may be causing the problem.
First - make sure you have the most recent version of the actions-on-google library. The isRequestFromAssistant() function was added in version 1.6.0, I believe.
Second - Make sure you're creating the right kind of App instance. If you're using Dialogflow (formerly API.AI), you should be creating it with something like
const App = require('actions-on-google').DialogflowApp;
const app = new App( {request, response} );
or
const { DialogflowApp } = require('actions-on-google');
const app = new DialogflowApp( {request, response} );
(They both do the same thing, but you'll see both forms in documentation.) You should switch to DialogflowApp from ApiAiApp (which your example uses) to reflect the new name, but the old form has been retained.
If you're using the Actions SDK directly (not using Dialogflow / API.AI), then you should be using the ActionsSdkApp object, something like
const { ActionsSdkApp } = require('actions-on-google');
const app = new ActionsSdkApp({request: request, response: response});
(Again, you'll see variants on this, but they're all fundamentally the same.)
Third - Make sure you're using the right function that matches the object you're using. The isRequestFromAssistant() function is only if you are using the Actions SDK.
If you are using Dialogflow, the corresponding function is isRequestFromDialogflow(). The parameters are different, however, since it requires you to set confirmation information as part of your Dialogflow configuration.
Finally - If you're getting a 500 error, then check your logs (or the output from stderr) for the node.js server that is running. Typically there will be an error message there that points you in the right direction. If not - posting that error message as part of your StackOverflow question is always helpful.
Set the secure (randomly generated) auth header & key values in the dialogflow Fulfillment page, then in nodejs:
if (app.isRequestFromDialogflow("replace_with_key", "replace_with_value")) {
console.log("Request came from dialogflow!");
// rest of bot
} else {
console.log("Request did not come from dialogflow!");
response.status(400).send();
}
Also see: https://developers.google.com/actions/reference/nodejs/DialogflowApp#isRequestFromDialogflow

How to run Alexa skill with the alexa-sdk on own server with Node.js without Lambda drop-in?

The Alexa skill docs will eventually allow you to send webhooks to https endpoints. However the SDK only documents lambda style alexa-sdk usage. How would one go about running Alexa applications on one's own server without anything abstracting Lambda? Is it possible to wrap the event and context objects?
You can already use your own endpoint. When you create a new skill, in the configuration tab, just choose HTTPS and provide your https endpoint. ASK will call your endpoint where you can run anything you want (tip, check ngrok.com to tunnel to your own dev machine). Regarding the event and context objects; your endpoint will receive the event object information. You don't need the context object for anything, that just lets you interact with Lambda-specific stuff (http://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html). Just make sure that you comply with the (undocumented) timeouts by ASK and you are good to go.
Here's a way to do this that requires only a small change to your Skill code:
In your main index.js entry point, instead of:
exports.handler = function (event, context) {
use something like:
exports.myAppName = function (funcEvent, res) {
Below that, add the following workaround:
var event = funcEvent.body
// since not using Lambda, create dummy context with fail and succeed functions
const context = {
fail: () => {
res.sendStatus(500);
},
succeed: data => {
res.send(data);
}
};
Install and use Google Cloud Functions Local Emulator on your laptop. When you start and deploy your function to the emulator, you will get back a Resource URL something like http://localhost:8010/my-project-id/us-central1/myAppName.
Create a tunnel with ngrok. Then take the ngrok endpoint and put it in place of localhost:8010 in the Resource URL above. Your resulting fulfillment URL will be something like: https://b0xyz04e.ngrok.io/my-project-id/us-central1/myAppName
Use the fulfillment URL (like above) under Configuration in the Alexa dev console, selecting https as the Service Endpoint Type.

Cloud Functions for Firebase and third party api

My problem is to make use of an API along with Firebase Functions, the API in question is Coinbase, I use the API with node, if I test in the terminal with the node command it works, however when I use it with Firebase Functions Does not work at all, I've been trying to solve the problem for almost a week now.
The code is as follows>
var functions = require('firebase-functions');
var Client = require('coinbase').Client;
var client = new Client({
"apiKey": "xxxxxxxxxxxx",
"apiSecret": "xxxxxxxxxxxxxxxxxxxxxxx"
});
exports.helloWorld = functions.https.onRequest((request, response) => {
this.client.getAccounts({}, function(err, accounts) {
if(accounts){
response.send(accounts);
}else{
response.send(err);
}
});
});
The error: https://us-central1-investimentos-b7406.cloudfunctions.net/helloWorld
The Coinbase API: https://developers.coinbase.com/docs/wallet/guides/bitcoin-wallet
There's a warning in the docs:
Firebase projects on the Spark plan can make only outbound requests to
Google APIs. Requests to third-party APIs fail with an error. For more
information about upgrading your project, see Pricing.
So you'll need to upgrade to a paid plan to use external APIs.

Resources