diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.CommandDecisions.cs b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.CommandDecisions.cs new file mode 100644 index 0000000..53cc890 --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.CommandDecisions.cs @@ -0,0 +1,252 @@ +using System.Collections.Generic; +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 BuildCurrentLocationDecision(TurnContext turn) + { + var locationName = TryResolveCurrentLocationName(turn); + if (string.IsNullOrWhiteSpace(locationName)) + return new JiboInteractionDecision( + "current_location", + "I'm not sure where we are right now."); + + return new JiboInteractionDecision( + "current_location", + $"We're at {NormalizeLocationForSpeech(locationName)} if I'm not mistaken.", + ContextUpdates: ScriptedResponseDecisionBuilder.BuildScriptedResponseContextUpdates()); + } + + private static JiboInteractionDecision BuildOrderPizzaDecision() + { + return new JiboInteractionDecision( + "order_pizza", + "I can't do that yet, but I bet I'll be able to do that sometime in the near future.", + "chitchat-skill", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["esml"] = + "I can't do that yet, but I bet I'll be able to do that sometime in the near future.", + ["mim_id"] = "RA_JBO_OrderPizza", + ["mim_type"] = "announcement", + ["prompt_id"] = "RA_JBO_OrderPizza_AN_01", + ["prompt_sub_category"] = "AN" + }); + } + + private JiboInteractionDecision BuildJokeDecision(JiboExperienceCatalog catalog) + { + var joke = randomizer.Choose(catalog.Jokes); + return new JiboInteractionDecision( + "joke", + joke, + "@be/joke", + new Dictionary + { + ["replyType"] = "joke" + }); + } + + private JiboInteractionDecision BuildRandomDanceDecision(JiboExperienceCatalog catalog) + { + var dance = randomizer.Choose(catalog.DanceAnimations); + var replyText = randomizer.Choose(catalog.DanceReplies); + return BuildDanceDecision("dance", dance, replyText); + } + + private JiboInteractionDecision BuildDanceQuestionDecision(JiboExperienceCatalog catalog) + { + return new JiboInteractionDecision("dance_question", randomizer.Choose(catalog.DanceQuestionReplies)); + } + + private static JiboInteractionDecision BuildDanceDecision(string intentName, string dance, string replyText) + { + return new JiboInteractionDecision( + intentName, + replyText, + "chitchat-skill", + new Dictionary + { + ["esml"] = + $"Okay. Watch this.", + ["mim_id"] = "runtime-chat", + ["mim_type"] = "announcement" + }); + } + + private static JiboInteractionDecision BuildVolumeControlDecision(string intentName, string globalIntent, + string globalValue) + { + return new JiboInteractionDecision( + intentName, + "Opening volume controls.", + "global_commands", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["skillId"] = "@be/settings", + ["globalIntent"] = globalIntent, + ["volumeLevel"] = globalValue + }); + } + + private static JiboInteractionDecision BuildSettingsVolumeDecision() + { + return new JiboInteractionDecision( + "volume_query", + "Opening volume controls.", + "@be/settings", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["skillId"] = "@be/settings", + ["localIntent"] = "volumeQuery" + }); + } + + private static JiboInteractionDecision BuildClockLaunchDecision(string intentName, string domain, + string clockIntent, string replyText) + { + return new JiboInteractionDecision( + intentName, + replyText, + "@be/clock", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["skillId"] = "@be/clock", + ["domain"] = domain, + ["clockIntent"] = clockIntent + }); + } + + private static JiboInteractionDecision BuildClockLaunchDecision(string domain, string replyText) + { + return BuildClockLaunchDecision($"{domain}_menu", domain, "menu", replyText); + } + + private static JiboInteractionDecision BuildClockClarifyDecision(string intentName, string domain, string replyText) + { + return new JiboInteractionDecision( + intentName, + replyText, + "@be/clock", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["skillId"] = "@be/clock", + ["domain"] = domain, + ["clockIntent"] = "set" + }); + } + + private static JiboInteractionDecision BuildTimerValueDecision( + string loweredTranscript, + bool allowImplicit, + IReadOnlyDictionary clientEntities) + { + var timer = TryReadStructuredTimerValue(clientEntities) ?? + TryParseTimerValue(loweredTranscript, allowImplicit) ?? + new ClockTimerValue("0", "1", "null"); + + return new JiboInteractionDecision( + "timer_value", + "Setting your timer.", + "@be/clock", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["skillId"] = "@be/clock", + ["domain"] = "timer", + ["clockIntent"] = "start", + ["hours"] = timer.Hours, + ["minutes"] = timer.Minutes, + ["seconds"] = timer.Seconds + }); + } + + private static JiboInteractionDecision BuildAlarmValueDecision( + string loweredTranscript, + bool allowImplicit, + DateTimeOffset? referenceLocalTime, + IReadOnlyDictionary clientEntities) + { + var alarm = TryReadStructuredAlarmValue(clientEntities) ?? + TryParseAlarmValue(loweredTranscript, allowImplicit, referenceLocalTime) ?? + new ClockAlarmValue("7:00", "am"); + + return new JiboInteractionDecision( + "alarm_value", + "Setting your alarm.", + "@be/clock", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["skillId"] = "@be/clock", + ["domain"] = "alarm", + ["clockIntent"] = "start", + ["time"] = alarm.Time, + ["ampm"] = alarm.AmPm + }); + } + + private static JiboInteractionDecision BuildRadioGenreLaunchDecision(string loweredTranscript) + { + var station = TryResolveRadioGenre(loweredTranscript) ?? "Country"; + + return new JiboInteractionDecision( + "radio_genre", + $"Playing {FormatRadioGenreForSpeech(station)} on the radio.", + "@be/radio", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["skillId"] = "@be/radio", + ["station"] = station + }); + } + + private static JiboInteractionDecision BuildWordOfTheDayGuessDecision( + IReadOnlyDictionary clientEntities, + string transcript, + IReadOnlyList listenAsrHints) + { + var guess = ResolveWordOfTheDayGuess(clientEntities, transcript, listenAsrHints); + + var reply = string.IsNullOrWhiteSpace(guess) + ? "I heard your word of the day guess." + : $"I heard {guess}."; + + return new JiboInteractionDecision( + "word_of_the_day_guess", + reply, + "@be/word-of-the-day", + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["guess"] = guess, + ["skillId"] = "@be/word-of-the-day", + ["cloudResponseMode"] = "completion_only" + }); + } + + private static string ResolveWordOfTheDayGuess( + IReadOnlyDictionary clientEntities, + string transcript, + IReadOnlyList listenAsrHints) + { + if (clientEntities.TryGetValue("guess", out var guessValue) && + !string.IsNullOrWhiteSpace(guessValue)) + return guessValue; + + var loweredTranscript = NormalizeGuessToken(transcript); + var hintIndex = loweredTranscript switch + { + "1" or "one" or "first" => 0, + "2" or "two" or "second" => 1, + "3" or "three" or "third" => 2, + _ => -1 + }; + + if (hintIndex >= 0 && hintIndex < listenAsrHints.Count) return listenAsrHints[hintIndex]; + + var fuzzyHintMatch = FindClosestHint(loweredTranscript, listenAsrHints); + return !string.IsNullOrWhiteSpace(fuzzyHintMatch) ? fuzzyHintMatch : transcript; + } +} diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.ReportFormatting.cs b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.ReportFormatting.cs index 8535d49..f062266 100644 --- a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.ReportFormatting.cs +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.ReportFormatting.cs @@ -8,6 +8,15 @@ namespace Jibo.Cloud.Application.Services; public sealed partial class JiboInteractionService { + private static string EscapeForEsml(string value) + { + return value + .Replace("&", "&", StringComparison.Ordinal) + .Replace("<", "<", StringComparison.Ordinal) + .Replace(">", ">", StringComparison.Ordinal) + .Replace("\"", """, StringComparison.Ordinal); + } + private static string BuildWeatherSpokenReply( WeatherReportSnapshot snapshot, WeatherDateEntity weatherDate, 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 405ff73..7065677 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,88 +803,6 @@ public sealed partial class JiboInteractionService( SkillPayload: new Dictionary { ["esml"] = OpenJiboCloudBuildInfo.EsmlVersion }); } - private static JiboInteractionDecision BuildCurrentLocationDecision(TurnContext turn) - { - var locationName = TryResolveCurrentLocationName(turn); - if (string.IsNullOrWhiteSpace(locationName)) - return new JiboInteractionDecision( - "current_location", - "I'm not sure where we are right now."); - - return new JiboInteractionDecision( - "current_location", - $"We're at {NormalizeLocationForSpeech(locationName)} if I'm not mistaken.", - ContextUpdates: ScriptedResponseDecisionBuilder.BuildScriptedResponseContextUpdates()); - } - - - private static string EscapeForEsml(string value) - { - return value - .Replace("&", "&", StringComparison.Ordinal) - .Replace("<", "<", StringComparison.Ordinal) - .Replace(">", ">", StringComparison.Ordinal) - .Replace("\"", """, StringComparison.Ordinal); - } - - private static JiboInteractionDecision BuildOrderPizzaDecision() - { - return new JiboInteractionDecision( - "order_pizza", - "I can't do that yet, but I bet I'll be able to do that sometime in the near future.", - "chitchat-skill", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["esml"] = - "I can't do that yet, but I bet I'll be able to do that sometime in the near future.", - ["mim_id"] = "RA_JBO_OrderPizza", - ["mim_type"] = "announcement", - ["prompt_id"] = "RA_JBO_OrderPizza_AN_01", - ["prompt_sub_category"] = "AN" - }); - } - - private JiboInteractionDecision BuildJokeDecision(JiboExperienceCatalog catalog) - { - var joke = randomizer.Choose(catalog.Jokes); - return new JiboInteractionDecision( - "joke", - joke, - "@be/joke", - new Dictionary - { - ["replyType"] = "joke" - }); - } - - private JiboInteractionDecision BuildRandomDanceDecision(JiboExperienceCatalog catalog) - { - var dance = randomizer.Choose(catalog.DanceAnimations); - var replyText = randomizer.Choose(catalog.DanceReplies); - return BuildDanceDecision("dance", dance, replyText); - } - - private JiboInteractionDecision BuildDanceQuestionDecision(JiboExperienceCatalog catalog) - { - return new JiboInteractionDecision("dance_question", randomizer.Choose(catalog.DanceQuestionReplies)); - } - - private static JiboInteractionDecision BuildDanceDecision(string intentName, string dance, string replyText) - { - return new JiboInteractionDecision( - intentName, - replyText, - "chitchat-skill", - new Dictionary - { - ["esml"] = - $"Okay. Watch this.", - ["mim_id"] = "runtime-chat", - ["mim_type"] = "announcement" - }); - } - - private JiboInteractionDecision BuildSurpriseDecision( JiboExperienceCatalog catalog, TurnContext turn, @@ -1081,176 +999,4 @@ public sealed partial class JiboInteractionService( }); } - private static JiboInteractionDecision BuildVolumeControlDecision(string intentName, string globalIntent, - string volumeLevel) - { - return new JiboInteractionDecision( - intentName, - "Adjusting volume.", - "global_commands", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["globalIntent"] = globalIntent, - ["nluDomain"] = "global_commands", - ["volumeLevel"] = volumeLevel - }); - } - - private static JiboInteractionDecision BuildSettingsVolumeDecision() - { - return new JiboInteractionDecision( - "volume_query", - "Opening volume controls.", - "@be/settings", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["skillId"] = "@be/settings", - ["localIntent"] = "volumeQuery" - }); - } - - private static JiboInteractionDecision BuildClockLaunchDecision(string intentName, string domain, - string clockIntent, string replyText) - { - return new JiboInteractionDecision( - intentName, - replyText, - "@be/clock", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["skillId"] = "@be/clock", - ["domain"] = domain, - ["clockIntent"] = clockIntent - }); - } - - private static JiboInteractionDecision BuildClockLaunchDecision(string domain, string replyText) - { - return BuildClockLaunchDecision($"{domain}_menu", domain, "menu", replyText); - } - - private static JiboInteractionDecision BuildClockClarifyDecision(string intentName, string domain, string replyText) - { - return new JiboInteractionDecision( - intentName, - replyText, - "@be/clock", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["skillId"] = "@be/clock", - ["domain"] = domain, - ["clockIntent"] = "set" - }); - } - - private static JiboInteractionDecision BuildTimerValueDecision( - string loweredTranscript, - bool allowImplicit, - IReadOnlyDictionary clientEntities) - { - var timer = TryReadStructuredTimerValue(clientEntities) ?? - TryParseTimerValue(loweredTranscript, allowImplicit) ?? - new ClockTimerValue("0", "1", "null"); - - return new JiboInteractionDecision( - "timer_value", - "Setting your timer.", - "@be/clock", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["skillId"] = "@be/clock", - ["domain"] = "timer", - ["clockIntent"] = "start", - ["hours"] = timer.Hours, - ["minutes"] = timer.Minutes, - ["seconds"] = timer.Seconds - }); - } - - private static JiboInteractionDecision BuildAlarmValueDecision( - string loweredTranscript, - bool allowImplicit, - DateTimeOffset? referenceLocalTime, - IReadOnlyDictionary clientEntities) - { - var alarm = TryReadStructuredAlarmValue(clientEntities) ?? - TryParseAlarmValue(loweredTranscript, allowImplicit, referenceLocalTime) ?? - new ClockAlarmValue("7:00", "am"); - - return new JiboInteractionDecision( - "alarm_value", - "Setting your alarm.", - "@be/clock", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["skillId"] = "@be/clock", - ["domain"] = "alarm", - ["clockIntent"] = "start", - ["time"] = alarm.Time, - ["ampm"] = alarm.AmPm - }); - } - - private static JiboInteractionDecision BuildRadioGenreLaunchDecision(string loweredTranscript) - { - var station = TryResolveRadioGenre(loweredTranscript) ?? "Country"; - - return new JiboInteractionDecision( - "radio_genre", - $"Playing {FormatRadioGenreForSpeech(station)} on the radio.", - "@be/radio", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["skillId"] = "@be/radio", - ["station"] = station - }); - } - - private static JiboInteractionDecision BuildWordOfTheDayGuessDecision( - IReadOnlyDictionary clientEntities, - string transcript, - IReadOnlyList listenAsrHints) - { - var guess = ResolveWordOfTheDayGuess(clientEntities, transcript, listenAsrHints); - - var reply = string.IsNullOrWhiteSpace(guess) - ? "I heard your word of the day guess." - : $"I heard {guess}."; - - return new JiboInteractionDecision( - "word_of_the_day_guess", - reply, - "@be/word-of-the-day", - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["guess"] = guess, - ["skillId"] = "@be/word-of-the-day", - ["cloudResponseMode"] = "completion_only" - }); - } - - private static string ResolveWordOfTheDayGuess( - IReadOnlyDictionary clientEntities, - string transcript, - IReadOnlyList listenAsrHints) - { - if (clientEntities.TryGetValue("guess", out var guessValue) && - !string.IsNullOrWhiteSpace(guessValue)) - return guessValue; - - var loweredTranscript = NormalizeGuessToken(transcript); - var hintIndex = loweredTranscript switch - { - "1" or "one" or "first" => 0, - "2" or "two" or "second" => 1, - "3" or "three" or "third" => 2, - _ => -1 - }; - - if (hintIndex >= 0 && hintIndex < listenAsrHints.Count) return listenAsrHints[hintIndex]; - - var fuzzyHintMatch = FindClosestHint(loweredTranscript, listenAsrHints); - return !string.IsNullOrWhiteSpace(fuzzyHintMatch) ? fuzzyHintMatch : transcript; - } - }