Reputation: 359
On Skype or Facebook, when the user goes offline on a Prompts or Form Flow question (don't know about the rest) and joins back later, the user is forced to provide an input for the last dialog stack he/she was left at; irrespective of the type (Choice, text, etc.). For example, if the user leaves at a Yes or No prompts, and joins later, he is forced to answer Yes or No (Prompts.Choice)
Is it possible to somehow reset the conversation, irrespective of where the user was in the dialog stack, when the user comes back online? (Probably a way to find out the user has connected/is online on Facebook and Skype, and reset?). It would be great if this reset can happen without the user typing in anything like a 'quit', in-order to actually trigger a reset. (proactive message?)
If the above solution is not possible, I have the following solution where the user can enter 'quit', and it will start from the beginning. It works on the Emulator, but not on Skype and Facebook. My code is as follows:
if (activity.Text.ToString() == "quit")
{
BotData oldActivityData = activity.GetStateClient().BotState.GetUserData(activity.ChannelId, activity.From.Id);
activity.GetStateClient().BotState.DeleteStateForUser(activity.ChannelId, activity.From.Id);
activity.GetStateClient().BotState.SetUserData(activity.ChannelId, activity.From.Id, oldActivityData);
await Conversation.SendAsync(activity, () => new RootDialog());
}
else
{
// Typing indicator
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity isTypingReply = activity.CreateReply();
isTypingReply.Type = ActivityTypes.Typing;
await connector.Conversations.ReplyToActivityAsync(isTypingReply);
// Sending the message to the dialog respective stack
await Conversation.SendAsync(activity, () => new RootDialog());
}
This perfectly works on the Emulator. I can type 'quit' from anywhere in the dialog (prompts,form flows, etc.), and it takes me to the first question. But on Skype/Facebook, when I enter 'quit', nothing happens. Then I have to send a message again (can be anything except 'quit'), to actually start the conversation from the beginning.
So, any ideas for both the non-user-initiated reset and user-initiated reset conversation?
Update 1: With codes showing my MessageController and PromptDialogs
MessageController:
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
if (listOfResetMessages.Contains(activity.Text.ToString().ToLower().Trim(' ')))
{
BotData oldActivityData = activity.GetStateClient().BotState.GetUserData(activity.ChannelId, activity.From.Id);
activity.GetStateClient().BotState.DeleteStateForUser(activity.ChannelId, activity.From.Id);
activity.GetStateClient().BotState.SetUserData(activity.ChannelId, activity.From.Id, oldActivityData);
await connector.Conversations.ReplyToActivityAsync(newConvoMessage);
await Conversation.SendAsync(activity, () => new RootDialog());
}
else
{
// Typing indicator
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity isTypingReply = activity.CreateReply();
isTypingReply.Type = ActivityTypes.Typing;
await connector.Conversations.ReplyToActivityAsync(isTypingReply);
// Sending the message to the dialog respective stack
await Conversation.SendAsync(activity, () => new RootDialog());
}
}
else
{
await this.HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
A Sample Prompt (is just like any other prompt, still posting):
public async Task StartAsync(IDialogContext context)
{
PromptDialog.Choice(context, this.NextFunction, new List<string>() { Constants.YES, Constants.NO }, "This is my question");
}
private async Task NextFunction(IDialogContext context, IAwaitable<string> result)
{
var optionSelected = await result;
switch (optionSelected)
{
case Constants.YES:
// Do whatever
break;
case Constants.NO:
// Do whatever
break;
}
}
Update 2: In-order to make the client unaware of the issue, I used a message to provoke the client to enter the second message to reset.
if (activity.Text.ToString().ToLower().Trim(' ') == "quit")
{
BotData oldActivityData = activity.GetStateClient().BotState.GetUserData(activity.ChannelId, activity.From.Id);
activity.GetStateClient().BotState.DeleteStateForUser(activity.ChannelId, activity.From.Id);
activity.GetStateClient().BotState.SetUserData(activity.ChannelId, activity.From.Id, oldActivityData);
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity newConvoMessage = activity.CreateReply();
newConvoMessage.Text = "You have just quit. Say 'Hello' to start a new conversation!";
await connector.Conversations.ReplyToActivityAsync(newConvoMessage);
await Conversation.SendAsync(activity, () => new RootDialog());
}
This does not solve the issue, since the user needs to come back online and enter 'quit' first. (Means, the user needs to know about the 'quit' command).
Upvotes: 4
Views: 1418
Reputation: 3426
The reason this works in emulator but not other channels in that in the emulator you can actually leave the channel. In Skype/Facebook the conversations persist even when not logged in. The only way to leave the conversation in Skype, for example, would be to remove the bot and add it again.
Maybe instead of asking the user to type something to stop you could use a timer. The flow would work like this:
Upvotes: 0