Microsoft Bot Framework: Same name across sessions - node.js

I have the following code which attempts to set the user's name during a chat session. E.g. if the user writes the message "Hi, my name is Bob", the bot will respond by greeting the user with his name, but only if the name was labeled as a "name" entity.
The issue is that the name is globally set for every user that is currently chatting with the bot and not for the current user only. The bot will, in other words, call every user currently chatting Bob in this case.
var intents = new builder.IntentDialog({ recognizers: [recognizer] })
// Check if the message user sent matches LUIS intent "greetingsWithName"
.matches('greetingsWithName', (session, args) => {
// Attempt to set content of LUIS entity "name" to variable "name"
name = builder.EntityRecognizer.findEntity(args.entities, 'navn');
// Check whether the name was successfully set or not
if (!name) {
session.send('Sorry, I didn't catch your name.')');
} else {
session.userData.userName = name.entity;
session.send('Hi, ' + session.userData.userName);
});
Later on I check in code whether the user has given his name to the bot or not during the session. If so, then say goodbye to the user with his name:
.matches('goodBye', (session) => {
if (!session.userData.userName) {
session.send('Good bye!');
} else {
session.send('Good bye, ' + session.userData.userName);
}
})
bot.dialog('/', intents);
Here is the HTML code from the file that initiates the web chat session:
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.botframework.com/botframework-webchat/latest/botchat.css" rel="stylesheet" />
</head>
<body>
<div id="bot"/>
<script src="https://cdn.botframework.com/botframework-webchat/latest/botchat.js"></script>
<script>
BotChat.App({
directLine: { secret: direct_line_secret },
user: { id: 'userid' },
bot: { id: 'botid' },
resize: 'detect'
}, document.getElementById("bot"));
</script>
</body>
</html>

You are storing the name of the user in userData, which is logical.
But in your tester, you set the same user id for every webchat user:
user: { id: 'userid' }
So every user will point to the same userData as the key is a combination of the channel name and the user id (activity.ChannelId, activity.From.Id in C#).
You can avoid this by generating unique identifiers for every webchat user, for example using https://www.npmjs.com/package/uuid-random
In that case, user: { id: uuid() }.
Moreover if you need to set a display name, add name: '...' to the definition of user: user: { id: uuid(), name: 'You' }.

Related

Stripe Connect - URL for onboarding crashes

I am building an onboarding flow for new customers on my platform, specifically the sellers right now, and I am running into an error I am unsure about. I have a node backend and a react frontend. I am able to create an account along with an onboarding link. I am in testing mode.
So my next step was to fill out the onboarding document and submit it for verification as if i was a seller. When I reach the final page and click submit my node server crashes with the following error. Am I misunderstanding how this should work? Or is this just success and now it's on me to redirect?
Error: ENOENT: no such file or directory, stat '/Users/mac/Documents/git_projects/client/index.html'
Node.js
app.post("/create-account-hosted", async (req, res) => {
const data = req.body;
try {
// Create account
var account = await stripe.accounts.create({
country: 'US',
type: 'custom',
business_type: 'individual',
capabilities: { card_payments: { requested: true }, transfers: { requested: true }, }
//requested_capabilities: ['card_payments', 'transfers'],
});
console.log('My Created Account..', account);
// Create accountLink
var accountLink = await stripe.accountLinks.create({
account: account.id,
success_url: 'http://localhost:4242?success',
failure_url: 'http://localhost:4242?failure',
type: 'custom_account_verification',
collect: 'eventually_due'
});
console.log('Account link info...', accountLink)
} catch (err) {
console.log(err);
res.status(400)
res.send({ error: err })
return;
}
res.send([accountLink, { "account_id": account.id }]);
});
Below are the pics of where I end up and at what part:
And then this happens:
Am I misunderstanding how this should work? Or is this just success and now it's on me to redirect?
The latter. You've successfully created the account link when you called the create()
var accountLink = await stripe.accountLinks.create({
account: account.id,
success_url: 'http://localhost:4242?success',
failure_url: 'http://localhost:4242?failure',
type: 'custom_account_verification',
collect: 'eventually_due'
});
The success_url would be a page on your site you'd want to redirect the user to. Same for the failure_url.
If you dig into the stripe docs we can see an example of their success.html page and it's just a sample dummy page users are sent to on payment success in this example.
success.html:
<html>
<head>
<title>Thanks for your order!</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section>
<p>
We appreciate your business! If you have any questions, please email
orders#example.com.
</p>
</section>
</body>
</html>
This again confirms that you can redirect to any page you want on success. Hope that helped!

Botframework v4 Directline integration: Is there a way to get the conversation id generated from directline transfer to the Chatbot (nodejs code)

This might be very simple, but I cannot find any reference regarding this.
I integrated the chat bot in the web app using direct line API; I’m using this API to generate conversation id:
POST: https://directline.botframework.com/v3/directline/conversations
I’m trying to get the generated conversation id from the above API (from web app code) to the chatbot code (NodeJS). Is there a way or any reference to do this?
one way as per this issue comment is to send data to bot before starting the conversation using:
var params = BotChat.queryParams(location.search);
var my_token = params['my_token'];
var botConnection = new BotChat.DirectLine({
secret: 'DIRECTLINE_SECRET'
});
BotChat.App({
botConnection: botConnection
,user: { id: 'USER_ID', name: 'User' } // user.id auto updates after first user message
}, document.getElementById("bot"));
botConnection.connectionStatus$.subscribe(function (status) {
if (status == 2) { // wait for connection is 'OnLine' to send data to bot
var convID = botConnection.conversationId;
botConnection.postActivity({
from: { id: convID } // because first time user ID == conversation ID
,type: 'event'
,name: 'registerUserData' // event name as we need
,value: my_token // data attached to event
}).subscribe(function (activityId) {
// This subscription is a MUST
// If I remove this handler the postActivity not reaches the bot
});
}
});
Here you subscribe to the botConnection.connectionStatus$ and when the status is equal to 2, you get the conversation ID from the botConnection object.
Then, you can add this middleware code in the bot code to get the data:
bot.use({ receive: function(event, next) {
if (!!event && !!event.address && event.name == 'registerUserData') {
var message = new builder.Message().address(event.address).text('my_token:' + event.value);
bot.send(message, function (err) {}); // simulate proactive message to user
}
next();
} });
Hope this helps.
I resolve it using Botframework Web Chat back channel, here's the link for reference:
https://github.com/Microsoft/BotFramework-WebChat
After I generated the conversation id using directline API:
POST: https://directline.botframework.com/v3/directline/conversations
I send data from the web app to the chatbot via backchannel.
<div id="webchat"></div>
<script>
(async function () {
// We are using a customized store to add hooks to connect event
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
// When we receive DIRECT_LINE/CONNECT_FULFILLED action, we will send an event activity using WEB_CHAT/SEND_EVENT
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { conversation_id: conversationID }
}
});
}
return next(action);
});
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
store
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
//Note: conversationID and token is generated in the backend code of the web app.
</script>

Send data from bot to client in DirectLine WebChat - NodeJS Botframework

I added bot to an HTML page on our intranet using the following code:
<link href="https://cdn.botframework.com/botframework-webchat/latest/botchat.css" rel="stylesheet" />
<style>
#bot{
height: 600px;
}
</style>
<div>
<div id="bot" />
</div>
<script src="https://cdn.botframework.com/botframework-webchat/latest/botchat.js"></script>
<script>
var user = {
id: 'user-id',
name: 'user name'
};
var botConnection = new BotChat.DirectLine({
token: '[token]',
user: user
});
BotChat.App({
user: user,
botConnection: botConnection,
bot: { id: 'test', name: 'test' }
}, document.getElementById("bot"));
botConnection
.postActivity({
from: user,
name: 'WelcomeDialog',
type: 'event',
value: ''
})
.subscribe(function (id) {
console.log('"trigger requestWelcomeDialog" sent');
});
</script>
Now, I need to send data back to this client, to be executed on that HTML page, since the page exists within the context of our intranet (internal servers), so I want to have the intent return from LUIS and directed to specific dialog, then send the required entity value from this dialog to the client to be executed there, then send the result back to the server so I can display a formatted message to the user.
So basically, I would need to have 2-way communication between the client (added to my intranet) and the bot itself (the nodejs app hosted in azure)
Update:
I implemented the backchannel in my bot, so now the code looks like this:
jQuery(function () {
//get user name from the system
var userid = _spPageContextInfo.userId;
var requestUri = _spPageContextInfo.webAbsoluteUrl + "/_api/web/getuserbyid(" + userid + ")";
var requestHeaders = { "accept": "application/json;odata=verbose" };
$.ajax({
url: requestUri,
contentType: "application/json;odata=verbose",
headers: requestHeaders,
success: onSuccess,
error: onError
});
function onSuccess(data, request) {
var loginName = data.d.Title;
var user = {
id: userid,
name: loginName
};
var botConnection = new BotChat.DirectLine({
token: '[token]',
user: user
});
let FindPerson = function (personName) {
let msg = `You asked for ${personName}`
botConnection
.postActivity({ type: "event", value: msg, from: { id: "me" }, name: "FindPersonResultFound" })
.subscribe(id => console.log("success"));
}
BotChat.App({
user: user,
botConnection: botConnection,
bot: { id: 'TestBot', name: 'test bot' }
}, document.getElementById("bot"));
botConnection
.postActivity({
from: user,
name: 'WelcomeDialog',
type: 'event',
value: ''
})
.subscribe(function (id) {
console.log('"trigger requestWelcomeDialog" sent');
});
botConnection.activity$
.filter(activity => activity.type === "event" && activity.name === "FindPerson")
.subscribe(activity => FindPerson(activity.value))
}
function onError(error) {
alert("error");
}
})
My server side code looks like this:
bot.on('event', function (message) {
if (message.name == 'WelcomeDialog') {
bot.beginDialog(message.address, message.name);
}
if (message.name === "FindPersonResultFound") {
bot.beginDialog(message.address, message.name, message.value)
}
});
However, if I send a message that's related to any dialog, it gets repeated as if the sender is me:
According to your output, I assumpt that your bot application would contain a default root dialog / which will return any thing you input.
If so, you can try to change beginDialog to replaceDialog in your bot event register functions, to clear the previous dialog stack.
Also, you could provide more code about your bot application, so that we can have a deeper looking over.

Trigger Bot with Drag & drop SharePoint Online

I want to be able to trigger my bot who's on my SharePoint online Site by Droping a local file to him.
I created a WebPart to use this bot on the site, and putting the embed code give by Azure.
But when i drop a file in the bot, it open the document in a new tab showing me the content.
I would like to start the conversation while drop a file like this :
Start of bot conversation by putting a file
I'd imagine some solution by using a drop zone on the iframe which contain the bot, but it's not working.
I visit some site who can help but i don't really know how to implement this : Bot in WebChat, DirectLine API, Send Activity to the bot
This GitHub could also be usefull.
You'll need to handle the ondragover and ondrop events (cancelling the default behavior) and post the activity manually:
html:
<div id="bot" ondrop="drop_handler(event);" ondragover="dragover_handler(event);" />
Javascript:
const dl = new BotChat.DirectLine({
secret: 'YourDLSecret',
webSocket: false
});
BotChat.App({
botConnection: dl,
user: { id: 'userid' },
bot: { id: 'botid' },
resize: 'detect'
}, document.getElementById("bot"));
function dragover_handler(ev) {
console.log("dragOver");
ev.preventDefault();
}
function drop_handler(ev) {
console.log("Drop");
ev.preventDefault();
ev.stopPropagation();
var files = [];
for (var i = 0; i < ev.dataTransfer.items.length; i++) {
// If dropped items aren't files, reject them
if (ev.dataTransfer.items[i].kind === 'file') {
var file = ev.dataTransfer.items[i].getAsFile();
files.push({
contentType: file.type,
contentUrl: window.URL.createObjectURL(file),
name: file.name
});
}
}
dl.postActivity({
from: { id: 'userid' },
type: 'message',
attachments: files
})
.subscribe(function (id) {
console.log('files sent');
});
}

Microsoft Bot: Offline DirectLine GSS Unable to post activity and receive data back

I have created a Microsoft bot on-premise (i.e. Hosted bot in IIS and Used Offline Directline for emulation using node package offline-directline-gss).
I am able to chat with the service but the issue I am facing is, since 'ConversationUpdate' doesn't work in webchat, I am posting the activity of type 'conversationupdate', text 'conversationupdate' on page load, and in the bot solution's Post method, I wrote a condition to check if activity.text is equal to 'conversationupdate' and wrote code to send a welcome message. But this is not happening.
In the command prompt which runs index.js, I can see the activity getting posted but the bot solution is not returning anything (or) something.
This the html page code:
<!DOCTYPE html>
<html>
<head>
<meta name="WebPartPageExpansion" content="full" />
<link href="BotChat/botchat.css" rel="stylesheet" />
</head>
<body>
<div id="bot"/>
<script src="Masterfiles/js/jquery-1.11.0.min.js"></script>
<script src="BotChat/botchat.js"></script>
<script>
$(window).on('load', function () {
try
{
botWindowExpandAndCollapse();
}
catch(err)
{
console.log(err.message);
}
});
function botWindowExpandAndCollapse()
{
try
{
var directLine = new BotChat.DirectLine({
secret: params['s'],
user: user,
bot: bot,
token: params['t'],
domain: 'http://127.0.0.1:3000/directline',
webSocket: false // defaults to true
});
directLine
.postActivity({ type: "conversationupdate", from: user, user:user, text:"conversationupdate"})
.subscribe(id => alert("Conversation updated"));
$('#bot .wc-chatview-panel').css('height','50px');
$('#bot .wc-chatview-panel').addClass('IconView');
//Script to hide
$( "<span class='DPfigure need-help'>Need Help</span>" ).insertAfter( ".wc-chatview-panel" );
if ($(".wc-chatview-panel").hasClass("fullHeight"))
{
$(".need-help").hide();
$('#bot .wc-chatview-panel').css('right','17px');
}
else
{
$(".need-help").show();
$('#bot .wc-chatview-panel').css('right','105px');
}
$('.DPfigure').click(function(){
$('#bot .wc-chatview-panel').toggleClass('fullHeight');
$('#bot .wc-chatview-panel').toggleClass('IconView');
if ($(".wc-chatview-panel").hasClass("fullHeight"))
{
$(".need-help").hide();
$('#bot .wc-chatview-panel').css('right','17px');
}
else
{
$(".need-help").show();
$('#bot .wc-chatview-panel').css('right','105px');
}
});
}
catch(err)
{
console.log(err.message);
}
}
var params = BotChat.queryParams(location.search);
debugger;
var user = {
id: Math.random().toString(36).substring(7),
name: params["username"] || 'username'
};
var bot = {
id: params['botid'] || 'botid',
name: params["botname"] || 'botname'
};
window['botchatDebug'] = params['debug'] && params['debug'] === "true";
BotChat.App({
directLine: {
secret: params['s'],
token: params['t'],
domain: 'http://127.0.0.1:3000/directline',
webSocket: false // defaults to true
},
user: user,
bot: bot,
locale: params['locale'],
resize: 'detect'
// sendTyping: true, // defaults to false. set to true to send 'typing' activities to bot (and other users) when user is typing
}, document.getElementById("bot"));
</script>
</body>
</html>
This is the index.js code:
const url = require("url");
const directline = require("offline-directline-gss/dist/bridge");
const express = require("express");
const app = express();
const config = {
localDirectLine: {
hostUrl: "http://localhost",
port: "3000"
},
apbots:[
{
botId:"TestingBot",
botUrl:"http://localhost:3374/api/messages",
"msaAppId": "",
"msaPassword": ""
},
]
};
directline.initializeRoutes(app, config);
command prompt indicating post message is successful:
Can anyone please throw some light on what could be the reason for this. Thank You!

Resources