diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.ProactivityDecisions.cs b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.ProactivityDecisions.cs new file mode 100644 index 0000000..5116fb1 --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.ProactivityDecisions.cs @@ -0,0 +1,106 @@ +using System.Linq; +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 readonly string[] PizzaPreferenceCategories = + [ + "food", + "meal", + "dish", + "dinner", + "lunch", + "snack" + ]; + + private JiboInteractionDecision BuildSurpriseDecision( + JiboExperienceCatalog catalog, + TurnContext turn, + DateTimeOffset? referenceLocalTime) + { + var tenantScope = ResolveTenantScope(turn); + var candidates = BuildProactivityCandidates(tenantScope, referenceLocalTime); + if (candidates.Count == 0) + return new JiboInteractionDecision("surprise", randomizer.Choose(catalog.SurpriseReplies)); + + var highestWeight = candidates.Max(static candidate => candidate.Weight); + var topCandidates = candidates + .Where(candidate => candidate.Weight == highestWeight) + .ToArray(); + var selected = topCandidates.Length == 1 + ? topCandidates[0] + : randomizer.Choose(topCandidates); + + return selected.IntentName switch + { + "proactive_pizza_day" => BuildProactivePizzaDayDecision(referenceLocalTime), + "proactive_pizza_preference" => BuildProactivePizzaPreferenceDecision(), + "proactive_offer_pizza_fact" => BuildProactivePizzaFactOfferDecision(), + "proactive_fun_fact" => BuildProactiveFunFactDecision(catalog), + "proactive_joke" => BuildProactiveJokeDecision(catalog), + _ => new JiboInteractionDecision("surprise", randomizer.Choose(catalog.SurpriseReplies)) + }; + } + + private List BuildProactivityCandidates( + PersonalMemoryTenantScope tenantScope, + DateTimeOffset? referenceLocalTime) + { + var candidates = new List(); + var referenceDate = (referenceLocalTime ?? DateTimeOffset.UtcNow).Date; + + var pizzaSignal = ResolvePizzaSignal(tenantScope); + if (pizzaSignal.Affinity == PersonalAffinity.Dislike) return candidates; + + if (referenceDate is { Month: 2, Day: 9 }) + { + var holidayWeight = pizzaSignal.Affinity switch + { + PersonalAffinity.Love => 170, + PersonalAffinity.Like => 160, + _ => 150 + }; + candidates.Add(new ProactivityCandidate("proactive_pizza_day", holidayWeight)); + } + + if (pizzaSignal.Affinity is PersonalAffinity.Love or PersonalAffinity.Like) + { + var preferenceWeight = pizzaSignal.Affinity == PersonalAffinity.Love ? 140 : 120; + candidates.Add(new ProactivityCandidate("proactive_pizza_preference", preferenceWeight)); + candidates.Add(new ProactivityCandidate("proactive_offer_pizza_fact", preferenceWeight - 5)); + return candidates; + } + + candidates.Add(new ProactivityCandidate("proactive_fun_fact", 90)); + candidates.Add(new ProactivityCandidate("proactive_joke", 90)); + candidates.Add(new ProactivityCandidate("proactive_offer_pizza_fact", 90)); + return candidates; + } + + private PizzaSignal ResolvePizzaSignal(PersonalMemoryTenantScope tenantScope) + { + var pizzaAffinity = personalMemoryStore.GetAffinity(tenantScope, "pizza"); + if (pizzaAffinity is not null) return new PizzaSignal(pizzaAffinity); + + var affinityMatch = personalMemoryStore.GetAffinities(tenantScope) + .Where(pair => pair.Key.Contains("pizza", StringComparison.OrdinalIgnoreCase)) + .OrderByDescending(static pair => + pair.Value == PersonalAffinity.Love ? 2 : pair.Value == PersonalAffinity.Like ? 1 : 0) + .FirstOrDefault(); + if (!string.IsNullOrWhiteSpace(affinityMatch.Key)) return new PizzaSignal(affinityMatch.Value); + + foreach (var category in PizzaPreferenceCategories) + { + var preference = personalMemoryStore.GetPreference(tenantScope, category); + if (!string.IsNullOrWhiteSpace(preference) && + preference.Contains("pizza", StringComparison.OrdinalIgnoreCase)) + return new PizzaSignal(PersonalAffinity.Like); + } + + return new PizzaSignal(null); + } +} 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 cc2faad..deb865a 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 @@ -262,16 +262,6 @@ public sealed partial class JiboInteractionService( ("what do i think about ", null) ]; - private static readonly string[] PizzaPreferenceCategories = - [ - "food", - "meal", - "dish", - "dinner", - "lunch", - "snack" - ]; - private static readonly HashSet GenericWeatherLocationTerms = new(StringComparer.OrdinalIgnoreCase) { "my area", @@ -1002,93 +992,6 @@ public sealed partial class JiboInteractionService( SkillPayload: new Dictionary { ["esml"] = OpenJiboCloudBuildInfo.EsmlVersion }); } - private JiboInteractionDecision BuildSurpriseDecision( - JiboExperienceCatalog catalog, - TurnContext turn, - DateTimeOffset? referenceLocalTime) - { - var tenantScope = ResolveTenantScope(turn); - var candidates = BuildProactivityCandidates(tenantScope, referenceLocalTime); - if (candidates.Count == 0) - return new JiboInteractionDecision("surprise", randomizer.Choose(catalog.SurpriseReplies)); - - var highestWeight = candidates.Max(static candidate => candidate.Weight); - var topCandidates = candidates - .Where(candidate => candidate.Weight == highestWeight) - .ToArray(); - var selected = topCandidates.Length == 1 - ? topCandidates[0] - : randomizer.Choose(topCandidates); - - return selected.IntentName switch - { - "proactive_pizza_day" => BuildProactivePizzaDayDecision(referenceLocalTime), - "proactive_pizza_preference" => BuildProactivePizzaPreferenceDecision(), - "proactive_offer_pizza_fact" => BuildProactivePizzaFactOfferDecision(), - "proactive_fun_fact" => BuildProactiveFunFactDecision(catalog), - "proactive_joke" => BuildProactiveJokeDecision(catalog), - _ => new JiboInteractionDecision("surprise", randomizer.Choose(catalog.SurpriseReplies)) - }; - } - - private List BuildProactivityCandidates( - PersonalMemoryTenantScope tenantScope, - DateTimeOffset? referenceLocalTime) - { - var candidates = new List(); - var referenceDate = (referenceLocalTime ?? DateTimeOffset.UtcNow).Date; - - var pizzaSignal = ResolvePizzaSignal(tenantScope); - if (pizzaSignal.Affinity == PersonalAffinity.Dislike) return candidates; - - if (referenceDate is { Month: 2, Day: 9 }) - { - var holidayWeight = pizzaSignal.Affinity switch - { - PersonalAffinity.Love => 170, - PersonalAffinity.Like => 160, - _ => 150 - }; - candidates.Add(new ProactivityCandidate("proactive_pizza_day", holidayWeight)); - } - - if (pizzaSignal.Affinity is PersonalAffinity.Love or PersonalAffinity.Like) - { - var preferenceWeight = pizzaSignal.Affinity == PersonalAffinity.Love ? 140 : 120; - candidates.Add(new ProactivityCandidate("proactive_pizza_preference", preferenceWeight)); - candidates.Add(new ProactivityCandidate("proactive_offer_pizza_fact", preferenceWeight - 5)); - return candidates; - } - - candidates.Add(new ProactivityCandidate("proactive_fun_fact", 90)); - candidates.Add(new ProactivityCandidate("proactive_joke", 90)); - candidates.Add(new ProactivityCandidate("proactive_offer_pizza_fact", 90)); - return candidates; - } - - private PizzaSignal ResolvePizzaSignal(PersonalMemoryTenantScope tenantScope) - { - var pizzaAffinity = personalMemoryStore.GetAffinity(tenantScope, "pizza"); - if (pizzaAffinity is not null) return new PizzaSignal(pizzaAffinity); - - var affinityMatch = personalMemoryStore.GetAffinities(tenantScope) - .Where(pair => pair.Key.Contains("pizza", StringComparison.OrdinalIgnoreCase)) - .OrderByDescending(static pair => - pair.Value == PersonalAffinity.Love ? 2 : pair.Value == PersonalAffinity.Like ? 1 : 0) - .FirstOrDefault(); - if (!string.IsNullOrWhiteSpace(affinityMatch.Key)) return new PizzaSignal(affinityMatch.Value); - - foreach (var category in PizzaPreferenceCategories) - { - var preference = personalMemoryStore.GetPreference(tenantScope, category); - if (!string.IsNullOrWhiteSpace(preference) && - preference.Contains("pizza", StringComparison.OrdinalIgnoreCase)) - return new PizzaSignal(PersonalAffinity.Like); - } - - return new PizzaSignal(null); - } - private static string ResolveSemanticIntent( string loweredTranscript, DateTimeOffset? referenceLocalTime,