update validation logic

This commit is contained in:
Alex Bezdieniezhnykh
2025-04-21 17:02:13 +03:00
parent 70148bdfdf
commit c68c293448
5 changed files with 43 additions and 19 deletions
+2
View File
@@ -35,4 +35,6 @@ public class AnnotationThumbnail(Annotation annotation) : INotifyPropertyChanged
{ {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} }
public void UpdateUI() => OnPropertyChanged(nameof(IsSeed));
} }
+3
View File
@@ -31,6 +31,9 @@ public class Annotation
[IgnoreMember]public SourceEnum Source { get; set; } [IgnoreMember]public SourceEnum Source { get; set; }
[IgnoreMember]public AnnotationStatus AnnotationStatus { get; set; } [IgnoreMember]public AnnotationStatus AnnotationStatus { get; set; }
[IgnoreMember]public DateTime ValidateDate { get; set; }
[IgnoreMember]public string ValidateEmail { get; set; } = null!;
[Key("d")] public IEnumerable<Detection> Detections { get; set; } = null!; [Key("d")] public IEnumerable<Detection> Detections { get; set; } = null!;
[Key("t")] public long Milliseconds { get; set; } [Key("t")] public long Milliseconds { get; set; }
+27 -16
View File
@@ -94,7 +94,6 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
new MemoryStream(msg.Image), new MemoryStream(msg.Image),
msg.CreatedRole, msg.CreatedRole,
msg.CreatedEmail, msg.CreatedEmail,
generateThumbnail: true,
fromQueue: true, fromQueue: true,
token: cancellationToken); token: cancellationToken);
} }
@@ -106,17 +105,12 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
{ {
a.Time = TimeSpan.FromMilliseconds(a.Milliseconds); a.Time = TimeSpan.FromMilliseconds(a.Milliseconds);
return await SaveAnnotationInner(DateTime.Now, a.OriginalMediaName, a.Time, a.Detections.ToList(), return await SaveAnnotationInner(DateTime.Now, a.OriginalMediaName, a.Time, a.Detections.ToList(),
SourceEnum.AI, new MemoryStream(a.Image), _api.CurrentUser.Role, _api.CurrentUser.Email, generateThumbnail: true, token: ct); SourceEnum.AI, new MemoryStream(a.Image), _api.CurrentUser.Role, _api.CurrentUser.Email, token: ct);
} }
//Manual //Manual
public async Task<Annotation> SaveAnnotation(string originalMediaName, TimeSpan time, List<Detection> detections, Stream? stream = null, CancellationToken token = default) => public async Task<Annotation> SaveAnnotation(string originalMediaName, TimeSpan time, List<Detection> detections, Stream? stream = null, CancellationToken token = default) =>
await SaveAnnotationInner(DateTime.UtcNow, originalMediaName, time, detections, SourceEnum.Manual, stream, await SaveAnnotationInner(DateTime.UtcNow, originalMediaName, time, detections, SourceEnum.Manual, stream,
_api.CurrentUser.Role, _api.CurrentUser.Email, generateThumbnail: true, token: token);
//Manual Validate existing
public async Task ValidateAnnotation(Annotation annotation, CancellationToken token = default) =>
await SaveAnnotationInner(DateTime.UtcNow, annotation.OriginalMediaName, annotation.Time, annotation.Detections.ToList(), SourceEnum.Manual, null,
_api.CurrentUser.Role, _api.CurrentUser.Email, token: token); _api.CurrentUser.Role, _api.CurrentUser.Email, token: token);
// Manual save from Validators -> Validated -> stream: azaion-annotations-confirm // Manual save from Validators -> Validated -> stream: azaion-annotations-confirm
@@ -124,11 +118,9 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
private async Task<Annotation> SaveAnnotationInner(DateTime createdDate, string originalMediaName, TimeSpan time, List<Detection> detections, SourceEnum source, Stream? stream, private async Task<Annotation> SaveAnnotationInner(DateTime createdDate, string originalMediaName, TimeSpan time, List<Detection> detections, SourceEnum source, Stream? stream,
RoleEnum userRole, RoleEnum userRole,
string createdEmail, string createdEmail,
bool generateThumbnail = false,
bool fromQueue = false, bool fromQueue = false,
CancellationToken token = default) CancellationToken token = default)
{ {
AnnotationStatus status; AnnotationStatus status;
var fName = originalMediaName.ToTimeName(time); var fName = originalMediaName.ToTimeName(time);
var annotation = await _dbFactory.Run(async db => var annotation = await _dbFactory.Run(async db =>
@@ -179,13 +171,10 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
img.Save(annotation.ImagePath, ImageFormat.Jpeg); //todo: check png images coming from queue img.Save(annotation.ImagePath, ImageFormat.Jpeg); //todo: check png images coming from queue
} }
await YoloLabel.WriteToFile(detections, annotation.LabelPath, token); await YoloLabel.WriteToFile(detections, annotation.LabelPath, token);
if (generateThumbnail)
{
await _galleryService.CreateThumbnail(annotation, token);
if (_uiConfig.GenerateAnnotatedImage)
await _galleryService.CreateAnnotatedImage(annotation, token);
}
await _galleryService.CreateThumbnail(annotation, token);
if (_uiConfig.GenerateAnnotatedImage)
await _galleryService.CreateAnnotatedImage(annotation, token);
if (!fromQueue) //Send to queue only if we're not getting from queue already if (!fromQueue) //Send to queue only if we're not getting from queue already
await _producer.SendToInnerQueue(annotation, token); await _producer.SendToInnerQueue(annotation, token);
@@ -195,10 +184,32 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
{ {
_dbFactory.SaveToDisk(); _dbFactory.SaveToDisk();
await Task.CompletedTask; await Task.CompletedTask;
}, SaveTaskId, TimeSpan.FromSeconds(5)); }, SaveTaskId, TimeSpan.FromSeconds(5), true);
return annotation; return annotation;
} }
public async Task ValidateAnnotations(List<Annotation> annotations, CancellationToken token = default)
{
if (!_api.CurrentUser.Role.IsValidator())
return;
var annNames = annotations.Select(x => x.Name).ToHashSet();
await _dbFactory.Run(async db =>
{
await db.Annotations
.Where(x => annNames.Contains(x.Name))
.Set(x => x.AnnotationStatus, AnnotationStatus.Validated)
.Set(x => x.ValidateDate, DateTime.UtcNow)
.Set(x => x.ValidateEmail, _api.CurrentUser.Email)
.UpdateAsync(token: token);
});
ThrottleExt.Throttle(async () =>
{
_dbFactory.SaveToDisk();
await Task.CompletedTask;
}, SaveTaskId, TimeSpan.FromSeconds(5), true);
}
public async Task Handle(AnnotationsDeletedEvent notification, CancellationToken cancellationToken) public async Task Handle(AnnotationsDeletedEvent notification, CancellationToken cancellationToken)
{ {
await _dbFactory.DeleteAnnotations(notification.Annotations, cancellationToken); await _dbFactory.DeleteAnnotations(notification.Annotations, cancellationToken);
@@ -2,6 +2,7 @@
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Threading; using System.Windows.Threading;
using Azaion.Common.Database;
using Azaion.Common.DTO; using Azaion.Common.DTO;
using Azaion.Common.DTO.Queue; using Azaion.Common.DTO.Queue;
using Azaion.Common.Events; using Azaion.Common.Events;
@@ -96,8 +97,14 @@ public class DatasetExplorerEventHandler(
var annotations = datasetExplorer.ThumbnailsView.SelectedItems.Cast<AnnotationThumbnail>() var annotations = datasetExplorer.ThumbnailsView.SelectedItems.Cast<AnnotationThumbnail>()
.Select(x => x.Annotation) .Select(x => x.Annotation)
.ToList(); .ToList();
foreach (var annotation in annotations) await annotationService.ValidateAnnotations(annotations, cancellationToken);
await annotationService.ValidateAnnotation(annotation, cancellationToken); foreach (var ann in datasetExplorer.SelectedAnnotations.Where(x => annotations.Contains(x.Annotation)))
{
ann.Annotation.AnnotationStatus = AnnotationStatus.Validated;
if (datasetExplorer.SelectedAnnotationDict.TryGetValue(ann.Annotation.Name, out var value))
value.Annotation.AnnotationStatus = AnnotationStatus.Validated;
ann.UpdateUI();
}
break; break;
} }
} }
+2 -1
View File
@@ -24,6 +24,7 @@
}, },
"UIConfig": { "UIConfig": {
"LeftPanelWidth": 170.0, "LeftPanelWidth": 170.0,
"RightPanelWidth": 120.0 "RightPanelWidth": 120.0,
"GenerateAnnotatedImage": true
} }
} }