forked from Manuel/meeting-assistant
109 lines
3.2 KiB
C#
109 lines
3.2 KiB
C#
using MeetingAssistant.Transcription;
|
|
|
|
namespace MeetingAssistant.Speakers;
|
|
|
|
internal static class SpeakerSampleSpanSelector
|
|
{
|
|
public static IReadOnlyList<TranscriptionSegment> SelectBestSameSpeakerSpan(
|
|
IReadOnlyList<TranscriptionSegment> segments,
|
|
string speaker,
|
|
TimeSpan minimumDuration,
|
|
TimeSpan maximumSampleDuration)
|
|
{
|
|
SpeakerSampleSpan? best = null;
|
|
SpeakerSampleSpan? current = null;
|
|
foreach (var segment in segments.OrderBy(segment => segment.Start))
|
|
{
|
|
if (!IsSpeaker(segment, speaker))
|
|
{
|
|
current = null;
|
|
continue;
|
|
}
|
|
|
|
current = ExtendOrStart(current, segment, maximumSampleDuration);
|
|
if (current is not null &&
|
|
(best is null || current.SpeechDuration > best.SpeechDuration))
|
|
{
|
|
best = current;
|
|
}
|
|
}
|
|
|
|
return best is not null && best.SpeechDuration >= minimumDuration
|
|
? best.Segments
|
|
: [];
|
|
}
|
|
|
|
public static IReadOnlyList<IReadOnlyList<TranscriptionSegment>> SelectBestSameSpeakerSpans(
|
|
IReadOnlyList<TranscriptionSegment> segments,
|
|
string speaker,
|
|
TimeSpan minimumDuration,
|
|
TimeSpan maximumSampleDuration,
|
|
int maxSpans)
|
|
{
|
|
if (maxSpans <= 0)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
var completed = new List<SpeakerSampleSpan>();
|
|
SpeakerSampleSpan? current = null;
|
|
TimeSpan? lastCompletedEnd = null;
|
|
foreach (var segment in segments.OrderBy(segment => segment.Start))
|
|
{
|
|
if (!IsSpeaker(segment, speaker))
|
|
{
|
|
current = null;
|
|
continue;
|
|
}
|
|
|
|
if (lastCompletedEnd is { } end && segment.Start < end)
|
|
{
|
|
current = null;
|
|
continue;
|
|
}
|
|
|
|
current = ExtendOrStart(current, segment, maximumSampleDuration);
|
|
if (current is null || current.SpeechDuration < minimumDuration)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
completed.Add(current);
|
|
lastCompletedEnd = current.End;
|
|
current = null;
|
|
}
|
|
|
|
return completed
|
|
.OrderByDescending(span => span.SpeechDuration)
|
|
.ThenBy(span => span.Start)
|
|
.Take(maxSpans)
|
|
.OrderBy(span => span.Start)
|
|
.Select(span => span.Segments)
|
|
.ToList();
|
|
}
|
|
|
|
public static TimeSpan SpanDuration(IReadOnlyList<TranscriptionSegment> segments)
|
|
{
|
|
return segments.Count == 0
|
|
? TimeSpan.Zero
|
|
: segments[^1].End - segments[0].Start;
|
|
}
|
|
|
|
private static SpeakerSampleSpan? ExtendOrStart(
|
|
SpeakerSampleSpan? current,
|
|
TranscriptionSegment segment,
|
|
TimeSpan maximumSampleDuration)
|
|
{
|
|
return current is not null && current.TryExtend(segment, out var extended)
|
|
? extended
|
|
: SpeakerSampleSpan.Create(segment, maximumSampleDuration);
|
|
}
|
|
|
|
private static bool IsSpeaker(
|
|
TranscriptionSegment segment,
|
|
string speaker)
|
|
{
|
|
return string.Equals(segment.Speaker, speaker, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
}
|