forked from Manuel/meeting-assistant
107 lines
3.9 KiB
C#
107 lines
3.9 KiB
C#
using MeetingAssistant.Speakers;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace MeetingAssistant.Tests;
|
|
|
|
public sealed class SpeakerVoiceVectorPersistenceTests
|
|
{
|
|
[Fact]
|
|
public async Task IdentityStoresVersionedVoiceVectorAndDeletesItWithIdentity()
|
|
{
|
|
var databasePath = Path.Combine(
|
|
Path.GetTempPath(),
|
|
"meeting-assistant-tests",
|
|
Guid.NewGuid().ToString("N"),
|
|
"speaker-identities.db");
|
|
Directory.CreateDirectory(Path.GetDirectoryName(databasePath)!);
|
|
var options = new DbContextOptionsBuilder<SpeakerIdentityDbContext>()
|
|
.UseSqlite($"Data Source={databasePath}")
|
|
.Options;
|
|
|
|
await using (var context = new SpeakerIdentityDbContext(options))
|
|
{
|
|
await SpeakerIdentitySchema.EnsureCreatedOrUpdatedAsync(context, CancellationToken.None);
|
|
context.SpeakerIdentities.Add(new SpeakerIdentity
|
|
{
|
|
CanonicalName = "Chris",
|
|
CreatedAt = DateTimeOffset.UtcNow,
|
|
UpdatedAt = DateTimeOffset.UtcNow,
|
|
VoiceVectors =
|
|
[
|
|
new SpeakerVoiceVector
|
|
{
|
|
ModelId = "resemblyzer-0.1.4-pretrained",
|
|
Dimensions = 256,
|
|
VectorBytes = new byte[256 * sizeof(float)],
|
|
Fingerprint = "vector-a",
|
|
CreatedAt = DateTimeOffset.UtcNow
|
|
}
|
|
]
|
|
});
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
await using (var context = new SpeakerIdentityDbContext(options))
|
|
{
|
|
var identity = await context.SpeakerIdentities
|
|
.Include(candidate => candidate.VoiceVectors)
|
|
.SingleAsync();
|
|
var vector = Assert.Single(identity.VoiceVectors);
|
|
Assert.Equal("resemblyzer-0.1.4-pretrained", vector.ModelId);
|
|
Assert.Equal(256, vector.Dimensions);
|
|
Assert.Equal(256 * sizeof(float), vector.VectorBytes.Length);
|
|
|
|
context.SpeakerIdentities.Remove(identity);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
await using (var context = new SpeakerIdentityDbContext(options))
|
|
{
|
|
Assert.Empty(await context.SpeakerVoiceVectors.ToListAsync());
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public async Task IdentityRejectsDuplicateVoiceVectorFingerprint()
|
|
{
|
|
var databasePath = Path.Combine(
|
|
Path.GetTempPath(),
|
|
"meeting-assistant-tests",
|
|
Guid.NewGuid().ToString("N"),
|
|
"speaker-identities.db");
|
|
Directory.CreateDirectory(Path.GetDirectoryName(databasePath)!);
|
|
var options = new DbContextOptionsBuilder<SpeakerIdentityDbContext>()
|
|
.UseSqlite($"Data Source={databasePath}")
|
|
.Options;
|
|
await using var context = new SpeakerIdentityDbContext(options);
|
|
await SpeakerIdentitySchema.EnsureCreatedOrUpdatedAsync(context, CancellationToken.None);
|
|
var identity = new SpeakerIdentity
|
|
{
|
|
CanonicalName = "Chris",
|
|
CreatedAt = DateTimeOffset.UtcNow,
|
|
UpdatedAt = DateTimeOffset.UtcNow
|
|
};
|
|
context.SpeakerIdentities.Add(identity);
|
|
await context.SaveChangesAsync();
|
|
|
|
context.SpeakerVoiceVectors.AddRange(
|
|
CreateVector(identity.Id, "same-vector"),
|
|
CreateVector(identity.Id, "same-vector"));
|
|
|
|
await Assert.ThrowsAsync<DbUpdateException>(() => context.SaveChangesAsync());
|
|
}
|
|
|
|
private static SpeakerVoiceVector CreateVector(int identityId, string fingerprint)
|
|
{
|
|
return new SpeakerVoiceVector
|
|
{
|
|
SpeakerIdentityId = identityId,
|
|
ModelId = "resemblyzer-0.1.4-pretrained",
|
|
Dimensions = 256,
|
|
VectorBytes = new byte[256 * sizeof(float)],
|
|
Fingerprint = fingerprint,
|
|
CreatedAt = DateTimeOffset.UtcNow
|
|
};
|
|
}
|
|
}
|