Files
meeting-assistant/MeetingAssistant/Speakers/SpeakerSampleSpan.cs
T
codex f86af983e8
PR and Push Build/Test / build-and-test (push) Successful in 12m37s
feat: add local Resemblyzer speaker recognition
2026-09-11 13:49:27 +02:00

83 lines
2.4 KiB
C#

using MeetingAssistant.Transcription;
namespace MeetingAssistant.Speakers;
internal sealed record SpeakerSampleSpan(
string Speaker,
TimeSpan Start,
TimeSpan End,
TimeSpan SpeechDuration,
TimeSpan MaximumDuration,
IReadOnlyList<TranscriptionSegment> Segments)
{
public static SpeakerSampleSpan? Create(
TranscriptionSegment segment,
TimeSpan maximumDuration)
{
if (maximumDuration <= TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(
nameof(maximumDuration),
maximumDuration,
"Speaker sample maximum duration must be greater than zero.");
}
var boundedEnd = Min(segment.End, segment.Start + maximumDuration);
return boundedEnd > segment.Start
? new SpeakerSampleSpan(
segment.Speaker,
segment.Start,
boundedEnd,
boundedEnd - segment.Start,
maximumDuration,
[segment with { End = boundedEnd }])
: null;
}
public bool TryExtend(
TranscriptionSegment segment,
out SpeakerSampleSpan extended)
{
extended = this;
if (!string.Equals(Speaker, segment.Speaker, StringComparison.OrdinalIgnoreCase) ||
segment.Start >= Start + MaximumDuration)
{
return false;
}
var boundedEnd = Min(segment.End, Start + MaximumDuration);
if (boundedEnd <= segment.Start)
{
return false;
}
var uncoveredStart = segment.Start > End ? segment.Start : End;
var additionalSpeechDuration = boundedEnd > uncoveredStart
? boundedEnd - uncoveredStart
: TimeSpan.Zero;
extended = this with
{
End = boundedEnd > End ? boundedEnd : End,
SpeechDuration = SpeechDuration + additionalSpeechDuration,
Segments = Segments.Append(segment with { End = boundedEnd }).ToList()
};
return true;
}
public TranscriptionSegment ToSegment()
{
return new TranscriptionSegment(
Start,
End,
Speaker,
string.Join(' ', Segments
.Select(segment => segment.Text)
.Where(text => !string.IsNullOrWhiteSpace(text))));
}
private static TimeSpan Min(TimeSpan left, TimeSpan right)
{
return left < right ? left : right;
}
}