Wrap personal report in report-skill payload
This commit is contained in:
@@ -269,11 +269,13 @@ internal static class PersonalReportOrchestrator
|
|||||||
userName)
|
userName)
|
||||||
};
|
};
|
||||||
var serviceError = string.Empty;
|
var serviceError = string.Empty;
|
||||||
|
IDictionary<string, object?>? weatherSkillPayload = null;
|
||||||
|
|
||||||
if (toggles.WeatherEnabled)
|
if (toggles.WeatherEnabled)
|
||||||
{
|
{
|
||||||
reportSections.Add("Weather.");
|
|
||||||
var weatherDecision = await buildWeatherDecisionAsync(turn, "weather", cancellationToken);
|
var weatherDecision = await buildWeatherDecisionAsync(turn, "weather", cancellationToken);
|
||||||
|
weatherSkillPayload = weatherDecision.SkillPayload;
|
||||||
|
reportSections.Add("Weather.");
|
||||||
reportSections.Add(weatherDecision.ReplyText);
|
reportSections.Add(weatherDecision.ReplyText);
|
||||||
if (IsWeatherErrorReply(weatherDecision.ReplyText)) serviceError = "weather";
|
if (IsWeatherErrorReply(weatherDecision.ReplyText)) serviceError = "weather";
|
||||||
}
|
}
|
||||||
@@ -282,7 +284,10 @@ internal static class PersonalReportOrchestrator
|
|||||||
reportSections.Add((await buildCalendarDecisionAsync(turn, cancellationToken)).ReplyText);
|
reportSections.Add((await buildCalendarDecisionAsync(turn, cancellationToken)).ReplyText);
|
||||||
|
|
||||||
if (toggles.CommuteEnabled)
|
if (toggles.CommuteEnabled)
|
||||||
reportSections.Add((await buildCommuteDecisionAsync(turn, cancellationToken)).ReplyText);
|
{
|
||||||
|
var commuteReply = (await buildCommuteDecisionAsync(turn, cancellationToken)).ReplyText;
|
||||||
|
reportSections.Add(ChooseFirstSentence(commuteReply));
|
||||||
|
}
|
||||||
|
|
||||||
if (toggles.NewsEnabled)
|
if (toggles.NewsEnabled)
|
||||||
{
|
{
|
||||||
@@ -310,9 +315,12 @@ internal static class PersonalReportOrchestrator
|
|||||||
"And that's your report for the day. I hope you had as much fun as I did."),
|
"And that's your report for the day. I hope you had as much fun as I did."),
|
||||||
userName));
|
userName));
|
||||||
|
|
||||||
|
var reportText = string.Join(" ", reportSections);
|
||||||
return new JiboInteractionDecision(
|
return new JiboInteractionDecision(
|
||||||
"personal_report_delivered",
|
"personal_report_delivered",
|
||||||
string.Join(" ", reportSections),
|
reportText,
|
||||||
|
"report-skill",
|
||||||
|
BuildPersonalReportSkillPayload(reportText, weatherSkillPayload),
|
||||||
ContextUpdates: BuildContextUpdates(
|
ContextUpdates: BuildContextUpdates(
|
||||||
IdleState,
|
IdleState,
|
||||||
0,
|
0,
|
||||||
@@ -323,6 +331,38 @@ internal static class PersonalReportOrchestrator
|
|||||||
serviceError));
|
serviceError));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IDictionary<string, object?> BuildPersonalReportSkillPayload(
|
||||||
|
string reportText,
|
||||||
|
IDictionary<string, object?>? weatherSkillPayload)
|
||||||
|
{
|
||||||
|
var payload = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
["skillId"] = "report-skill",
|
||||||
|
["cloudSkill"] = "personal_report",
|
||||||
|
["mim_id"] = "runtime-personal-report",
|
||||||
|
["mim_type"] = "announcement",
|
||||||
|
["prompt_id"] = "PersonalReport_AN_01",
|
||||||
|
["prompt_sub_category"] = "AN",
|
||||||
|
["esml"] =
|
||||||
|
$"<speak><es cat='neutral' filter='!ssa-only, !sfx-only' endNeutral='true'>{EscapeForEsml(reportText)}</es></speak>",
|
||||||
|
["personal_report_report_text"] = reportText
|
||||||
|
};
|
||||||
|
|
||||||
|
if (weatherSkillPayload is null) return payload;
|
||||||
|
|
||||||
|
foreach (var (key, value) in weatherSkillPayload)
|
||||||
|
if (!string.Equals(key, "esml", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
!string.Equals(key, "skillId", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
!string.Equals(key, "cloudSkill", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
!string.Equals(key, "mim_id", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
!string.Equals(key, "mim_type", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
!string.Equals(key, "prompt_id", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
!string.Equals(key, "prompt_sub_category", StringComparison.OrdinalIgnoreCase))
|
||||||
|
payload[key] = value;
|
||||||
|
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
private static JiboInteractionDecision BuildNoInputDecision(
|
private static JiboInteractionDecision BuildNoInputDecision(
|
||||||
TurnContext turn,
|
TurnContext turn,
|
||||||
string state,
|
string state,
|
||||||
@@ -667,6 +707,16 @@ internal static class PersonalReportOrchestrator
|
|||||||
return string.IsNullOrWhiteSpace(firstSentence) ? selected : firstSentence;
|
return string.IsNullOrWhiteSpace(firstSentence) ? selected : firstSentence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string ChooseFirstSentence(string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value)) return string.Empty;
|
||||||
|
|
||||||
|
var firstSentence = value.Split(['.', '!', '?'], 2,
|
||||||
|
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||||
|
.FirstOrDefault();
|
||||||
|
return string.IsNullOrWhiteSpace(firstSentence) ? value.Trim() : firstSentence;
|
||||||
|
}
|
||||||
|
|
||||||
private static string? ChooseShortestTemplate(IEnumerable<string> templates)
|
private static string? ChooseShortestTemplate(IEnumerable<string> templates)
|
||||||
{
|
{
|
||||||
var selected = templates
|
var selected = templates
|
||||||
@@ -686,6 +736,16 @@ internal static class PersonalReportOrchestrator
|
|||||||
.Trim();
|
.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string EscapeForEsml(string value)
|
||||||
|
{
|
||||||
|
return value
|
||||||
|
.Replace("&", "&", StringComparison.Ordinal)
|
||||||
|
.Replace("<", "<", StringComparison.Ordinal)
|
||||||
|
.Replace(">", ">", StringComparison.Ordinal)
|
||||||
|
.Replace("\"", """, StringComparison.Ordinal)
|
||||||
|
.Replace("'", "'", StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
private readonly record struct PersonalReportServiceToggles(
|
private readonly record struct PersonalReportServiceToggles(
|
||||||
bool WeatherEnabled,
|
bool WeatherEnabled,
|
||||||
bool CalendarEnabled,
|
bool CalendarEnabled,
|
||||||
|
|||||||
@@ -1871,6 +1871,7 @@ public sealed class JiboInteractionServiceTests
|
|||||||
});
|
});
|
||||||
|
|
||||||
Assert.Equal("personal_report_delivered", decision.IntentName);
|
Assert.Equal("personal_report_delivered", decision.IntentName);
|
||||||
|
Assert.Equal("report-skill", decision.SkillName);
|
||||||
Assert.Contains("Sure alex. Here it is.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("Sure alex. Here it is.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
|
||||||
Assert.Contains("Weather.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("Weather.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
|
||||||
Assert.Contains(
|
Assert.Contains(
|
||||||
@@ -1882,6 +1883,13 @@ public sealed class JiboInteractionServiceTests
|
|||||||
Assert.True(StripMarkup(decision.ReplyText).Length < 500,
|
Assert.True(StripMarkup(decision.ReplyText).Length < 500,
|
||||||
$"Personal report speech was still too long: {StripMarkup(decision.ReplyText).Length} chars.");
|
$"Personal report speech was still too long: {StripMarkup(decision.ReplyText).Length} chars.");
|
||||||
Assert.Contains("alex", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("alex", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.NotNull(decision.SkillPayload);
|
||||||
|
Assert.Equal("report-skill", decision.SkillPayload!["skillId"]);
|
||||||
|
Assert.Equal("personal_report", decision.SkillPayload["cloudSkill"]);
|
||||||
|
Assert.Equal(true, decision.SkillPayload["weather_view_enabled"]);
|
||||||
|
Assert.Equal("runtime-personal-report", decision.SkillPayload["mim_id"]);
|
||||||
|
Assert.Contains("Weather. For your weather.", decision.SkillPayload["personal_report_report_text"]?.ToString(),
|
||||||
|
StringComparison.OrdinalIgnoreCase);
|
||||||
Assert.NotNull(decision.ContextUpdates);
|
Assert.NotNull(decision.ContextUpdates);
|
||||||
Assert.Equal("idle", decision.ContextUpdates![PersonalReportStateKey]);
|
Assert.Equal("idle", decision.ContextUpdates![PersonalReportStateKey]);
|
||||||
Assert.Equal(true, decision.ContextUpdates[PersonalReportUserVerifiedKey]);
|
Assert.Equal(true, decision.ContextUpdates[PersonalReportUserVerifiedKey]);
|
||||||
|
|||||||
Reference in New Issue
Block a user