How to use API in actions-on-google - actions-on-google

I have tried the following javascript code, using a railway API in aog for getting names of trains between 2 stations.
train : function(conv,src,dst) {
const options={
method:'GET',
url : `https://api.railwayapi.com/v2/between/source/${src}/dest/${dst}/date/23-09-2018/apikey/<api_key>/`,
json : true
};
var data=[];
return rp(options)
.then(function(parseBody){
for(var i=0;i<2;i++){
data.push(parseBody.trains[i].name);
}
console.log(data);
return conv.ask(data[0] + data[1]);
}).catch(err=>{
console.log("api error" + err);
});
}
When I run it in my computer using terminal(node filename.js) it shows the data[] array with correct values. But when I try to run it from actions-on-google simulator it catches an error as follows...
api errorRequestError: Error: getaddrinfo ENOTFOUND api.railwayapi.com api.railwayapi.com:443

If you are trying to do this using Firebase Cloud Functions (FCF) or the Dialogflow Built-In editor (which uses FCF under the covers), the most likely cause is that you are using the free tier of FCF which does not allow calls outside Google's network.
You can upgrade to the Blaze Plan to get around this. While this does require a credit card to be on file, it includes a free tier which is quite sufficient for some basic testing and probably even some very light usage once you're in production. Once you have your Action approved, you will be eligible to receive cloud credits from Google which can be used to offset costs associated with using Cloud Functions.

Related

Attempting a Google Drive partial Download (Flutter) throws a header error

Here's my issue :
I am creating a small application based on audio files stored on Google Drive, in Flutter.
I am using the drive api to make my requests, with these scopes in my google sign in :
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [
'email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/contacts.readonly',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/docs',
'https://www.googleapis.com/auth/drive.appdata',
],
);
I have an auth element and handle signing in and out. Until then, no issues.
I can also request my files with an implementation looking like this :
var api = widget.api.getAPI();
var files = await api.files.list($fields: '*');
This works perfectly, and so does :
var api = widget.api.getAPI();
var files = await api.files.get("myFileId"); (//does get a file instance)
But since I'd like to retrieve some of the Metadata included in my audio files, and since the drive API doesn't natively support extracting audio metadata and sending it as a google metadata, I thought I'd extract it with a partial download on the file itself.
Here's the catch : I can't seem to get the partial download to work.
Based on the doc, I thought the implementation would look something like this :
import 'package:googleapis/drive/v3.dart' as ga;
(...)
try {
var partiallyDownloadedFile = await api.files.get(
"myFileIdHere",
downloadOptions: ga.PartialDownloadOptions(ga.ByteRange(0, 10))); //should get a ga.Media instance
print("partial download succeeded");
print(partiallyDownloadedFile);
//(...do stuff...)
return;
} catch (err) {
print('Error occured : ');
print(err);
return;
}
But this always throws this error :
ApiRequestError(message: Attempting partial download but got invalid
'Content-Range' header (was: null, expected: bytes 0-10/).)
I tried using it on Wav files, but also MP4 files. The error is always the same, which leads me to believe it's my implementation that's somehow wrong, but I'm not sure what I'm supposed to do to fix it. Is it my request missing the header ? The response not including it ?
While very clear, that error doesn't help me troubleshoot my issue at all. I can't seem to find any documentation on how to conduct a partial media request. I haven't found any example projects to compare it with.
PartialDownloadOptions does not have much documentation.
I could handmake a partial request through the download links (which is how I can read the music to begin with) but the drive API supposedly allows this. Could anyone familiar with Flutter/the google APIs help me correct my implementation?
EDIT : This was due to an error within the commons library in the Dart google APIs, and was (at the very least superficially) fixed thanks to Kevmoo's efforts : https://github.com/google/googleapis.dart/issues/462
It was a Content-Range error happening due to browser specifications with access-control-expose-header compared to iOS/Android-type requests that typically expose every header.

How to request synthesis with a positive volume gain?

The API for Google Cloud Text-to-speech provide an option to add/remove volume gain when requesting synthesis.
Link: Documentation
The field that enable that option is volume_gain_db
I'm using the RPC APIv1 (Google Text-to-Speech) on a project using the Go library.
The code is running from an instance inside Google Cloud virtual machine instance.
The API (Google Text-to-Speech) access is enabled and granted for that virtual machine.
Here is an example of a request:
import texttospeechpb "google.golang.org/genproto/googleapis/cloud/texttospeech/v1"
// Setting up the client..
req := texttospeechpb.SynthesizeSpeechRequest{
Input: &texttospeechpb.SynthesisInput{
InputSource: &texttospeechpb.SynthesisInput_Ssml{Ssml: "Hello this is a test"},
},
Voice: &texttospeechpb.VoiceSelectionParams{
LanguageCode: "en",
SsmlGender: texttospeechpb.SsmlVoiceGender_MALE,
},
AudioConfig: &texttospeechpb.AudioConfig{
AudioEncoding: texttospeechpb.AudioEncoding_OGG_OPUS,
VolumeGainDb: 6,
},
}
// Making the request..
The current problem is that setting a positive gain ex: [0, 1, 6, 16]db, throws the following error:
Unable to get speech rpc error:
code = InvalidArgument
desc = Request contains an invalid argument.
Testing with negative value ex: [-6, -0.1, 0]db is working.
Testing with invalid positive/negative value ex: 20db/-100db is not working as expected.
Unable to get speech rpc error:
code = OutOfRange
desc = Out of range: valid volume_gain_db is between -96.0 and 16.0.
I would like to know if there is an option I need to enable somewhere in order to have positive volume gain for the synthesis or if it is a bug on the API?

Getting response from API - DialogFlow Chatbot

I am creating a chatbot using DialogFlow. Here, I am trying to get response from the API, which has been created by my development team (using python). They provided the API URL and requested to fetch data from it according to the users query. I have created a function in the inline editor and pasted the given API URL.
Below is the API format they have created,
{
“data”: [{
“pincode”: “”,
“location_formatted_address”: “”,
“user_id”: “”,
“department_name”: “Education”,
“locality”: “”,
“status”: “Select_Status”
}]
}
Here, when a user gives a department name, it must respond the user with locality of that specific department.
In the Inline editor, I have applied the following logic to fetch the locality,
function getDatafromApI(agent){
const name = agent.parameters.name;
return getAPIData().then(res => {
res.data.map(issues => {
if(issues.department_name === name)
agent.add(`${name}. ${issues.locality}`);
intentMap.set('Fetch API', APIData);
In the above code, "name" is the parameter given in the intent section.
But, I am not getting any response. Any help?
The inline editor uses Firebase. You will have to upgrade to Firebase "Blaze" OR "Flame" plan as the "Spark"(free) plan does not allow external api calls.
However if you have already upgraded Firebase plan and still seeing this error, you can see the execution logs by clicking "view execution logs" link at bottom of Dialogflow fulfillment window.

IoT Phone recipe connects but not sending data

I am working with Bluemix tutorial recipe "Real Time Data Analysis Using IBM Watson IoT Platform Analytics" presented here:
https://developer.ibm.com/recipes/tutorials/real-time-data-analysis-using-ibm-watson-iot-platform-analytics
I am not seeing the behavior in my Watson IoT dashboard as described; the phone device does connect and register itself but I see no events or data.
In the node server logs a couple things seem concerning:
404 on fetch of util.js; in fact that file is not in my code repository downloaded from the recipe's github.
Three deprecated warnings:
...deprecated multipart: use parser (multiparty, busboy, formidable) npm module instead at node_modules/express/node_modules/connect/lib/middleware/bodyParser.js:56:20
...deprecated limit: Restrict request size at location of read at node_modules/express/node_modules/connect/lib/middleware/multipart.js:86:15
...deprecated methodOverride: use method-override npm module instead at app.js:63:17
The phone device shows some fluttering data values but stays in state "connecting". On the WatsonIoT dashboard it shows registered but "Disconnected".
Is the missing util.js a fatal condition? If not then how next to troubleshoot it as I am new to the whole package?
Solved. The recipe checks for whether it needs to create its cloudant database, unaware that I'm sharing my cloudant service instance with other apps; it finds a db exists, blithely assumes that's the one it needs, and skips the create. Change app.js from:
cloudant.db.list(function(err, all_dbs) {
if (all_dbs.length == 0) {
// first time -- need to create the iotzone-devices database
cloudant.db.create('device_credentials', function()
to e.g.:
cloudant.db.list(function(err, all_dbs) {
if (all_dbs.indexOf(dbName) < 0) {
// first time -- need to create the iotzone-devices database
cloudant.db.create(dbName, function()
[etc...]
With the db in place, WatsonIoT accepts events coming from phone and shows the data as expected.
I found this by following the print statements in log.

Firebase: Authenticate an existing user using REST API and Firebases hidden Auth URL

For the past 3 years we have used HTML/Js only with Firebase but now we are using Unity as well.
The current Unity/Firebase only works on Android/iOS when deployed and 99% of our work is on the windows store.
I've actually got a pretty decent Unity/Firebase codebase going but it requires me to use a full App Secret.
All the other libraries expose a method to login with Email/Password but the REST API only allows the use of a token or your app secret that it then states is ill advised to put into your client; I guess the thinking is if you're using a different library that you'll have your own auth/user method which we don't...
Now, I've pulled apart the web version and got this:
https://auth.firebase.com/v2/<myfirebase>/auth/password?&email=dennis%40<mysite>&password=<mypassword>v=js-2.2.9&transport=json&suppress_status_codes=true
So there IS an endpoint that I can send stuff to and I've tested it inside unity with good results.
Obviously the URL isn't guaranteed to stay working but I'm wondering if there is any reason NOT to use this?
Also, Why not just expose this endpoint in the official REST API?
As I understand it, that URL will continue to work for your Legacy Firebase project. You will have to do the same sort of reverse engineering if you want to update to the new Firebase 3.0 API. However, if you are still using a legacy Firebase project -- I encourage you to take a look at this. It has not been updated to work with Firebase 3.0 -- so I needed to do something similar to what you did to allow login to the new API.
I was able to do this with the new API using C# as follows (where FirebaseManager is a Singleton I wrote for Global variables and functions to write and read from/to the DB :
Hashtable loginData = new Hashtable();
loginData.Add ("email", <EMAIL-GOES-HERE>);
loginData.Add ("password", <PASSWORD-GOES-HERE>);
loginData.Add ("returnSecureToken", true);
UnityHTTP.Request loginRequest = new UnityHTTP.Request ("post",
"https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key="
+ <YOUR-PROJECT-API-KEY-GOES-HERE>, loginData);
loginRequest.Send ((request) => {
Hashtable jsonResponse = (Hashtable)JSON.JsonDecode(request.response.Text);
if (jsonResponse == null) {
DisplayErrorMessage("Error logging in. Server returned null or malformed response");
}
FirebaseManager.Instance.idToken = (string)jsonResponse["idToken"]; // This is your auth token
FirebaseManager.Instance.uid = (string)jsonResponse["localId"]; // this is your "uid"
});
// I have a list of users in my db keyed by the "uid" -- I access them like this
UnityHTTP.Request fullnameRequest = new UnityHTTP.Request ("get",
<YOUR-DATABASE-ROOT-URL-HERE>
+ "/users/" + FirebaseManager.Instance.uid + ".json?auth=" + FirebaseManager.Instance.idToken);
fullnameRequest.Send ((request) => {
Debug.Log(request.response.Text);
Hashtable jsonResponse = (Hashtable)JSON.JsonDecode(request.response.Text);
if (jsonResponse == null) {
DisplayErrorMessage("Error getting user info. Server returned null or malformed response");
}
FirebaseManager.Instance.fullname = (string)jsonResponse["fullname"];
FirebaseManager.Instance.groupId = (string)jsonResponse["group"]; // just storing this in memory
});
So I don't think there is any harm in using the URL, just make sure you budget time for more work when things change.