mapping radio
This commit is contained in:
@@ -72,6 +72,8 @@ public sealed class DemoConversationBroker(JiboInteractionService interactionSer
|
||||
{
|
||||
"word_of_the_day" => false,
|
||||
"word_of_the_day_guess" => false,
|
||||
"radio" => false,
|
||||
"radio_genre" => false,
|
||||
_ => true
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ public sealed class JiboInteractionService(
|
||||
"dance" => BuildDanceDecision(catalog),
|
||||
"time" => new JiboInteractionDecision("time", $"It is {DateTime.Now:h:mm tt}."),
|
||||
"date" => new JiboInteractionDecision("date", $"Today is {DateTime.Now:dddd, MMMM d}."),
|
||||
"radio" => BuildRadioLaunchDecision(),
|
||||
"radio_genre" => BuildRadioGenreLaunchDecision(lowered),
|
||||
"hello" => new JiboInteractionDecision("hello", randomizer.Choose(catalog.GreetingReplies)),
|
||||
"how_are_you" => new JiboInteractionDecision("how_are_you", randomizer.Choose(catalog.HowAreYouReplies)),
|
||||
"yes" => new JiboInteractionDecision("yes", "Yes."),
|
||||
@@ -151,6 +153,16 @@ public sealed class JiboInteractionService(
|
||||
return "joke";
|
||||
}
|
||||
|
||||
if (TryResolveRadioGenre(loweredTranscript) is not null)
|
||||
{
|
||||
return "radio_genre";
|
||||
}
|
||||
|
||||
if (MatchesAny(loweredTranscript, "open the radio", "play the radio", "turn on the radio", "radio"))
|
||||
{
|
||||
return "radio";
|
||||
}
|
||||
|
||||
if (MatchesAny(loweredTranscript, "dance", "boogie"))
|
||||
{
|
||||
return "dance";
|
||||
@@ -235,6 +247,33 @@ public sealed class JiboInteractionService(
|
||||
});
|
||||
}
|
||||
|
||||
private static JiboInteractionDecision BuildRadioLaunchDecision()
|
||||
{
|
||||
return new JiboInteractionDecision(
|
||||
"radio",
|
||||
"Opening the radio.",
|
||||
"@be/radio",
|
||||
new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["skillId"] = "@be/radio"
|
||||
});
|
||||
}
|
||||
|
||||
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<string, object?>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["skillId"] = "@be/radio",
|
||||
["station"] = station
|
||||
});
|
||||
}
|
||||
|
||||
private static JiboInteractionDecision BuildWordOfTheDayGuessDecision(
|
||||
IReadOnlyDictionary<string, string> clientEntities,
|
||||
string transcript,
|
||||
@@ -417,6 +456,66 @@ public sealed class JiboInteractionService(
|
||||
{
|
||||
return candidates.Any(candidate => loweredTranscript.Contains(candidate, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private static string? TryResolveRadioGenre(string loweredTranscript)
|
||||
{
|
||||
foreach (var (phrase, station) in RadioGenreAliases)
|
||||
{
|
||||
if (loweredTranscript.Contains(phrase, StringComparison.Ordinal))
|
||||
{
|
||||
return station;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string FormatRadioGenreForSpeech(string station)
|
||||
{
|
||||
return station switch
|
||||
{
|
||||
"EightiesAndNinetiesHits" => "eighties and nineties hits",
|
||||
"ChristianAndGospel" => "Christian and gospel",
|
||||
"ClassicRock" => "classic rock",
|
||||
"CollegeRadio" => "college radio",
|
||||
"HipHop" => "hip hop",
|
||||
"NewsAndTalk" => "news and talk",
|
||||
"ReggaeAndIsland" => "reggae and island music",
|
||||
"SoftRock" => "soft rock",
|
||||
_ => station
|
||||
};
|
||||
}
|
||||
|
||||
private static readonly (string Phrase, string Station)[] RadioGenreAliases =
|
||||
[
|
||||
("country music", "Country"),
|
||||
("country radio", "Country"),
|
||||
("country", "Country"),
|
||||
("classic rock", "ClassicRock"),
|
||||
("soft rock", "SoftRock"),
|
||||
("hip hop", "HipHop"),
|
||||
("hip-hop", "HipHop"),
|
||||
("news and talk", "NewsAndTalk"),
|
||||
("news talk", "NewsAndTalk"),
|
||||
("news radio", "NewsAndTalk"),
|
||||
("sports radio", "Sports"),
|
||||
("christian music", "ChristianAndGospel"),
|
||||
("gospel music", "ChristianAndGospel"),
|
||||
("oldies", "Oldies"),
|
||||
("pop music", "Pop"),
|
||||
("jazz", "Jazz"),
|
||||
("latin music", "Latin"),
|
||||
("dance music", "Dance"),
|
||||
("reggae", "ReggaeAndIsland"),
|
||||
("island music", "ReggaeAndIsland"),
|
||||
("alternative", "Alternative"),
|
||||
("blues", "Blues"),
|
||||
("classical music", "Classical"),
|
||||
("classical", "Classical"),
|
||||
("college radio", "CollegeRadio"),
|
||||
("comedy radio", "Comedy"),
|
||||
("npr", "NPR")
|
||||
];
|
||||
}
|
||||
|
||||
public sealed record JiboInteractionDecision(
|
||||
|
||||
@@ -23,9 +23,14 @@ public sealed class ResponsePlanToSocketMessagesMapper
|
||||
string.Equals(plan.IntentName, "no", StringComparison.OrdinalIgnoreCase);
|
||||
var isWordOfDayLaunch = string.Equals(plan.IntentName, "word_of_the_day", StringComparison.OrdinalIgnoreCase);
|
||||
var isWordOfDayGuess = string.Equals(plan.IntentName, "word_of_the_day_guess", StringComparison.OrdinalIgnoreCase);
|
||||
var isRadioLaunch = string.Equals(plan.IntentName, "radio", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(plan.IntentName, "radio_genre", StringComparison.OrdinalIgnoreCase);
|
||||
var radioStation = ReadSkillPayloadString(skill, "station");
|
||||
var nluGuess = ReadClientEntity(turn, "guess");
|
||||
var wordOfDayGuess = ResolveWordOfDayGuess(turn, transcript, nluGuess);
|
||||
var outboundIntent = isWordOfDayLaunch
|
||||
? "menu"
|
||||
: isRadioLaunch
|
||||
? "menu"
|
||||
: isWordOfDayGuess
|
||||
? "guess"
|
||||
@@ -36,6 +41,8 @@ public sealed class ResponsePlanToSocketMessagesMapper
|
||||
? wordOfDayGuess
|
||||
: isWordOfDayLaunch
|
||||
? string.Empty
|
||||
: isRadioLaunch
|
||||
? transcript
|
||||
: string.Equals(clientIntent, "guess", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(nluGuess)
|
||||
? nluGuess
|
||||
: isYesNoTurn && isYesNoIntent
|
||||
@@ -45,10 +52,12 @@ public sealed class ResponsePlanToSocketMessagesMapper
|
||||
: transcript;
|
||||
var outboundRules = isWordOfDayLaunch
|
||||
? ["word-of-the-day/menu"]
|
||||
: isRadioLaunch
|
||||
? Array.Empty<string>()
|
||||
: isWordOfDayGuess
|
||||
? ["word-of-the-day/puzzle"]
|
||||
: isYesNoTurn && isYesNoIntent ? [yesNoRule!] : rules;
|
||||
var entities = ReadEntities(turn, messageType, isYesNoTurn && isYesNoIntent, isWordOfDayLaunch, isWordOfDayGuess, wordOfDayGuess);
|
||||
var entities = ReadEntities(turn, messageType, isYesNoTurn && isYesNoIntent, isWordOfDayLaunch, isRadioLaunch, isWordOfDayGuess, wordOfDayGuess, radioStation);
|
||||
var listenMessage = new
|
||||
{
|
||||
type = "LISTEN",
|
||||
@@ -61,7 +70,7 @@ public sealed class ResponsePlanToSocketMessagesMapper
|
||||
final = true,
|
||||
text = outboundAsrText
|
||||
},
|
||||
nlu = BuildNluPayload(outboundIntent, outboundRules, entities, isWordOfDayLaunch ? "@be/word-of-the-day" : null),
|
||||
nlu = BuildNluPayload(outboundIntent, outboundRules, entities, isWordOfDayLaunch ? "@be/word-of-the-day" : isRadioLaunch ? "@be/radio" : null),
|
||||
match = new
|
||||
{
|
||||
intent = outboundIntent,
|
||||
@@ -100,6 +109,22 @@ public sealed class ResponsePlanToSocketMessagesMapper
|
||||
DelayMs: 125));
|
||||
}
|
||||
|
||||
if (isRadioLaunch)
|
||||
{
|
||||
messages.Add(new SocketReplyPlan(
|
||||
JsonSerializer.Serialize(BuildSkillRedirectPayload(
|
||||
transId,
|
||||
"@be/radio",
|
||||
outboundIntent,
|
||||
outboundAsrText,
|
||||
outboundRules,
|
||||
entities)),
|
||||
DelayMs: 75));
|
||||
messages.Add(new SocketReplyPlan(
|
||||
JsonSerializer.Serialize(BuildCompletionOnlySkillPayload(transId, "@be/radio")),
|
||||
DelayMs: 125));
|
||||
}
|
||||
|
||||
if (emitSkillActions && speak is not null)
|
||||
{
|
||||
messages.Add(new SocketReplyPlan(
|
||||
@@ -242,8 +267,10 @@ public sealed class ResponsePlanToSocketMessagesMapper
|
||||
string? messageType,
|
||||
bool yesNoCreateTurn,
|
||||
bool wordOfDayLaunch,
|
||||
bool radioLaunch,
|
||||
bool wordOfDayGuess,
|
||||
string? guess)
|
||||
string? guess,
|
||||
string? radioStation)
|
||||
{
|
||||
if (yesNoCreateTurn)
|
||||
{
|
||||
@@ -261,6 +288,17 @@ public sealed class ResponsePlanToSocketMessagesMapper
|
||||
};
|
||||
}
|
||||
|
||||
if (radioLaunch)
|
||||
{
|
||||
var entities = new Dictionary<string, object?>();
|
||||
if (!string.IsNullOrWhiteSpace(radioStation))
|
||||
{
|
||||
entities["station"] = radioStation;
|
||||
}
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
if (wordOfDayGuess)
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
|
||||
@@ -544,6 +544,8 @@ public sealed class WebSocketTurnFinalizationService(
|
||||
: DateTimeOffset.UtcNow.Add(WebSocketTurnState.DefaultLateAudioIgnoreWindow);
|
||||
|
||||
var emitSkillActions = !string.Equals(plan.IntentName, "word_of_the_day", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(plan.IntentName, "radio", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(plan.IntentName, "radio_genre", StringComparison.OrdinalIgnoreCase) &&
|
||||
(messageType != "CLIENT_NLU" ||
|
||||
string.Equals(plan.IntentName, "word_of_the_day_guess", StringComparison.OrdinalIgnoreCase));
|
||||
var replies = ResponsePlanToSocketMessagesMapper.Map(plan, finalizedTurn, session, emitSkillActions).Select(map => new WebSocketReply
|
||||
|
||||
Reference in New Issue
Block a user