This commit is contained in:
Jacob Dubin
2026-05-19 06:03:34 -05:00
parent 6bae858da9
commit 54b32bc9cf
41 changed files with 135 additions and 117 deletions

View File

@@ -12,6 +12,7 @@ public sealed record MediaContentSnapshot
{ {
public string ContentType { get; init; } = "application/octet-stream"; public string ContentType { get; init; } = "application/octet-stream";
public byte[] Content { get; init; } = []; public byte[] Content { get; init; } = [];
public IReadOnlyDictionary<string, object?> Meta { get; init; } = public IReadOnlyDictionary<string, object?> Meta { get; init; } =
new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase); new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
} }

View File

@@ -1,3 +1,4 @@
using System.Text;
using System.Text.Json; using System.Text.Json;
using Jibo.Cloud.Application.Abstractions; using Jibo.Cloud.Application.Abstractions;
using Jibo.Cloud.Domain.Models; using Jibo.Cloud.Domain.Models;
@@ -6,7 +7,6 @@ namespace Jibo.Cloud.Application.Services;
public sealed class JiboCloudProtocolService(ICloudStateStore stateStore, IMediaContentStore? mediaContentStore = null) public sealed class JiboCloudProtocolService(ICloudStateStore stateStore, IMediaContentStore? mediaContentStore = null)
{ {
private readonly IMediaContentStore _mediaContentStore = mediaContentStore ?? new NullMediaContentStore();
private static readonly string[] AcceptedHosts = private static readonly string[] AcceptedHosts =
[ [
"api.jibo.com", "api.jibo.com",
@@ -15,6 +15,8 @@ public sealed class JiboCloudProtocolService(ICloudStateStore stateStore, IMedia
"localhost" "localhost"
]; ];
private readonly IMediaContentStore _mediaContentStore = mediaContentStore ?? new NullMediaContentStore();
public Task<ProtocolDispatchResult> DispatchAsync(ProtocolEnvelope envelope, public Task<ProtocolDispatchResult> DispatchAsync(ProtocolEnvelope envelope,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
@@ -344,7 +346,7 @@ public sealed class JiboCloudProtocolService(ICloudStateStore stateStore, IMedia
if (!string.IsNullOrWhiteSpace(envelope.BodyText)) meta["bodyText"] = envelope.BodyText; if (!string.IsNullOrWhiteSpace(envelope.BodyText)) meta["bodyText"] = envelope.BodyText;
_mediaContentStore.StoreAsync(path, contentType, _mediaContentStore.StoreAsync(path, contentType,
string.IsNullOrWhiteSpace(envelope.BodyText) ? [] : System.Text.Encoding.UTF8.GetBytes(envelope.BodyText), string.IsNullOrWhiteSpace(envelope.BodyText) ? [] : Encoding.UTF8.GetBytes(envelope.BodyText),
meta as IReadOnlyDictionary<string, object?>, CancellationToken.None).GetAwaiter().GetResult(); meta as IReadOnlyDictionary<string, object?>, CancellationToken.None).GetAwaiter().GetResult();
return ProtocolDispatchResult.Ok( return ProtocolDispatchResult.Ok(
@@ -367,7 +369,8 @@ public sealed class JiboCloudProtocolService(ICloudStateStore stateStore, IMedia
{ {
var body = envelope.TryParseBody(); var body = envelope.TryParseBody();
var requestedName = ReadString(body, "name") ?? ReadString(body, "backupName"); var requestedName = ReadString(body, "name") ?? ReadString(body, "backupName");
return ProtocolDispatchResult.Ok(stateStore.CreateBackup(requestedName ?? $"backup-{DateTimeOffset.UtcNow:yyyyMMddHHmmss}")); return ProtocolDispatchResult.Ok(
stateStore.CreateBackup(requestedName ?? $"backup-{DateTimeOffset.UtcNow:yyyyMMddHHmmss}"));
} }
return ProtocolDispatchResult.Ok(Array.Empty<object>()); return ProtocolDispatchResult.Ok(Array.Empty<object>());
@@ -512,27 +515,13 @@ public sealed class JiboCloudProtocolService(ICloudStateStore stateStore, IMedia
var storedContent = _mediaContentStore.LoadAsync(media.Path, CancellationToken.None).GetAwaiter().GetResult(); var storedContent = _mediaContentStore.LoadAsync(media.Path, CancellationToken.None).GetAwaiter().GetResult();
var contentType = storedContent?.ContentType ?? TryReadMetaString(media.Meta, "contentType") ?? var contentType = storedContent?.ContentType ?? TryReadMetaString(media.Meta, "contentType") ??
"application/octet-stream"; "application/octet-stream";
var bodyText = storedContent is not null var bodyText = storedContent is not null
? System.Text.Encoding.UTF8.GetString(storedContent.Content) ? Encoding.UTF8.GetString(storedContent.Content)
: TryReadMetaString(media.Meta, "bodyText") ?? string.Empty; : TryReadMetaString(media.Meta, "bodyText") ?? string.Empty;
return ProtocolDispatchResult.Raw(200, bodyText, contentType); return ProtocolDispatchResult.Raw(200, bodyText, contentType);
} }
private sealed class NullMediaContentStore : IMediaContentStore
{
public Task StoreAsync(string path, string contentType, byte[] content,
IReadOnlyDictionary<string, object?>? meta, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
public Task<MediaContentSnapshot?> LoadAsync(string path, CancellationToken cancellationToken = default)
{
return Task.FromResult<MediaContentSnapshot?>(null);
}
}
private ProtocolDispatchResult HandleGetUpdateFrom(string? subsystem, string? fromVersion, string? filter) private ProtocolDispatchResult HandleGetUpdateFrom(string? subsystem, string? fromVersion, string? filter)
{ {
var update = stateStore.GetUpdateFrom(subsystem, fromVersion, filter); var update = stateStore.GetUpdateFrom(subsystem, fromVersion, filter);
@@ -662,4 +651,18 @@ public sealed class JiboCloudProtocolService(ICloudStateStore stateStore, IMedia
bool.TryParse(value, out var parsed) && bool.TryParse(value, out var parsed) &&
parsed; parsed;
} }
private sealed class NullMediaContentStore : IMediaContentStore
{
public Task StoreAsync(string path, string contentType, byte[] content,
IReadOnlyDictionary<string, object?>? meta, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
public Task<MediaContentSnapshot?> LoadAsync(string path, CancellationToken cancellationToken = default)
{
return Task.FromResult<MediaContentSnapshot?>(null);
}
}
} }

View File

@@ -1524,10 +1524,10 @@ public sealed class JiboInteractionService(
{ {
"walking" => lowered.Contains("walk", StringComparison.OrdinalIgnoreCase), "walking" => lowered.Contains("walk", StringComparison.OrdinalIgnoreCase),
"transit" => lowered.Contains("public transportation", StringComparison.OrdinalIgnoreCase) || "transit" => lowered.Contains("public transportation", StringComparison.OrdinalIgnoreCase) ||
lowered.Contains("transit", StringComparison.OrdinalIgnoreCase) || lowered.Contains("transit", StringComparison.OrdinalIgnoreCase) ||
lowered.Contains("transportation", StringComparison.OrdinalIgnoreCase), lowered.Contains("transportation", StringComparison.OrdinalIgnoreCase),
"bicycling" => lowered.Contains("bike", StringComparison.OrdinalIgnoreCase) || "bicycling" => lowered.Contains("bike", StringComparison.OrdinalIgnoreCase) ||
lowered.Contains("ride", StringComparison.OrdinalIgnoreCase), lowered.Contains("ride", StringComparison.OrdinalIgnoreCase),
_ => lowered.Contains("drive", StringComparison.OrdinalIgnoreCase) || _ => lowered.Contains("drive", StringComparison.OrdinalIgnoreCase) ||
lowered.Contains("commute", StringComparison.OrdinalIgnoreCase) lowered.Contains("commute", StringComparison.OrdinalIgnoreCase)
}; };
@@ -4617,13 +4617,13 @@ public sealed class JiboInteractionService(
{ {
var normalized = NormalizeCommandPhrase(loweredTranscript); var normalized = NormalizeCommandPhrase(loweredTranscript);
return normalized.StartsWith("what is my favorite", StringComparison.Ordinal) || return normalized.StartsWith("what is my favorite", StringComparison.Ordinal) ||
normalized.StartsWith("what s my favorite", StringComparison.Ordinal) || normalized.StartsWith("what s my favorite", StringComparison.Ordinal) ||
normalized.StartsWith("what's my favorite", StringComparison.Ordinal) || normalized.StartsWith("what's my favorite", StringComparison.Ordinal) ||
normalized.StartsWith("what is my favourite", StringComparison.Ordinal) || normalized.StartsWith("what is my favourite", StringComparison.Ordinal) ||
normalized.StartsWith("what s my favourite", StringComparison.Ordinal) || normalized.StartsWith("what s my favourite", StringComparison.Ordinal) ||
normalized.StartsWith("what's my favourite", StringComparison.Ordinal) || normalized.StartsWith("what's my favourite", StringComparison.Ordinal) ||
normalized.StartsWith("do you remember my favorite", StringComparison.Ordinal) || normalized.StartsWith("do you remember my favorite", StringComparison.Ordinal) ||
normalized.StartsWith("do you remember my favourite", StringComparison.Ordinal); normalized.StartsWith("do you remember my favourite", StringComparison.Ordinal);
} }
private static string? TryExtractPreferenceLookupCategory(string transcript) private static string? TryExtractPreferenceLookupCategory(string transcript)

View File

@@ -676,7 +676,8 @@ internal static class PersonalReportOrchestrator
var selected = ChooseShortestTemplate(briefings); var selected = ChooseShortestTemplate(briefings);
if (string.IsNullOrWhiteSpace(selected)) return string.Empty; if (string.IsNullOrWhiteSpace(selected)) return string.Empty;
var firstSentence = selected.Split(['.', '!', '?'], 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) var firstSentence = selected.Split(['.', '!', '?'], 2,
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.FirstOrDefault(); .FirstOrDefault();
return string.IsNullOrWhiteSpace(firstSentence) ? selected : firstSentence; return string.IsNullOrWhiteSpace(firstSentence) ? selected : firstSentence;
} }

View File

@@ -1,3 +1,4 @@
using System.Text.RegularExpressions;
using Jibo.Runtime.Abstractions; using Jibo.Runtime.Abstractions;
namespace Jibo.Cloud.Application.Services; namespace Jibo.Cloud.Application.Services;
@@ -57,10 +58,10 @@ public sealed class SyntheticBufferedAudioSttStrategy : ISttStrategy
if (string.IsNullOrWhiteSpace(value)) return string.Empty; if (string.IsNullOrWhiteSpace(value)) return string.Empty;
var lowered = value.Trim().ToLowerInvariant(); var lowered = value.Trim().ToLowerInvariant();
lowered = System.Text.RegularExpressions.Regex.Replace(lowered, @"[^\p{L}\p{N}\s']+", " ", lowered = Regex.Replace(lowered, @"[^\p{L}\p{N}\s']+", " ",
System.Text.RegularExpressions.RegexOptions.CultureInvariant | System.Text.RegularExpressions.RegexOptions.Compiled); RegexOptions.CultureInvariant | RegexOptions.Compiled);
lowered = System.Text.RegularExpressions.Regex.Replace(lowered, @"\s+"," ", lowered = Regex.Replace(lowered, @"\s+", " ",
System.Text.RegularExpressions.RegexOptions.CultureInvariant | System.Text.RegularExpressions.RegexOptions.Compiled); RegexOptions.CultureInvariant | RegexOptions.Compiled);
return lowered.Trim(); return lowered.Trim();
} }
} }

View File

@@ -2,7 +2,7 @@ using System.Text.RegularExpressions;
namespace Jibo.Cloud.Application.Services; namespace Jibo.Cloud.Application.Services;
internal static partial class TranscriptTextNormalizer internal static class TranscriptTextNormalizer
{ {
private static readonly Regex PunctuationToSpaceRegex = new( private static readonly Regex PunctuationToSpaceRegex = new(
@"[^\p{L}\p{N}\s']+", @"[^\p{L}\p{N}\s']+",

View File

@@ -1,12 +1,11 @@
using System.Text.Json; using System.Text.Json;
using System.Text.RegularExpressions;
using Jibo.Cloud.Application.Abstractions; using Jibo.Cloud.Application.Abstractions;
using Jibo.Cloud.Domain.Models; using Jibo.Cloud.Domain.Models;
using Jibo.Runtime.Abstractions; using Jibo.Runtime.Abstractions;
namespace Jibo.Cloud.Application.Services; namespace Jibo.Cloud.Application.Services;
public sealed partial class WebSocketTurnFinalizationService( public sealed class WebSocketTurnFinalizationService(
IConversationBroker conversationBroker, IConversationBroker conversationBroker,
ISttStrategySelector sttStrategySelector, ISttStrategySelector sttStrategySelector,
ITurnTelemetrySink sink ITurnTelemetrySink sink

View File

@@ -371,18 +371,17 @@ public static class LegacyMimCatalogImporter
{ {
private readonly List<string> _calendarNothingReplies = []; private readonly List<string> _calendarNothingReplies = [];
private readonly List<string> _calendarNothingTodayReplies = []; private readonly List<string> _calendarNothingTodayReplies = [];
private readonly List<string> _calendarServiceDownReplies = [];
private readonly List<string> _calendarOutroReplies = []; private readonly List<string> _calendarOutroReplies = [];
private readonly List<string> _calendarServiceDownReplies = [];
private readonly List<string> _commuteNowReplies = []; private readonly List<string> _commuteNowReplies = [];
private readonly List<string> _commuteServiceDownReplies = []; private readonly List<string> _commuteServiceDownReplies = [];
private readonly List<JiboConditionedReply> _emotionReplies = []; private readonly List<JiboConditionedReply> _emotionReplies = [];
private readonly List<string> _fallbacks = []; private readonly List<string> _fallbacks = [];
private readonly List<string> _greetings = [];
private readonly List<string> _jokes = [];
private readonly List<string> _robotFacts = [];
private readonly List<string> _humanFacts = [];
private readonly List<string> _howAreYous = [];
private readonly List<string> _funFacts = []; private readonly List<string> _funFacts = [];
private readonly List<string> _greetings = [];
private readonly List<string> _howAreYous = [];
private readonly List<string> _humanFacts = [];
private readonly List<string> _jokes = [];
private readonly List<string> _newsCategoryIntroReplies = []; private readonly List<string> _newsCategoryIntroReplies = [];
private readonly List<string> _newsIntroReplies = []; private readonly List<string> _newsIntroReplies = [];
private readonly List<string> _newsOutroReplies = []; private readonly List<string> _newsOutroReplies = [];
@@ -390,6 +389,7 @@ public static class LegacyMimCatalogImporter
private readonly List<string> _personalReportKickOffReplies = []; private readonly List<string> _personalReportKickOffReplies = [];
private readonly List<string> _personalReportOutroReplies = []; private readonly List<string> _personalReportOutroReplies = [];
private readonly List<string> _reportSkillTemplates = []; private readonly List<string> _reportSkillTemplates = [];
private readonly List<string> _robotFacts = [];
private readonly List<string> _weatherIntroReplies = []; private readonly List<string> _weatherIntroReplies = [];
private readonly List<string> _weatherServiceDownReplies = []; private readonly List<string> _weatherServiceDownReplies = [];
private readonly List<string> _weatherTodayHighLowReplies = []; private readonly List<string> _weatherTodayHighLowReplies = [];
@@ -564,7 +564,8 @@ public static class LegacyMimCatalogImporter
private LegacyMimBucket ResolveFunFactTarget(string prompt) private LegacyMimBucket ResolveFunFactTarget(string prompt)
{ {
var lowered = NormalizePrompt(prompt, false).ToLowerInvariant(); var lowered = NormalizePrompt(prompt, false).ToLowerInvariant();
if (ContainsAny(lowered, "robot", "humanoid", "machine", "about me", "my cameras", "turing", "deep blue", "rossum")) if (ContainsAny(lowered, "robot", "humanoid", "machine", "about me", "my cameras", "turing", "deep blue",
"rossum"))
return LegacyMimBucket.RobotFacts; return LegacyMimBucket.RobotFacts;
if (ContainsAny(lowered, "human", "people", "grown ups", "human being", "humans")) if (ContainsAny(lowered, "human", "people", "grown ups", "human being", "humans"))

View File

@@ -67,7 +67,8 @@ public static class ServiceCollectionExtensions
configuration.GetSection("OpenJibo:Media").Bind(mediaOptions); configuration.GetSection("OpenJibo:Media").Bind(mediaOptions);
if (string.IsNullOrWhiteSpace(mediaOptions.ConnectionString)) if (string.IsNullOrWhiteSpace(mediaOptions.ConnectionString))
mediaOptions.ConnectionString = Environment.GetEnvironmentVariable("OPENJIBO_MEDIA_STORAGE_CONNECTION_STRING"); mediaOptions.ConnectionString =
Environment.GetEnvironmentVariable("OPENJIBO_MEDIA_STORAGE_CONNECTION_STRING");
services.AddSingleton<IPersistenceSnapshotStoreFactory, PersistenceSnapshotStoreFactory>(); services.AddSingleton<IPersistenceSnapshotStoreFactory, PersistenceSnapshotStoreFactory>();
services.AddSingleton<IMediaContentStoreFactory, MediaContentStoreFactory>(); services.AddSingleton<IMediaContentStoreFactory, MediaContentStoreFactory>();

View File

@@ -30,14 +30,14 @@ internal sealed class AzureBlobMediaContentStore : IMediaContentStore
var contentBlob = _containerClient.GetBlobClient($"{relative}.bin"); var contentBlob = _containerClient.GetBlobClient($"{relative}.bin");
var metaBlob = _containerClient.GetBlobClient($"{relative}.json"); var metaBlob = _containerClient.GetBlobClient($"{relative}.json");
await _containerClient.CreateIfNotExistsAsync(cancellationToken: cancellationToken); await _containerClient.CreateIfNotExistsAsync(cancellationToken: cancellationToken);
await contentBlob.UploadAsync(new MemoryStream(content), overwrite: true, cancellationToken); await contentBlob.UploadAsync(new MemoryStream(content), true, cancellationToken);
var payload = JsonSerializer.Serialize(new var payload = JsonSerializer.Serialize(new
{ {
path, path,
contentType, contentType,
meta meta
}, JsonOptions); }, JsonOptions);
await metaBlob.UploadAsync(BinaryData.FromString(payload), overwrite: true, cancellationToken); await metaBlob.UploadAsync(BinaryData.FromString(payload), true, cancellationToken);
} }
public async Task<MediaContentSnapshot?> LoadAsync(string path, CancellationToken cancellationToken = default) public async Task<MediaContentSnapshot?> LoadAsync(string path, CancellationToken cancellationToken = default)
@@ -52,7 +52,6 @@ internal sealed class AzureBlobMediaContentStore : IMediaContentStore
var metaBlob = _containerClient.GetBlobClient($"{relative}.json"); var metaBlob = _containerClient.GetBlobClient($"{relative}.json");
if (await metaBlob.ExistsAsync(cancellationToken)) if (await metaBlob.ExistsAsync(cancellationToken))
{
try try
{ {
var json = (await metaBlob.DownloadContentAsync(cancellationToken)).Value.Content.ToString(); var json = (await metaBlob.DownloadContentAsync(cancellationToken)).Value.Content.ToString();
@@ -70,7 +69,6 @@ internal sealed class AzureBlobMediaContentStore : IMediaContentStore
{ {
// Keep the raw binary available even if metadata parsing fails. // Keep the raw binary available even if metadata parsing fails.
} }
}
return new MediaContentSnapshot return new MediaContentSnapshot
{ {

View File

@@ -53,7 +53,6 @@ internal sealed class FileMediaContentStore : IMediaContentStore
IDictionary<string, object?> meta = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase); IDictionary<string, object?> meta = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
if (File.Exists(metaPath)) if (File.Exists(metaPath))
{
try try
{ {
using var document = JsonDocument.Parse(await File.ReadAllTextAsync(metaPath, cancellationToken)); using var document = JsonDocument.Parse(await File.ReadAllTextAsync(metaPath, cancellationToken));
@@ -72,7 +71,6 @@ internal sealed class FileMediaContentStore : IMediaContentStore
{ {
// Keep binary content available even if the manifest is malformed. // Keep binary content available even if the manifest is malformed.
} }
}
return new MediaContentSnapshot return new MediaContentSnapshot
{ {

View File

@@ -5,7 +5,8 @@ internal static class MediaPathHelper
public static string GetRelativeStoragePath(string path) public static string GetRelativeStoragePath(string path)
{ {
var trimmed = path.Trim().TrimStart('/', '\\'); var trimmed = path.Trim().TrimStart('/', '\\');
var segments = trimmed.Split(['/', '\\'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) var segments = trimmed
.Split(['/', '\\'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Select(SanitizeSegment) .Select(SanitizeSegment)
.Where(segment => !string.IsNullOrWhiteSpace(segment)) .Where(segment => !string.IsNullOrWhiteSpace(segment))
.ToArray(); .ToArray();

View File

@@ -10,7 +10,8 @@ internal static class CaptureIndexWriter
WriteIndented = false WriteIndented = false
}; };
private static readonly ConcurrentDictionary<string, SemaphoreSlim> DirectoryLocks = new(StringComparer.OrdinalIgnoreCase); private static readonly ConcurrentDictionary<string, SemaphoreSlim> DirectoryLocks =
new(StringComparer.OrdinalIgnoreCase);
public static async Task AppendAsync( public static async Task AppendAsync(
string directoryPath, string directoryPath,

View File

@@ -218,7 +218,8 @@ public sealed class OpenWeatherReportProvider(
var summary = TryReadWeatherSummary(root); var summary = TryReadWeatherSummary(root);
var condition = TryReadWeatherCondition(root); var condition = TryReadWeatherCondition(root);
var temperature = TryReadInt(main, "temp"); var temperature = TryReadInt(main, "temp");
var currentDayHighLow = await TryResolveCurrentDayHighLowFromForecastAsync(location, useCelsius, cancellationToken); var currentDayHighLow =
await TryResolveCurrentDayHighLowFromForecastAsync(location, useCelsius, cancellationToken);
var high = currentDayHighLow?.High ?? TryReadInt(main, "temp_max"); var high = currentDayHighLow?.High ?? TryReadInt(main, "temp_max");
var low = currentDayHighLow?.Low ?? TryReadInt(main, "temp_min"); var low = currentDayHighLow?.Low ?? TryReadInt(main, "temp_min");

View File

@@ -92,7 +92,8 @@ public sealed class LegacyMimCatalogImporterTests
Assert.Contains("I like all the colors of the rainbow. But blue is my favorite.", Assert.Contains("I like all the colors of the rainbow. But blue is my favorite.",
catalog.PersonalityReplies); catalog.PersonalityReplies);
Assert.Contains("I never eat, so I don't have a favorite food by taste. But my favorite food by shape, is macaroni.", Assert.Contains(
"I never eat, so I don't have a favorite food by taste. But my favorite food by shape, is macaroni.",
catalog.PersonalityReplies); catalog.PersonalityReplies);
Assert.Contains("I mostly like fun music I can dance to.", catalog.PersonalityReplies); Assert.Contains("I mostly like fun music I can dance to.", catalog.PersonalityReplies);
Assert.Contains("The only thing I consume is electricity.", catalog.PersonalityReplies); Assert.Contains("The only thing I consume is electricity.", catalog.PersonalityReplies);
@@ -199,7 +200,8 @@ public sealed class LegacyMimCatalogImporterTests
var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory); var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory);
Assert.Contains("I love jokes. Did you hear about the theater actor who fell through the floorboards? He was just going through a stage.", Assert.Contains(
"I love jokes. Did you hear about the theater actor who fell through the floorboards? He was just going through a stage.",
catalog.Jokes); catalog.Jokes);
Assert.Contains("Sure I got one. What did the zero say to the eight. Nice belt.", catalog.Jokes); Assert.Contains("Sure I got one. What did the zero say to the eight. Nice belt.", catalog.Jokes);
Assert.Contains(catalog.RobotFacts, reply => Assert.Contains(catalog.RobotFacts, reply =>
@@ -211,7 +213,8 @@ public sealed class LegacyMimCatalogImporterTests
Assert.Contains(catalog.RobotFacts, reply => Assert.Contains(catalog.RobotFacts, reply =>
reply.Contains("two cameras but they're different focal lengths", StringComparison.OrdinalIgnoreCase)); reply.Contains("two cameras but they're different focal lengths", StringComparison.OrdinalIgnoreCase));
Assert.Contains("A random fact for you. A shrimp's heart is in its head.", catalog.FunFacts); Assert.Contains("A random fact for you. A shrimp's heart is in its head.", catalog.FunFacts);
Assert.Contains("An amazing but true fact for you. Dogs and elephants are the only animals that understand pointing.", Assert.Contains(
"An amazing but true fact for you. Dogs and elephants are the only animals that understand pointing.",
catalog.FunFacts); catalog.FunFacts);
} }

View File

@@ -426,7 +426,8 @@ public sealed class ProviderCachingTests
entries.Select(entry => entries.Select(entry =>
$$"""{"dt":{{entry.Timestamp.ToUnixTimeSeconds()}},"main":{"temp":{{entry.Temp}},"temp_min":{{entry.Low}},"temp_max":{{entry.High}}},"weather":[{"main":"{{entry.Main}}","description":"{{entry.Description}}"}]}""")); $$"""{"dt":{{entry.Timestamp.ToUnixTimeSeconds()}},"main":{"temp":{{entry.Temp}},"temp_min":{{entry.Low}},"temp_max":{{entry.High}}},"weather":[{"main":"{{entry.Main}}","description":"{{entry.Description}}"}]}"""));
return $$"""{"city":{"name":"{{cityName}}","country":"{{country}}","timezone":{{timezoneSeconds}}},"list":[{{list}}]}"""; return
$$"""{"city":{"name":"{{cityName}}","country":"{{country}}","timezone":{{timezoneSeconds}}},"list":[{{list}}]}""";
} }
private sealed class CountingHttpMessageHandler(Func<HttpRequestMessage, HttpResponseMessage> responseFactory) private sealed class CountingHttpMessageHandler(Func<HttpRequestMessage, HttpResponseMessage> responseFactory)

View File

@@ -60,7 +60,8 @@ public sealed class FileProtocolTelemetrySinkTests : IDisposable
Assert.Contains("Notification_20150505", contents); Assert.Contains("Notification_20150505", contents);
Assert.DoesNotContain(Path.Combine("bin", "Debug"), captureFile, StringComparison.OrdinalIgnoreCase); Assert.DoesNotContain(Path.Combine("bin", "Debug"), captureFile, StringComparison.OrdinalIgnoreCase);
Assert.Contains(indexLines, line => line.Contains("\"eventType\":\"protocol_record\"", StringComparison.Ordinal)); Assert.Contains(indexLines,
line => line.Contains("\"eventType\":\"protocol_record\"", StringComparison.Ordinal));
Assert.Contains(indexLines, line => line.Contains("\"servicePrefix\":\"Notification_20150505\"", Assert.Contains(indexLines, line => line.Contains("\"servicePrefix\":\"Notification_20150505\"",
StringComparison.Ordinal)); StringComparison.Ordinal));
} }

View File

@@ -163,7 +163,8 @@ public sealed class JiboCloudProtocolServiceTests
Method = "POST", Method = "POST",
ServicePrefix = "Update_20160715", ServicePrefix = "Update_20160715",
Operation = "CreateUpdate", Operation = "CreateUpdate",
BodyText = """{"fromVersion":"1.0.0","toVersion":"1.0.1","changes":"Restore proof","subsystem":"robot"}""" BodyText =
"""{"fromVersion":"1.0.0","toVersion":"1.0.1","changes":"Restore proof","subsystem":"robot"}"""
}); });
await firstService.DispatchAsync(new ProtocolEnvelope await firstService.DispatchAsync(new ProtocolEnvelope
@@ -209,16 +210,15 @@ public sealed class JiboCloudProtocolServiceTests
Assert.NotNull(secondInfo.LastLoadedUtc); Assert.NotNull(secondInfo.LastLoadedUtc);
Assert.NotNull(secondInfo.LastSavedUtc); Assert.NotNull(secondInfo.LastSavedUtc);
Assert.NotEmpty(updatesPayload.RootElement.EnumerateArray()); Assert.NotEmpty(updatesPayload.RootElement.EnumerateArray());
Assert.Contains(updatesPayload.RootElement.EnumerateArray(), item => item.GetProperty("changes").GetString() == "Restore proof"); Assert.Contains(updatesPayload.RootElement.EnumerateArray(),
item => item.GetProperty("changes").GetString() == "Restore proof");
Assert.NotEmpty(backupsPayload.RootElement.EnumerateArray()); Assert.NotEmpty(backupsPayload.RootElement.EnumerateArray());
Assert.Contains(backupsPayload.RootElement.EnumerateArray(), item => item.TryGetProperty("Name", out var name) && name.GetString() == "manual-backup"); Assert.Contains(backupsPayload.RootElement.EnumerateArray(),
item => item.TryGetProperty("Name", out var name) && name.GetString() == "manual-backup");
} }
finally finally
{ {
if (File.Exists(persistencePath)) if (File.Exists(persistencePath)) File.Delete(persistencePath);
{
File.Delete(persistencePath);
}
} }
} }

View File

@@ -62,9 +62,11 @@ public sealed class FileTurnTelemetrySinkTests
var indexPath = Path.Combine(directoryPath, "capture-index.ndjson"); var indexPath = Path.Combine(directoryPath, "capture-index.ndjson");
var lines = await File.ReadAllLinesAsync(indexPath); var lines = await File.ReadAllLinesAsync(indexPath);
Assert.Contains(lines, line => line.Contains("\"eventType\":\"yes_no_turn_received\"", StringComparison.Ordinal)); Assert.Contains(lines,
line => line.Contains("\"eventType\":\"yes_no_turn_received\"", StringComparison.Ordinal));
Assert.Contains(lines, line => line.Contains("\"eventType\":\"transcript_error\"", StringComparison.Ordinal)); Assert.Contains(lines, line => line.Contains("\"eventType\":\"transcript_error\"", StringComparison.Ordinal));
Assert.Contains(lines, line => line.Contains("\"message\":\"Turn telemetry diagnostic\"", StringComparison.Ordinal)); Assert.Contains(lines,
line => line.Contains("\"message\":\"Turn telemetry diagnostic\"", StringComparison.Ordinal));
Assert.Contains(lines, line => line.Contains("\"message\":\"Turn telemetry error\"", StringComparison.Ordinal)); Assert.Contains(lines, line => line.Contains("\"message\":\"Turn telemetry error\"", StringComparison.Ordinal));
} }

View File

@@ -1,5 +1,5 @@
using System.Text.Json;
using System.Text; using System.Text;
using System.Text.Json;
using Jibo.Cloud.Application.Abstractions; using Jibo.Cloud.Application.Abstractions;
using Jibo.Cloud.Application.Services; using Jibo.Cloud.Application.Services;
using Jibo.Cloud.Infrastructure.Content; using Jibo.Cloud.Infrastructure.Content;
@@ -3108,7 +3108,8 @@ public sealed class JiboInteractionServiceTests
}); });
Assert.Equal("robot_can_sleep", decision.IntentName); Assert.Equal("robot_can_sleep", decision.IntentName);
Assert.Contains("I do. I usually fall asleep at night.", decision.ReplyText, StringComparison.OrdinalIgnoreCase); Assert.Contains("I do. I usually fall asleep at night.", decision.ReplyText,
StringComparison.OrdinalIgnoreCase);
Assert.Equal("ScriptedResponse", decision.ContextUpdates![ChitchatRouteKey]); Assert.Equal("ScriptedResponse", decision.ContextUpdates![ChitchatRouteKey]);
} }

View File

@@ -1,5 +1,5 @@
using System.Text.Json;
using System.Text; using System.Text;
using System.Text.Json;
using Jibo.Cloud.Application.Abstractions; using Jibo.Cloud.Application.Abstractions;
using Jibo.Cloud.Application.Services; using Jibo.Cloud.Application.Services;
using Jibo.Cloud.Domain.Models; using Jibo.Cloud.Domain.Models;
@@ -21,7 +21,7 @@ public sealed class JiboWebSocketServiceTests
var contentRepository = new InMemoryJiboExperienceContentRepository(); var contentRepository = new InMemoryJiboExperienceContentRepository();
var contentCache = new JiboExperienceContentCache(contentRepository); var contentCache = new JiboExperienceContentCache(contentRepository);
var conversationBroker = new DemoConversationBroker(new JiboInteractionService(contentCache, var conversationBroker = new DemoConversationBroker(new JiboInteractionService(contentCache,
new LastItemRandomizer(), new InMemoryPersonalMemoryStore(), null, null, null)); new LastItemRandomizer(), new InMemoryPersonalMemoryStore()));
var sttSelector = new DefaultSttStrategySelector( var sttSelector = new DefaultSttStrategySelector(
[ [
new SyntheticBufferedAudioSttStrategy() new SyntheticBufferedAudioSttStrategy()
@@ -2727,7 +2727,8 @@ public sealed class JiboWebSocketServiceTests
Path = "/listen", Path = "/listen",
Kind = "neo-hub-listen", Kind = "neo-hub-listen",
Token = "hub-radio-noise-token", Token = "hub-radio-noise-token",
Text = """{"type":"CLIENT_ASR","transID":"trans-radio-noise","data":{"text":"Hey Jibo - so open the radio"}}""" Text =
"""{"type":"CLIENT_ASR","transID":"trans-radio-noise","data":{"text":"Hey Jibo - so open the radio"}}"""
}); });
Assert.Equal(4, replies.Count); Assert.Equal(4, replies.Count);
@@ -4749,7 +4750,8 @@ public sealed class JiboWebSocketServiceTests
Path = "/listen", Path = "/listen",
Kind = "neo-hub-listen", Kind = "neo-hub-listen",
Token = token, Token = token,
Text = """{"type":"LISTEN","transID":"trans-smoke-greeting","data":{"text":"hello jibo","rules":["wake-word"]}}""" Text =
"""{"type":"LISTEN","transID":"trans-smoke-greeting","data":{"text":"hello jibo","rules":["wake-word"]}}"""
}); });
Assert.Equal(3, greetingReplies.Count); Assert.Equal(3, greetingReplies.Count);
@@ -4794,7 +4796,8 @@ public sealed class JiboWebSocketServiceTests
Path = "/listen", Path = "/listen",
Kind = "neo-hub-listen", Kind = "neo-hub-listen",
Token = token, Token = token,
Text = """{"type":"CLIENT_ASR","transID":"trans-smoke-color","data":{"text":"what is your favorite color"}}""" Text =
"""{"type":"CLIENT_ASR","transID":"trans-smoke-color","data":{"text":"what is your favorite color"}}"""
}); });
Assert.Equal(3, personalityReplies.Count); Assert.Equal(3, personalityReplies.Count);

View File

@@ -190,7 +190,8 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
return page; return page;
} }
private sealed class FakeExternalProcessRunner(string whisperStdOut = "[00:00:00.000 --> 00:00:01.000] tell me a joke") private sealed class FakeExternalProcessRunner(
string whisperStdOut = "[00:00:00.000 --> 00:00:01.000] tell me a joke")
: IExternalProcessRunner : IExternalProcessRunner
{ {
public List<(string FileName, IReadOnlyList<string> Arguments)> Calls { get; } = []; public List<(string FileName, IReadOnlyList<string> Arguments)> Calls { get; } = [];