/// <summary> /// we call for every turn while the topic is still active /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task <bool> ContinueTopic(AlarmBotContext context) { // for messages if (context.Activity.Type == ActivityTypes.Message) { switch (context.RecognizedIntents.TopIntent?.Name) { case "showAlarms": // allow show alarm to interrupt, but it's one turn, so we show the data without changing the topic await new ShowAlarmsTopic().StartTopic(context); return(await this.PromptForMissingData(context)); case "help": // show contextual help await AddAlarmResponses.ReplyWithHelp(context, this.Alarm); return(await this.PromptForMissingData(context)); case "cancel": // prompt to cancel await AddAlarmResponses.ReplyWithCancelPrompt(context, this.Alarm); this.TopicState = TopicStates.CancelConfirmation; return(true); default: return(await ProcessTopicState(context)); } } return(true); }
public async Task OnTurn(ITurnContext turnContext) { // Get the current ActiveTopic from my persisted conversation state var context = new AlarmBotContext(turnContext); // Trace top intent // await turnContext.SendActivity(context.Activity.CreateTrace("conversationState", value: context.ConversationState)); await turnContext.TraceActivity("context.ConversationState", value : context.ConversationState); var handled = false; // if we don't have an active topic yet if (context.ConversationState.ActiveTopic == null) { // use the default topic context.ConversationState.ActiveTopic = new DefaultTopic(); handled = await context.ConversationState.ActiveTopic.StartTopic(context); } else { // we do have an active topic, so call it handled = await context.ConversationState.ActiveTopic.ContinueTopic(context); } // if activeTopic's result is false and the activeTopic is NOT already the default topic if (handled == false && !(context.ConversationState.ActiveTopic is DefaultTopic)) { // Use DefaultTopic as the active topic context.ConversationState.ActiveTopic = new DefaultTopic(); await context.ConversationState.ActiveTopic.ResumeTopic(context); } }
/// <summary> /// Method which is called when this topic is resumed after an interruption /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task <bool> ResumeTopic(AlarmBotContext context) { // just prompt the user to ask what they want to do await DefaultResponses.ReplyWithResumeTopic(context); return(true); }
/// <summary> /// Called when the default topic is started /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task <bool> StartTopic(AlarmBotContext context) { switch (context.Activity.Type) { case ActivityTypes.ConversationUpdate: { // greet when added to conversation var activity = context.Activity.AsConversationUpdateActivity(); if (activity.MembersAdded.Any(m => m.Id == activity.Recipient.Id)) { await DefaultResponses.ReplyWithGreeting(context); await DefaultResponses.ReplyWithHelp(context); this.Greeted = true; } } break; case ActivityTypes.Message: // greet on first message if we haven't already if (!Greeted) { await DefaultResponses.ReplyWithGreeting(context); this.Greeted = true; } return(await this.ContinueTopic(context)); } return(true); }
/// <summary> /// Called when the topic is started /// </summary> /// <param name="context"></param> /// <returns></returns> public Task <bool> StartTopic(AlarmBotContext context) { this.AlarmTitle = context.RecognizedIntents.TopIntent.Entities.Where(entity => entity.GroupName == "AlarmTitle") .Select(entity => entity.ValueAs <string>()).FirstOrDefault(); return(FindAlarm(context)); }
/// <summary> /// Called when topic is activated (SINGLE TURN) /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task <bool> StartTopic(AlarmBotContext context) { await ShowAlarms(context); // end the topic immediately return(false); }
public async Task OnReceiveActivity(IBotContext botContext) { var context = new AlarmBotContext(botContext); // --- Our receive handler simply inspects the persisted ITopic class and calls to it as appropriate --- bool handled = false; // if we don't have an active topic yet if (context.ConversationState.ActiveTopic == null) { // use the default topic context.ConversationState.ActiveTopic = new DefaultTopic(); handled = await context.ConversationState.ActiveTopic.StartTopic(context); } else { // we do have an active topic, so call it handled = await context.ConversationState.ActiveTopic.ContinueTopic(context); } // if activeTopic's result is false and the activeTopic is NOT already the default topic if (handled == false && !(context.ConversationState.ActiveTopic is DefaultTopic)) { // USe DefaultTopic as the active topic context.ConversationState.ActiveTopic = new DefaultTopic(); handled = await context.ConversationState.ActiveTopic.ResumeTopic(context); } }
public async Task <bool> FindAlarm(AlarmBotContext context) { if (context.UserState.Alarms == null) { context.UserState.Alarms = new List <Alarm>(); } // Ensure there are context.UserState.Alarms to delete if (context.UserState.Alarms.Count == 0) { await DeleteAlarmResponses.ReplyWithNoAlarms(context); return(false); } // Validate title if (!String.IsNullOrWhiteSpace(this.AlarmTitle)) { if (int.TryParse(this.AlarmTitle.Split(' ').FirstOrDefault(), out int index)) { if (index > 0 && index <= context.UserState.Alarms.Count) { index--; // Delete selected alarm and end topic var alarm = context.UserState.Alarms.Skip(index).First(); context.UserState.Alarms.Remove(alarm); await DeleteAlarmResponses.ReplyWithDeletedAlarm(context, alarm); return(false); // cancel topic } } else { var parts = this.AlarmTitle.Split(' '); var choices = context.UserState.Alarms.Where(alarm => parts.Any(part => alarm.Title.Contains(part))).ToList(); if (choices.Count == 0) { await DeleteAlarmResponses.ReplyWithNoAlarmsFound(context, this.AlarmTitle); return(false); } else if (choices.Count == 1) { // Delete selected alarm and end topic var alarm = choices.First(); context.UserState.Alarms.Remove(alarm); await DeleteAlarmResponses.ReplyWithDeletedAlarm(context, alarm); return(false); // cancel topic } } } // Prompt for title await DeleteAlarmResponses.ReplyWithTitlePrompt(context); return(true); }
/// <summary> /// Called for every turn while active /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task <bool> ContinueTopic(AlarmBotContext context) { if (context.Activity.Type == ActivityTypes.Message) { this.AlarmTitle = context.Activity.Text.Trim(); return(await this.FindAlarm(context)); } return(true); }
/// <summary> /// Called when the add alarm topic is started /// </summary> /// <param name="context"></param> /// <returns></returns> public Task <bool> StartTopic(AlarmBotContext context) { var times = context.RecognizedIntents.TopIntent?.Entities.Where(entity => entity.GroupName == "AlarmTime") .Select(entity => DateTimeOffset.Parse(entity.Value as string)); this.Alarm = new Alarm() { // initialize from intent entities Title = context.RecognizedIntents.TopIntent?.Entities.Where(entity => entity.GroupName == "AlarmTitle") .Select(entity => entity.Value as string).FirstOrDefault(), // initialize from intent entities Time = times.Any() ? times.First() : (DateTimeOffset?)null }; return(PromptForMissingData(context)); }
/// <summary> /// Continue the topic, method which is routed to while this topic is active /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task <bool> ContinueTopic(AlarmBotContext context) { switch (context.Activity.Type) { case ActivityTypes.Message: switch (context.RecognizedIntents.TopIntent?.Name) { case "addAlarm": // switch to addAlarm topic context.ConversationState.ActiveTopic = new AddAlarmTopic(); return(await context.ConversationState.ActiveTopic.StartTopic(context)); case "showAlarms": // switch to show alarms topic context.ConversationState.ActiveTopic = new ShowAlarmsTopic(); return(await context.ConversationState.ActiveTopic.StartTopic(context)); case "deleteAlarm": // switch to delete alarm topic context.ConversationState.ActiveTopic = new DeleteAlarmTopic(); return(await context.ConversationState.ActiveTopic.StartTopic(context)); case "help": // show help await DefaultResponses.ReplyWithHelp(context); return(true); default: // show our confusion await DefaultResponses.ReplyWithConfused(context); return(true); } default: break; } return(true); }
public static IMessageActivity GetDeleteActivity(AlarmBotContext context, IEnumerable <Alarm> alarms, string title, string message) { StringBuilder sb = new StringBuilder(); int i = 1; if (alarms.Any()) { foreach (var alarm in alarms) { sb.AppendLine($"{i++}. {alarm.Title} {alarm.Time.Value.ToString("f")}"); } } else { sb.AppendLine("There are no alarms defined"); } i = 1; return(ResponseHelpers.ReplyWithSuggestions(context, title, $"{message}\n\n{sb.ToString()}", alarms.Select(alarm => $"{i++} {alarm.Title}").ToArray())); }
/// <summary> /// Called when this topic is resumed after being interrupted /// </summary> /// <param name="context"></param> /// <returns></returns> public Task <bool> ResumeTopic(AlarmBotContext context) { // simply prompt again based on our state return(this.PromptForMissingData(context)); }
private async Task <bool> ProcessTopicState(AlarmBotContext context) { string utterance = (context.Activity.AsMessageActivity().Text ?? "").Trim(); // we ar eusing TopicState to remember what we last asked switch (this.TopicState) { case TopicStates.TitlePrompt: this.Alarm.Title = utterance; return(await this.PromptForMissingData(context)); case TopicStates.TimePrompt: // take first one in the future if a valid time has been parsed var times = context.GetDateTimes(); if (times.Any(t => t > DateTimeOffset.Now)) { this.Alarm.Time = times.FirstOrDefault(t => t > DateTimeOffset.Now); } return(await this.PromptForMissingData(context)); case TopicStates.CancelConfirmation: switch (context.RecognizedIntents.TopIntent?.Name) { case "confirmYes": await AddAlarmResponses.ReplyWithTopicCanceled(context); // End current topic return(false); case "confirmNo": // Re-prompt user for current field. await AddAlarmResponses.ReplyWithTopicCanceled(context); return(await this.PromptForMissingData(context)); default: // prompt again to confirm the cancelation await AddAlarmResponses.ReplyWithCancelReprompt(context, this.Alarm); return(true); } case TopicStates.AddConfirmation: switch (context.RecognizedIntents.TopIntent?.Name) { case "confirmYes": if (context.UserState.Alarms == null) { context.UserState.Alarms = new List <Alarm>(); } context.UserState.Alarms.Add(this.Alarm); await AddAlarmResponses.ReplyWithAddedAlarm(context, this.Alarm); // end topic return(false); case "confirmNo": await AddAlarmResponses.ReplyWithTopicCanceled(context); // End current topic return(false); default: return(await this.PromptForMissingData(context)); } default: return(await this.PromptForMissingData(context)); } }
public static void ReplyWithTitlePrompt(AlarmBotContext context) { context.Reply(GetDeleteActivity(context, context.UserState.Alarms, "Delete Alarms", "What alarm do you want to delete?")); }
public static void ReplyWithDeletedAlarm(AlarmBotContext context, Alarm alarm = null) { context.Reply($"I have deleted {alarm.Title} alarm"); }
public static void ReplyWithNoAlarms(AlarmBotContext context) { context.Reply($"There are no alarms defined."); }
public static void ReplyWithNoAlarmsFound(AlarmBotContext context, string text) { context.Reply($"There were no alarms found for {(string)text}."); }
/// <summary> /// Called when resuming from an interruption /// </summary> /// <param name="context"></param> /// <returns></returns> public Task <bool> ResumeTopic(AlarmBotContext context) { return(this.FindAlarm(context)); }
public static async Task ReplyWithDeletedAlarm(AlarmBotContext context, Alarm alarm = null) { await context.SendActivity($"I have deleted {alarm.Title} alarm"); }
public static async Task ReplyWithNoAlarmsFound(AlarmBotContext context, string text) { await context.SendActivity($"There were no alarms found for {(string)text}."); }
public static async Task ReplyWithNoAlarms(AlarmBotContext context) { await context.SendActivity($"There are no alarms defined."); }
public static async Task ShowAlarms(AlarmBotContext context) { await ShowAlarmsResponses.ReplyWithShowAlarms(context, context.UserState.Alarms); }
public static Task ShowAlarms(AlarmBotContext context) { ShowAlarmsResponses.ReplyWithShowAlarms(context, context.UserState.Alarms); return(Task.CompletedTask); }
public Task <bool> ResumeTopic(AlarmBotContext context) { throw new System.NotImplementedException(); }
/// <summary> /// Method which is called when this topic is resumed after an interruption /// </summary> /// <param name="context"></param> /// <returns></returns> public Task <bool> ResumeTopic(AlarmBotContext context) { // just prompt the user to ask what they want to do DefaultResponses.ReplyWithResumeTopic(context); return(Task.FromResult(true)); }
public static async Task ReplyWithTitlePrompt(AlarmBotContext context) { var deleteActivity = GetDeleteActivity(context, context.UserState.Alarms, "Delete Alarms", "What alarm do you want to delete?"); await context.SendActivity(deleteActivity); }