Kendo-ui JQuery not autostarting conversation with microsoft botframework - kendo-ui

I want to use the Kendo-UI for JQuery as the front end for my bot.
This demo is what I'm trying to use. When you start the demo the bot automaticly greets you, but when I change the secret to mine it doesn't start the conversation. With my secret it just waits for user input before starting. When I test my bot with the bot framework emulator it does send a message when connecting.
I do not know why this happens. I did not change any code of the kendo demo, which makes me think that the problem lies with my bot framework. On the other hand the emulator does give me the desired outcome. I'm at a loss on how to solve my issue.
Below is the onMembersAddedAsync function of MyBot.cs, which to my understanding should send the greeting message when a new client connects.
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
foreach (var member in membersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
//sends some messages to welcome the user + suggestedactions
await WelcomeNewUser(turnContext, cancellationToken);
}
}
}

I found a possible solution, instead of using the OnMembersAddedAsync function I send the welcome message from OnTurnAsync. I deleted the OnMembersAddedAsync because it doesn't do anything anymore.
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
await base.OnTurnAsync(turnContext, cancellationToken);
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// Save any state changes that might have occured during the turn.
await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
}
else
{
// Send an initial welcome message
if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate && turnContext.Activity.MembersAdded.FirstOrDefault()?.Id == turnContext.Activity.Recipient.Id)
{
await WelcomeNewUser(turnContext, cancellationToken);
}
}
}

Related

Bot Framework v4 welcome message in Webchat Channel

I am working with Bot framework v4 webchat, trying to send a welcome message when a bot is initialized. First i send an event activity to the bot from webchat channel and got a 200 status response from but i can't able to capture the event activity in OneventActivityAsync action.
I have go though the below given solution.
https://github.com/microsoft/BotFramework-WebChat/tree/master/samples/04.api/a.welcome-event
OneventActivityAsync Section:
if (turnContext.Activity.Name == "webchat/join")
{
await turnContext.SendActivityAsync("Welcome Message!");
}
Could anyone help me on this?
I really appreciate any help :)
Your approach should work for v3. But for v4 you need to handle this event in OnMembersAddedAsync method.
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITur
nContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
if (turnContext.Activity.ChannelId != "webchat" && turnContext.Activity.ChannelId != "directline") {
foreach (var member in membersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
await turnContext.SendActivityAsync("Welcome");
}
}
}
}
Br,
Pdeepa

Skill bot sending proactive messages to a user

I have developed a bot which sends Proactive messages to user
I also cretaed bots which trigger skills.
I was trying to write something where a skills bot/Dialog would be able to send proactive message received via webhooks to the user and continue with the existing Skill dialog.
I am not able to quite understand that. If anyone could help me there.
I used the sample from here to create a simple Skill bot which saves the ConversationReference of the current Activity and calls a service in OnMessageActivityReceived()
// Save ConversationReference
var conversationReference = activity.GetConversationReference();
_conversationReferences.AddOrUpdate(conversationReference.User.Id, conversationReference, (key, newValue) => conversationReference);
// Calling external service
HttpResponseMessage responsemMsg = await client.PostAsync(RequestURI, stringContent);
if (responsemMsg.IsSuccessStatusCode)
{
var apiResponse = await responsemMsg.Content.ReadAsStringAsync();
//Post the API response to bot again
await turnContext.SendActivityAsync(MessageFactory.Text($"Message Sent {turnContext.Activity.Text}"), cancellationToken);
}
The called service eventually emits an event which calls an action in the NotifyController in my Skills Bot. It tries to grab the ConverstaionReference and send the activity using the TurnContext.
//I am using the Skill Bot Id for _appId parameter
await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, async (context, token) =>
{
await context.SendActivityAsync(proMsg.eventName);
await context.SendActivityAsync(proMsg.context.ToString());
}, new System.Threading.CancellationToken());
This SendActivity fails and OnTurnError from the Skill Bot handles the exception.
I am not sure where excatly I am going wrong. I am new to the Bot framework learning.
My issue got resolved by using the ContinueConversation() overload with ClaimsIdentity and setting the right claims for audience, appid etc. It was basically authentication issue.
public virtual Task ContinueConversationAsync(ClaimsIdentity claimsIdentity, ConversationReference reference, string audience, BotCallbackHandler callback, CancellationToken cancellationToken);
This is how I created the ClaimsIdentity:
System.Collections.Generic.List<Claim> lclaim = new System.Collections.Generic.List<Claim>
{
new Claim(AuthenticationConstants.VersionClaim, "2.0"),
new Claim(AuthenticationConstants.AudienceClaim, <SkillBotId>),
new Claim(AuthenticationConstants.AppIdClaim, <SkillBotId>),
new Claim(AuthenticationConstants.AuthorizedParty, <SkillBotId>),
};
ClaimsIdentity ci = new ClaimsIdentity(lclaim);
async Task BotCallBack(ITurnContext turnContext, CancellationToken token)
{
<code to send activity back to parent bot>
}
await ((BotAdapter)this.botFrameworkHttpAdapter).ContinueConversationAsync(
ci,
conversationData.ConversationReference,
<ParentBotId>,
callback: BotCallBack,
default).ConfigureAwait(false);

Bot Framework Proactive Message Passing Id Into Conversation State

I have a SMS / Twilio Channel that I'm using to send out a Proactive message to the user. To send the Proactive message I'm calling a API method passing in MySpecialId which is used later in the conversation.
I want to save this MySpecialId into the conversation but at the point I have the MySpecialId the conversation doesn't exist yet, and I don't have a turnContext, so I can't really save it yet.
Is there a way to pass this Id from my API method into the BotCallback? I created a quick example. (Here is the original example I'm using https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/16.proactive-messages)
Thanks
[HttpGet("{number}")]
public async Task<IActionResult> Get(string MySpecialId)
{
//For Twillio Channel
MicrosoftAppCredentials.TrustServiceUrl("https://sms.botframework.com/");
var NewConversation = new ConversationReference
{
User = new ChannelAccount { Id = $"+1{PHONENUMBERTOTEXTHERE}" },
Bot = new ChannelAccount { Id = "+1MYPHONENUMBERHERE" },
Conversation = new ConversationAccount { Id = $"+1{PHONENUMBERTOTEXTHERE}" },
ChannelId = "sms",
ServiceUrl = "https://sms.botframework.com/"
};
BotAdapter ba = (BotAdapter)_HttpAdapter;
await ((BotAdapter)_HttpAdapter).ContinueConversationAsync(_AppId, NewConversation, BotCallback, default(CancellationToken));
return new ContentResult()
{
Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
};
}
private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
{
try
{
var MyConversationState = _ConversationState.CreateProperty<MyConversationData>(nameof(MyConversationData));
var ConversationState = await MyConversationState.GetAsync(turnContext, () => new MyConversationData(), cancellationToken);
//********************************************************************************************************************
ConversationState.MySpecialId = //HOW DO I GET MySpecialId FROM THE GET METHOD ABOVE HERE?
//********************************************************************************************************************
await _ConversationState.SaveChangesAsync((turnContext, false, cancellationToken);
await turnContext.SendActivityAsync("Starting proactive message bot call back");
}
catch (Exception ex)
{
this._Logger.LogError(ex.Message);
}
}
I don't believe that you can. Normally, you would do something like this by passing values through Activity.ChannelData, but ChannelData doesn't exist on ConversationReference.
Per comments below, #Ryan pointed out that you can pass data on ConversationAccount.Properties. Note, however, this is currently only available in the C# SDK. I've opened an issue to bring this into the Node SDK, but ETA is unknown at this point.
Instead, I'd suggest using a something more native to C#, like:
Create a ConcurrentDictionary
private ConcurrentDictionary<string, string> _idMap;
Map MySpecialId to Conversation.Id (in your Get function)
_idMap.AddOrUpdate(conversationReference.Conversation.Id, MySpecialId, (key, newValue) => MySpecialId);
Access the MySpecialId from the Activity.Conversation.Id (in BotCallback)
var ConversationState = await MyConversationState.GetAsync(turnContext, () => new MyConversationData(), cancellationToken);
ConversationState.MySpecialId = _idMap.GetValueOrDefault(turnContext.Activity.Conversation.Id);
Save ConversationState
await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
There's other ways you could do this and some validation checks you'll need to add, but this should get you started.

How to send an activity from a bot dialog (c#) trough direct line to a client (angular)

I'm trying to send an event activity from the bot to the client when I'm in a certain dialog, but I just can't get it to work... Any suggestions or code samples I can look at?
Also I already tried to make a back channel and it works but on the bot side as far as I could tell it only works in the message controller.
EDIT*
I'm sorry, for not providing any details, I was in a hurry last week.
So i'm making a bot that will fill a "report" for a user, the bot asks questions, and the user gives the answers. For the first question i have to call a function in my angular app when i'm in the first dialog, that is after the root dialog, that will check the user input and return an "Account" object to the bot if the account exists, if it doesn't then it returns null... (and i know it would be easier to just make an API and connect directly to the bot, but i have to use angular)
I'm using the back channel like so:
botConnection.activity$
.filter( activity => {
// tslint:disable-next-line:max-line-length
return (activity.type === 'message' && activity.from['id'] === 'VisitReportV3' && activity.text === 'Please select an account...') ||
(activity.type === 'message' && activity.from['id'] === 'user' && this.accountFlag)
})
.subscribe(activity => {
if (activity.from['id'] === 'VisitReportV3' && activity.text === 'Please select an account...') {
console.log('"account" received');
this.accountFlag = true;
postAccountInfo();
} else if (activity.from['id'] === 'user' && this.accountFlag) {
console.log('"account" flag recieved');
this.accountFlag = false;
}
});
It's probably completely wrong but i didn't know how else to do it..
tl;dr:
So in short, i need to check if i'm in the first dialog (or the one that asks me for the account) and if I am then wait for the next user input and call the angular function to check the input and see if there are any accounts that match, if not return null if they do return the serialized object to the bot for some more processing... I hope this explains some more.
In your messages controller you are probably only forwarding activities with a type of Message to your dialogs. If you used the default bot template, you probably have something like
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.GetActivityType() == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
that you need to change to
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.GetActivityType() == ActivityTypes.Message || activity.GetActivityType() == ActivityTypes.Event)
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
That will send both messages and events to your dialogs. Keep in mind though that you need to check for both of them in each of you dialog methods now especially when you are expecting events as the user can type and send a message before your event gets sent.
EDIT
You can't get the dialog name from activity.from['id']. However, in your dialog you can create an Activity reply and set the name to be something else. For example in your dialog,
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
Activity activity = await result as Activity;
Activity reply = activity.CreateReply();
reply.Text = "Please select an account...";
reply.Name = "VisitReportV3";
await context.PostAsync(reply);
}
then in your back channel JavaScript you would change from checking if activity.from['id'] === "VisitReportV3" to activity.name === "VisitReportV3".

Invokeresponse in botframework v4

How can I return an InvokeResponse in botframework v4 for C#? I need this to respond to compose extension activity messages. In the old framework this was done by returning in the response a composeExtension object from the controller.
How can this be done when implementing the IBot interface.
In the old framework there were MS Teams extensions, not available for the new framework version.
To respond to an invoke activity you have to set the "BotFrameworkAdapter.InvokeResponse" in turnContext.TurnState like in the below example
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// do stuff
}
if (turnContext.Activity.Type == ActivityTypes.Invoke)
{
// do stuff
var invokeResponse = new InvokeResponse()
{
Body = response,
Status = (int)HttpStatusCode.OK
};
var activity = new Activity();
activity.Value = invokeResponse;
// set the response
turnCoontext.TurnState.Add<InvokeResponse>(InvokeReponseKey, activity);
}
}
For what I think you are asking:
There is an example of handling an invoke response in this sample. In your OnTurnAsync you need to catch the Invoke activity and do whatever it is you need to do with the activity like in the sample.
I'm unsure which SDK you are using as you did not include it in your question but, a simple example in C# (Node would be similar) might look like this:
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
if (turnContext.Activity.Type == ActivityTypes.Message)
{
//do stuff
}
if (turnContext.Activity.Type == ActivityTypes.Invoke)
{
//do stuff
}
}
From the BF SDK v4 code here:
https://github.com/Microsoft/botbuilder-dotnet/blob/4bb6b8d5faa4b252379ac331d6f5140ea27c177b/libraries/Microsoft.Bot.Builder/BotFrameworkAdapter.cs#L216
https://github.com/Microsoft/botbuilder-dotnet/blob/4bb6b8d5faa4b252379ac331d6f5140ea27c177b/libraries/Microsoft.Bot.Builder/BotFrameworkAdapter.cs#L285
what you do is use ITurnContext to "reply" with a fake activity of type ActivityTypesEx.InvokeResponse, setting Activity.Value to an InvokeResponse object with your desired status code and payload.

Resources