Add inactivity safeguard and speaker diagnostics
PR and Push Build/Test / build-and-test (push) Failing after 8m31s

This commit is contained in:
2026-06-02 13:16:02 +02:00
parent c56ecb6ab3
commit 0e9d525b63
24 changed files with 1780 additions and 117 deletions
@@ -3,6 +3,7 @@ using MeetingAssistant.MeetingNotes;
using MeetingAssistant.Speakers;
using MeetingAssistant.Transcription;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
@@ -149,6 +150,28 @@ public sealed class SpeakerIdentityServiceTests
});
}
[Fact]
public async Task RejectedUnmatchedSpeakerSampleIsLoggedWithSpeakerAndCandidateContext()
{
await using var fixture = await SpeakerIdentityFixture.CreateAsync();
fixture.MatchValidator.SampleIsValid = false;
var logger = new CapturingLogger<SpeakerIdentityService>();
var service = fixture.CreateService(logger);
await service.ProcessFinishedTranscriptAsync(
fixture.CreateRequest(
["John", "Mike"],
[new TranscriptionSegment(TimeSpan.Zero, TimeSpan.FromSeconds(4), "Guest01", "unknown speaker")]),
CancellationToken.None);
var message = Assert.Single(
logger.Messages,
message => message.Contains("Skipping speaker identity candidate for Guest01", StringComparison.Ordinal));
Assert.Contains("Skipping speaker identity candidate for Guest01", message);
Assert.Contains("candidate names John, Mike", message);
Assert.Contains("sample bytes 3", message);
}
[Fact]
public async Task UnmatchedSpeakersExcludeAliasesOfMatchedIdentitiesFromCandidates()
{
@@ -648,14 +671,14 @@ public sealed class SpeakerIdentityServiceTests
return new SpeakerIdentityFixture(tempDirectory, dbPath, context, options);
}
public SpeakerIdentityService CreateService()
public SpeakerIdentityService CreateService(ILogger<SpeakerIdentityService>? logger = null)
{
return new SpeakerIdentityService(
new TestSpeakerIdentityDbContextFactory(dbPath),
SnippetExtractor,
Matcher,
Options.Create(new MeetingAssistantOptions { SpeakerIdentification = options }),
NullLogger<SpeakerIdentityService>.Instance,
logger ?? NullLogger<SpeakerIdentityService>.Instance,
MatchValidator);
}
@@ -836,4 +859,30 @@ public sealed class SpeakerIdentityServiceTests
return Task.FromResult(true);
}
}
private sealed class CapturingLogger<T> : ILogger<T>
{
public List<string> Messages { get; } = [];
public IDisposable? BeginScope<TState>(TState state)
where TState : notnull
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception? exception,
Func<TState, Exception?, string> formatter)
{
Messages.Add(formatter(state, exception));
}
}
}