I want my bot to display an introductory message when a user begins a new conversation. I've seen this working with bots in Skype where the bot sends a message before the user types anything.
I have got this working using the Bot Framework Channel Emulator with this code in the MessagesController class:
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
else
{
await this.HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
private async Task HandleSystemMessage(Activity message)
{
if (message.Type == ActivityTypes.ConversationUpdate)
{
var reply = message.CreateReply("Hello World!");
var connector = new ConnectorClient(new Uri(message.ServiceUrl));
await connector.Conversations.SendToConversationAsync(reply);
}
}
This displays 'Hello World!' at the beginning of a new conversation. No input required. However on Skype this introductory message does not appear. What I am misunderstanding here? I know it is possible.
Skype is throwing different ActivityTypes given the situation:
You will get a contactRelationUpdate after adding the bot in your contacts. Then we you start talking to the bot, there is no special Activity
When you start a conversation group with the bot included, you will get conversationUpdate
So if you want to welcome your user, you should add the contactRelationUpdate activity type in your test, like:
private async Task HandleSystemMessage(Activity message)
{
if (message.Type == ActivityTypes.ConversationUpdate || message.Type == ActivityTypes.ContactRelationUpdate)
{
var reply = message.CreateReply("Hello World!");
var connector = new ConnectorClient(new Uri(message.ServiceUrl));
await connector.Conversations.SendToConversationAsync(reply);
}
}
Extract of the content of the message you receive when adding the bot:
Here From is my user and Recipient is bot. You can see that the Action value is add
Related
I am building a bot using the Microsoft C# bot framework v4. When the bot is first added to a team, I want it to proactively 1:1 message each member of the team, introducing itself. I know it should be possible to start a chat with a user, even if the user has not previously interacted with the bot. This process is described in the documentation:
When using proactive messaging to send a welcome message to a user you must keep in mind that for most people receiving the message they will have no context for why they are receiving it. This is also the first time they will have interacted with your app; it is your opportunity to create a good first impression. The best welcome messages will include:
Why are they receiving this message. It should be very clear to the user why they are receiving the message. If your bot was installed in a channel and you sent a welcome message to all users, let them know what channel it was installed in and potentially who installed it.
To me this indicates that I should be able to initiate a chat message with each member of the channel, but I cannot get the bot to message anyone in the channel other than me. In the TeamsConversationBot sample provided by Microsoft, there is a MessageAllMembers() method that seems to be what I am looking for, however when I call it in my code, and add the bot to a team in Teams, the bot only messages me.
Here is the MessageAllMembers() code I am using:
private async Task MessageAllMembersAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var Id = turnContext.Activity.TeamsGetChannelId();
var serviceUrl = turnContext.Activity.ServiceUrl;
var credentials = new MicrosoftAppCredentials(_configuration["MicrosoftAppId"], _configuration["MicrosoftAppPassword"]);
ConversationReference conversationReference = null;
var members = await TeamsInfo.GetMembersAsync(turnContext, cancellationToken);
foreach (var teamMember in members)
{
if (teamMember.Id != turnContext.Activity.Recipient.Id) {
var proactiveMessage = MessageFactory.Text($"Hello {teamMember.GivenName} {teamMember.Surname}. I'm a Teams conversation bot.");
var conversationParameters = new ConversationParameters
{
IsGroup = false,
Bot = turnContext.Activity.Recipient,
Members = new ChannelAccount[] { teamMember },
TenantId = turnContext.Activity.Conversation.TenantId,
};
await ((BotFrameworkAdapter)turnContext.Adapter).CreateConversationAsync(
Id,
serviceUrl,
credentials,
conversationParameters,
async (t1, c1) =>
{
conversationReference = t1.Activity.GetConversationReference();
await ((BotFrameworkAdapter)turnContext.Adapter).ContinueConversationAsync(
_configuration["MicrosoftAppId"],
conversationReference,
async (t2, c2) =>
{
await t2.SendActivityAsync(proactiveMessage, c2);
},
cancellationToken);
},
cancellationToken);
}
}
await turnContext.SendActivityAsync(MessageFactory.Text("All messages have been sent."), cancellationToken);
}
It is not throwing any exceptions, it's just not doing what I expect.
I have a simple bot with help of Luis. It's very basic code and I don't know why I get 412 error after I past message to Luis intent. My code look like:
MessageController:
if (activity.Type == ActivityTypes.Message)
{
// Get any saved values
StateClient sc = activity.GetStateClient();
await sc.BotState.GetUserDataAsync(activity.ChannelId,activity.From.Id);
var haveGreeting = userData.GetProperty<bool>("HaveGreeting");
// Create text for a reply message
StringBuilder strReplyMessage = new StringBuilder();
if (haveGreeting == false)
{
strReplyMessage.Append($"Hi, how are you today?");
userData.SetProperty("HaveGreeting", true);
}
else
{
await Conversation.SendAsync(activity, () => new MeBotLuisDialog());
}
// Save BotUserData
var botaData = await sc.BotState.SetUserDataAsync(activity.ChannelId,
activity.From.Id, userData);
// Create a reply message
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity replyMessage = activity.CreateReply(strReplyMessage.ToString());
await connector.Conversations.ReplyToActivityAsync(replyMessage);
}
Luis intent:
[LuisIntent("HowAreYou")]
public async Task HowAreYou(IDialogContext context, IAwaitable<IMessageActivity> activity, LuisResult result)
{
await context.PostAsync("Great! Thank for asking");
context.Wait(MessageReceived);
}
Please help!
Try adding the following code in your Global.asax.cs file
var builder = new ContainerBuilder();
builder
.Register(c => new CachingBotDataStore(c.Resolve<ConnectorStore>(), CachingBotDataStoreConsistencyPolicy.LastWriteWins))
.As<IBotDataStore<BotData>>()
.AsSelf()
.InstancePerLifetimeScope();
builder.Update(Conversation.Container);
And please, review the relevant technical FAQs around this issue:
What is an ETag? How does it relate to bot data bag storage?
What causes “precondition failed” (412) or “conflict” (409) HTTP errors?
How can I fix “precondition failed” (412) or “conflict” (409) HTTP errors?
I want to display a welcome message whenever someone connects to my bot. I've used the technique from the demo-ContosoFlowers sample on github (https://github.com/Microsoft/BotBuilder-Samples/tree/master/CSharp/demo-ContosoFlowers) which works fine in the Bot Framework Emulator, but not in Skype or Facebook Messenger. Specifically, this code in MessageController.HandleSystemMessage doesn't trigger:
else if (message.Type == ActivityTypes.ConversationUpdate)
{
if (message.MembersAdded.Any(o => o.Id == message.Recipient.Id))
{
var reply = message.CreateReply(Resources.RootDialog_Welcome_Message);
ConnectorClient connector = new ConnectorClient(new Uri(message.ServiceUrl));
await connector.Conversations.ReplyToActivityAsync(reply);
}
}
Does anyone know how to do this correctly?
I also tried out the ContosoFlowers demo today. I experienced the same behavior you describe: in the emulator, ConversationUpdate code is triggered but in Skype it is not. However, I did notice that the ContactRelationUpdate activity type does fire in Skype (I haven't tried Facebook Messenger). If your goal is to display a welcome message whenever someone "connects" to your bot, you could try using the ContactRelationUpdate activity type like this:
else if (message.Type == ActivityTypes.ContactRelationUpdate)
{
if(message.Action == "add")
{
var reply = message.CreateReply("WELCOME!!!");
ConnectorClient connector = new ConnectorClient(new Uri(message.ServiceUrl));
await connector.Conversations.ReplyToActivityAsync(reply);
}
}
Create a class and have this in you callback url of fb. FacebookProfile is my class that holds the name and other information after the call.
public static async Task<FacebookProfile> GetFacebookProfile(string accessToken)
{
var uri = GetUri("https://graph.facebook.com/v2.6/me",
Tuple.Create("fields", "name,email,id,first_name,last_name"),
Tuple.Create("access_token", accessToken));
var res = await FacebookRequest<FacebookProfile>(uri);
return res;
}
I am trying to give intro for my BOT . when the user is added to their conversation/contact list. I have tried by handling ActivityTypes.ConversationUpdate message type. but it is not working in skype. is there any common way for this that should work in all channels.
this is the code i used:
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
if (activity.Type == ActivityTypes.Message)
{
// calculate something for us to return
int length = (activity.Text ?? string.Empty).Length;
// return our reply to the user
Activity reply = activity.CreateReply($"You sent {activity.Text} which was {length} characters");
await connector.Conversations.ReplyToActivityAsync(reply);
}
else if(activity.Type == ActivityTypes.ConversationUpdate)
{
StateClient stateClient = activity.GetStateClient();
BotData userData = await stateClient.BotState.GetUserDataAsync(activity.ChannelId, activity.From.Id);
if (!userData.GetProperty<bool>("SentGreeting"))
{
Activity reply = activity.CreateReply($"Hi " + activity.From.Name + ", I'm the Microsoft Bot");
userData.SetProperty<bool>("SentGreeting", true);
await stateClient.BotState.SetUserDataAsync(activity.ChannelId, activity.From.Id, userData);
await connector.Conversations.ReplyToActivityAsync(reply);
}
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
works here
thanks in advance.
The Skype channel doesn't send the ConversationUpdate message. The Bot Framework Emulator and other channels like WebChat do. There isn't a way to send a message to the user before receiving a message from the user in the Skype channel.
I'm using MS Bot Framework and C# to build a bot that can handle 3 dialogs. Each dialog is built using the FormDialog and FormBuilder, like this:
internal static IDialog<OrderDialogForm> BuildDialog()
{
return Chain.From(() => FormDialog.FromForm(BuildForm));
}
When you first talk to the bot, it offers you to select one of the three dialogs, e.g. "fill in the order", "enter your user profile", "get support",
Once the users selects, for example, "fill in the order", the bot launches the appropriate dialog.
Obviously, the user should just continue answering the questions inside the dialog until the dialog is over.
But every time the user sends a message, it is passed to this method in the API controller:
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
From here, the bot needs to decide which of the three dialogs is currently in progress, and continue that dialog.
How do I do that, remember which dialog is currently in progress and with each new message from the user, continue that dialog instead of returning the user to the main screen?
My idea is to create some kind of global variable or a record that is stored somewhere else, maybe in the database. The record would contain the type of the current dialog that this user is having with the bot right now. Every time the bot receives a message, it would query the database to find out that the last interaction of the user was with the OrderDialog, and so the program code can decide to continue with the OrderDialog. But it seems slow and maybe there is some kind of built-in function in Bot Framework to store data about the user, such as which dialog type it last interacted with.
Use the Bot State Service
https://docs.botframework.com/en-us/csharp/builder/sdkreference/stateapi.html
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
// Detect if this is a Message activity
if (activity.Type == ActivityTypes.Message)
{
// Get any saved values
StateClient sc = activity.GetStateClient();
BotData userData = sc.BotState.GetPrivateConversationData(
activity.ChannelId, activity.Conversation.Id, activity.From.Id);
var boolProfileComplete = userData.GetProperty<bool>("ProfileComplete");
if (!boolProfileComplete)
{
// Call our FormFlow by calling MakeRootDialog
await Conversation.SendAsync(activity, MakeRootDialog);
}
else
{
// Get the saved profile values
var FirstName = userData.GetProperty<string>("FirstName");
var LastName = userData.GetProperty<string>("LastName");
var Gender = userData.GetProperty<string>("Gender");
// Tell the user their profile is complete
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append("Your profile is complete.\n\n");
sb.Append(String.Format("FirstName = {0}\n\n", FirstName));
sb.Append(String.Format("LastName = {0}\n\n", LastName));
sb.Append(String.Format("Gender = {0}", Gender));
// Create final reply
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity replyMessage = activity.CreateReply(sb.ToString());
await connector.Conversations.ReplyToActivityAsync(replyMessage);
}
}
else
{
// This was not a Message activity
HandleSystemMessage(activity);
}
// Send response
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
Sample From:
Introduction To FormFlow With The Microsoft Bot Framework
http://aihelpwebsite.com/Blog/EntryId/8/Introduction-To-FormFlow-With-The-Microsoft-Bot-Framework