fixes for version 13 bugs
This commit is contained in:
@@ -184,6 +184,8 @@ Latest clock discovery findings:
|
||||
- The `jibo test 15` bundle shows stock OS 1.9 rejecting our older top-level `timerValue` launch with `found no matching transition`, so the safer cloud contract is a stock-style `start` intent with the timer/alarm entities attached.
|
||||
- The same bundle also shows local follow-up rules like `clock/timer_set_value`, so bare replies such as `five minutes` or `ten twenty five` need to be parsed when the robot is already collecting a timer/alarm value.
|
||||
- The newest `.NET` pass now routes `open the clock` into the direct `askForTime` clock-view path, moves plain time/date/day questions onto stock-shaped local `@be/clock` handoffs, and keeps malformed timer/alarm requests on a clarification reply path instead of generic chat echo.
|
||||
- The `jibo test 17` bundle shows two remaining clock realities on stock OS 1.9: some alarm misses are genuine STT loss before the cloud ever sees the minutes, and empty cleanup turns like `clock/alarm_timer_okay` must stay local instead of degrading into `heyJibo`/Nimbus.
|
||||
- When the robot context includes a usable local `runtime.location.iso`, ambiguous alarm times now prefer the next real local occurrence rather than defaulting blindly.
|
||||
|
||||
Latest photo discovery findings:
|
||||
|
||||
@@ -191,11 +193,13 @@ Latest photo discovery findings:
|
||||
- `snapshot` and `photobooth` are not gallery submodes; stock main-menu logic remaps them into `@be/create` with `createOnePhoto` and `createSomePhotos`.
|
||||
- The newest `.NET` pass keeps that routing, adds local-file persistence for media metadata, and serves stored media URLs back through `/media/{path}` as a first hosted-gallery slice.
|
||||
- The remaining gap is binary fidelity: the current HTTP capture path stores request bodies as text, which is enough to preserve metadata and a placeholder payload, but may still be too lossy for perfect thumbnails/original fetches.
|
||||
- The `jibo test 17` gallery blue-ring report is at least partly tangled up with the gallery-empty path: stock `@be/gallery` says `there's nothing in the gallery yet. want to take a picture now?`, so lingering mic state there is not purely a launch-routing issue.
|
||||
|
||||
Latest update and state findings:
|
||||
|
||||
- unstaged update queries should not fabricate placeholder no-op manifests, because stock settings logic can treat any returned object like a pending update
|
||||
- the hosted `.NET` cloud now persists update/media/backups state to a local state file by default, which is a better bridge toward Azure SQL / Blob storage than the old process-memory-only behavior
|
||||
- The `jibo test 17` session also includes a real on-robot backup announcement and temporary settings connectivity turbulence, so not all sluggishness from that run should be attributed to the newer cloud protocol changes.
|
||||
|
||||
## Speech, Animation, And ESML
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
This is the production-oriented path for restoring device connectivity and creating a foundation for future runtime, AI, and OTA work.
|
||||
|
||||
Current spoken cloud version: `Open Jibo Cloud version 1.0.10.`
|
||||
Current spoken cloud version: `Open Jibo Cloud version 1.0.14.`
|
||||
|
||||
Release hygiene reminder:
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ public sealed class JiboInteractionService(
|
||||
var catalog = await contentCache.GetCatalogAsync(cancellationToken);
|
||||
var transcript = (turn.NormalizedTranscript ?? turn.RawTranscript ?? string.Empty).Trim();
|
||||
var lowered = transcript.ToLowerInvariant();
|
||||
var referenceLocalTime = TryResolveReferenceLocalTime(turn);
|
||||
var clientIntent = turn.Attributes.TryGetValue("clientIntent", out var rawClientIntent)
|
||||
? rawClientIntent?.ToString()
|
||||
: null;
|
||||
@@ -27,6 +28,7 @@ public sealed class JiboInteractionService(
|
||||
var isAlarmValueTurn = IsClockAlarmValueTurn(clientRules, listenRules);
|
||||
var semanticIntent = ResolveSemanticIntent(
|
||||
lowered,
|
||||
referenceLocalTime,
|
||||
clientIntent,
|
||||
clientRules,
|
||||
listenRules,
|
||||
@@ -38,7 +40,7 @@ public sealed class JiboInteractionService(
|
||||
{
|
||||
"joke" => BuildJokeDecision(catalog),
|
||||
"dance" => BuildRandomDanceDecision(catalog),
|
||||
"twerk" => BuildDanceDecision("rom-twerk", "Watch me twerk."),
|
||||
"twerk" => BuildDanceDecision("twerk", "rom-twerk", "Watch me twerk."),
|
||||
"time" => BuildClockLaunchDecision("time", "clock", "askForTime", "Showing the time."),
|
||||
"date" => BuildClockLaunchDecision("date", "clock", "askForDate", "Showing the date."),
|
||||
"day" => BuildClockLaunchDecision("day", "clock", "askForDay", "Showing the day."),
|
||||
@@ -50,7 +52,7 @@ public sealed class JiboInteractionService(
|
||||
"timer_menu" => BuildClockLaunchDecision("timer", "Opening the timer."),
|
||||
"alarm_menu" => BuildClockLaunchDecision("alarm", "Opening the alarm."),
|
||||
"timer_value" => BuildTimerValueDecision(lowered, isTimerValueTurn),
|
||||
"alarm_value" => BuildAlarmValueDecision(lowered, isAlarmValueTurn),
|
||||
"alarm_value" => BuildAlarmValueDecision(lowered, isAlarmValueTurn, referenceLocalTime),
|
||||
"timer_clarify" => new JiboInteractionDecision("timer_clarify", "How long should I set the timer for?"),
|
||||
"alarm_clarify" => new JiboInteractionDecision("alarm_clarify", "What time should I set the alarm for?"),
|
||||
"photo_gallery" => BuildPhotoGalleryLaunchDecision(),
|
||||
@@ -89,13 +91,13 @@ public sealed class JiboInteractionService(
|
||||
{
|
||||
var dance = randomizer.Choose(catalog.DanceAnimations);
|
||||
var replyText = randomizer.Choose(catalog.DanceReplies);
|
||||
return BuildDanceDecision(dance, replyText);
|
||||
return BuildDanceDecision("dance", dance, replyText);
|
||||
}
|
||||
|
||||
private static JiboInteractionDecision BuildDanceDecision(string dance, string replyText)
|
||||
private static JiboInteractionDecision BuildDanceDecision(string intentName, string dance, string replyText)
|
||||
{
|
||||
return new JiboInteractionDecision(
|
||||
"dance",
|
||||
intentName,
|
||||
replyText,
|
||||
"chitchat-skill",
|
||||
new Dictionary<string, object?>
|
||||
@@ -147,6 +149,7 @@ public sealed class JiboInteractionService(
|
||||
|
||||
private static string ResolveSemanticIntent(
|
||||
string loweredTranscript,
|
||||
DateTimeOffset? referenceLocalTime,
|
||||
string? clientIntent,
|
||||
IReadOnlyList<string> clientRules,
|
||||
IReadOnlyList<string> listenRules,
|
||||
@@ -285,7 +288,7 @@ public sealed class JiboInteractionService(
|
||||
return "alarm_menu";
|
||||
}
|
||||
|
||||
if (TryParseAlarmValue(loweredTranscript, isAlarmValueTurn) is not null)
|
||||
if (TryParseAlarmValue(loweredTranscript, isAlarmValueTurn, referenceLocalTime) is not null)
|
||||
{
|
||||
return "alarm_value";
|
||||
}
|
||||
@@ -342,16 +345,16 @@ public sealed class JiboInteractionService(
|
||||
return "photo_gallery";
|
||||
}
|
||||
|
||||
if (MatchesAny(loweredTranscript, "dance", "boogie"))
|
||||
{
|
||||
return "dance";
|
||||
}
|
||||
|
||||
if (MatchesAny(loweredTranscript, "twerk"))
|
||||
{
|
||||
return "twerk";
|
||||
}
|
||||
|
||||
if (MatchesAny(loweredTranscript, "dance", "boogie"))
|
||||
{
|
||||
return "dance";
|
||||
}
|
||||
|
||||
if (MatchesAny(loweredTranscript, "surprise", "surprise me", "show me something fun"))
|
||||
{
|
||||
return "surprise";
|
||||
@@ -512,9 +515,12 @@ public sealed class JiboInteractionService(
|
||||
});
|
||||
}
|
||||
|
||||
private static JiboInteractionDecision BuildAlarmValueDecision(string loweredTranscript, bool allowImplicit)
|
||||
private static JiboInteractionDecision BuildAlarmValueDecision(
|
||||
string loweredTranscript,
|
||||
bool allowImplicit,
|
||||
DateTimeOffset? referenceLocalTime)
|
||||
{
|
||||
var alarm = TryParseAlarmValue(loweredTranscript, allowImplicit) ?? new ClockAlarmValue("7:00", "am");
|
||||
var alarm = TryParseAlarmValue(loweredTranscript, allowImplicit, referenceLocalTime) ?? new ClockAlarmValue("7:00", "am");
|
||||
|
||||
return new JiboInteractionDecision(
|
||||
"alarm_value",
|
||||
@@ -724,6 +730,43 @@ public sealed class JiboInteractionService(
|
||||
};
|
||||
}
|
||||
|
||||
private static DateTimeOffset? TryResolveReferenceLocalTime(TurnContext turn)
|
||||
{
|
||||
if (!turn.Attributes.TryGetValue("context", out var value) || value is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var contextJson = value.ToString();
|
||||
if (string.IsNullOrWhiteSpace(contextJson))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using var document = JsonDocument.Parse(contextJson);
|
||||
if (!document.RootElement.TryGetProperty("runtime", out var runtime) ||
|
||||
runtime.ValueKind != JsonValueKind.Object ||
|
||||
!runtime.TryGetProperty("location", out var location) ||
|
||||
location.ValueKind != JsonValueKind.Object ||
|
||||
!location.TryGetProperty("iso", out var iso) ||
|
||||
iso.ValueKind != JsonValueKind.String)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var isoValue = iso.GetString();
|
||||
return DateTimeOffset.TryParse(isoValue, out var parsed)
|
||||
? parsed
|
||||
: null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool MatchesAny(string loweredTranscript, params string[] candidates)
|
||||
{
|
||||
return candidates.Any(candidate => loweredTranscript.Contains(candidate, StringComparison.Ordinal));
|
||||
@@ -780,7 +823,10 @@ public sealed class JiboInteractionService(
|
||||
seconds is null ? "null" : seconds.Value.ToString());
|
||||
}
|
||||
|
||||
private static ClockAlarmValue? TryParseAlarmValue(string loweredTranscript, bool allowImplicit = false)
|
||||
private static ClockAlarmValue? TryParseAlarmValue(
|
||||
string loweredTranscript,
|
||||
bool allowImplicit = false,
|
||||
DateTimeOffset? referenceLocalTime = null)
|
||||
{
|
||||
if (!allowImplicit && !loweredTranscript.Contains("alarm", StringComparison.Ordinal))
|
||||
{
|
||||
@@ -807,7 +853,7 @@ public sealed class JiboInteractionService(
|
||||
};
|
||||
if (compactHour is >= 1 and <= 12 && compactMinute is >= 0 and <= 59)
|
||||
{
|
||||
var compactAmPm = ResolveAmPm(compactMatch.Groups["ampm"].Value);
|
||||
var compactAmPm = ResolveAmPm(compactMatch.Groups["ampm"].Value, compactHour, compactMinute, referenceLocalTime);
|
||||
return new ClockAlarmValue($"{compactHour}:{compactMinute:00}", compactAmPm);
|
||||
}
|
||||
}
|
||||
@@ -833,15 +879,59 @@ public sealed class JiboInteractionService(
|
||||
return null;
|
||||
}
|
||||
|
||||
var ampm = ResolveAmPm(match.Groups["ampm"].Value);
|
||||
var ampm = ResolveAmPm(match.Groups["ampm"].Value, hour.Value, minute.Value, referenceLocalTime);
|
||||
return new ClockAlarmValue($"{hour}:{minute:00}", ampm);
|
||||
}
|
||||
|
||||
private static string ResolveAmPm(string token)
|
||||
private static string ResolveAmPm(string token, int hour, int minute, DateTimeOffset? referenceLocalTime)
|
||||
{
|
||||
var normalized = token.Replace(" ", string.Empty, StringComparison.Ordinal)
|
||||
.Replace(".", string.Empty, StringComparison.Ordinal);
|
||||
return normalized.StartsWith("p", StringComparison.OrdinalIgnoreCase) ? "pm" : "am";
|
||||
if (normalized.StartsWith("p", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "pm";
|
||||
}
|
||||
|
||||
if (normalized.StartsWith("a", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "am";
|
||||
}
|
||||
|
||||
return referenceLocalTime.HasValue
|
||||
? ResolveNextOccurrenceAmPm(hour, minute, referenceLocalTime.Value)
|
||||
: "am";
|
||||
}
|
||||
|
||||
private static string ResolveNextOccurrenceAmPm(int hour, int minute, DateTimeOffset referenceLocalTime)
|
||||
{
|
||||
var amCandidate = BuildAlarmCandidate(referenceLocalTime, hour, minute, isPm: false);
|
||||
var pmCandidate = BuildAlarmCandidate(referenceLocalTime, hour, minute, isPm: true);
|
||||
return amCandidate <= pmCandidate ? "am" : "pm";
|
||||
}
|
||||
|
||||
private static DateTimeOffset BuildAlarmCandidate(DateTimeOffset referenceLocalTime, int hour, int minute, bool isPm)
|
||||
{
|
||||
var hour24 = hour % 12;
|
||||
if (isPm)
|
||||
{
|
||||
hour24 += 12;
|
||||
}
|
||||
|
||||
var candidate = new DateTimeOffset(
|
||||
referenceLocalTime.Year,
|
||||
referenceLocalTime.Month,
|
||||
referenceLocalTime.Day,
|
||||
hour24,
|
||||
minute,
|
||||
0,
|
||||
referenceLocalTime.Offset);
|
||||
|
||||
if (candidate <= referenceLocalTime)
|
||||
{
|
||||
candidate = candidate.AddDays(1);
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
private static bool IsTimerRequest(string loweredTranscript)
|
||||
|
||||
@@ -2,7 +2,7 @@ namespace Jibo.Cloud.Application.Services;
|
||||
|
||||
public static class OpenJiboCloudBuildInfo
|
||||
{
|
||||
public const string Version = "1.0.13";
|
||||
public const string Version = "1.0.14";
|
||||
|
||||
public static string VersionWords => Version.Replace(".", " dot ");
|
||||
|
||||
|
||||
@@ -469,6 +469,24 @@ public sealed class WebSocketTurnFinalizationService(
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
if (ShouldHandleAsLocalNoInput(finalizedTurn))
|
||||
{
|
||||
turnState.AwaitingTurnCompletion = false;
|
||||
session.LastTranscript = string.Empty;
|
||||
session.LastIntent = null;
|
||||
session.LastListenType = "no-input";
|
||||
var localRule = ReadPrimaryNoInputRule(finalizedTurn);
|
||||
var noInputReplies = ResponsePlanToSocketMessagesMapper.MapNoInput(
|
||||
turnState.TransId ?? session.LastTransId ?? string.Empty,
|
||||
string.IsNullOrWhiteSpace(localRule) ? turnState.ListenRules : [localRule])
|
||||
.Select(map => new WebSocketReply { Text = map.Text, DelayMs = map.DelayMs })
|
||||
.ToArray();
|
||||
ResetBufferedAudio(session);
|
||||
turnState.SawListen = false;
|
||||
turnState.SawContext = false;
|
||||
return noInputReplies;
|
||||
}
|
||||
|
||||
if (ShouldIgnoreInitialEmptyHotphraseTurn(finalizedTurn, turnState))
|
||||
{
|
||||
turnState.HotphraseEmptyTurnCount += 1;
|
||||
@@ -639,7 +657,7 @@ public sealed class WebSocketTurnFinalizationService(
|
||||
|
||||
private static bool ShouldIgnorePassiveLocalSkillContext(CloudSession session, string? text)
|
||||
{
|
||||
if (session.FollowUpOpen || session.TurnState.SawListen)
|
||||
if (session.FollowUpOpen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -805,6 +823,31 @@ public sealed class WebSocketTurnFinalizationService(
|
||||
string.Equals(rule, "surprises-ota/want_to_download_now", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static bool ShouldHandleAsLocalNoInput(TurnContext turn)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(turn.NormalizedTranscript) || !string.IsNullOrWhiteSpace(turn.RawTranscript))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ReadRules(turn, "listenRules")
|
||||
.Concat(ReadRules(turn, "clientRules"))
|
||||
.Any(static rule =>
|
||||
string.Equals(rule, "clock/alarm_timer_okay", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static string? ReadPrimaryNoInputRule(TurnContext turn)
|
||||
{
|
||||
return ReadRules(turn, "listenRules")
|
||||
.Concat(ReadRules(turn, "clientRules"))
|
||||
.FirstOrDefault(static rule =>
|
||||
string.Equals(rule, "clock/alarm_timer_okay", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "create/is_it_a_keeper", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "settings/download_now_later", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "surprises-date/offer_date_fact", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "surprises-ota/want_to_download_now", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static string? ReadPrimaryYesNoRule(TurnContext turn)
|
||||
{
|
||||
return ReadRules(turn, "listenRules")
|
||||
|
||||
@@ -41,6 +41,21 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Equal("<speak>Okay.<break size='0.2'/> Watch this.<anim cat='dance' filter='music, rom-upbeat' /></speak>", decision.SkillPayload!["esml"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_TwerkQuestion_PrefersSpecificTwerkIntent()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "can you twerk",
|
||||
NormalizedTranscript = "can you twerk"
|
||||
});
|
||||
|
||||
Assert.Equal("twerk", decision.IntentName);
|
||||
Assert.Equal("chitchat-skill", decision.SkillName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_ClientNluAskForDate_MapsToDateIntent()
|
||||
{
|
||||
@@ -368,6 +383,46 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Equal("pm", decision.SkillPayload["ampm"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_SetAlarmForSevenEighteen_UsesNextOccurrenceFromContext()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "set an alarm for 7:18",
|
||||
NormalizedTranscript = "set an alarm for 7:18",
|
||||
Attributes = new Dictionary<string, object?>
|
||||
{
|
||||
["context"] = """{"runtime":{"location":{"iso":"2026-04-22T07:15:00-05:00"}}}"""
|
||||
}
|
||||
});
|
||||
|
||||
Assert.Equal("alarm_value", decision.IntentName);
|
||||
Assert.Equal("7:18", decision.SkillPayload!["time"]);
|
||||
Assert.Equal("am", decision.SkillPayload["ampm"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_SetAlarmForSevenTen_UsesNextOccurrenceFromContext()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "set an alarm for 7:10",
|
||||
NormalizedTranscript = "set an alarm for 7:10",
|
||||
Attributes = new Dictionary<string, object?>
|
||||
{
|
||||
["context"] = """{"runtime":{"location":{"iso":"2026-04-22T07:15:00-05:00"}}}"""
|
||||
}
|
||||
});
|
||||
|
||||
Assert.Equal("alarm_value", decision.IntentName);
|
||||
Assert.Equal("7:10", decision.SkillPayload!["time"]);
|
||||
Assert.Equal("pm", decision.SkillPayload["ampm"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_TimerValueFollowUp_ParsesBareDuration()
|
||||
{
|
||||
|
||||
@@ -561,6 +561,41 @@ public sealed class JiboWebSocketServiceTests
|
||||
Assert.Equal("pm", listenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("entities").GetProperty("ampm").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClientAsr_SetAlarmForSevenTen_UsesNextOccurrenceFromContext()
|
||||
{
|
||||
await _service.HandleMessageAsync(new WebSocketMessageEnvelope
|
||||
{
|
||||
HostName = "neo-hub.jibo.com",
|
||||
Path = "/listen",
|
||||
Kind = "neo-hub-listen",
|
||||
Token = "hub-clock-next-occurrence-token",
|
||||
Text = """{"type":"LISTEN","transID":"trans-clock-next-occurrence","data":{"rules":["globals/global_commands_launch"]}}"""
|
||||
});
|
||||
|
||||
await _service.HandleMessageAsync(new WebSocketMessageEnvelope
|
||||
{
|
||||
HostName = "neo-hub.jibo.com",
|
||||
Path = "/listen",
|
||||
Kind = "neo-hub-listen",
|
||||
Token = "hub-clock-next-occurrence-token",
|
||||
Text = """{"type":"CONTEXT","transID":"trans-clock-next-occurrence","data":{"runtime":{"location":{"iso":"2026-04-22T07:15:00-05:00"}}}}"""
|
||||
});
|
||||
|
||||
var replies = await _service.HandleMessageAsync(new WebSocketMessageEnvelope
|
||||
{
|
||||
HostName = "neo-hub.jibo.com",
|
||||
Path = "/listen",
|
||||
Kind = "neo-hub-listen",
|
||||
Token = "hub-clock-next-occurrence-token",
|
||||
Text = """{"type":"CLIENT_ASR","transID":"trans-clock-next-occurrence","data":{"text":"set an alarm for 7:10"}}"""
|
||||
});
|
||||
|
||||
using var listenPayload = JsonDocument.Parse(replies[0].Text!);
|
||||
Assert.Equal("7:10", listenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("entities").GetProperty("time").GetString());
|
||||
Assert.Equal("pm", listenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("entities").GetProperty("ampm").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClientAsr_TimerValueFollowUp_ParsesBareDurationIntoClockStartIntent()
|
||||
{
|
||||
@@ -739,6 +774,36 @@ public sealed class JiboWebSocketServiceTests
|
||||
Assert.Equal(0, session.TurnState.BufferedAudioChunkCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClientAsr_AlarmTimerOkayEmptyReply_MapsToLocalNoInputInsteadOfFallback()
|
||||
{
|
||||
await _service.HandleMessageAsync(new WebSocketMessageEnvelope
|
||||
{
|
||||
HostName = "neo-hub.jibo.com",
|
||||
Path = "/listen",
|
||||
Kind = "neo-hub-listen",
|
||||
Token = "hub-clock-alarm-okay-token",
|
||||
Text = """{"type":"LISTEN","transID":"trans-clock-alarm-okay","data":{"rules":["clock/alarm_timer_okay","globals/gui_nav","globals/mim_repeat","globals/global_commands_launch"]}}"""
|
||||
});
|
||||
|
||||
var replies = await _service.HandleMessageAsync(new WebSocketMessageEnvelope
|
||||
{
|
||||
HostName = "neo-hub.jibo.com",
|
||||
Path = "/listen",
|
||||
Kind = "neo-hub-listen",
|
||||
Token = "hub-clock-alarm-okay-token",
|
||||
Text = """{"type":"CLIENT_ASR","transID":"trans-clock-alarm-okay","data":{}}"""
|
||||
});
|
||||
|
||||
Assert.Equal(2, replies.Count);
|
||||
Assert.Equal("LISTEN", ReadReplyType(replies[0]));
|
||||
Assert.Equal("EOS", ReadReplyType(replies[1]));
|
||||
|
||||
using var listenPayload = JsonDocument.Parse(replies[0].Text!);
|
||||
Assert.Equal(string.Empty, listenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("intent").GetString());
|
||||
Assert.Equal("clock/alarm_timer_okay", listenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("rules")[0].GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClientAsr_SnapAPicture_RedirectsIntoCreateSkill()
|
||||
{
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"exception": "System.InvalidOperationException: whisper.cpp returned no transcript for the buffered audio turn.\n at Jibo.Cloud.Infrastructure.Audio.LocalWhisperCppBufferedAudioSttStrategy.TranscribeAsync(TurnContext turn, CancellationToken cancellationToken) in /home/jake-dubin/JiboExperiments/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Audio/LocalWhisperCppBufferedAudioSttStrategy.cs:line 58\n at Jibo.Cloud.Application.Services.WebSocketTurnFinalizationService.ResolveTranscriptAsync(TurnContext turn, CloudSession session, CancellationToken cancellationToken) in /home/jake-dubin/JiboExperiments/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/WebSocketTurnFinalizationService.cs:line 219",
|
||||
"message": "Error during STT processing"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"exception": "System.InvalidOperationException: whisper.cpp returned no transcript for the buffered audio turn.\n at Jibo.Cloud.Infrastructure.Audio.LocalWhisperCppBufferedAudioSttStrategy.TranscribeAsync(TurnContext turn, CancellationToken cancellationToken) in /home/jake-dubin/JiboExperiments/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Audio/LocalWhisperCppBufferedAudioSttStrategy.cs:line 58\n at Jibo.Cloud.Application.Services.WebSocketTurnFinalizationService.ResolveTranscriptAsync(TurnContext turn, CloudSession session, CancellationToken cancellationToken) in /home/jake-dubin/JiboExperiments/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/WebSocketTurnFinalizationService.cs:line 242",
|
||||
"message": "Error during STT processing"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,127 @@
|
||||
{
|
||||
"name": "neohubjibocom-neohublisten-tid52b6f46e3b6a11f191515cf821ea55ae",
|
||||
"session": {
|
||||
"hostName": "neo-hub.jibo.com",
|
||||
"path": "/v1/listen",
|
||||
"kind": "neo-hub-listen",
|
||||
"token": "hub-usr_openjibo_owner-1776545569192"
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"text": {
|
||||
"type": "LISTEN",
|
||||
"ts": 1776546327052,
|
||||
"msgID": "mid-5303b5f6-3b6a-11f1-adc4-5cf821ea55ae",
|
||||
"transID": "tid-52b6f46e-3b6a-11f1-9151-5cf821ea55ae",
|
||||
"data": {
|
||||
"lang": "en-US",
|
||||
"hotphrase": true,
|
||||
"rules": [
|
||||
"launch",
|
||||
"globals/global_commands_launch"
|
||||
],
|
||||
"mode": "CLIENT_ASR",
|
||||
"asr": {
|
||||
"hints": [],
|
||||
"earlyEOS": [],
|
||||
"encoding": "OGG_OPUS",
|
||||
"sampleRate": 16000,
|
||||
"sosTimeout": 7000,
|
||||
"maxSpeechTimeout": 20000
|
||||
}
|
||||
}
|
||||
},
|
||||
"binary": null,
|
||||
"expectedReplyTypes": [
|
||||
"OPENJIBO_TURN_PENDING"
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"type": "CLIENT_ASR",
|
||||
"ts": 1776546327052,
|
||||
"msgID": "mid-5303bd76-3b6a-11f1-81d4-5cf821ea55ae",
|
||||
"transID": "tid-52b6f46e-3b6a-11f1-9151-5cf821ea55ae",
|
||||
"data": {
|
||||
"text": "tell me about the news"
|
||||
}
|
||||
},
|
||||
"binary": null,
|
||||
"expectedReplyTypes": [
|
||||
"LISTEN",
|
||||
"EOS",
|
||||
"SKILL_ACTION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"type": "CONTEXT",
|
||||
"ts": 1776546327177,
|
||||
"msgID": "mid-5316cf2e-3b6a-11f1-8aa7-5cf821ea55ae",
|
||||
"transID": "tid-52b6f46e-3b6a-11f1-9151-5cf821ea55ae",
|
||||
"data": {
|
||||
"runtime": {
|
||||
"character": {
|
||||
"emotion": {
|
||||
"name": "NEUTRAL",
|
||||
"valence": 0.45,
|
||||
"confidence": 0.2
|
||||
},
|
||||
"motivation": {
|
||||
"social": 1,
|
||||
"playful": 1
|
||||
}
|
||||
},
|
||||
"perception": {
|
||||
"speaker": null,
|
||||
"peoplePresent": []
|
||||
},
|
||||
"location": {
|
||||
"city": "Pleasant Hill",
|
||||
"state": "Missouri",
|
||||
"stateAbbr": "MO",
|
||||
"country": "United States",
|
||||
"countryCode": "US",
|
||||
"lat": 38.8358494,
|
||||
"lng": -94.1427229,
|
||||
"iso": "2026-04-18T16:05:27.073-05:00"
|
||||
},
|
||||
"loop": {
|
||||
"loopId": "5c0b221fdf9d450019c5e253",
|
||||
"users": [
|
||||
{
|
||||
"firstName": "Erin",
|
||||
"lastName": "Picone",
|
||||
"phoneticName": "Erin",
|
||||
"gender": "female",
|
||||
"birthdate": 649209600000,
|
||||
"id": "5c0b221fdf9d450019c5e255",
|
||||
"accountId": "5c0b20547c46170019235759"
|
||||
}
|
||||
],
|
||||
"jibo": {
|
||||
"color": "WHITE",
|
||||
"birthdate": 1544234645598,
|
||||
"id": "5c0b221fdf9d450019c5e254"
|
||||
},
|
||||
"owner": "5c0b221fdf9d450019c5e255"
|
||||
},
|
||||
"dialog": {
|
||||
"referent": null
|
||||
}
|
||||
},
|
||||
"skill": {
|
||||
"id": null
|
||||
},
|
||||
"general": {
|
||||
"release": "1.9.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"binary": null,
|
||||
"expectedReplyTypes": [
|
||||
"OPENJIBO_CONTEXT_ACK"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
{
|
||||
"name": "neohubjibocom-neohublisten-tida8165b823b9411f195545cf821ea55ae",
|
||||
"session": {
|
||||
"hostName": "neo-hub.jibo.com",
|
||||
"path": "/v1/listen",
|
||||
"kind": "neo-hub-listen",
|
||||
"token": "hub-usr_openjibo_owner-1776563295273"
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"text": {
|
||||
"type": "LISTEN",
|
||||
"ts": 1776564508900,
|
||||
"msgID": "mid-a83d9076-3b94-11f1-978d-5cf821ea55ae",
|
||||
"transID": "tid-a8165b82-3b94-11f1-9554-5cf821ea55ae",
|
||||
"data": {
|
||||
"lang": "en-US",
|
||||
"hotphrase": true,
|
||||
"rules": [
|
||||
"launch",
|
||||
"globals/global_commands_launch"
|
||||
],
|
||||
"mode": "",
|
||||
"asr": {
|
||||
"hints": [],
|
||||
"earlyEOS": [],
|
||||
"encoding": "OGG_OPUS",
|
||||
"sampleRate": 16000,
|
||||
"sosTimeout": 7000,
|
||||
"maxSpeechTimeout": 20000
|
||||
}
|
||||
}
|
||||
},
|
||||
"binary": null,
|
||||
"expectedReplyTypes": [
|
||||
"LISTEN",
|
||||
"EOS",
|
||||
"SKILL_ACTION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": null,
|
||||
"binary": [
|
||||
79,
|
||||
103,
|
||||
103,
|
||||
83,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
62,
|
||||
200,
|
||||
6,
|
||||
48,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
146,
|
||||
142,
|
||||
146,
|
||||
101,
|
||||
1,
|
||||
19,
|
||||
79,
|
||||
112,
|
||||
117,
|
||||
115,
|
||||
72,
|
||||
101,
|
||||
97,
|
||||
100,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
128,
|
||||
62,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"expectedReplyTypes": [
|
||||
"OPENJIBO_AUDIO_RECEIVED"
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"type": "CONTEXT",
|
||||
"ts": 1776564510009,
|
||||
"msgID": "mid-a8e6d640-3b94-11f1-b2b0-5cf821ea55ae",
|
||||
"transID": "tid-a8165b82-3b94-11f1-9554-5cf821ea55ae",
|
||||
"data": {
|
||||
"runtime": {
|
||||
"character": {
|
||||
"emotion": {
|
||||
"name": "NEUTRAL",
|
||||
"valence": 0.45,
|
||||
"confidence": 0.2
|
||||
},
|
||||
"motivation": {
|
||||
"social": 1,
|
||||
"playful": 1
|
||||
}
|
||||
},
|
||||
"perception": {
|
||||
"speaker": null,
|
||||
"peoplePresent": [
|
||||
{
|
||||
"id": "NOT_TRAINED",
|
||||
"entityId": 1282,
|
||||
"type": "fused",
|
||||
"confidence": 0.25
|
||||
}
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"city": "Pleasant Hill",
|
||||
"state": "Missouri",
|
||||
"stateAbbr": "MO",
|
||||
"country": "United States",
|
||||
"countryCode": "US",
|
||||
"lat": 38.8358494,
|
||||
"lng": -94.1427229,
|
||||
"iso": "2026-04-18T21:08:29.921-05:00"
|
||||
},
|
||||
"loop": {
|
||||
"loopId": "5c0b221fdf9d450019c5e253",
|
||||
"users": [
|
||||
{
|
||||
"firstName": "Erin",
|
||||
"lastName": "Picone",
|
||||
"phoneticName": "Erin",
|
||||
"gender": "female",
|
||||
"birthdate": 649209600000,
|
||||
"id": "5c0b221fdf9d450019c5e255",
|
||||
"accountId": "5c0b20547c46170019235759"
|
||||
}
|
||||
],
|
||||
"jibo": {
|
||||
"color": "WHITE",
|
||||
"birthdate": 1544234645598,
|
||||
"id": "5c0b221fdf9d450019c5e254"
|
||||
},
|
||||
"owner": "5c0b221fdf9d450019c5e255"
|
||||
},
|
||||
"dialog": {
|
||||
"referent": null
|
||||
}
|
||||
},
|
||||
"skill": {
|
||||
"id": null
|
||||
},
|
||||
"general": {
|
||||
"release": "1.9.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"binary": null,
|
||||
"expectedReplyTypes": [
|
||||
"OPENJIBO_CONTEXT_ACK"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"name": "neohubjibocom-neohublisten-tidd2b591403b6811f1a5735cf821ea55ae",
|
||||
"session": {
|
||||
"hostName": "neo-hub.jibo.com",
|
||||
"path": "/v1/listen",
|
||||
"kind": "neo-hub-listen",
|
||||
"token": "hub-usr_openjibo_owner-1776545569192"
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"text": {
|
||||
"type": "LISTEN",
|
||||
"ts": 1776545682509,
|
||||
"msgID": "mid-d2d657ea-3b68-11f1-985b-5cf821ea55ae",
|
||||
"transID": "tid-d2b59140-3b68-11f1-a573-5cf821ea55ae",
|
||||
"data": {
|
||||
"lang": "en-US",
|
||||
"hotphrase": true,
|
||||
"rules": [
|
||||
"launch",
|
||||
"globals/global_commands_launch"
|
||||
],
|
||||
"mode": "",
|
||||
"asr": {
|
||||
"hints": [],
|
||||
"earlyEOS": [],
|
||||
"encoding": "OGG_OPUS",
|
||||
"sampleRate": 16000,
|
||||
"sosTimeout": 7000,
|
||||
"maxSpeechTimeout": 20000
|
||||
}
|
||||
}
|
||||
},
|
||||
"binary": null,
|
||||
"expectedReplyTypes": [
|
||||
"OPENJIBO_TURN_PENDING"
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": null,
|
||||
"binary": [
|
||||
79,
|
||||
103,
|
||||
103,
|
||||
83,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
94,
|
||||
132,
|
||||
99,
|
||||
103,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
234,
|
||||
141,
|
||||
12,
|
||||
246,
|
||||
1,
|
||||
19,
|
||||
79,
|
||||
112,
|
||||
117,
|
||||
115,
|
||||
72,
|
||||
101,
|
||||
97,
|
||||
100,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
128,
|
||||
62,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"expectedReplyTypes": [
|
||||
"OPENJIBO_AUDIO_RECEIVED"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
8182
artifact-output/jibo-test-17/jibo test 17.txt
Normal file
8182
artifact-output/jibo-test-17/jibo test 17.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user