using MeetingAssistant.Transcription; namespace MeetingAssistant.Speakers; internal sealed record SpeakerSampleSpan( string Speaker, TimeSpan Start, TimeSpan End, TimeSpan SpeechDuration, TimeSpan MaximumDuration, IReadOnlyList 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; } }