Update commit message generation

This commit is contained in:
Jacob Dubin
2026-05-10 20:31:07 -05:00
parent d434138f9b
commit 8c17ad4035
5 changed files with 162 additions and 20 deletions

View File

@@ -608,18 +608,64 @@ public sealed class JiboInteractionService(
"I can check weather once my weather service is connected.");
}
var locationQuery = TryResolveWeatherLocationQuery(transcript);
var weatherCoordinates = string.IsNullOrWhiteSpace(locationQuery)
? TryResolveWeatherCoordinates(turn)
: null;
var useCelsius = ShouldUseCelsius(turn, transcript);
var isNextWeekForecast = IsNextWeekForecastRequest(normalizedTranscript);
if (isNextWeekForecast)
{
var weeklySnapshots = new List<(int DayOffset, WeatherReportSnapshot Snapshot)>();
for (var offset = 1; offset <= MaxWeatherForecastDayOffset; offset += 1)
{
WeatherReportSnapshot? weeklySnapshot;
try
{
weeklySnapshot = await weatherReportProvider.GetReportAsync(
new WeatherReportRequest(
locationQuery,
weatherCoordinates?.Latitude,
weatherCoordinates?.Longitude,
IsTomorrow: offset == 1,
useCelsius,
ForecastDayOffset: offset),
cancellationToken);
}
catch (Exception) when (!cancellationToken.IsCancellationRequested)
{
weeklySnapshot = null;
}
if (weeklySnapshot is not null)
{
weeklySnapshots.Add((offset, weeklySnapshot));
}
}
if (weeklySnapshots.Count == 0)
{
return new JiboInteractionDecision(
"weather",
"I couldn't fetch the weather right now. Please try again.");
}
var weeklySpokenReply = BuildNextWeekForecastSpokenReply(weeklySnapshots, referenceLocalTime);
var weeklyWeatherPayload = BuildWeatherSkillPayload(weeklySpokenReply, weeklySnapshots[0].Snapshot, referenceLocalTime);
return new JiboInteractionDecision(
"weather",
weeklySpokenReply,
"chitchat-skill",
SkillPayload: weeklyWeatherPayload);
}
if (weatherDate.ForecastDayOffset > MaxWeatherForecastDayOffset)
{
return new JiboInteractionDecision(
"weather",
$"I can forecast up to {MaxWeatherForecastDayOffset} days ahead. Try tomorrow or another day this week.");
}
var locationQuery = TryResolveWeatherLocationQuery(transcript);
var weatherCoordinates = string.IsNullOrWhiteSpace(locationQuery)
? TryResolveWeatherCoordinates(turn)
: null;
var useCelsius = ShouldUseCelsius(turn, transcript);
WeatherReportSnapshot? snapshot;
try
{
@@ -688,6 +734,52 @@ public sealed class JiboInteractionService(
return $"Right now in {location}, it is {summary} and {snapshot.Temperature} degrees {unit}.";
}
private static string BuildNextWeekForecastSpokenReply(
IReadOnlyList<(int DayOffset, WeatherReportSnapshot Snapshot)> snapshots,
DateTimeOffset? referenceLocalTime)
{
if (snapshots.Count == 0)
{
return "I couldn't build a forecast right now.";
}
var location = snapshots[0].Snapshot.LocationName;
if (string.IsNullOrWhiteSpace(location))
{
location = "your area";
}
var unit = snapshots[0].Snapshot.UseCelsius ? "Celsius" : "Fahrenheit";
var referenceDate = (referenceLocalTime ?? DateTimeOffset.UtcNow).Date;
var segments = snapshots
.OrderBy(static item => item.DayOffset)
.Take(MaxWeatherForecastDayOffset)
.Select(item =>
{
var dayName = referenceDate.AddDays(item.DayOffset).ToString("dddd", CultureInfo.InvariantCulture);
var summary = string.IsNullOrWhiteSpace(item.Snapshot.Summary)
? "partly cloudy"
: item.Snapshot.Summary.Trim().TrimEnd('.');
var high = item.Snapshot.HighTemperature ?? item.Snapshot.Temperature;
var low = item.Snapshot.LowTemperature ?? item.Snapshot.Temperature;
return $"{dayName}: {summary}, high {high}, low {low}.";
});
return $"I can share the next five-day forecast in {location}. {string.Join(" ", segments)} Temperatures are in {unit}.";
}
private static bool IsNextWeekForecastRequest(string normalizedTranscript)
{
if (string.IsNullOrWhiteSpace(normalizedTranscript) ||
!normalizedTranscript.Contains("next week", StringComparison.Ordinal))
{
return false;
}
return normalizedTranscript.Contains("forecast", StringComparison.Ordinal) ||
normalizedTranscript.Contains("weather", StringComparison.Ordinal);
}
private static bool ShouldDefaultForecastToTomorrow(string normalizedTranscript, WeatherDateEntity weatherDate)
{
if (weatherDate.ForecastDayOffset > 0 ||
@@ -946,7 +1038,11 @@ public sealed class JiboInteractionService(
["skillId"] = "news",
["cloudSkill"] = "news",
["mim_id"] = "runtime-news",
["mim_type"] = "announcement"
["mim_type"] = "announcement",
["prompt_id"] = "NewsHeadline_AN_01",
["prompt_sub_category"] = "AN",
["esml"] =
$"<speak><anim cat='news' meta='news-stinger' nonBlocking='true' /><break size='0.35'/><es cat='neutral' filter='!ssa-only, !sfx-only' endNeutral='true'>{EscapeForEsml(spokenBriefing)}</es></speak>"
};
if (!string.IsNullOrWhiteSpace(sourceName))
@@ -4100,6 +4196,10 @@ public sealed class JiboInteractionService(
("technology", "technology"),
("tech", "technology"),
("ai", "technology"),
("a i", "technology"),
("a eye", "technology"),
("aye eye", "technology"),
("artificial intelligence", "technology"),
("science", "science"),
("business", "business"),
("finance", "business"),

View File

@@ -844,9 +844,10 @@ public sealed class ResponsePlanToSocketMessagesMapper
["view"] = resolvedGuiConfig
};
playConfig["gui"] = resolvedGuiConfig;
playConfig["no_matches_for_gui"] = 0;
playConfig["no_inputs_for_gui"] = 0;
jcpConfig["timeout"] = 6;
jcpConfig["barge_in"] = true;
jcpConfig["no_matches_for_gui"] = 0;
jcpConfig["no_inputs_for_gui"] = 0;
var weatherViews = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase)
{

View File

@@ -668,6 +668,22 @@ public sealed partial class WebSocketTurnFinalizationService(
UpdatePendingProactivityOffer(session, plan.IntentName);
await ApplyContextUpdatesAsync(session, plan.ContextUpdates, envelope, plan.IntentName, cancellationToken);
var invokedSkillAction = plan.Actions.OfType<InvokeNativeSkillAction>().FirstOrDefault();
if ((string.Equals(plan.IntentName, "weather", StringComparison.OrdinalIgnoreCase) ||
string.Equals(plan.IntentName, "news", StringComparison.OrdinalIgnoreCase)) &&
invokedSkillAction is not null)
{
await sink.RecordTurnDiagnosticAsync(
"skill_payload_summary",
BuildTurnDiagnosticSnapshot(session, envelope, new Dictionary<string, object?>
{
["intent"] = plan.IntentName,
["skillName"] = invokedSkillAction.SkillName,
["payload"] = invokedSkillAction.Payload
}),
cancellationToken);
}
session.FollowUpExpiresUtc = plan.FollowUp.KeepMicOpen
? DateTimeOffset.UtcNow.Add(plan.FollowUp.Timeout)
: null;