Call QnAMaker inside LUIS dialog - node.js

I have a QnA bot and a LUIS bot. I would like to make a post request inside my LUIS dialog when the dialog for QnA is triggered to get a response. I have it testing just with the question: Hi which should respond hello.
I am not sure if my port is correct because I got it from another stackoverflow question that is similar so that might be where my error is. I have tried without any port as well.
When I ask questions I get the error: Error: read ECONNRESET
I am running this on Azure Bot Service which I suspect could be a reason for this peticular error.
Here is my code:
var request = require('request');
var http = require('http');
var options = {
host:'westus.api.cognitive.microsoft.com',
path:'/qnamaker/v2.0/knowledgebases/<kb-key>/generateAnswer',
port:443,
method:'POST',
headers:{
'Ocp-Apim-Subscription-Key':<sub-key>,
'Content-Type':'application/json'
}
};
//http POST request
var reqPost = http.request(options,function(res){
res.setEncoding('utf-8');
var responseString = '';
res.on('data',function(chunk){
responseString += chunk;
});
res.on('end', function () {
session.send(responseString);
});
});
//LUIS dialog when question is asked.
bot.dialog('qnaReq', function (session, args) {
//call QnA Bot and ask that bot the question
reqPost.write({"question":"hi"}); //Just testing "hi" for now.
reqPost.end();
reqPost.on('error',function(e){
session.send('error: ' + e);
});
}).triggerAction({
matches: 'QnA'
});

Related

Error: getaddrinfo ENOTFOUND in node.js webhook for dialogflow

I am trying to follow the dialogflow tutorial. I have set up a node.js webhook, that is called from Dialogflow, inside the webhook code I call out to an api. However, my node.js webhook is saying "Error: getaddrinfo ENOTFOUND". This works fine when I run it in visual code but cannot find the api with in the nodejs webhook, when called via DialogFlow. There is something about the fact that it is being called from Dialogflow that seems to be making it not work.
I have spent a lot of time on this, and had previsouly discovered that DialogFlow wont work with https where it is a self signed certificate, as such I put an azure function, so the webhook calls the azure function and then the azure function call the api that I need.
Sorry for the long post...
Here is the node.js code:
'use strict';
const http = require('http');
var request = require('request');
const apiUrl ="https://myapi";
exports.saledurationWebhook = (req, res) => {
// Get the city and date from the request
// let city = req.body.queryResult.parameters['geo-city']; // city is a required param
let city = "sdjk";
// Call the weather API
callSalesDurationApi(city).then((output) => {
res.json({ 'fulfillmentText': output }); // Return the results of the weather API to Dialogflow
})
.catch((err) => {
console.log(err);
//res.json({ 'fulfillmentText': `I don't know the sales duration is but I hope it's quick!` });
res.json({ 'fulfillmentText': err.message});
})
;
};
function callSalesDurationApi(city) {
return new Promise((resolve, reject) => {
console.log('API Request: ' + apiUrl);
var myJSONObject = {
"Inputs": "stuff"
};
request({
url: apiUrl,
method: "POST",
json: true, // <--Very important!!!
body: myJSONObject
}, function (error, response, body) {
console.log("successfully called api");
let output = "Current conditions in the " + body;
console.log(output);
console.log(body);
resolve(output);
});
});
}
Does anyone know why this might be happening? Or what frther steps I can take to investigate it? I have already looked at the loges for the webhook, and for the azure function.
Any help would be really gratefully recieved, I have already wasted days on this. If this is a duplicate question then I am sorry, I have tried to look for existing answers on this issue.
Thanks Laura
I have found this question already answered at: https://stackoverflow.com/a/46692487/7654050
It is because I have not set billing up for this project. I thought it been set up as it is on my work account.

Alexa: REST API call from intent

I am trying to code a simple skill. I'm trying to call Rest API from each intent.
For example:
TM.prototype.intentHandlers = {
"startIntent": function (intent, session, response) {
console.log("startIntent start");
// HOW TO CALL get http://mysite.site.com/app/start/1234
console.log("startIntent end");
response.ask("bla bla");
},
"endIntent": function (intent, session, response) {
console.log("endIntent start");
//HOW TO CALL post http://mysite.site.com/app/end/1234
console.log("endIntent end");
response.ask("bla bla bla");
},
Can anyone point me how would I called the URLS. I have try in many ways but the it seems that the request never arrived to the server.
Many thanks, Jeff
Repository of Alexa Cookbooks contains a lot of examples. Performing HTTP calls one of them.
The cookbook describes itself as:
AWS Lambda functions running Node.JS can make calls over the Internet
to APIs and services using the https module included in Javascript.
It contains the example how make HTTP calls.
you can use below sample code to call a REST api,
var req = http.get(url, (res) => {
var body = "";
res.on("data", (chunk) => {
body += chunk
});
res.on("end", () => {
var body = JSON.parse(body);
callBack(body)
});
}).on("error", (error) => {
callBack(err);
});
}
Please don't forgot to add the HTTP package like below,
var http = require('http');

Node.js Lambda Function "response is invalid" Amazon Alexa

UPDATE: I had a mistake on my http request endpoint. I had not set the appropriate authentication options so that fixed a lot of errors possibly this specific one.
My question is similar to one here:
Node.js Lambda function returns "The response is invalid" back to Alexa Service Simulator from REST call
However the solution to that question does not solve my problem. So I make an http request call to an xsjs service in Hana cloud. I am getting the 'response is invalid' error message. I can't see why. Here is my function:
// Create a web request and handle the response.
function httpGet(query, callback) {
console.log("/n QUERY: "+ query);
var host = 'datacloudyd070518trial.hanatrial.ondemand.com';
var path = '/LocationInformation/getLocationInfo.xsjs?location=';
var hostname = 'https://' + host + path + query;
var auth = 'user1:D1anafer';
var req = http.request({'hostname': hostname,
'auth': auth
}, (res) => {
var body = '';
res.on('data', (d) => {
body += JSON.stringify(d);
});
res.on('end', function () {
callback(body);
});
});
req.end();
req.on('error', (e) => {
console.error(e);
});
}
And the function that calls it:
'getNewsIntent': function () {
//self = this;
httpGet(location, function (response) {
// Parse the response into a JSON object ready to be formatted.
//var output = JSON.parse(response);
//output = output['change'];
var output = response;
var cardTitle = location;
var cardContent = output;
alexa.emit(':tellWithCard', output, cardTitle, cardContent);
});
},
Thank You
-Diana
Inside your AWS account go to your Lambda function and click on the monitoring tab, where you should see "View Logs in Cloudwatch" in the right hand corner. If you click that link and you should see the errors that are being produced.
You can also use console.log() to log any information being returned from your REST api, which will be logged in cloudwatch and can help you see where your errors are.
This is just a guess from the top of my head. To really help some detailed error message would be required like mentioned about.
But just a guess: Your http.request() is using the http module (https://nodejs.org/api/http.html) and your are accessing the a https resource. If so there is a https (https://nodejs.org/api/https.html) module or use something like axios https://www.npmjs.com/package/axios or requestjs (https://github.com/request/request) this will handle both.
Like I said just a blind guess without detailed error message and seeing your require statements but I am happy to dive deeper if you happen to have details.
HTH
Your callback from the Lambda has to return a valid status code and body. Like this:
let payload = {
statusCode: 400,
body: JSON.stringify('body'),
headers: {"Access-Control-Allow-Origin": "*"}
};
callback(null, payload);
On top of that, to call this from client side code, you have to pass the CORS header back.

Using Bing Speech Recognition API with node.js Bot Framework on Skype

I would like to use the Bing Speech Recognition API to convert speech to text when sending audio attachments in Skype to my node.js chatbot. I have tried using the code from BotBuilder-Samples intelligence-SpeechToText, however the speech recognition only works in the Emulator. When sending an audio/wave file in Skype, the bot does not respond at all instead of "You said: What’s the weather like?".
I suspected that the issue might be due to the fact that a JWT Token is required to access attachments in Skype. Hence, I have tried accessing the audio attachment in Skype using the code from BotBuilder-Samples core-ReceiveAttachment which uses request-promise instead of needle to make the HTTP request. However, the result from request-promise is not a stream and cannot be processed by the function getTextFromAudioStream().
I there would like to ask how to get speech recognition to work with audio attachments in Skype.
Thanks and best regards!
// Add your requirements
var restify = require("restify");
var builder = require("botbuilder");
var fs = require("fs");
var needle = require("needle");
var request = require("request");
var speechService = require("./speech-service.js");
var Promise = require('bluebird');
var request = require('request-promise').defaults({ encoding: null });
//=========================================================
// Bot Setup
//=========================================================
// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.PORT || 3000, function() {
console.log("%s listening to %s", server.name, server.url);
});
// Create chat bot
var connector = new builder.ChatConnector ({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
server.post("/api/messages", connector.listen());
var bot = new builder.UniversalBot(connector);
//=========================================================
// Bots Middleware
//=========================================================
// Anytime the major version is incremented any existing conversations will be restarted.
bot.use(builder.Middleware.dialogVersion({ version: 1.0, resetCommand: /^reset/i }));
//=========================================================
// Bots Dialogs
//=========================================================
bot.dialog("/", [
function (session, results, next) {
var msg = session.message;
if (hasAudioAttachment(msg)) {
// Message with attachment, proceed to download it.
// Skype attachment URLs are secured by a JwtToken, so we need to pass the token from our bot.
var attachment = msg.attachments[0];
var fileDownload = isSkypeMessage(msg)
? requestWithToken(attachment.contentUrl)
: request(attachment.contentUrl);
fileDownload.then(
function (response) {
// Send reply with attachment type & size
var reply = new builder.Message(session)
.text('Attachment from %s of %s type and size of %s bytes received.', msg.source, attachment.contentType, response.length);
session.send(reply);
}).catch(function (err) {
console.log('Error downloading attachment:', { statusCode: err.statusCode, message: err.response.statusMessage });
});
var stream = isSkypeMessage(msg)
? getAudioStreamWithToken(attachment)
: getAudioStream(attachment);
speechService.getTextFromAudioStream(stream)
.then(text => {
session.send("You said: " + text);
})
.catch(error => {
session.send("Oops! Something went wrong. Try again later.");
console.error(error);
});
}
else {
session.send("Did you upload an audio file? I'm more of an audible person. Try sending me a wav file");
}
}
]);
function getAudioStream(attachment) {
return needle.get(attachment.contentUrl, { headers: {'Content-Type': "audio/wav"} });
}
function getAudioStreamWithToken(attachment) {
var headers = {};
connector.getAccessToken((error, token) => {
headers['Authorization'] = 'Bearer ' + token;
});
headers['Content-Type'] = attachment.contentType;
return needle.get(attachment.contentUrl, { headers: headers });
}
// Request file with Authentication Header
function requestWithToken(url) {
return obtainToken().then(function (token) {
return request({
url: url,
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/octet-stream'
}
});
});
};
// Promise for obtaining JWT Token (requested once)
var obtainToken = Promise.promisify(connector.getAccessToken.bind(connector));
function isSkypeMessage(message) {
return message.source === "skype";
};
The code in the sample is already considering Skype when accessing to the attachments (see here). I think the problem you were hitting is because the key in the sample exceeded the quota. Yesterday a new Bing Speech Key was added to the sample, so I would suggest you to try again.
Also, an updated version of the sample is going to be added soon. The code is currently under code review.

How to make web service calls in Expressjs?

app.get('/', function(req, res){
var options = {
host: 'www.google.com'
};
http.get(options, function(http_res) {
http_res.on('data', function (chunk) {
res.send('BODY: ' + chunk);
});
res.end("");
});
});
I am trying to download google.com homepage, and reprint it, but I get an "Can't use mutable header APIs after sent." error
Anyone know why? or how to make http call?
Check out the example here on the node.js doc.
The method http.get is a convenience method, it handles a lot of basic stuff for a GET request, which usually has no body to it. Below is a sample of how to make a simple HTTP GET request.
var http = require("http");
var options = {
host: 'www.google.com'
};
http.get(options, function (http_res) {
// initialize the container for our data
var data = "";
// this event fires many times, each time collecting another piece of the response
http_res.on("data", function (chunk) {
// append this chunk to our growing `data` var
data += chunk;
});
// this event fires *one* time, after all the `data` events/chunks have been gathered
http_res.on("end", function () {
// you can use res.send instead of console.log to output via express
console.log(data);
});
});

Resources