BotFramework-DirectLine JS - Initial Message Missing - node.js

I have a Bot I have built with MS BotFramework, hosted on Azure. The Bot is built to start the convo with a Welcome Message. When I test the bot through emulator, or on Azure test webchat, the bot will initiate the conversation as expected with the welcome message.
However, in my chat client using BotFramework-DirectLineJS, it isn't until I send a message that the bot will respond with the Welcome message (along with a response to the message the user just sent).
My expectation is that when I create a new instance of DirectLine and subscribe to its activities, this Welcome message would come through. However, that doesn't seem to be happening.
Am I missing something to get this functionality working?

Given this is working for you on "Test in Webchat", I'm assuming your if condition isn't the issue, but check if it is if (member.id === context.activity.recipient.id) { (instead of !==). The default on the template is !== but that doesn't work for me outside of emulator. With === it works both in emulator and other deployed channels.
However, depending on your use cases you may want to have a completely different welcome message for Directline sessions. This is what I do. In my onMembersAdded handler I actually get channelId from the activity via const { channelId, membersAdded } = context.activity;. Then I check that channelId != 'directline' before proceeding.
Instead, I use the onEvent handler to look for and respond to the 'webchat/join' event from Directline. That leaves for no ambiguity in the welcome response. For a very simple example, it would look something like this:
this.onEvent(async (context, next) => {
if (context.activity.name && context.activity.name === 'webchat/join') {
await context.sendActivity('Welcome to the Directline channel bot!');
}
await this.userState.saveChanges(context);
await this.conversationState.saveChanges(context);
})
You'll still want to have something in your onMembersAdded for non-directline channel welcome messages if you use this approach.

Related

How to get all non bot users in discord js using a discord bot in nodejs

I have created a discord bot by taking reference from this digital ocean link.
Now I can send message to any channel using the bot but my requirement is to send dm to user of that server.
For that I have tried many SO answers and followed other links, but all the solutions end up to be same.
I have tried this two way to get the users of a guild and send dm to any one selected user.
1st way - Get all users of guild (server)
const client_notification = new Discord.Client();
client_notification.on('ready', () => {
console.log("Notification manager ready");
let guild = client_notification.guilds.cache.get("Server ID");
guild.members.cache.forEach(member => console.log("===>>>", member.user.username));
});
client_notification.login("login");
Output
Notification manager ready
===>>> discord notification
By this way it only returns me the bot name itself. Although the membersCount is 6.
2nd way - send dm to user directly (server)
client.users.cache.get('<id>').send('<message>');
It gives me undefined in output.
My configs,
Node version: 10.16.3
discord.js version: 12.5.1
My question is how to get all the guild members in discord.js?
Discord added privileged gateway intents recently. So to fetch all member data you need to enable that in the developer portal. After that you need to fetch all the members available, for that we can use the fetchAllMembers client option, and then we need to filter out bot users, so that we don't message them.
const client_notification = new Discord.Client({fetchAllMembers:true}); //Fetches all members available on startup.
client_notification.on('ready', () => {
console.log("Notification manager ready");
let guild = client_notification.guilds.cache.get("Server ID");
guild.members.cache.filter(member => !member.user.bot).forEach(member => console.log("===>>>", member.user.username));
});
client_notification.login("login");
The .filter() method filters out all the bots and gives only the real users.
You should avoid using fetchAllMembers when your bot gets larger though, as it could slow down your bot and use lots of memory.
I think the problem is related to updating the bot policy for discord. Do you have this checkbox checked in the bot settings?
https://discord.com/developers/applications
Some info about client.users.cache:
Its a cache collection, so if you restart bot, or bot never handle user message or actions before, this collection will be empty. Better use guild.members.cache.get('')

Telegram: Cannot send message/photo into a channel with Telegraf (NodeJs)

I would send a message on telegram channel with telegraf. I'v einvited the bot and put him admin.
I've tested with this code:
bot.on('text', (ctx) => {
// Explicit usage
ctx.telegram.sendMessage(ctx.message.chat.id, `Hello ${ctx.state.role}`)
// Using context shortcut
// ctx.reply(`Hello ${ctx.state.role}`)
})
bot.launch();
But it replies only if i wrote on private.
So why it doesn't work on a channel?
Than how can i send a message in that channel without a command? (For example with and interval?
I i try this one:
bot.use((ctx) => {
console.log(ctx.message)
})
when i use the bot on private chat (with him) it returns all the message data. On the channel i receive undefined
In your case CTX have current chat info, if you want to send message to channel provide correct id as documented for Telegraf sendMessage:
telegram.sendMessage(process.env.TELEGRAM_CHANNEL, ctx.message.text);
I am using a bot for a public channel, so in my case it's:
TELEGRAM_CHANNEL=#MY_PUBLIC_CHANNEL_NAME
The channel name is available in channel info settings t.me/MY_PUBLIC_CHANNEL_NAME

Is the Bot Framework Emulator handling new members differently from Bot Framework Webchat?

According to this official sample project (https://github.com/microsoft/BotBuilder-Samples/blob/master/samples/typescript_nodejs/13.core-bot/src/bots/dialogAndWelcomeBot.ts) I can identity new members and send them a welcome message using this (my code):
this.onMembersAdded(async (context) => {
const welcomeCardTemplate = require("../lib/data/resources/cards/welcomeCard.json");
const membersAdded = context.activity.membersAdded;
for (const member of membersAdded) {
if (member.id !== context.activity.recipient.id) {
const welcomeCard = CardFactory.adaptiveCard(welcomeCardTemplate );
await context.sendActivity({ attachments: [welcomeCard] });
}
}
});
It works great when using the emulator. As soon as I connect to the chat I get my welcome message, but when using the Chat on Azure or the WebChat it's not triggered until I first enter some kind of text input to the chat.
One thing I noticed is that when I'm using the emulator two activities are sent to the bot as soon as I connect to the chat, one that contains the Id of the bot and one that contains the Id of the user but when using the other chat options (Azure Chat and WebChat) only one activity is being sent (where the memberId is the same as the recipientId) so it never goes past the if-statement.
What am I missing here, why is only one activity being sent from the Azure Chat and WebChat?
At this time, WebChat and DirectLine behaves differently from the emulator in certain scenarios like the one you describe. There is an open issue for this particular situation where you can find more information.
As stated in the issue, there is a workaround to force the ConversationUpdate event which you can try and test if it suits your needs (I haven't tried myself).

Azure Bot Framework(Node.js) - Waterfall doesn't work in dialog using Web Chat

I have this code:
bot.on('conversationUpdate', (message) => {
if (message.membersAdded) {
message.membersAdded.forEach((identity) => {
if (identity.id === message.address.bot.id) {
bot.beginDialog(message.address, 'start');
}
});
}
});
bot.dialog('start', [
(session) => {
var msg = new builder.Message(session);
msg.attachments([
new builder.HeroCard(session)
.title('test')
.buttons([{ title: 'testButton', type: 'imBack', value: 'testButton' }])
]);
builder.Prompts.choice(session, msg, ['testButton']);
},
(session, results) => {
session.send('Reached 2nd function!');
console.dir(results);
var message = results.response.entity;
session.beginDialog('anotherDialog', message);
}
]);
It works fine by using Bot Framework Emulator.
Bot Framework Emulator Result
However, It doesn't reach 2nd function in the waterfall steps by using Web Chat(Azure Console).
Test in Web Chat Result
What is the difference of behavior between Bot Framework Emulator and Web Chat?
And what should I modify in the code?
Do you have any idea?
Node.js version: 8.10.0
Bot Framework Emulator version: 4.0.15-alpha
I understand that what you want to do is have the bot start the conversation instead of waiting for the user to say something, which is a very common objective. Unfortunately this is not exactly an easy task with built-in functionality, but fortunately there is a blog post explaining how to do it. The blog post is taken from a workaround posted in a GitHub issue that's linked to in the one Fei Han linked.
The gist is that conversationUpdate events don't contain enough information to allow for bot state and so dialogs and prompts and such shouldn't be spawned from the event handler. You can get around this by generating your own event in your client-side code. Of course this probably wouldn't help you when testing in the Azure portal.
In general you should expect there to be many differences between the different channels, especially when it comes to the nature of the events produced by the channels. conversationUpdate is a particularly contentious event, and it's known to behave differently in Bot Emulator from the other channels. From the blog post (emphasis mine):
If you’re using WebChat or directline, the bot’s ConversationUpdate is
sent when the conversation is created and the user sides’
ConversationUpdate is sent when they first send a message. When
ConversationUpdate is initially sent, there isn’t enough information
in the message to construct the dialog stack. The reason that this
appears to work in the emulator, is that the emulator simulates a sort
of pseudo DirectLine, but both conversationUpdates are resolved at the
same time in the emulator, and this is not the case for how the actual
service performs.
If you want to avoid writing client code and you're sure your bot is only going to be used in channels that support the conversationUpdate event, I may have another workaround for you. Even though the blog post is clear that you shouldn't be using conversationUpdate, it may still be acceptable in cases when you just need to send a single message. You could simulate a prompt by sending a single message in your event handler and then behaving as though you're following up on that message in your root dialog. Here's a proof of concept:
bot.on('conversationUpdate', (message) => {
if (message.membersAdded) {
message.membersAdded.forEach((identity) => {
if (identity.id === message.address.bot.id) {
var msg = new builder.Message()
.address(message.address)
.attachments([
new builder.HeroCard()
.title('test')
.buttons([{ title: 'testButton', type: 'imBack', value: 'testButton' }])
]);
bot.send(msg);
}
});
}
});
bot.dialog('/', function (session) {
if (session.message.text == "testButton") {
session.send('Reached 2nd function!');
session.beginDialog('/getStarted');
} else {
builder.Prompts.choice(session, "I didn’t understand. Please choose an option from the list.", ['testButton']);
}
});
Note that this proof of concept is far from robust. Since the root dialog is likely to be accessed from many different places in a real bot, you'll probably want to put a condition in there to make sure it only responds to the intro prompt one time and you'll also probably want to spawn other dialogs.

How to catch Facebook messaging_optins with Azure Bot Channels Registration + Botbuilder SDK?

I've got a chatbot up and running, built using Node.JS Microsoft Bot Framework, and deployed to an Azure server as a Web App, with a Bot Channels Registration resource as the frontend endpoint.
This Bot Channels Registration is connected to Facebook Messenger (via a FB App) - meaning, the webhook for the Facebook App points to https://facebook.botframework.com/api/v1/bots/<BOT_CHANNELS_REGISTRATION_RESOURCE_NAME>.
This all works well for normal chat functionality.
However, I'd now like to add an opt-in checkbox to a separate web page I have. This checkbox works by pinging FB, which then sends a very specific payload to the already configured bot webhook.
{
"recipient":{
"id":"<PAGE_ID>"
},
"timestamp":<UNIX_TIMESTAMP>,
"optin":{
"ref":"<PASS_THROUGH_PARAM>",
"user_ref":"<UNIQUE_REF_PARAM>"
}
}
My question is this:
How does the Bot Channels Registration receive and handle the above payload? Will it just automatically forward it to the Messaging Endpoint I have configured in the Bot Channels Registration settings? Or will it get stuck, and never reach my actual bot Web App?
Finally, if it does reach my normal messages endpoint, how can I handle the specific payload with my botbuilder.ChatConnector() listener? Given that my web app code looks like (in essence)
var restify = require('restify');
var builder = require('botbuilder');
var dialogues = require('./dialogues');
var chatbot = function (config) {
var bot = {};
chatbot.listen = function () {
var stateStorage = new builder.MemoryBotStorage();
var connector = new builder.ChatConnector({
appId: process.env.APP_ID,
appPassword: process.env.APP_PASSWORD
});
bot = new builder.UniversalBot(connector, function (session) {
session.beginDialog(dialogues.base(bot).name);
}).set('storage', stateStorage);
return connector.listen();
};
return chatbot;
}
var server = restify.createServer();
// Listen for messages from users
server.post('/api/messages', chatbot.listen());
server.listen(process.env.port, function () {
console.log('%s listening to %s', server.name, server.url);
});
Thanks!
EDIT: I've figured out how to handle the above payload within my messaging endpoint - by adding a server.pre() handler to my server, e.g.
server.pre(function (req, res, next) {
if (req.body && req.body.optin_payload_specific_field){
// handle opt-in payload
} else {
return next();
}
});
However, via extra logging lines, it seems the opt-in payload isn't even making it to this endpoint. It seems to be stopped within the Bot Channels Registration. Currently looking for a way to resolve that major roadblock.
So, per #JJ_Wailes investigation, it seems like this is not a supported feature (in fact, it's a current feature request). See his comments on the original post for more details.
However, I did find a half-workaround to capture the user_ref identifier generated by the checkbox_plugin, for those interested:
1) From your external site, follow the steps from the documentation here for sending the initial user_ref to FB. FB will then make a callout to your bot, but per the above, that gets blocked by the Bot Channels Registration piece, so it's ignored.
2) From that same external site, use the user_ref to send a message to the user (just using the normal requests library). A successful send means that the user_ref was properly registered in FB by that step #1 call - a failure means you'll need to repeat step #1 (or use some other error handling flow).
3) After that, the next time the user responds to your bot in FB (as long as you don't send any other messages to them), the message your bot will receive will contain this as part of the payload:
{ ...
channelData:
{ ...
prior_message:
{ source: 'checkbox_plugin',
identifier: <user_ref> }
}
}
So I've currently added a check within my bot.use(), where if that section is present in the incoming message payload (session.message.sourceEvent.prior_message) and the source is "checkbox_plugin", I store the corresponding user_ref in the session.userData, and can work from there.
I would love to see this feature added into the supported Azure bot stack, but in the meantime hopefully this helps anyone else encountering this (admittedly niche) hurdle.

Resources