namespace MeetingAssistant.Speakers; internal static class SpeakerIdentityMerger { public static void MergeInto( SpeakerIdentity target, SpeakerIdentity source, int maxSnippets) { AddAlias(target, source.CanonicalName); foreach (var alias in source.Aliases) { AddAlias(target, alias.Name); } foreach (var candidate in source.CandidateNames) { AddAlias(target, candidate.Name); } foreach (var reference in source.References) { SpeakerIdentityReferences.AddIfMissing(target, reference); } var retainedSnippets = target.Snippets .Concat(source.Snippets) .OrderBy(snippet => StableSnippetKey(snippet.WavBytes)) .Take(Math.Max(1, maxSnippets)) .Select(snippet => new SpeakerSnippet { WavBytes = snippet.WavBytes, CreatedAt = snippet.CreatedAt }) .ToList(); target.Snippets.Clear(); target.Snippets.AddRange(retainedSnippets); target.UpdatedAt = DateTimeOffset.UtcNow; } private static void AddAlias(SpeakerIdentity identity, string? alias) { if (string.IsNullOrWhiteSpace(alias) || string.Equals(identity.CanonicalName, alias, StringComparison.OrdinalIgnoreCase) || identity.Aliases.Any(existing => string.Equals(existing.Name, alias, StringComparison.OrdinalIgnoreCase))) { return; } identity.Aliases.Add(new SpeakerAlias { Name = alias.Trim() }); } private static int StableSnippetKey(byte[] snippet) { var hash = new HashCode(); foreach (var value in snippet) { hash.Add(value); } return hash.ToHashCode(); } }