refactor
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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']+",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"))
|
||||||
|
|||||||
@@ -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>();
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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; } = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user