bot.beginDialog to specific User and Channel - node.js

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

Related

Ionic 4 chat application and how to send message to particular user?

I created application in Ionic 4, and for backend I use Lumen. Application should have chat page and in that purpose I add Redis, Socket.io and nodejs. I successfully created public room, and chat between users in that room works. Problem is how to send private message for user, how to initialize users for their private room.
This is how I created public room:
constructor(private socket: Socket) {
this.getMessages().subscribe(message => {
this.messages.push(message);
});
}
getMessages() {
const observable = new Observable(observer => {
this.socket.on('message', (data) => {
observer.next(data);
});
});
return observable;
}
I send message from Lumen application and Redis:
public function sendMessage()
{
$redis = Redis::Connection();
$sendMessage = json_encode(['user' => 'John Doe', 'text' => 'Some message, text', 'channel' => 'message']);
$redis->publish('add-message', $sendMessage);
}
And my node server is:
let express = require('express');
let app = express();
let http = require('http').Server(app);
let redis = require('redis');
let client = redis.createClient("redis://127.0.0.1:6379");
let io = require('socket.io')(http);
app.use('/', express.static('www'));
http.listen(3000, '192.168.10.10', function(){
console.log('listening on *:3000');
});
client.on('message', function(chan, msg) {
let data = JSON.parse(msg);
io.sockets.emit(data.channel, msg);
});
client.subscribe('add-message');
Bottom line everyone who is subscribed on 'message' channel will get message. Problem is that I subscribe user on channel when came to chat page. I don't know how to subscribe user, and when, on channel where some another user send him message.Also how that sender user to create new room, I suppose to use id of users for room name (per instance user1_user2).
Does anyone know how I can solve this problem? I don't know even I described well.
Thanks in advance

How can I send the disconnect messages to subscribed clients if one client is disconnected in MQTT?

I tried client 1 and client 2 program I can able to easily communicate with them. I can easily send the messages and receive the messages with them, but I don't know if one client is disconnected, how can I send the disconnected message to subscribed clients.
client 1:
var mqtt=require("mqtt");
var express=require("express");
var app=express();
var options={
keepalive:100,
port: 1883,
clientId:'1',
clientSession:false,
host: "http://localhost:8000",
will:
{
topic:'willMag',
payload:"connection closed abnormallly r",
qos:1,
retain:true
}
};
var client=mqtt.connect("tcp://192.168.43.137:1883",options);
client.on("connect",function()
{
setInterval(function()
{
client.publish("ranjith/princy","hello love you princy",function()
{
console.log("message published in client1");
});
},2000);
client.subscribe("bv/nivi");
client.on("message",function(topic,message)
{
console.log("I recieved the topic:"+topic);
console.log("I recieved the message:"+message);
});
});
client.on("disconnect",function()
{
console.log("disconnected client1");
});
app.listen(8000,function()
{
console.log("server listen at port 8000");
});
client 2:
var mqtt=require("mqtt");
var express=require("express");
var app=express();
var options={
keepalive:100,
port: 1883,
clientId:'2',
clientSession:false,
host: "http://localhost:8086",
will:
{
topic:'willMag',
payload:"connection closed abnormallly b",
qos:1,
retain:true
}
};
var client=mqtt.connect("tcp://192.168.43.137:1883",options);
client.on("connect",function()
{
setInterval(function(){
client.publish("bv/nivi","hello love you nivi",function()
{
console.log("message published in client2");
});
},2000);
client.subscribe("ranjith/princy");
client.on("message",function(topic,message)
{
console.log("I recieved the topic:"+topic);
console.log("I recieved the message:"+message);
});
});
client.on("disconnect",function()
{
console.log("disconnected client2");
});
app.listen(8086,function()
{
console.log("server listen at port 8000");
});
It's not totally clear what you are asking here, but:
With MQTT you can not know what clients are subscribed to what topics
There is no way to know if a message has been delivered to a specific client
You can build a system to determine if a client is probably online. You need to make use of the Last Will and Testament (LWT) feature.
When your client connects it publishes a retained message to a given topic (e.g. client1/online payload: 1)
You set the LWT to publish payload 0 to the same topic if the client goes off line due to a crash/network failure
When you shut the client down cleanly you need to publish a 0 to the topic manually as the LWT will only fire if there is a failure.

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.

Unable to return JSON from REST API with RESTIFY

I'm new to Node.js. I'm trying to create a web server that will 1) serve up static html web pages and 2) provide a basic JSON / REST API. I've been told by my management that I must use RESTIFY (I don't know why). Currently, I have the following:
var restify = require('restify');
var fs = require('fs');
var mime = require('mime');
var ecstatic = require('ecstatic');
var ws = restify.createServer({
name: 'site',
version: '0.2.0'
});
ws.use(restify.acceptParser(server.acceptable));
ws.use(restify.queryParser());
ws.use(restify.bodyParser());
ws.use(ecstatic({ root: __dirname + '/' }));
ws.get('/rest/customers', findCustomers);
ws.get('/', ecstatic({ root:__dirname }));
ws.get(/^\/([a-zA-0-9_\.~-]+\/(.*)/, ecstatic({ root:__dirname }));
server.listen(90, function() {
console.log('%s running on %s', server.name, server.url);
});
function findCustomers() {
var customers = [
{ name: 'Felix Jones', gender:'M' },
{ name: 'Sam Wilson', gender:'M' },
{ name: 'Bridget Fonda', gender:'F'}
];
return customers;
}
After I start the web server, and I try to visit http://localhost:90/rest/customers/ in my browser, the request is made. However, it just sits there and I never seem to get a response. I'm using Fiddler to monitor the traffic and the result stays as '-' for a long time.
How can I return some JSON from this type of REST call?
Thank you
At 2017, the modern way to do this is:
server.get('/rest/customer', (req,res) => {
let customer = {
data: 'sample value'
};
res.json(customer);
});
never worked with ecstatic but i don't think you need a file server for static content since you run restify and return json.
you are not getting a response because you don't terminate with res.send
the following code looks ok
ws.get('/rest/customers', findCustomers);
but try to change the findCustomers function like this
function findCustomers(req,res,next) {
var customers = [
{ name: 'Felix Jones', gender:'M' },
{ name: 'Sam Wilson', gender:'M' },
{ name: 'Bridget Fonda', gender:'F'}
];
res.send(200,JSON.stringify(customers));
}

Resources