Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Webreaper committed Mar 13, 2024
2 parents ff11549 + f1e6ce3 commit 00a6eab
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 18 deletions.
21 changes: 21 additions & 0 deletions Damselfly.Core.DbModels/Models/Entities/ImageMetaData.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Runtime.CompilerServices;

namespace Damselfly.Core.Models;

Expand Down Expand Up @@ -51,4 +52,24 @@ public class ImageMetaData
// Date we last performed face/object/image recognition
// If this is null, AI will be reprocessed
public DateTime? AILastUpdated { get; set; }

public void Clear()
{
this.DateTaken = DateTime.MinValue;
this.Height = 0;
this.Width = 0;
this.Description = null;
this.Caption = null;
this.DominantColor = null;
this.AspectRatio = 1;
this.Rating = 0;
this.Credit = null;
this.ISO = null;
this.FNum = null;
this.Exposure = null;
this.FNum = null;
this.FlashFired = false;
this.Latitude = null;
this.Longitude = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,7 @@ private async Task<Image> LoadAndCacheImage(int imageId)
if (_memoryCache.TryGetValue<Image>(imageId, out var image))
return image;

// This should never happen, if our caching is working. :)
_logger.LogWarning($"No image found in client-side cache for ID: {imageId}.");
_logger.LogTrace($"No image found in client-side cache for ID: {imageId}.");

try
{
Expand Down
34 changes: 28 additions & 6 deletions Damselfly.Core/Services/ImageRecognitionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -328,17 +328,13 @@ public async Task CreateMissingPeople(IEnumerable<ImageDetectResult> detectedFac
State = Person.PersonState.Unknown,
LastUpdated = DateTime.UtcNow,
PersonGuid = x.PersonGuid,
FaceData = new List<PersonFaceData> { new()
{
Score = x.Score,
Embeddings = string.Join( ",", x.Embeddings)
} },
FaceData = BuildFaceData(x),
}).ToList();

if ( newPeople.Any() )
{
await db.People.AddRangeAsync( newPeople );
await db.SaveChangesAsync();
await db.SaveChangesAsync("AddPeople");

// Add or replace the new people in the cache (this should always add)
newPeople.ForEach(x => _peopleCache[x.PersonGuid] = x);
Expand All @@ -352,6 +348,32 @@ public async Task CreateMissingPeople(IEnumerable<ImageDetectResult> detectedFac
}
}

/// <summary>
/// Create the face data for an image detect result - being careful
/// not to return anything if the detect result didn't actually
/// contain any embeddings.
/// </summary>
/// <param name="detectResult"></param>
/// <returns></returns>
private List<PersonFaceData> BuildFaceData( ImageDetectResult detectResult )
{
List<PersonFaceData>? result = new();

if( detectResult.Embeddings.Length > 0 )
{
result = new List<PersonFaceData>
{
new()
{
Score = detectResult.Score,
Embeddings = string.Join( ",", detectResult.Embeddings)
}
};
}

return result;
}

/// <summary>
/// Given a collection of detected objects, create the tags, put them in the cache,
/// and then return a list of keyword => TagID key-value pairs
Expand Down
32 changes: 25 additions & 7 deletions Damselfly.Core/Services/MetaDataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public void StartService()

_workService.AddJobSource(this);
}

/// <summary>
/// Read the metadata, and handle any exceptions.
/// </summary>
Expand Down Expand Up @@ -216,6 +216,20 @@ private IReadOnlyList<Directory> SafeReadImageMetadata(string imagePath)
return metadata;
}

private string? GetXMPFieldValue( Dictionary<string, string> kvps, string prefix )
{
if( kvps.TryGetValue( prefix, out var result ) && ! string.IsNullOrEmpty(result))
return result;

var possibilities = Enumerable.Range(1, 5).Select( n => $"{prefix}[{n}]");

foreach( var key in possibilities )
if( kvps.TryGetValue( key, out var indexed ) && ! string.IsNullOrEmpty(indexed) )
return indexed;

return null;
}

/// <summary>
/// Pull out the XMP attributes
/// </summary>
Expand All @@ -227,18 +241,19 @@ private void ReadXMPData(XmpDirectory xmpDirectory, Image image)
{
var nvps = xmpDirectory.XmpMeta.Properties
.Where(x => !string.IsNullOrEmpty(x.Path))
.ToDictionary(x => x.Path, y => y.Value);
.ToDictionary(x => x.Path, y => y.Value, StringComparer.OrdinalIgnoreCase);

if( image.MetaData.DateTaken == DateTime.MinValue )
{
if( nvps.ContainsKey("exif:DateTimeOriginal") && DateTime.TryParse(nvps["exif:DateTimeOriginal"], out var dateTime) )
image.MetaData.DateTaken = dateTime;
}
if( string.IsNullOrEmpty(image.MetaData.Description) && nvps.ContainsKey("exif:Description"))
image.MetaData.Description = nvps["exif:Description"];

if( string.IsNullOrEmpty(image.MetaData.Caption) && nvps.ContainsKey("exif:Caption") )
image.MetaData.Caption = nvps["exif:Caption"];

if( string.IsNullOrEmpty(image.MetaData.Description) )
image.MetaData.Description = GetXMPFieldValue( nvps, "dc:Description" );

if( string.IsNullOrEmpty(image.MetaData.Caption) )
image.MetaData.Caption = GetXMPFieldValue( nvps, "dc:Caption" );
}
catch ( Exception ex )
{
Expand Down Expand Up @@ -359,6 +374,9 @@ private bool GetImageMetaData(ref ImageMetaData imgMetaData, out string[] keywor

if ( metadata != null )
{
// We've read some EXIF data, so clear out the existing metadata to replace it
imgMetaData.Clear();

metaDataReadSuccess = true;

var subIfdDirectory = metadata.OfType<ExifSubIfdDirectory>().FirstOrDefault();
Expand Down
2 changes: 1 addition & 1 deletion Damselfly.Core/Utils/DBSetExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,6 @@ public static async Task<int> BulkUpdateWithSaveChanges<T>(this BaseDBModel db,
dbSet.Update(e);
}

return await db.SaveChangesAsync();
return await db.SaveChangesAsync("BulkUpdateWithSaveChanges");
}
}
2 changes: 1 addition & 1 deletion Damselfly.Web.Client/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static async Task Main(string[] args)

// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("DamselflyAPI"));
builder.Services.AddMemoryCache(x => x.SizeLimit = 5000);
builder.Services.AddMemoryCache(x => x.SizeLimit = 500);

builder.Services.AddAuthorizationCore(config => config.SetupPolicies(builder.Services));

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.1.0
4.1.1

0 comments on commit 00a6eab

Please sign in to comment.