feat: Add face encoder settings including GPU support, parallelism, and thumbnail options
Some checks failed
Build Windows Avalonia / build (push) Failing after 1m19s
Build Windows Avalonia / release (push) Has been skipped

This commit is contained in:
MaddoScientisto 2026-05-09 15:46:41 +02:00
commit 25fdb82d2f
9 changed files with 595 additions and 136 deletions

View file

@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Threading.Tasks;
using ImageCatalog_2;
using ImageCatalog_2.Services;
@ -134,6 +135,61 @@ public class DataModelCharacterizationTests
model.FontSize.ShouldBe(42);
}
[TestMethod]
public void FaceExecutableFolder_EnablesGpuToggleWhenBothVariantsExist()
{
using var root = new TemporaryDirectory();
CreateFaceEncoderExecutable(root.Path, "cpu");
CreateFaceEncoderExecutable(root.Path, "gpu");
var model = CreateModel();
model.FaceExecutablePath = root.Path;
model.FaceGpuOptionEnabled.ShouldBeTrue();
model.UseFaceGpu.ShouldBeFalse();
}
[TestMethod]
public void UseFaceGpu_UpdatesUpsampleWhenUsingRecommendedDefault()
{
using var root = new TemporaryDirectory();
CreateFaceEncoderExecutable(root.Path, "cpu");
CreateFaceEncoderExecutable(root.Path, "gpu");
var model = CreateModel();
model.FaceExecutablePath = root.Path;
model.FaceUpsample.ShouldBeTrue();
model.UseFaceGpu = true;
model.FaceUpsample.ShouldBeFalse();
}
[TestMethod]
public void ResolveConfiguredFaceEncoderExecutablePath_UsesFolderLayoutFromPowerShellScript()
{
using var root = new TemporaryDirectory();
var cpuExecutable = CreateFaceEncoderExecutable(root.Path, "cpu");
var gpuExecutable = CreateFaceEncoderExecutable(root.Path, "gpu");
DataModel.ResolveConfiguredFaceEncoderExecutablePath(root.Path, useGpu: false).ShouldBe(cpuExecutable);
DataModel.ResolveConfiguredFaceEncoderExecutablePath(root.Path, useGpu: true).ShouldBe(gpuExecutable);
}
[TestMethod]
public void BuildFaceEncoderOutputPaths_UsesTimestampAndSanitizedFolderName()
{
var timestamp = new DateTime(2026, 5, 9, 14, 30, 45);
var output = DataModel.BuildFaceEncoderOutputPaths(
@"C:\out",
@"C:\images\04 APRILE: gara?",
timestamp);
output.OutputFilePath.ShouldBe(@"C:\out\face_encodings_20260509_143045_04_APRILE_gara.pkl");
output.LogFilePath.ShouldBe(@"C:\out\encoder_log_20260509_143045_04_APRILE_gara.txt");
}
private static DataModel CreateModel(
ISettingsService? settingsService = null,
ITestService? testService = null)
@ -169,4 +225,33 @@ public class DataModelCharacterizationTests
Substitute.For<ILogger<DataModel>>(),
versionProvider: null);
}
private static string CreateFaceEncoderExecutable(string rootPath, string variant)
{
var variantDirectory = Path.Combine(rootPath, $"face_encoder_{variant}");
Directory.CreateDirectory(variantDirectory);
var executablePath = Path.Combine(variantDirectory, $"face_encoder_{variant}.exe");
File.WriteAllText(executablePath, "stub");
return executablePath;
}
private sealed class TemporaryDirectory : IDisposable
{
public TemporaryDirectory()
{
Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName());
Directory.CreateDirectory(Path);
}
public string Path { get; }
public void Dispose()
{
if (Directory.Exists(Path))
{
Directory.Delete(Path, recursive: true);
}
}
}
}