diff --git a/Azaion.Annotator/Annotator.xaml.cs b/Azaion.Annotator/Annotator.xaml.cs index c8c34da..5e809aa 100644 --- a/Azaion.Annotator/Annotator.xaml.cs +++ b/Azaion.Annotator/Annotator.xaml.cs @@ -393,6 +393,7 @@ public partial class Annotator private void OnFormClosed(object? sender, EventArgs e) { MainCancellationSource.Cancel(); + _inferenceService.StopInference(); DetectionCancellationSource.Cancel(); _mediaPlayer.Stop(); _mediaPlayer.Dispose(); @@ -500,30 +501,30 @@ public partial class Annotator IsInferenceNow = true; FollowAI = true; DetectionCancellationSource = new CancellationTokenSource(); - var ct = DetectionCancellationSource.Token; + var detectToken = DetectionCancellationSource.Token; _ = Task.Run(async () => { - while (!ct.IsCancellationRequested) + while (!detectToken.IsCancellationRequested) { var files = new List(); await Dispatcher.Invoke(async () => { - //Take not annotataed medias + //Take all medias files = (LvFiles.ItemsSource as IEnumerable)?.Skip(LvFiles.SelectedIndex) - .Where(x => !x.HasAnnotations) + //.Where(x => !x.HasAnnotations) .Take(Constants.DETECTION_BATCH_SIZE) .Select(x => x.Path) .ToList() ?? []; if (files.Count != 0) { - await _mediator.Publish(new AnnotatorControlEvent(PlaybackControlEnum.Play), ct); + await _mediator.Publish(new AnnotatorControlEvent(PlaybackControlEnum.Play), detectToken); await ReloadAnnotations(); } }); if (files.Count == 0) break; - await _inferenceService.RunInference(files, async annotationImage => await ProcessDetection(annotationImage, ct), ct); + await _inferenceService.RunInference(files, async annotationImage => await ProcessDetection(annotationImage, detectToken), detectToken); Dispatcher.Invoke(() => { diff --git a/Azaion.Annotator/AnnotatorEventHandler.cs b/Azaion.Annotator/AnnotatorEventHandler.cs index 58c1845..9578a45 100644 --- a/Azaion.Annotator/AnnotatorEventHandler.cs +++ b/Azaion.Annotator/AnnotatorEventHandler.cs @@ -25,7 +25,8 @@ public class AnnotatorEventHandler( FormState formState, AnnotationService annotationService, ILogger logger, - IOptions dirConfig) + IOptions dirConfig, + IInferenceService inferenceService) : INotificationHandler, INotificationHandler, @@ -141,6 +142,7 @@ public class AnnotatorEventHandler( } break; case PlaybackControlEnum.Stop: + inferenceService.StopInference(); await mainWindow.DetectionCancellationSource.CancelAsync(); mediaPlayer.Stop(); break; diff --git a/Azaion.Common/Services/AnnotationService.cs b/Azaion.Common/Services/AnnotationService.cs index 9d68233..22de3f6 100644 --- a/Azaion.Common/Services/AnnotationService.cs +++ b/Azaion.Common/Services/AnnotationService.cs @@ -144,6 +144,9 @@ public class AnnotationService : INotificationHandler .Where(x => x.Name == fName) .Set(x => x.Source, source) .Set(x => x.AnnotationStatus, status) + .Set(x => x.CreatedDate, createdDate) + .Set(x => x.CreatedEmail, createdEmail) + .Set(x => x.CreatedRole, userRole) .UpdateAsync(token: token); ann.Detections = detections; } diff --git a/Azaion.Common/Services/InferenceService.cs b/Azaion.Common/Services/InferenceService.cs index 60482ba..414ecf8 100644 --- a/Azaion.Common/Services/InferenceService.cs +++ b/Azaion.Common/Services/InferenceService.cs @@ -13,30 +13,31 @@ namespace Azaion.Common.Services; public interface IInferenceService { - Task RunInference(List mediaPaths, Func processAnnotation, CancellationToken ct = default); + Task RunInference(List mediaPaths, Func processAnnotation, CancellationToken detectToken = default); + void StopInference(); } public class InferenceService(ILogger logger, [FromKeyedServices(SecurityConstants.EXTERNAL_INFERENCE_PATH)] IExternalClient externalClient, IOptions aiConfigOptions) : IInferenceService { - public async Task RunInference(List mediaPaths, Func processAnnotation, CancellationToken ct = default) + public async Task RunInference(List mediaPaths, Func processAnnotation, CancellationToken detectToken = default) { var aiConfig = aiConfigOptions.Value; aiConfig.Paths = mediaPaths; externalClient.Send(RemoteCommand.Create(CommandType.Inference, aiConfig)); - while (!ct.IsCancellationRequested) + while (!detectToken.IsCancellationRequested) { try { - var bytes = externalClient.GetBytes(ct: ct); + var bytes = externalClient.GetBytes(ct: detectToken); if (bytes == null) throw new Exception("Can't get bytes from inference client"); if (bytes.Length == 4 && Encoding.UTF8.GetString(bytes) == "DONE") return; - var annotationImage = MessagePackSerializer.Deserialize(bytes, cancellationToken: ct); + var annotationImage = MessagePackSerializer.Deserialize(bytes, cancellationToken: detectToken); await processAnnotation(annotationImage); } @@ -47,4 +48,9 @@ public class InferenceService(ILogger logger, [FromKeyedServic } } } + + public void StopInference() + { + externalClient.Send(RemoteCommand.Create(CommandType.StopInference)); + } } \ No newline at end of file diff --git a/Azaion.CommonSecurity/DTO/Commands/RemoteCommand.cs b/Azaion.CommonSecurity/DTO/Commands/RemoteCommand.cs index 4d22bfc..9fd9f7e 100644 --- a/Azaion.CommonSecurity/DTO/Commands/RemoteCommand.cs +++ b/Azaion.CommonSecurity/DTO/Commands/RemoteCommand.cs @@ -11,11 +11,11 @@ public class RemoteCommand(CommandType commandType, byte[]? data = null) [Key("Data")] public byte[]? Data { get; set; } = data; - public static RemoteCommand Create(CommandType commandType, T data) where T : class - { - var dataBytes = MessagePackSerializer.Serialize(data); - return new RemoteCommand(commandType, dataBytes); - } + public static RemoteCommand Create(CommandType commandType) => + new(commandType); + + public static RemoteCommand Create(CommandType commandType, T data) where T : class => + new(commandType, MessagePackSerializer.Serialize(data)); } [MessagePackObject] diff --git a/Azaion.Inference/constants.pyx b/Azaion.Inference/constants.pyx index 1988c2e..ba1de2d 100644 --- a/Azaion.Inference/constants.pyx +++ b/Azaion.Inference/constants.pyx @@ -11,8 +11,6 @@ cdef str QUEUE_CONFIG_FILENAME = "secured-config.json" cdef str AI_MODEL_FILE_BIG = "azaion.onnx.big" cdef str AI_MODEL_FILE_SMALL = "azaion.onnx.small" -cdef bytes DONE_SIGNAL = b"DONE" - cdef log(str log_message, bytes client_id=None): local_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) client_str = '' if client_id is None else f' {client_id}' diff --git a/Azaion.Inference/requirements.txt b/Azaion.Inference/requirements.txt index 4d3dcec..91fbcfb 100644 --- a/Azaion.Inference/requirements.txt +++ b/Azaion.Inference/requirements.txt @@ -1,3 +1,4 @@ +pyinstaller Cython opencv-python numpy diff --git a/Azaion.Suite/Azaion.Suite.csproj b/Azaion.Suite/Azaion.Suite.csproj index 48eb08b..e4fea8c 100644 --- a/Azaion.Suite/Azaion.Suite.csproj +++ b/Azaion.Suite/Azaion.Suite.csproj @@ -12,6 +12,7 @@ + @@ -31,8 +32,8 @@ - - + + @@ -60,8 +61,8 @@ - - + + diff --git a/Azaion.Suite/config.json b/Azaion.Suite/config.json index 59c158e..1da7146 100644 --- a/Azaion.Suite/config.json +++ b/Azaion.Suite/config.json @@ -37,8 +37,8 @@ { "Id": 13, "Name": "Маскування гілками", "ShortName": "Гілки" } ], "LastSelectedExplorerClass": null, - "VideoFormats": [ "mp4", "mov", "avi" ], - "ImageFormats": [ "jpg", "jpeg", "png", "bmp" ], + "VideoFormats": [ ".mp4", ".mov", ".avi" ], + "ImageFormats": [ ".jpg", ".jpeg", ".png", ".bmp" ], "AnnotationsDbFile": "annotations.db", "LeftPanelWidth": 220.0, "RightPanelWidth": 230.0 diff --git a/Azaion.Suite/config.production.json b/Azaion.Suite/config.production.json index c242cec..109d428 100644 --- a/Azaion.Suite/config.production.json +++ b/Azaion.Suite/config.production.json @@ -37,8 +37,8 @@ { "Id": 13, "Name": "Маскування гілками", "ShortName": "Гілки" } ], "LastSelectedExplorerClass": null, - "VideoFormats": [ "mp4", "mov", "avi" ], - "ImageFormats": [ "jpg", "jpeg", "png", "bmp" ], + "VideoFormats": [ ".mp4", ".mov", ".avi" ], + "ImageFormats": [ ".jpg", ".jpeg", ".png", ".bmp" ], "AnnotationsDbFile": "annotations.db", "LeftPanelWidth": 240.0, "RightPanelWidth": 240.0 diff --git a/build/publish.cmd b/build/publish.cmd index 3940206..81320c4 100644 --- a/build/publish.cmd +++ b/build/publish.cmd @@ -21,8 +21,7 @@ move dist\Azaion.Dataset.dll dist\dummy\ echo Build Cython app cd Azaion.Inference -call ".\venv\Scripts\activate.bat" -pyinstaller --onefile ^ +.\venv\Scripts\pyinstaller --onefile ^ --collect-all jwt ^ --collect-all requests ^ --collect-all psutil ^