From b9d1133932b18a781a8aca0fa0b41b99d49706a9 Mon Sep 17 00:00:00 2001 From: Mark Otway Date: Thu, 7 Mar 2024 19:07:47 +0000 Subject: [PATCH] Merge functionality --- .../Services/ImageRecognitionService.cs | 60 +++++++++++++++++-- .../Shared/Dialogs/NameDialog.razor | 4 +- .../Shared/Dialogs/NameDialog.razor.css | 4 ++ Damselfly.Web.Client/Shared/PersonTile.razor | 3 + Damselfly.Web.Client/wwwroot/version.js | 2 +- 5 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 Damselfly.Web.Client/Shared/Dialogs/NameDialog.razor.css diff --git a/Damselfly.Core/Services/ImageRecognitionService.cs b/Damselfly.Core/Services/ImageRecognitionService.cs index 6d992ee8..d224d227 100644 --- a/Damselfly.Core/Services/ImageRecognitionService.cs +++ b/Damselfly.Core/Services/ImageRecognitionService.cs @@ -17,6 +17,7 @@ using Damselfly.Shared.Utils; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using SixLabors.ImageSharp.PixelFormats; using Image = Damselfly.Core.Models.Image; @@ -27,7 +28,8 @@ public class ImageRecognitionService(IServiceScopeFactory _scopeFactory, MetaDataService _metdataService, FaceONNXService _faceOnnxService, ThumbnailService _thumbService, ConfigService _configService, ImageClassifier _imageClassifier, ImageCache _imageCache, - WorkService _workService, ExifService _exifService) : IPeopleService, IProcessJobFactory, IRescanProvider + WorkService _workService, ExifService _exifService, + ILogger _logger) : IPeopleService, IProcessJobFactory, IRescanProvider { // WASM: This should be a MemoryCache private readonly IDictionary _peopleCache = new ConcurrentDictionary(); @@ -64,11 +66,50 @@ public async Task> GetPeopleNames(string searchText) return names; } - public async Task UpdateName(ImageObject faceObject, string name, bool merge) + private async Task MergeWithNamne(ImageObject faceObject, string name) { - if (!faceObject.IsFace) - throw new ArgumentException("Image object passed to name update."); + using var scope = _scopeFactory.CreateScope(); + using var db = scope.ServiceProvider.GetService(); + + var transaction = db.Database.BeginTransaction(); + + try + { + var matchingPeople = await GetAllPeople(); + + var oldPersonId = faceObject.PersonId; + var newPersonId = matchingPeople.Where( x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) + .Select( x => x.PersonId ) + .SingleOrDefault(-1); + + if( newPersonId != -1 ) + { + // Update personID in image objects to the new person ID + await db.ImageObjects.Where( x => x.PersonId == oldPersonId ) + .ExecuteUpdateAsync( x => x.SetProperty( p => p.PersonId, newPersonId)); + + // Update personID in FaceData + await db.FaceData.Where( x => x.PersonId == oldPersonId ) + .ExecuteUpdateAsync( x => x.SetProperty( p => p.PersonId, newPersonId)); + + // Delete old personID + await db.People.Where( x => x.PersonId == oldPersonId ) + .ExecuteDeleteAsync(); + + await transaction.CommitAsync(); + await LoadPersonCache( true ); + } + } + catch( Exception ex ) + { + _logger.LogError( $"Exception while merging person {faceObject.PersonId} => {name}"); + await transaction.RollbackAsync(); + } + } + + private async Task ChangeName(ImageObject faceObject, string name) + { using var scope = _scopeFactory.CreateScope(); using var db = scope.ServiceProvider.GetService(); @@ -89,6 +130,17 @@ public async Task UpdateName(ImageObject faceObject, string name, bool merge) await db.SaveChangesAsync("SetName"); + } + public async Task UpdateName(ImageObject faceObject, string name, bool merge) + { + if (!faceObject.IsFace) + throw new ArgumentException("Image object passed to name update."); + + if( merge ) + await MergeWithNamne(faceObject, name); + else + await ChangeName( faceObject, name); + if (faceObject.Person.PersonGuid != null) { // Add/update the cache diff --git a/Damselfly.Web.Client/Shared/Dialogs/NameDialog.razor b/Damselfly.Web.Client/Shared/Dialogs/NameDialog.razor index da4d4c9b..9c97f120 100644 --- a/Damselfly.Web.Client/Shared/Dialogs/NameDialog.razor +++ b/Damselfly.Web.Client/Shared/Dialogs/NameDialog.razor @@ -19,10 +19,10 @@ Variant="UIConstants.MudVariant" AutoFocus="true"/> @if( showDupeMessage ) { -

+

There is already an entry for '@TypeAheadName'. By selecting that Name, you will merge/add this face to that person. -

+
} diff --git a/Damselfly.Web.Client/Shared/Dialogs/NameDialog.razor.css b/Damselfly.Web.Client/Shared/Dialogs/NameDialog.razor.css new file mode 100644 index 00000000..ecba39fb --- /dev/null +++ b/Damselfly.Web.Client/Shared/Dialogs/NameDialog.razor.css @@ -0,0 +1,4 @@ + +.merge-message { + margin: 10px; +} diff --git a/Damselfly.Web.Client/Shared/PersonTile.razor b/Damselfly.Web.Client/Shared/PersonTile.razor index 889d041a..ffac9df5 100644 --- a/Damselfly.Web.Client/Shared/PersonTile.razor +++ b/Damselfly.Web.Client/Shared/PersonTile.razor @@ -10,6 +10,9 @@ +
+ @Person.FaceData.Count sets of face data +
diff --git a/Damselfly.Web.Client/wwwroot/version.js b/Damselfly.Web.Client/wwwroot/version.js index 9895f1b5..bf5f32c1 100644 --- a/Damselfly.Web.Client/wwwroot/version.js +++ b/Damselfly.Web.Client/wwwroot/version.js @@ -1 +1 @@ -const CACHE_VERSION='4.1.0-20240307145827' +const CACHE_VERSION='4.1.0-20240307190510'