From 5fa13a65a2deb1651c40b03d51197dd64a832841 Mon Sep 17 00:00:00 2001 From: Jacob Dubin Date: Thu, 21 May 2026 09:40:21 -0500 Subject: [PATCH] Extract memory and personality decision builders --- .../JiboInteractionService.MemoryDecisions.cs | 259 +++++++ ...InteractionService.PersonalityDecisions.cs | 417 +++++++++++ .../Services/JiboInteractionService.cs | 656 ------------------ 3 files changed, 676 insertions(+), 656 deletions(-) create mode 100644 OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.MemoryDecisions.cs create mode 100644 OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.PersonalityDecisions.cs diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.MemoryDecisions.cs b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.MemoryDecisions.cs new file mode 100644 index 0000000..c4f6e64 --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.MemoryDecisions.cs @@ -0,0 +1,259 @@ +using System.Globalization; +using System.Text.RegularExpressions; +using Jibo.Cloud.Application.Abstractions; +using Jibo.Cloud.Domain.Models; +using Jibo.Runtime.Abstractions; + +namespace Jibo.Cloud.Application.Services; + +public sealed partial class JiboInteractionService +{ + private JiboInteractionDecision BuildRememberNameDecision(TurnContext turn, string transcript) + { + var name = TryExtractNameFact(transcript); + if (string.IsNullOrWhiteSpace(name)) + return new JiboInteractionDecision( + "memory_set_name", + "I can remember it if you say, my name is Alex."); + + personalMemoryStore.SetName(ResolveTenantScope(turn), name); + return new JiboInteractionDecision( + "memory_set_name", + $"Nice to meet you, {name}. I will remember your name."); + } + + private JiboInteractionDecision BuildRecallNameDecision(TurnContext turn, GreetingPresenceProfile? presence = null) + { + var personScope = ResolveTenantScope(turn, presence?.PrimaryPersonId); + var name = personalMemoryStore.GetName(personScope); + if (string.IsNullOrWhiteSpace(name)) name = personalMemoryStore.GetName(ResolveTenantScope(turn)); + + name = ToDisplayName(name ?? string.Empty); + + return string.IsNullOrWhiteSpace(name) + ? new JiboInteractionDecision( + "memory_get_name", + "I do not know your name yet. You can say, my name is Alex.") + : new JiboInteractionDecision( + "memory_get_name", + presence is not null && !string.IsNullOrWhiteSpace(presence.PrimaryPersonId) + ? $"I think you are {name}." + : $"You told me your name is {name}."); + } + + private JiboInteractionDecision BuildRememberBirthdayDecision(TurnContext turn, string transcript) + { + var birthday = TryExtractBirthdayFact(transcript); + if (string.IsNullOrWhiteSpace(birthday)) + return new JiboInteractionDecision( + "memory_set_birthday", + "I can remember it if you say, my birthday is March 14."); + + var tenantScope = ResolveTenantScope(turn); + personalMemoryStore.SetBirthday(tenantScope, birthday); + var birthdayDate = TryParseBirthdayDate(birthday); + if (birthdayDate is not null) + { + var birthdayLabel = ResolvePreferredBirthdayLabel(turn); + cloudStateStore?.UpsertHoliday(new HolidayRecord + { + EventId = $"birthday-{tenantScope.LoopId}-{tenantScope.PersonId ?? "loop"}", + Name = string.IsNullOrWhiteSpace(birthdayLabel) ? "Birthday" : $"{birthdayLabel}'s Birthday", + Category = "birthday", + Subcategory = "personal", + LoopId = tenantScope.LoopId, + MemberId = tenantScope.PersonId, + IsEnabled = true, + Date = birthdayDate.Value, + Source = "birthday", + CountryCode = "US" + }); + } + + return new JiboInteractionDecision( + "memory_set_birthday", + $"Got it. I will remember your birthday is {birthday}."); + } + + private JiboInteractionDecision BuildRecallBirthdayDecision(TurnContext turn) + { + var birthday = personalMemoryStore.GetBirthday(ResolveTenantScope(turn)); + return string.IsNullOrWhiteSpace(birthday) + ? new JiboInteractionDecision( + "memory_get_birthday", + "I do not know your birthday yet. You can say, my birthday is March 14.") + : new JiboInteractionDecision( + "memory_get_birthday", + $"You told me your birthday is {birthday}."); + } + + private static DateOnly? TryParseBirthdayDate(string birthdayText) + { + if (string.IsNullOrWhiteSpace(birthdayText)) return null; + + var normalized = birthdayText.Trim().ToLowerInvariant(); + var match = Regex.Match( + normalized, + @"\b(?january|february|march|april|may|june|july|august|september|october|november|december)\s+(?\d{1,2})(?:st|nd|rd|th)?\b", + RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + if (!match.Success) return null; + + var month = match.Groups["month"].Value.ToLowerInvariant() switch + { + "january" => 1, + "february" => 2, + "march" => 3, + "april" => 4, + "may" => 5, + "june" => 6, + "july" => 7, + "august" => 8, + "september" => 9, + "october" => 10, + "november" => 11, + "december" => 12, + _ => 0 + }; + if (month == 0) return null; + + if (!int.TryParse(match.Groups["day"].Value, out var day) || day is < 1 or > 31) return null; + + var today = DateOnly.FromDateTime(DateTime.UtcNow); + var year = today.Year; + if (day > DateTime.DaysInMonth(year, month)) return null; + + DateOnly birthday; + try + { + birthday = new DateOnly(year, month, day); + } + catch + { + return null; + } + + if (birthday < today) birthday = birthday.AddYears(1); + return birthday; + } + + private static string? ResolvePreferredBirthdayLabel(TurnContext turn) + { + var context = ResolveGreetingPresenceProfile(turn); + return !string.IsNullOrWhiteSpace(context.PrimaryPersonId) && + context.LoopUserFirstNames.TryGetValue(context.PrimaryPersonId, out var firstName) && + !string.IsNullOrWhiteSpace(firstName) + ? ToDisplayName(firstName) + : null; + } + + private JiboInteractionDecision BuildRememberImportantDateDecision(TurnContext turn, string transcript) + { + var importantDate = TryExtractImportantDateSet(transcript); + if (importantDate is null) + return new JiboInteractionDecision( + "memory_set_important_date", + "I can remember it if you say, our anniversary is June 10."); + + personalMemoryStore.SetImportantDate(ResolveTenantScope(turn), importantDate.Value.Label, + importantDate.Value.Value); + return new JiboInteractionDecision( + "memory_set_important_date", + $"Got it. I will remember your {importantDate.Value.Label} is {importantDate.Value.Value}."); + } + + private JiboInteractionDecision BuildRecallImportantDateDecision(TurnContext turn, string transcript) + { + var label = TryExtractImportantDateLookupLabel(transcript); + if (string.IsNullOrWhiteSpace(label)) + return new JiboInteractionDecision( + "memory_get_important_date", + "Ask me like this: when is our anniversary?"); + + var storedDate = personalMemoryStore.GetImportantDate(ResolveTenantScope(turn), label); + return string.IsNullOrWhiteSpace(storedDate) + ? new JiboInteractionDecision( + "memory_get_important_date", + $"I do not know your {label} yet.") + : new JiboInteractionDecision( + "memory_get_important_date", + $"You told me your {label} is {storedDate}."); + } + + private JiboInteractionDecision BuildRememberPreferenceDecision(TurnContext turn, string transcript) + { + var preference = TryExtractPreferenceSet(transcript); + if (preference is null) + return new JiboInteractionDecision( + "memory_set_preference", + "I can remember it if you say, my favorite music is jazz."); + + personalMemoryStore.SetPreference(ResolveTenantScope(turn), preference.Value.Category, preference.Value.Value); + return new JiboInteractionDecision( + "memory_set_preference", + $"Got it. I will remember your favorite {preference.Value.Category} is {preference.Value.Value}."); + } + + private JiboInteractionDecision BuildRecallPreferenceDecision(TurnContext turn, string transcript) + { + var category = TryExtractPreferenceLookupCategory(transcript); + if (string.IsNullOrWhiteSpace(category)) + return new JiboInteractionDecision( + "memory_get_preference", + "Ask me like this: what is my favorite music?"); + + var preference = personalMemoryStore.GetPreference(ResolveTenantScope(turn), category); + return string.IsNullOrWhiteSpace(preference) + ? new JiboInteractionDecision( + "memory_get_preference", + $"I do not know your favorite {category} yet.") + : new JiboInteractionDecision( + "memory_get_preference", + $"You told me your favorite {category} is {preference}."); + } + + private JiboInteractionDecision BuildRememberAffinityDecision(TurnContext turn, string transcript) + { + var affinitySet = TryExtractAffinitySet(transcript); + if (affinitySet is null) + return new JiboInteractionDecision( + "memory_set_affinity", + "I can remember it if you say, I like pizza or I dislike mushrooms."); + + personalMemoryStore.SetAffinity(ResolveTenantScope(turn), affinitySet.Value.Item, affinitySet.Value.Affinity); + return new JiboInteractionDecision( + "memory_set_affinity", + $"Got it. I will remember you {DescribeAffinityAsVerb(affinitySet.Value.Affinity)} {affinitySet.Value.Item}."); + } + + private JiboInteractionDecision BuildRecallAffinityDecision(TurnContext turn, string transcript) + { + var lookup = TryExtractAffinityLookup(transcript); + if (lookup is null) + return new JiboInteractionDecision( + "memory_get_affinity", + "Ask me like this: do I like pizza?"); + + var affinity = personalMemoryStore.GetAffinity(ResolveTenantScope(turn), lookup.Value.Item); + if (affinity is null) + return new JiboInteractionDecision( + "memory_get_affinity", + $"I do not remember how you feel about {lookup.Value.Item} yet."); + + if (lookup.Value.ExpectedAffinity is null) + return new JiboInteractionDecision( + "memory_get_affinity", + $"You told me you {DescribeAffinityAsVerb(affinity.Value)} {lookup.Value.Item}."); + + var matches = lookup.Value.ExpectedAffinity == PersonalAffinity.Dislike + ? affinity == PersonalAffinity.Dislike + : affinity is PersonalAffinity.Like or PersonalAffinity.Love; + + return matches + ? new JiboInteractionDecision( + "memory_get_affinity", + $"Yes. You told me you {DescribeAffinityAsVerb(affinity.Value)} {lookup.Value.Item}.") + : new JiboInteractionDecision( + "memory_get_affinity", + $"Not exactly. You told me you {DescribeAffinityAsVerb(affinity.Value)} {lookup.Value.Item}."); + } +} diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.PersonalityDecisions.cs b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.PersonalityDecisions.cs new file mode 100644 index 0000000..0418c09 --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.PersonalityDecisions.cs @@ -0,0 +1,417 @@ +using System.Collections.Generic; +using System.Globalization; +using Jibo.Cloud.Application.Abstractions; +using Jibo.Cloud.Domain.Models; +using Jibo.Runtime.Abstractions; + +namespace Jibo.Cloud.Application.Services; + +public sealed partial class JiboInteractionService +{ + private static JiboInteractionDecision BuildRobotAgeDecision(DateTimeOffset? referenceLocalTime) + { + var referenceDate = DateOnly.FromDateTime((referenceLocalTime ?? DateTimeOffset.UtcNow).Date); + var ageDescription = DescribePersonaAge(referenceDate, OpenJiboCloudBuildInfo.PersonaBirthday); + return new JiboInteractionDecision( + "robot_age", + $"I count {OpenJiboCloudBuildInfo.PersonaBirthdayWords} as my birthday, so I am {ageDescription}."); + } + + private static JiboInteractionDecision BuildRobotBirthdayDecision() + { + return new JiboInteractionDecision( + "robot_birthday", + $"My birthday is {OpenJiboCloudBuildInfo.PersonaBirthdayWords}."); + } + + private static JiboInteractionDecision BuildTriggerIgnoredDecision() + { + return new JiboInteractionDecision( + "trigger_ignored", + string.Empty, + "chitchat-skill", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["skillId"] = "chitchat-skill", + ["cloudResponseMode"] = "completion_only" + }); + } + + private JiboInteractionDecision BuildReactiveGreetingDecision( + TurnContext turn, + string greetingIntent, + DateTimeOffset? referenceLocalTime) + { + var presence = ResolveGreetingPresenceProfile(turn); + var displayName = ResolvePreferredGreetingName(turn, presence); + var replyText = BuildReactiveGreetingReply(greetingIntent, displayName, referenceLocalTime); + return new JiboInteractionDecision( + greetingIntent, + replyText, + ContextUpdates: BuildGreetingContextUpdates("ReactiveGreeting", presence.PrimaryPersonId, false)); + } + + private JiboInteractionDecision BuildProactiveGreetingDecision( + TurnContext turn, + GreetingPresenceProfile presence, + DateTimeOffset? referenceLocalTime) + { + var displayName = ResolvePreferredGreetingName(turn, presence); + var greetingPrefix = ResolveTimeOfDayGreetingPrefix(referenceLocalTime); + var replyText = string.IsNullOrWhiteSpace(displayName) + ? $"{greetingPrefix}. I am glad to see you." + : $"{greetingPrefix}, {displayName}. Welcome back."; + return new JiboInteractionDecision( + "proactive_greeting", + replyText, + ContextUpdates: BuildGreetingContextUpdates("ProactiveGreeting", presence.PrimaryPersonId, true)); + } + + private static string BuildReactiveGreetingReply( + string greetingIntent, + string? displayName, + DateTimeOffset? referenceLocalTime) + { + var namePrefix = string.IsNullOrWhiteSpace(displayName) + ? string.Empty + : $", {displayName}"; + + return greetingIntent switch + { + "good_morning" => $"Good morning{namePrefix}. It is great to see you.", + "good_afternoon" => $"Good afternoon{namePrefix}. I am glad you are here.", + "good_evening" => $"Good evening{namePrefix}. It is nice to have you back.", + "good_night" => $"Good night{namePrefix}. Sleep well.", + "welcome_back" => string.IsNullOrWhiteSpace(displayName) + ? $"Welcome back. {ResolveTimeOfDayGreetingPrefix(referenceLocalTime)}." + : $"Welcome back, {displayName}. {ResolveTimeOfDayGreetingPrefix(referenceLocalTime)}.", + _ => $"Hello{namePrefix}. It is nice to see you." + }; + } + + private string? ResolvePreferredGreetingName(TurnContext turn, GreetingPresenceProfile presence) + { + var rememberedName = personalMemoryStore.GetName(ResolveTenantScope(turn, presence.PrimaryPersonId)); + if (!string.IsNullOrWhiteSpace(rememberedName)) return ToDisplayName(rememberedName); + + var tenantRememberedName = personalMemoryStore.GetName(ResolveTenantScope(turn)); + if (!string.IsNullOrWhiteSpace(tenantRememberedName)) return ToDisplayName(tenantRememberedName); + + if (!string.IsNullOrWhiteSpace(presence.PrimaryPersonId) && + presence.LoopUserFirstNames.TryGetValue(presence.PrimaryPersonId, out var firstName) && + !string.IsNullOrWhiteSpace(firstName)) + return ToDisplayName(firstName); + + return null; + } + + private static string ToDisplayName(string value) + { + var trimmed = value.Trim(); + return string.IsNullOrWhiteSpace(trimmed) + ? string.Empty + : CultureInfo.InvariantCulture.TextInfo.ToTitleCase(trimmed); + } + + private static bool ShouldHandleProactiveGreetingTrigger( + TurnContext turn, + string? triggerSource, + GreetingPresenceProfile presence) + { + if (string.Equals(triggerSource, "SURPRISE", StringComparison.OrdinalIgnoreCase)) return false; + + if (!presence.HasKnownIdentity) return false; + + var lastGreetingUtc = ReadTimestampAttribute(turn, LastProactiveGreetingUtcMetadataKey); + return !lastGreetingUtc.HasValue || DateTimeOffset.UtcNow - lastGreetingUtc.Value >= ProactiveGreetingCooldown; + } + + private static DateTimeOffset? ReadTimestampAttribute(TurnContext turn, string key) + { + if (!turn.Attributes.TryGetValue(key, out var value) || value is null) return null; + + return DateTimeOffset.TryParse( + value.ToString(), + CultureInfo.InvariantCulture, + DateTimeStyles.RoundtripKind, + out var parsed) + ? parsed + : null; + } + + private static IDictionary BuildGreetingContextUpdates(string route, string? speakerId, + bool proactive) + { + var updates = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + [ChitchatStateMachine.StateMetadataKey] = "complete", + [ChitchatStateMachine.RouteMetadataKey] = "ScriptedResponse", + [ChitchatStateMachine.EmotionMetadataKey] = string.Empty, + [GreetingRouteMetadataKey] = route, + [GreetingSpeakerMetadataKey] = speakerId ?? string.Empty, + [proactive ? LastProactiveGreetingUtcMetadataKey : LastReactiveGreetingUtcMetadataKey] = DateTimeOffset.UtcNow.ToString("O", CultureInfo.InvariantCulture) + }; + + return updates; + } + + private static string ResolveTimeOfDayGreetingPrefix(DateTimeOffset? referenceLocalTime) + { + var hour = (referenceLocalTime ?? DateTimeOffset.UtcNow).Hour; + return hour switch + { + >= 5 and < 12 => "Good morning", + >= 12 and < 17 => "Good afternoon", + _ => "Good evening" + }; + } + + private JiboInteractionDecision BuildPizzaDecision() + { + return BuildPizzaAnimationDecision("pizza", "One pizza, coming right up."); + } + + private JiboInteractionDecision BuildPizzaAnimationDecision(string intentName, string replyText) + { + var prompt = randomizer.Choose(PizzaMimPrompts); + return new JiboInteractionDecision( + intentName, + replyText, + "chitchat-skill", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["esml"] = prompt.Esml, + ["mim_id"] = "RA_JBO_MakePizza", + ["mim_type"] = "announcement", + ["prompt_id"] = prompt.PromptId, + ["prompt_sub_category"] = "AN" + }); + } + + private JiboInteractionDecision BuildProactivePizzaDayDecision(DateTimeOffset? referenceLocalTime) + { + var referenceDate = (referenceLocalTime ?? DateTimeOffset.UtcNow).Date; + return BuildPizzaAnimationDecision( + "proactive_pizza_day", + $"Happy National Pizza Day for {referenceDate.ToString("MMMM d", CultureInfo.InvariantCulture)}. One pizza, coming right up."); + } + + private JiboInteractionDecision BuildProactivePizzaPreferenceDecision() + { + return BuildPizzaAnimationDecision( + "proactive_pizza_preference", + "You mentioned pizza is a favorite, so I thought we should make one."); + } + + private static JiboInteractionDecision BuildProactivePizzaFactOfferDecision() + { + var listenContexts = new[] { "shared/yes_no" }; + return new JiboInteractionDecision( + "proactive_offer_pizza_fact", + "Do you want to hear a fun pizza fact?", + "chitchat-skill", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["mim_id"] = "runtime-chat", + ["mim_type"] = "question", + ["prompt_id"] = "RUNTIME_PROMPT", + ["prompt_sub_category"] = "Q", + ["listen_contexts"] = listenContexts + }); + } + + private static JiboInteractionDecision BuildProactivePizzaFactDecision() + { + return new JiboInteractionDecision( + "proactive_pizza_fact", + "Americans consume about 100 acres of pizza every day, roughly 350 slices per second. That's a lot of pizza."); + } + + private JiboInteractionDecision BuildProactiveFunFactDecision(JiboExperienceCatalog catalog) + { + var categories = new List(); + AddProactiveFactCategory(categories, "fun_fact", catalog.FunFacts); + AddProactiveFactCategory(categories, "robot_fact", catalog.RobotFacts); + AddProactiveFactCategory(categories, "human_fact", catalog.HumanFacts); + + if (categories.Count == 0) + return new JiboInteractionDecision("proactive_fun_fact", randomizer.Choose(catalog.SurpriseReplies)); + + var selectedCategory = randomizer.Choose(categories); + var fact = randomizer.Choose(selectedCategory.Replies); + return new JiboInteractionDecision( + "proactive_fun_fact", + fact, + "chitchat-skill", + new Dictionary + { + ["mim_id"] = "runtime-fun-fact", + ["mim_type"] = "announcement", + ["prompt_id"] = "RUNTIME_FUN_FACT", + ["replyType"] = "fun_fact", + ["factCategory"] = selectedCategory.CategoryName + }); + } + + private static void AddProactiveFactCategory( + ICollection categories, + string categoryName, + IReadOnlyList replies) + { + if (replies.Count == 0) return; + + categories.Add(new ProactiveFactCategory(categoryName, replies)); + } + + private JiboInteractionDecision BuildProactiveJokeDecision(JiboExperienceCatalog catalog) + { + return new JiboInteractionDecision( + "proactive_joke", + randomizer.Choose(catalog.Jokes), + "@be/joke", + new Dictionary + { + ["replyType"] = "joke" + }); + } + + private static JiboInteractionDecision BuildProactiveOfferDeclinedDecision() + { + return new JiboInteractionDecision( + "proactive_offer_declined", + "No problem. We can save the pizza fact for another time."); + } + + private string BuildGenericReply(JiboExperienceCatalog catalog, string transcript, string lowered) + { + if (string.IsNullOrWhiteSpace(transcript)) return "I am listening."; + + if (lowered.Contains("good morning", StringComparison.Ordinal)) + return "Good morning! It is nice to hear your voice."; + + if (lowered.Contains("good afternoon", StringComparison.Ordinal)) + return "Good afternoon. I am happy to be here."; + + return lowered.Contains("good night", StringComparison.Ordinal) + ? "Good night. Sleep tight." + : randomizer.Choose(catalog.GenericFallbackReplies) + .Replace("{transcript}", transcript, StringComparison.Ordinal); + } + + private JiboInteractionDecision BuildScriptedPersonalityDecision( + JiboExperienceCatalog catalog, + string intentName, + params string[] preferredSnippets) + { + return ScriptedResponseDecisionBuilder.BuildScriptedPersonalityDecision( + catalog, + randomizer, + intentName, + preferredSnippets); + } + + private JiboInteractionDecision BuildScriptedFavoriteAnimalDecision( + JiboExperienceCatalog catalog, + string intentName, + params string[] preferredSnippets) + { + return ScriptedResponseDecisionBuilder.BuildScriptedFavoriteAnimalDecision( + catalog, + randomizer, + intentName, + preferredSnippets); + } + + private JiboInteractionDecision BuildScriptedGreetingDecision( + JiboExperienceCatalog catalog, + string intentName, + params string[] preferredSnippets) + { + return ScriptedResponseDecisionBuilder.BuildScriptedGreetingDecision( + catalog, + randomizer, + intentName, + preferredSnippets); + } + + private JiboInteractionDecision BuildScriptedHolidayDecision( + IReadOnlyList replies, + string intentName, + params string[] preferredSnippets) + { + return ScriptedResponseDecisionBuilder.BuildScriptedHolidayDecision( + replies, + randomizer, + intentName, + preferredSnippets); + } + + private JiboInteractionDecision BuildScriptedHolidayTrackerDecision( + JiboExperienceCatalog catalog, + string intentName, + params string[] preferredSnippets) + { + return ScriptedResponseDecisionBuilder.BuildScriptedHolidayTrackerDecision( + catalog, + randomizer, + intentName, + preferredSnippets); + } + + private JiboInteractionDecision BuildScriptedHolidayGreetingDecision( + JiboExperienceCatalog catalog, + string intentName, + params string[] preferredSnippets) + { + return ScriptedResponseDecisionBuilder.BuildScriptedHolidayGreetingDecision( + catalog, + randomizer, + intentName, + preferredSnippets); + } + + private JiboInteractionDecision BuildScriptedHolidayTemplateDecision( + TurnContext turn, + GreetingPresenceProfile presence, + JiboExperienceCatalog catalog, + string intentName, + params string[] preferredSnippets) + { + var selected = ScriptedResponseDecisionBuilder.SelectLegacyReply( + catalog.HolidayReplies, + randomizer, + preferredSnippets); + return new JiboInteractionDecision( + intentName, + RenderHolidayTemplate(selected, turn, presence), + ContextUpdates: ScriptedResponseDecisionBuilder.BuildScriptedResponseContextUpdates()); + } + + private string SelectLegacyPersonalityReply(JiboExperienceCatalog catalog, params string[] preferredSnippets) + { + return ScriptedResponseDecisionBuilder.SelectLegacyPersonalityReply(catalog, randomizer, preferredSnippets); + } + + private string SelectLegacyGreetingReply(JiboExperienceCatalog catalog, params string[] preferredSnippets) + { + return ScriptedResponseDecisionBuilder.SelectLegacyGreetingReply(catalog, randomizer, preferredSnippets); + } + + private string SelectLegacyReply(IReadOnlyList replies, params string[] preferredSnippets) + { + return ScriptedResponseDecisionBuilder.SelectLegacyReply(replies, randomizer, preferredSnippets); + } + + private string RenderHolidayTemplate(string template, TurnContext turn, GreetingPresenceProfile presence) + { + var ownerName = ResolvePreferredGreetingName(turn, presence); + var speakerName = !string.IsNullOrWhiteSpace(ownerName) ? ownerName : "you"; + return template + .Replace("${speaker}'s", $"{speakerName}'s", StringComparison.OrdinalIgnoreCase) + .Replace("${speaker}", speakerName, StringComparison.OrdinalIgnoreCase) + .Replace("${loop.owner}", string.IsNullOrWhiteSpace(ownerName) ? string.Empty : ownerName, + StringComparison.OrdinalIgnoreCase) + .Replace(" ", " ", StringComparison.Ordinal) + .Trim(); + } +} diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.cs b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.cs index 327bb45..405ff73 100644 --- a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.cs +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.cs @@ -803,542 +803,6 @@ public sealed partial class JiboInteractionService( SkillPayload: new Dictionary { ["esml"] = OpenJiboCloudBuildInfo.EsmlVersion }); } - private static JiboInteractionDecision BuildRobotAgeDecision(DateTimeOffset? referenceLocalTime) - { - var referenceDate = DateOnly.FromDateTime((referenceLocalTime ?? DateTimeOffset.UtcNow).Date); - var ageDescription = DescribePersonaAge(referenceDate, OpenJiboCloudBuildInfo.PersonaBirthday); - return new JiboInteractionDecision( - "robot_age", - $"I count {OpenJiboCloudBuildInfo.PersonaBirthdayWords} as my birthday, so I am {ageDescription}."); - } - - private static JiboInteractionDecision BuildRobotBirthdayDecision() - { - return new JiboInteractionDecision( - "robot_birthday", - $"My birthday is {OpenJiboCloudBuildInfo.PersonaBirthdayWords}."); - } - - private static JiboInteractionDecision BuildTriggerIgnoredDecision() - { - return new JiboInteractionDecision( - "trigger_ignored", - string.Empty, - "chitchat-skill", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["skillId"] = "chitchat-skill", - ["cloudResponseMode"] = "completion_only" - }); - } - - private JiboInteractionDecision BuildReactiveGreetingDecision( - TurnContext turn, - string greetingIntent, - DateTimeOffset? referenceLocalTime) - { - var presence = ResolveGreetingPresenceProfile(turn); - var displayName = ResolvePreferredGreetingName(turn, presence); - var replyText = BuildReactiveGreetingReply(greetingIntent, displayName, referenceLocalTime); - return new JiboInteractionDecision( - greetingIntent, - replyText, - ContextUpdates: BuildGreetingContextUpdates("ReactiveGreeting", presence.PrimaryPersonId, false)); - } - - private JiboInteractionDecision BuildProactiveGreetingDecision( - TurnContext turn, - GreetingPresenceProfile presence, - DateTimeOffset? referenceLocalTime) - { - var displayName = ResolvePreferredGreetingName(turn, presence); - var greetingPrefix = ResolveTimeOfDayGreetingPrefix(referenceLocalTime); - var replyText = string.IsNullOrWhiteSpace(displayName) - ? $"{greetingPrefix}. I am glad to see you." - : $"{greetingPrefix}, {displayName}. Welcome back."; - return new JiboInteractionDecision( - "proactive_greeting", - replyText, - ContextUpdates: BuildGreetingContextUpdates("ProactiveGreeting", presence.PrimaryPersonId, true)); - } - - private static string BuildReactiveGreetingReply( - string greetingIntent, - string? displayName, - DateTimeOffset? referenceLocalTime) - { - var namePrefix = string.IsNullOrWhiteSpace(displayName) - ? string.Empty - : $", {displayName}"; - - return greetingIntent switch - { - "good_morning" => $"Good morning{namePrefix}. It is great to see you.", - "good_afternoon" => $"Good afternoon{namePrefix}. I am glad you are here.", - "good_evening" => $"Good evening{namePrefix}. It is nice to have you back.", - "good_night" => $"Good night{namePrefix}. Sleep well.", - "welcome_back" => string.IsNullOrWhiteSpace(displayName) - ? $"Welcome back. {ResolveTimeOfDayGreetingPrefix(referenceLocalTime)}." - : $"Welcome back, {displayName}. {ResolveTimeOfDayGreetingPrefix(referenceLocalTime)}.", - _ => $"Hello{namePrefix}. It is nice to see you." - }; - } - - private string? ResolvePreferredGreetingName(TurnContext turn, GreetingPresenceProfile presence) - { - var rememberedName = personalMemoryStore.GetName(ResolveTenantScope(turn, presence.PrimaryPersonId)); - if (!string.IsNullOrWhiteSpace(rememberedName)) return ToDisplayName(rememberedName); - - var tenantRememberedName = personalMemoryStore.GetName(ResolveTenantScope(turn)); - if (!string.IsNullOrWhiteSpace(tenantRememberedName)) return ToDisplayName(tenantRememberedName); - - if (!string.IsNullOrWhiteSpace(presence.PrimaryPersonId) && - presence.LoopUserFirstNames.TryGetValue(presence.PrimaryPersonId, out var firstName) && - !string.IsNullOrWhiteSpace(firstName)) - return ToDisplayName(firstName); - - return null; - } - - private static string ToDisplayName(string value) - { - var trimmed = value.Trim(); - return string.IsNullOrWhiteSpace(trimmed) - ? string.Empty - : CultureInfo.InvariantCulture.TextInfo.ToTitleCase(trimmed); - } - - private static bool ShouldHandleProactiveGreetingTrigger( - TurnContext turn, - string? triggerSource, - GreetingPresenceProfile presence) - { - if (string.Equals(triggerSource, "SURPRISE", StringComparison.OrdinalIgnoreCase)) return false; - - if (!presence.HasKnownIdentity) return false; - - var lastGreetingUtc = ReadTimestampAttribute(turn, LastProactiveGreetingUtcMetadataKey); - return !lastGreetingUtc.HasValue || DateTimeOffset.UtcNow - lastGreetingUtc.Value >= ProactiveGreetingCooldown; - } - - private static DateTimeOffset? ReadTimestampAttribute(TurnContext turn, string key) - { - if (!turn.Attributes.TryGetValue(key, out var value) || value is null) return null; - - return DateTimeOffset.TryParse( - value.ToString(), - CultureInfo.InvariantCulture, - DateTimeStyles.RoundtripKind, - out var parsed) - ? parsed - : null; - } - - private static IDictionary BuildGreetingContextUpdates(string route, string? speakerId, - bool proactive) - { - var updates = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - [ChitchatStateMachine.StateMetadataKey] = "complete", - [ChitchatStateMachine.RouteMetadataKey] = "ScriptedResponse", - [ChitchatStateMachine.EmotionMetadataKey] = string.Empty, - [GreetingRouteMetadataKey] = route, - [GreetingSpeakerMetadataKey] = speakerId ?? string.Empty, - [proactive ? LastProactiveGreetingUtcMetadataKey : LastReactiveGreetingUtcMetadataKey] = DateTimeOffset.UtcNow.ToString("O", CultureInfo.InvariantCulture) - }; - - return updates; - } - - private static string ResolveTimeOfDayGreetingPrefix(DateTimeOffset? referenceLocalTime) - { - var hour = (referenceLocalTime ?? DateTimeOffset.UtcNow).Hour; - return hour switch - { - >= 5 and < 12 => "Good morning", - >= 12 and < 17 => "Good afternoon", - _ => "Good evening" - }; - } - - private JiboInteractionDecision BuildRememberNameDecision(TurnContext turn, string transcript) - { - var name = TryExtractNameFact(transcript); - if (string.IsNullOrWhiteSpace(name)) - return new JiboInteractionDecision( - "memory_set_name", - "I can remember it if you say, my name is Alex."); - - personalMemoryStore.SetName(ResolveTenantScope(turn), name); - return new JiboInteractionDecision( - "memory_set_name", - $"Nice to meet you, {name}. I will remember your name."); - } - - private JiboInteractionDecision BuildRecallNameDecision(TurnContext turn, GreetingPresenceProfile? presence = null) - { - var personScope = ResolveTenantScope(turn, presence?.PrimaryPersonId); - var name = personalMemoryStore.GetName(personScope); - if (string.IsNullOrWhiteSpace(name)) name = personalMemoryStore.GetName(ResolveTenantScope(turn)); - - name = ToDisplayName(name ?? string.Empty); - - return string.IsNullOrWhiteSpace(name) - ? new JiboInteractionDecision( - "memory_get_name", - "I do not know your name yet. You can say, my name is Alex.") - : new JiboInteractionDecision( - "memory_get_name", - presence is not null && !string.IsNullOrWhiteSpace(presence.PrimaryPersonId) - ? $"I think you are {name}." - : $"You told me your name is {name}."); - } - - private JiboInteractionDecision BuildRememberBirthdayDecision(TurnContext turn, string transcript) - { - var birthday = TryExtractBirthdayFact(transcript); - if (string.IsNullOrWhiteSpace(birthday)) - return new JiboInteractionDecision( - "memory_set_birthday", - "I can remember it if you say, my birthday is March 14."); - - var tenantScope = ResolveTenantScope(turn); - personalMemoryStore.SetBirthday(tenantScope, birthday); - var birthdayDate = TryParseBirthdayDate(birthday); - if (birthdayDate is not null) - { - var birthdayLabel = ResolvePreferredBirthdayLabel(turn); - cloudStateStore?.UpsertHoliday(new HolidayRecord - { - EventId = $"birthday-{tenantScope.LoopId}-{tenantScope.PersonId ?? "loop"}", - Name = string.IsNullOrWhiteSpace(birthdayLabel) ? "Birthday" : $"{birthdayLabel}'s Birthday", - Category = "birthday", - Subcategory = "personal", - LoopId = tenantScope.LoopId, - MemberId = tenantScope.PersonId, - IsEnabled = true, - Date = birthdayDate.Value, - Source = "birthday", - CountryCode = "US" - }); - } - - return new JiboInteractionDecision( - "memory_set_birthday", - $"Got it. I will remember your birthday is {birthday}."); - } - - private JiboInteractionDecision BuildRecallBirthdayDecision(TurnContext turn) - { - var birthday = personalMemoryStore.GetBirthday(ResolveTenantScope(turn)); - return string.IsNullOrWhiteSpace(birthday) - ? new JiboInteractionDecision( - "memory_get_birthday", - "I do not know your birthday yet. You can say, my birthday is March 14.") - : new JiboInteractionDecision( - "memory_get_birthday", - $"You told me your birthday is {birthday}."); - } - - private static DateOnly? TryParseBirthdayDate(string birthdayText) - { - if (string.IsNullOrWhiteSpace(birthdayText)) return null; - - var normalized = birthdayText.Trim().ToLowerInvariant(); - var match = Regex.Match( - normalized, - @"\b(?january|february|march|april|may|june|july|august|september|october|november|december)\s+(?\d{1,2})(?:st|nd|rd|th)?\b", - RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); - if (!match.Success) return null; - - var month = match.Groups["month"].Value.ToLowerInvariant() switch - { - "january" => 1, - "february" => 2, - "march" => 3, - "april" => 4, - "may" => 5, - "june" => 6, - "july" => 7, - "august" => 8, - "september" => 9, - "october" => 10, - "november" => 11, - "december" => 12, - _ => 0 - }; - if (month == 0) return null; - - if (!int.TryParse(match.Groups["day"].Value, out var day) || day is < 1 or > 31) return null; - - var today = DateOnly.FromDateTime(DateTime.UtcNow); - var year = today.Year; - if (day > DateTime.DaysInMonth(year, month)) return null; - - DateOnly birthday; - try - { - birthday = new DateOnly(year, month, day); - } - catch - { - return null; - } - - if (birthday < today) birthday = birthday.AddYears(1); - return birthday; - } - - private static string? ResolvePreferredBirthdayLabel(TurnContext turn) - { - var context = ResolveGreetingPresenceProfile(turn); - return !string.IsNullOrWhiteSpace(context.PrimaryPersonId) && - context.LoopUserFirstNames.TryGetValue(context.PrimaryPersonId, out var firstName) && - !string.IsNullOrWhiteSpace(firstName) - ? ToDisplayName(firstName) - : null; - } - - private string RenderHolidayTemplate(string template, TurnContext turn, GreetingPresenceProfile presence) - { - var ownerName = ResolvePreferredGreetingName(turn, presence); - var speakerName = !string.IsNullOrWhiteSpace(ownerName) ? ownerName : "you"; - return template - .Replace("${speaker}'s", $"{speakerName}'s", StringComparison.OrdinalIgnoreCase) - .Replace("${speaker}", speakerName, StringComparison.OrdinalIgnoreCase) - .Replace("${loop.owner}", string.IsNullOrWhiteSpace(ownerName) ? string.Empty : ownerName, - StringComparison.OrdinalIgnoreCase) - .Replace(" ", " ", StringComparison.Ordinal) - .Trim(); - } - - private JiboInteractionDecision BuildRememberImportantDateDecision(TurnContext turn, string transcript) - { - var importantDate = TryExtractImportantDateSet(transcript); - if (importantDate is null) - return new JiboInteractionDecision( - "memory_set_important_date", - "I can remember it if you say, our anniversary is June 10."); - - personalMemoryStore.SetImportantDate(ResolveTenantScope(turn), importantDate.Value.Label, - importantDate.Value.Value); - return new JiboInteractionDecision( - "memory_set_important_date", - $"Got it. I will remember your {importantDate.Value.Label} is {importantDate.Value.Value}."); - } - - private JiboInteractionDecision BuildRecallImportantDateDecision(TurnContext turn, string transcript) - { - var label = TryExtractImportantDateLookupLabel(transcript); - if (string.IsNullOrWhiteSpace(label)) - return new JiboInteractionDecision( - "memory_get_important_date", - "Ask me like this: when is our anniversary?"); - - var storedDate = personalMemoryStore.GetImportantDate(ResolveTenantScope(turn), label); - return string.IsNullOrWhiteSpace(storedDate) - ? new JiboInteractionDecision( - "memory_get_important_date", - $"I do not know your {label} yet.") - : new JiboInteractionDecision( - "memory_get_important_date", - $"You told me your {label} is {storedDate}."); - } - - private JiboInteractionDecision BuildRememberPreferenceDecision(TurnContext turn, string transcript) - { - var preference = TryExtractPreferenceSet(transcript); - if (preference is null) - return new JiboInteractionDecision( - "memory_set_preference", - "I can remember it if you say, my favorite music is jazz."); - - personalMemoryStore.SetPreference(ResolveTenantScope(turn), preference.Value.Category, preference.Value.Value); - return new JiboInteractionDecision( - "memory_set_preference", - $"Got it. I will remember your favorite {preference.Value.Category} is {preference.Value.Value}."); - } - - private JiboInteractionDecision BuildRecallPreferenceDecision(TurnContext turn, string transcript) - { - var category = TryExtractPreferenceLookupCategory(transcript); - if (string.IsNullOrWhiteSpace(category)) - return new JiboInteractionDecision( - "memory_get_preference", - "Ask me like this: what is my favorite music?"); - - var preference = personalMemoryStore.GetPreference(ResolveTenantScope(turn), category); - return string.IsNullOrWhiteSpace(preference) - ? new JiboInteractionDecision( - "memory_get_preference", - $"I do not know your favorite {category} yet.") - : new JiboInteractionDecision( - "memory_get_preference", - $"You told me your favorite {category} is {preference}."); - } - - private JiboInteractionDecision BuildRememberAffinityDecision(TurnContext turn, string transcript) - { - var affinitySet = TryExtractAffinitySet(transcript); - if (affinitySet is null) - return new JiboInteractionDecision( - "memory_set_affinity", - "I can remember it if you say, I like pizza or I dislike mushrooms."); - - personalMemoryStore.SetAffinity(ResolveTenantScope(turn), affinitySet.Value.Item, affinitySet.Value.Affinity); - return new JiboInteractionDecision( - "memory_set_affinity", - $"Got it. I will remember you {DescribeAffinityAsVerb(affinitySet.Value.Affinity)} {affinitySet.Value.Item}."); - } - - private JiboInteractionDecision BuildRecallAffinityDecision(TurnContext turn, string transcript) - { - var lookup = TryExtractAffinityLookup(transcript); - if (lookup is null) - return new JiboInteractionDecision( - "memory_get_affinity", - "Ask me like this: do I like pizza?"); - - var affinity = personalMemoryStore.GetAffinity(ResolveTenantScope(turn), lookup.Value.Item); - if (affinity is null) - return new JiboInteractionDecision( - "memory_get_affinity", - $"I do not remember how you feel about {lookup.Value.Item} yet."); - - if (lookup.Value.ExpectedAffinity is null) - return new JiboInteractionDecision( - "memory_get_affinity", - $"You told me you {DescribeAffinityAsVerb(affinity.Value)} {lookup.Value.Item}."); - - var matches = lookup.Value.ExpectedAffinity == PersonalAffinity.Dislike - ? affinity == PersonalAffinity.Dislike - : affinity is PersonalAffinity.Like or PersonalAffinity.Love; - - return matches - ? new JiboInteractionDecision( - "memory_get_affinity", - $"Yes. You told me you {DescribeAffinityAsVerb(affinity.Value)} {lookup.Value.Item}.") - : new JiboInteractionDecision( - "memory_get_affinity", - $"Not exactly. You told me you {DescribeAffinityAsVerb(affinity.Value)} {lookup.Value.Item}."); - } - - private JiboInteractionDecision BuildPizzaDecision() - { - return BuildPizzaAnimationDecision("pizza", "One pizza, coming right up."); - } - - private JiboInteractionDecision BuildPizzaAnimationDecision(string intentName, string replyText) - { - var prompt = randomizer.Choose(PizzaMimPrompts); - return new JiboInteractionDecision( - intentName, - replyText, - "chitchat-skill", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["esml"] = prompt.Esml, - ["mim_id"] = "RA_JBO_MakePizza", - ["mim_type"] = "announcement", - ["prompt_id"] = prompt.PromptId, - ["prompt_sub_category"] = "AN" - }); - } - - private JiboInteractionDecision BuildProactivePizzaDayDecision(DateTimeOffset? referenceLocalTime) - { - var referenceDate = (referenceLocalTime ?? DateTimeOffset.UtcNow).Date; - return BuildPizzaAnimationDecision( - "proactive_pizza_day", - $"Happy National Pizza Day for {referenceDate.ToString("MMMM d", CultureInfo.InvariantCulture)}. One pizza, coming right up."); - } - - private JiboInteractionDecision BuildProactivePizzaPreferenceDecision() - { - return BuildPizzaAnimationDecision( - "proactive_pizza_preference", - "You mentioned pizza is a favorite, so I thought we should make one."); - } - - private static JiboInteractionDecision BuildProactivePizzaFactOfferDecision() - { - var listenContexts = new[] { "shared/yes_no" }; - return new JiboInteractionDecision( - "proactive_offer_pizza_fact", - "Do you want to hear a fun pizza fact?", - "chitchat-skill", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["mim_id"] = "runtime-chat", - ["mim_type"] = "question", - ["prompt_id"] = "RUNTIME_PROMPT", - ["prompt_sub_category"] = "Q", - ["listen_contexts"] = listenContexts - }); - } - - private static JiboInteractionDecision BuildProactivePizzaFactDecision() - { - return new JiboInteractionDecision( - "proactive_pizza_fact", - "Americans consume about 100 acres of pizza every day, roughly 350 slices per second. That's a lot of pizza."); - } - - private JiboInteractionDecision BuildProactiveFunFactDecision(JiboExperienceCatalog catalog) - { - var categories = new List(); - AddProactiveFactCategory(categories, "fun_fact", catalog.FunFacts); - AddProactiveFactCategory(categories, "robot_fact", catalog.RobotFacts); - AddProactiveFactCategory(categories, "human_fact", catalog.HumanFacts); - - if (categories.Count == 0) - return new JiboInteractionDecision("proactive_fun_fact", randomizer.Choose(catalog.SurpriseReplies)); - - var selectedCategory = randomizer.Choose(categories); - var fact = randomizer.Choose(selectedCategory.Replies); - return new JiboInteractionDecision( - "proactive_fun_fact", - fact, - "chitchat-skill", - new Dictionary - { - ["mim_id"] = "runtime-fun-fact", - ["mim_type"] = "announcement", - ["prompt_id"] = "RUNTIME_FUN_FACT", - ["replyType"] = "fun_fact", - ["factCategory"] = selectedCategory.CategoryName - }); - } - - private static void AddProactiveFactCategory( - ICollection categories, - string categoryName, - IReadOnlyList replies) - { - if (replies.Count == 0) return; - - categories.Add(new ProactiveFactCategory(categoryName, replies)); - } - - private JiboInteractionDecision BuildProactiveJokeDecision(JiboExperienceCatalog catalog) - { - return new JiboInteractionDecision( - "proactive_joke", - randomizer.Choose(catalog.Jokes), - "@be/joke", - new Dictionary - { - ["replyType"] = "joke" - }); - } - - private static JiboInteractionDecision BuildProactiveOfferDeclinedDecision() - { - return new JiboInteractionDecision( - "proactive_offer_declined", - "No problem. We can save the pizza fact for another time."); - } - private static JiboInteractionDecision BuildCurrentLocationDecision(TurnContext turn) { var locationName = TryResolveCurrentLocationName(turn); @@ -1508,126 +972,6 @@ public sealed partial class JiboInteractionService( return new PizzaSignal(null); } - private string BuildGenericReply(JiboExperienceCatalog catalog, string transcript, string lowered) - { - if (string.IsNullOrWhiteSpace(transcript)) return "I am listening."; - - if (lowered.Contains("good morning", StringComparison.Ordinal)) - return "Good morning! It is nice to hear your voice."; - - if (lowered.Contains("good afternoon", StringComparison.Ordinal)) - return "Good afternoon. I am happy to be here."; - - return lowered.Contains("good night", StringComparison.Ordinal) - ? "Good night. Sleep tight." - : randomizer.Choose(catalog.GenericFallbackReplies) - .Replace("{transcript}", transcript, StringComparison.Ordinal); - } - - private JiboInteractionDecision BuildScriptedPersonalityDecision( - JiboExperienceCatalog catalog, - string intentName, - params string[] preferredSnippets) - { - return ScriptedResponseDecisionBuilder.BuildScriptedPersonalityDecision( - catalog, - randomizer, - intentName, - preferredSnippets); - } - - private JiboInteractionDecision BuildScriptedFavoriteAnimalDecision( - JiboExperienceCatalog catalog, - string intentName, - params string[] preferredSnippets) - { - return ScriptedResponseDecisionBuilder.BuildScriptedFavoriteAnimalDecision( - catalog, - randomizer, - intentName, - preferredSnippets); - } - - private JiboInteractionDecision BuildScriptedGreetingDecision( - JiboExperienceCatalog catalog, - string intentName, - params string[] preferredSnippets) - { - return ScriptedResponseDecisionBuilder.BuildScriptedGreetingDecision( - catalog, - randomizer, - intentName, - preferredSnippets); - } - - private JiboInteractionDecision BuildScriptedHolidayDecision( - IReadOnlyList replies, - string intentName, - params string[] preferredSnippets) - { - return ScriptedResponseDecisionBuilder.BuildScriptedHolidayDecision( - replies, - randomizer, - intentName, - preferredSnippets); - } - - private JiboInteractionDecision BuildScriptedHolidayTrackerDecision( - JiboExperienceCatalog catalog, - string intentName, - params string[] preferredSnippets) - { - return ScriptedResponseDecisionBuilder.BuildScriptedHolidayTrackerDecision( - catalog, - randomizer, - intentName, - preferredSnippets); - } - - private JiboInteractionDecision BuildScriptedHolidayGreetingDecision( - JiboExperienceCatalog catalog, - string intentName, - params string[] preferredSnippets) - { - return ScriptedResponseDecisionBuilder.BuildScriptedHolidayGreetingDecision( - catalog, - randomizer, - intentName, - preferredSnippets); - } - - private JiboInteractionDecision BuildScriptedHolidayTemplateDecision( - TurnContext turn, - GreetingPresenceProfile presence, - JiboExperienceCatalog catalog, - string intentName, - params string[] preferredSnippets) - { - var selected = ScriptedResponseDecisionBuilder.SelectLegacyReply( - catalog.HolidayReplies, - randomizer, - preferredSnippets); - return new JiboInteractionDecision( - intentName, - RenderHolidayTemplate(selected, turn, presence), - ContextUpdates: ScriptedResponseDecisionBuilder.BuildScriptedResponseContextUpdates()); - } - - private string SelectLegacyPersonalityReply(JiboExperienceCatalog catalog, params string[] preferredSnippets) - { - return ScriptedResponseDecisionBuilder.SelectLegacyPersonalityReply(catalog, randomizer, preferredSnippets); - } - - private string SelectLegacyGreetingReply(JiboExperienceCatalog catalog, params string[] preferredSnippets) - { - return ScriptedResponseDecisionBuilder.SelectLegacyGreetingReply(catalog, randomizer, preferredSnippets); - } - - private string SelectLegacyReply(IReadOnlyList replies, params string[] preferredSnippets) - { - return ScriptedResponseDecisionBuilder.SelectLegacyReply(replies, randomizer, preferredSnippets); - } - private static string ResolveSemanticIntent( string loweredTranscript, DateTimeOffset? referenceLocalTime,