Polish weather news and STT filtering
This commit is contained in:
@@ -284,6 +284,46 @@ public sealed class ProviderCachingTests
|
||||
Assert.Equal(2, handler.GetCallCount("/v2/top-headlines"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NewsApiBriefingProvider_SkipsCorrectionAndSummarylessHeadlines_BeforeFallback()
|
||||
{
|
||||
var handler = new CountingHttpMessageHandler(message =>
|
||||
{
|
||||
var path = message.RequestUri?.AbsolutePath ?? string.Empty;
|
||||
if (!string.Equals(path, "/v2/top-headlines", StringComparison.OrdinalIgnoreCase))
|
||||
return new HttpResponseMessage(HttpStatusCode.NotFound);
|
||||
|
||||
var query = message.RequestUri?.Query ?? string.Empty;
|
||||
return JsonResponse(query.Contains("category=sports", StringComparison.OrdinalIgnoreCase)
|
||||
? """
|
||||
{"status":"ok","articles":[
|
||||
{"title":"Correction: robots everywhere","description":"","source":{"name":"AP News"},"url":"https://example.com/correction"}
|
||||
]}
|
||||
"""
|
||||
: """
|
||||
{"status":"ok","articles":[
|
||||
{"title":"General robotics update","description":"Top story","source":{"name":"AP News"},"url":"https://example.com/general"}
|
||||
]}
|
||||
""");
|
||||
});
|
||||
var provider = new NewsApiBriefingProvider(
|
||||
new HttpClient(handler),
|
||||
new NewsApiOptions
|
||||
{
|
||||
ApiKey = "test-key",
|
||||
CacheTtlSeconds = 300,
|
||||
FailureCacheTtlSeconds = 30
|
||||
},
|
||||
NullLogger<NewsApiBriefingProvider>.Instance);
|
||||
|
||||
var result = await provider.GetBriefingAsync(new NewsBriefingRequest(["sports"]));
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Single(result!.Headlines);
|
||||
Assert.Equal("General robotics update", result.Headlines[0].Title);
|
||||
Assert.Equal(2, handler.GetCallCount("/v2/top-headlines"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NewsApiBriefingProvider_FallsBackToEverything_WhenTopHeadlinesAreEmpty()
|
||||
{
|
||||
@@ -457,4 +497,4 @@ public sealed class ProviderCachingTests
|
||||
return Task.FromResult(responseFactory(request));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2770,6 +2770,8 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Contains("Temperatures are in Fahrenheit.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.NotNull(decision.SkillPayload);
|
||||
Assert.True(decision.SkillPayload!.TryGetValue("weather_weekly_cards", out var weeklyCardsValue));
|
||||
Assert.Equal("weatherWeekly", decision.SkillPayload["weather_view_kind"]);
|
||||
Assert.Equal("forecast", decision.SkillPayload["weather_view_mode"]);
|
||||
var weeklyCards = Assert.IsAssignableFrom<IReadOnlyList<IDictionary<string, object?>>>(weeklyCardsValue);
|
||||
Assert.Equal(5, weeklyCards.Count);
|
||||
var firstCard = weeklyCards[0];
|
||||
|
||||
@@ -77,6 +77,31 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
|
||||
Assert.False(strategy.CanHandle(turn));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanHandle_ReturnsFalse_WhenBufferedAudioIsBelowNoiseFloor()
|
||||
{
|
||||
var strategy = new LocalWhisperCppBufferedAudioSttStrategy(
|
||||
new BufferedAudioSttOptions
|
||||
{
|
||||
EnableLocalWhisperCpp = true,
|
||||
FfmpegPath = "ffmpeg",
|
||||
WhisperCliPath = "whisper-cli",
|
||||
WhisperModelPath = "model.bin"
|
||||
},
|
||||
new FakeExternalProcessRunner());
|
||||
|
||||
var turn = new TurnContext
|
||||
{
|
||||
Attributes = new Dictionary<string, object?>
|
||||
{
|
||||
["bufferedAudioBytes"] = 47,
|
||||
["bufferedAudioFrames"] = new[] { BuildMinimalOggPage() }
|
||||
}
|
||||
};
|
||||
|
||||
Assert.False(strategy.CanHandle(turn));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TranscribeAsync_UsesFfmpegAndWhisperCpp_WhenConfigured()
|
||||
{
|
||||
@@ -103,7 +128,7 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
|
||||
Locale = "en-US",
|
||||
Attributes = new Dictionary<string, object?>
|
||||
{
|
||||
["bufferedAudioBytes"] = 47,
|
||||
["bufferedAudioBytes"] = 147,
|
||||
["bufferedAudioFrames"] = new[] { BuildMinimalOggPage() }
|
||||
}
|
||||
};
|
||||
@@ -115,7 +140,7 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
|
||||
Assert.Equal(2, runner.Calls.Count);
|
||||
Assert.Equal("ffmpeg", runner.Calls[0].FileName);
|
||||
Assert.Equal("whisper-cli", runner.Calls[1].FileName);
|
||||
Assert.Equal(47, result.Metadata["bufferedAudioBytes"]);
|
||||
Assert.Equal(147, result.Metadata["bufferedAudioBytes"]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -149,7 +174,7 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
|
||||
Locale = "en-US",
|
||||
Attributes = new Dictionary<string, object?>
|
||||
{
|
||||
["bufferedAudioBytes"] = 47,
|
||||
["bufferedAudioBytes"] = 147,
|
||||
["bufferedAudioFrames"] = new[] { BuildMinimalOggPage() }
|
||||
}
|
||||
};
|
||||
@@ -165,6 +190,47 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TranscribeAsync_Throws_WhenBufferedAudioIsBelowNoiseFloor()
|
||||
{
|
||||
var tempDirectory = Path.Combine(Path.GetTempPath(), $"openjibo-stt-test-{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(tempDirectory);
|
||||
|
||||
try
|
||||
{
|
||||
var runner = new FakeExternalProcessRunner();
|
||||
var strategy = new LocalWhisperCppBufferedAudioSttStrategy(
|
||||
new BufferedAudioSttOptions
|
||||
{
|
||||
EnableLocalWhisperCpp = true,
|
||||
FfmpegPath = "ffmpeg",
|
||||
WhisperCliPath = "whisper-cli",
|
||||
WhisperModelPath = "model.bin",
|
||||
TempDirectory = tempDirectory
|
||||
},
|
||||
runner);
|
||||
|
||||
var turn = new TurnContext
|
||||
{
|
||||
TurnId = "turn-local-stt-noise-floor",
|
||||
Locale = "en-US",
|
||||
Attributes = new Dictionary<string, object?>
|
||||
{
|
||||
["bufferedAudioBytes"] = 47,
|
||||
["bufferedAudioFrames"] = new[] { BuildMinimalOggPage() }
|
||||
}
|
||||
};
|
||||
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => strategy.TranscribeAsync(turn));
|
||||
Assert.Contains("too short or noisy", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Empty(runner.Calls);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(tempDirectory)) Directory.Delete(tempDirectory, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] BuildMinimalOggPage()
|
||||
{
|
||||
return
|
||||
@@ -209,4 +275,4 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
|
||||
return Task.FromResult(new ExternalProcessResult(0, string.Empty, string.Empty));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user