forked from Manuel/meeting-assistant
104 lines
4.3 KiB
C#
104 lines
4.3 KiB
C#
using MeetingAssistant.MeetingNotes;
|
|
|
|
namespace MeetingAssistant.Speakers;
|
|
|
|
internal static class SpeakerIdentityNaming
|
|
{
|
|
public static IReadOnlySet<string> GetAcceptedNames(SpeakerIdentity identity)
|
|
{
|
|
return new[] { identity.CanonicalName }
|
|
.Concat(identity.Aliases.Select(alias => alias.Name))
|
|
.Concat(identity.CandidateNames.Select(candidate => candidate.Name))
|
|
.Where(name => !string.IsNullOrWhiteSpace(name))
|
|
.Select(name => name!.Trim())
|
|
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
|
|
public static bool MatchesAnyAcceptedName(
|
|
SpeakerIdentity identity,
|
|
IReadOnlySet<string> names)
|
|
{
|
|
return GetAcceptedNames(identity).Any(names.Contains);
|
|
}
|
|
|
|
public static bool MatchesAttendees(
|
|
SpeakerIdentity identity,
|
|
IReadOnlyList<string> attendees)
|
|
{
|
|
var attendeeSet = attendees.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
return GetAcceptedNames(identity).Any(attendeeSet.Contains);
|
|
}
|
|
|
|
public static IReadOnlyList<string> NormalizeAttendees(IEnumerable<string> attendees)
|
|
{
|
|
return attendees
|
|
.Select(MeetingAttendeeNames.NormalizeDisplayName)
|
|
.Where(attendee => !string.IsNullOrWhiteSpace(attendee))
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
.Order(StringComparer.OrdinalIgnoreCase)
|
|
.ToList();
|
|
}
|
|
|
|
public static bool IsDiarizedSpeakerLabel(string speaker)
|
|
{
|
|
var normalized = speaker.Trim();
|
|
return normalized.Equals("Unknown", StringComparison.OrdinalIgnoreCase) ||
|
|
normalized.StartsWith("Guest", StringComparison.OrdinalIgnoreCase) ||
|
|
normalized.StartsWith("Speaker", StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
public static bool UpdateCandidateNames(
|
|
SpeakerIdentity identity,
|
|
IReadOnlyList<string> attendees)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(identity.CanonicalName) || attendees.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var currentCandidates = identity.CandidateNames
|
|
.Select(candidate => candidate.Name)
|
|
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
var fallbackAliasCandidate = currentCandidates.Count == 1 ? currentCandidates.Single() : null;
|
|
var aliasToCandidate = identity.Aliases
|
|
.Where(alias => !string.IsNullOrWhiteSpace(alias.Name))
|
|
.SelectMany(alias => currentCandidates.Select(candidate => new { Alias = alias.Name, Candidate = candidate }))
|
|
.Where(pair => string.Equals(pair.Alias, pair.Candidate, StringComparison.OrdinalIgnoreCase) ||
|
|
pair.Alias.Contains(pair.Candidate, StringComparison.OrdinalIgnoreCase) ||
|
|
pair.Candidate.Contains(pair.Alias, StringComparison.OrdinalIgnoreCase))
|
|
.ToDictionary(pair => pair.Alias, pair => pair.Candidate, StringComparer.OrdinalIgnoreCase);
|
|
var intersection = attendees
|
|
.Select(attendee => currentCandidates.Contains(attendee)
|
|
? attendee
|
|
: aliasToCandidate.GetValueOrDefault(attendee) ??
|
|
(identity.Aliases.Any(alias => string.Equals(alias.Name, attendee, StringComparison.OrdinalIgnoreCase))
|
|
? fallbackAliasCandidate
|
|
: null))
|
|
.Where(candidate => !string.IsNullOrWhiteSpace(candidate))
|
|
.Select(candidate => candidate!)
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
.Order(StringComparer.OrdinalIgnoreCase)
|
|
.ToList();
|
|
var resetToAttendees = intersection.Count == 0;
|
|
SetCandidates(identity, resetToAttendees ? attendees : intersection);
|
|
if (intersection.Count == 1)
|
|
{
|
|
identity.CanonicalName = intersection[0];
|
|
}
|
|
|
|
return resetToAttendees;
|
|
}
|
|
|
|
public static void SetCandidates(
|
|
SpeakerIdentity identity,
|
|
IEnumerable<string> candidates)
|
|
{
|
|
identity.CandidateNames.Clear();
|
|
identity.CandidateNames.AddRange(candidates
|
|
.Where(candidate => !string.IsNullOrWhiteSpace(candidate))
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
.Order(StringComparer.OrdinalIgnoreCase)
|
|
.Select(candidate => new SpeakerCandidateName { Name = candidate }));
|
|
}
|
|
}
|