Botkit console chat integration with DialogFlow not working - dialogflow-es

I am working on a console bot (it's the console_bot.js example from Botkit). Setup agent on DialogFlow console, downloaded son file with private key, downloaded botkit-middleware-dialogflow.
This is the actual code:
var Botkit = require('./lib/Botkit.js');
var os = require('os');
var controller = Botkit.consolebot({
debug: true,
});
const dialogflowMiddleware = require('botkit-middleware-dialogflow')({
keyFilename: './botkit-test-file.json', // service account private key file from Google Cloud Console
});
//******************* */
var bot = controller.spawn();
controller.middleware.receive.use(dialogflowMiddleware.receive);
controller.middleware.send.use(function(bot, message, next) {
if (message.intent == 'hey') {
message.text = 'Hello from DialogFlow!!!';
}
console.log('SENDING ', message.text,'TO USER', message.text);
next();
});
//lifecycle convo events
controller.on('conversationStarted', function(bot, convo) {
console.log('----------------> A conversation started with ', convo.context.user);
});
controller.on('conversationEnded', function(bot, convo) {
console.log('<----------------- A conversation ended with ', convo.context.user);
});
controller.hears(['Default Welcome Intent'], 'direct_message', dialogflowMiddleware.hears, function(bot, message) {
var replyText = message.fulfillment.text; // message object has new fields added by Dialogflow
bot.reply(message, replyText);
});
After setting debug mode on, i got these lines in the console:
debug: Setting up a handler for conversationStarted
debug: Setting up a handler for conversationEnded
debug: Setting up a handler for direct_message
hey
debug: RECEIVED MESSAGE
debug: CUSTOM FIND CONVO user text
This is the problem: when i type the utterances that should trigger the DF intent ('hey', for example), the bot doesn't reply anything

Fixed it, it was the type of message, message_received instead of direct message.
So this is the correction:
// USE MESSAGE_RECEIVED, NOT DIRECT MESSAGE
controller.hears(['Default Welcome Intent'], 'message_received', dialogflowMiddleware.hears, function(bot, message) {
var replyText = message.fulfillment.text;
bot.reply(message, replyText);
});

Related

Call QnAMaker inside LUIS dialog

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'
});

Node.js: How to send a direct message in Slack with MS Bot Framework?

I am trying to create a Slack bot using LUIS where when the bot sees a greeting in a channel it is added to, it sends a direct message to the user that sent the greeting.
I have looked at Issue #431 and wrote a bot. Here is my code:
var builder = require('botbuilder');
var restify = require('restify');
// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log("%s listening to %s", server.name, server.url);
});
server.get(/.*/, restify.serveStatic({
'directory': '.',
'default': 'index.html'
}));
// Create Chat Bot
var connector = new builder.ChatConnector({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
var bot = new builder.UniversalBot(connector, {
persistConversationData: true // need persistent data for dictionary
});
server.post('/api/messages', connector.listen());
// Create LUIS recognizer that points at our model and add it as the root '/' dialog
var model = (omitted);
var recognizer = new builder.LuisRecognizer(model);
var dialog = new builder.IntentDialog({ recognizers: [recognizer] });
bot.dialog('/', dialog);
// Add intent handlers
dialog.matches('Greeting', [
function(session, args, next) {
var language = builder.EntityRecognizer.findEntity(args.entities, 'Language');
next({ response: language });
},
function(session, results) {
bot.beginDialog({
text: 'Hello',
to: {channelId: "emulator", address:"User1", id:"(omitted)", isBot:false},
from: { channelId:"emulator", address:"Bot1", id:"(omitted)", isBot:true}
}, '/');
}
]);
However, currently when the bot receives a greeting, it gives the following error message:
ERROR: ChatConnector: startConversation - address is invalid.
Error: Invalid address.
at ChatConnector.startConversation (C:\..\node_modules\botbuilder\lib\bots\ChatConnector.js:173:18)
at C:\..\node_modules\botbuilder\lib\bots\UniversalBot.js:308:27
at UniversalBot.tryCatch (C:\..\node_modules\botbuilder\lib\bots\UniversalBot.js:381:13)
at UniversalBot.ensureConversation (C:\..\node_modules\botbuilder\lib\bots\UniversalBot.js:302:14)
at C:\..\node_modules\botbuilder\lib\bots\UniversalBot.js:163:19
at C:\..\node_modules\botbuilder\lib\bots\UniversalBot.js:337:53
at UniversalBot.tryCatch (C:\..\node_modules\botbuilder\lib\bots\UniversalBot.js:381:13)
at C:\..\node_modules\botbuilder\lib\bots\UniversalBot.js:337:23
at UniversalBot.tryCatch (C:\..\node_modules\botbuilder\lib\bots\UniversalBot.js:381:13)
at UniversalBot.lookupUser (C:\..\node_modules\botbuilder\lib\bots\UniversalBot.js:324:14)
(I've omitted part of directory)
I have looked at Issue #687 but still I couldn't figure out the problem. How can I make the bot work?
I am using Botbuilder v3.4.4 and Node v4.6.0.
The way to go here I think is:
Save the session.message.address somewhere as you will have to use it later in the bot.beginDialog you are doing.
Before beginning the new dialog, you need to remove the conversation object as you want to create a new conversation
Use the address to begin the dialog.
It would be something like
// consider making this an array insted
var address
// probably in the function that matches the greeting
address = session.message.address;
// in the step where you want to send the direct messsage
var newConversationAddress = Object.assign({}, address);
delete newConversationAddress.conversation;
// begin dialog with address without conversation
bot.beginDialog(newConversationAddress,...
Take a look to the CreateNewConversation sample. You will see that something pretty similar is being done.

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.

bot.beginDialog to specific User and Channel

I'd like my bot to initiate a new conversation with other user at some point in the future. Rather than initiated by incoming POST message as in Bot Connector Node.js documentation, I'm trying to initiate from the conversation itself.
It's not so clear which one is the recommended approach for Node:
Using require('botconnector'),ConnectorClient(), or Bot Connector REST API.
However, based on run-async and LUIS example, I noticed beginDialog actually allows you to specify intended address: bot.beginDialog(address, '/run-async/runner', { name: name }); or cortanaBot.beginDialog({ from: alarm.from, to: alarm.to }, '/notify', alarm);
I thought it's quite straightforward and clearer approach, however, the bot simply stops responding when I include such parameter (It works, if I just use session.beginDialog('/myalarm', { alarm: "some alarm" });). Do I miss out anything?
require('dotenv').config();
var restify = require('restify');
var builder = require('botbuilder');
// Get secrets from server environment
var botConnectorOptions = {
appId: process.env.BOTFRAMEWORK_APPID,
appSecret: process.env.BOTFRAMEWORK_APPSECRET
};
// Create bot
var bot = new builder.BotConnectorBot(botConnectorOptions);
function addressConverter(message) {
return {
to: message.from,
from: message.to//,
// conversationId: message.conversationId,
// channelConversationId: message.channelConversationId,
// channelMessageId: message.channelMessageId
};
}
bot.add('/myalarm', function(session) {
session.send('My Automatic Message');
session.endDialog();
});
bot.add('/', function(session) {
session.send('Hi');
// Delay sending the reply for 5 seconds
setTimeout(function() {
session.send({ text: '5s Time out!' })
var address = addressConverter(session.message);
console.log("Message Address:")
console.log(address)
session.beginDialog(address, '/myalarm', { alarm: "some alarm" });
}, 5000);
session.send({ text: 'I will automatically message you in 5 seconds.' })
});
// Setup Restify Server
var server = restify.createServer();
//server.pre(restify.pre.pause());
// Handle Bot Framework messages
server.post('/api/messages', bot.verifyBotFramework(), bot.listen());
// Serve a static web page
server.get(/.*/, restify.serveStatic({
'directory': '.',
'default': 'index.html'
}));
server.listen(process.env.port || 3978, function() {
console.log('%s listening to %s', server.name, server.url);
})
;

Anyone using Node.js with Amazon SNS and Apple Push Notifications?

I'm looking for examples of using node.js with Amazon SNS and Apple APN push notifications. We use Amazon for our hosting, and I have used SNS before, it's pretty simple. But the examples they have for push notifications are for java, and there is no examples for Node. It's confusing, as usual with them, and I'm hoping to cut my research and time spent short. It can't be that hard. I'm also wondering how they deal with errors, and the differences between the sandbox and production. Apple reacts differently between the two environments, not failing in the sandbox as they do in production.
It ends up not being that hard, just figuring out the documentation was unpleasant. You need to create the main endpoint for the SNS topic in the console, by far the easiest way, including the loading of the certificate. You then used createPlatformEnpoint to create an endpoint for each device id. That returns another SNS topic, specific fo that device, that you then use to send the message.
So, the following works to send a single message to a single client. If you want send something en masse, not sure you can do that. Also not sure how you deal with Apple's feedback, which you are supposed to check for failed sends.
config = require("./config.js").config;
var token = "1234567898123456789";
var AWS = require('aws-sdk');
AWS.config.update({accessKeyId: config.AWSAccessKeyId, secretAccessKey: config.AWSSecretKey});
AWS.config.update({region: config.AWSRegion});
var sns = new AWS.SNS();
var params = {'PlatformApplicationArn':config["AWSTargetARN"],'Token':token};
var message = 'Test';
var subject = 'Stuff';
sns.createPlatformEndpoint(params,function(err,EndPointResult)
{
var client_arn = EndPointResult["EndpointArn"];
sns.publish({
TargetArn: client_arn,
Message: message,
Subject: subject},
function(err,data){
if (err)
{
console.log("Error sending a message "+err);
}
else
{
console.log("Sent message: "+data.MessageId);
}
});
});
It's fairly straightforward as CargoMeister pointed out.
I've written a blog post about getting it setup check it out here http://evanshortiss.com/development/mobile/2014/02/22/sns-push-notifications-using-nodejs.html
I've also a Node.js wrapper module that is easier to use than the AWS SDK as I've worked around the documentation. It supports iOS and Android Push Services (as that's all I've tested/worked with), manages message formats other than Strings and exposes events: https://npmjs.org/package/sns-mobile
I haven't used topics to manage endpoints, not sure is that an issue though. You just create PlatformEndpoints first via the SNS console.
var AWS = require('aws-sdk');
var express = require('express');
var app = express();
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'add IdentityPoolId'
});
AWS.config.region = 'add region';
var sns = new AWS.SNS();
sns.createPlatformEndpoint({
PlatformApplicationArn: 'add platform application arn',
Token: 'add device token'
}, function (err, data) {
if (err) {
console.log("errorMessage" + err.stack);
return;
}
var endpointArn = data.EndpointArn;
var payload = {
default: 'Hello World',
APNS: {
aps: {
alert: 'Hello World',
sound: 'default',
badge: 1
}
}
};
// first have to stringify the inner APNS object...
payload.APNS = JSON.stringify(payload.APNS);
// then have to stringify the entire message payload
payload = JSON.stringify(payload);
console.log('sending push');
sns.publish({
Message: payload,
MessageStructure: 'json',
TargetArn: endpointArn
}, function (err, data) {
if (err) {
console.log(err.stack);
return;
}
console.log('push sent');
console.log(data);
});
});
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})

Resources