mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 22:36:31 +00:00
refactor external clients
put model batch size as parameter in config
This commit is contained in:
@@ -226,8 +226,9 @@ public class AnnotatorEventHandler(
|
|||||||
mediaPlayer.Stop();
|
mediaPlayer.Stop();
|
||||||
mainWindow.Title = $"Azaion Annotator - {mediaInfo.Name}";
|
mainWindow.Title = $"Azaion Annotator - {mediaInfo.Name}";
|
||||||
mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.PauseForAnnotations]);
|
mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.PauseForAnnotations]);
|
||||||
if (formState.CurrentMedia.MediaType == MediaTypes.Video)
|
mediaPlayer.Play(new Media(libVLC, mediaInfo.Path));
|
||||||
mediaPlayer.Play(new Media(libVLC, mediaInfo.Path));
|
if (formState.CurrentMedia.MediaType == MediaTypes.Image)
|
||||||
|
mediaPlayer.SetPause(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//SAVE: MANUAL
|
//SAVE: MANUAL
|
||||||
|
|||||||
@@ -5,14 +5,15 @@ namespace Azaion.Common.DTO.Config;
|
|||||||
[MessagePackObject]
|
[MessagePackObject]
|
||||||
public class AIRecognitionConfig
|
public class AIRecognitionConfig
|
||||||
{
|
{
|
||||||
[Key(nameof(FramePeriodRecognition))] public int FramePeriodRecognition { get; set; }
|
[Key("f_pr")] public int FramePeriodRecognition { get; set; }
|
||||||
[Key(nameof(FrameRecognitionSeconds))] public double FrameRecognitionSeconds { get; set; }
|
[Key("f_rs")] public double FrameRecognitionSeconds { get; set; }
|
||||||
[Key(nameof(ProbabilityThreshold))] public double ProbabilityThreshold { get; set; }
|
[Key("pt")] public double ProbabilityThreshold { get; set; }
|
||||||
|
|
||||||
[Key(nameof(TrackingDistanceConfidence))] public double TrackingDistanceConfidence { get; set; }
|
[Key("t_dc")] public double TrackingDistanceConfidence { get; set; }
|
||||||
[Key(nameof(TrackingProbabilityIncrease))] public double TrackingProbabilityIncrease { get; set; }
|
[Key("t_pi")] public double TrackingProbabilityIncrease { get; set; }
|
||||||
[Key(nameof(TrackingIntersectionThreshold))] public double TrackingIntersectionThreshold { get; set; }
|
[Key("t_it")] public double TrackingIntersectionThreshold { get; set; }
|
||||||
|
|
||||||
[Key(nameof(Data))] public byte[] Data { get; set; } = null!;
|
[Key("d")] public byte[] Data { get; set; } = null!;
|
||||||
[Key(nameof(Paths))] public List<string> Paths { get; set; } = null!;
|
[Key("p")] public List<string> Paths { get; set; } = null!;
|
||||||
|
[Key("m_bs")] public int ModelBatchSize { get; set; } = 2;
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,9 @@ namespace Azaion.Common.DTO.Config;
|
|||||||
|
|
||||||
public class AppConfig
|
public class AppConfig
|
||||||
{
|
{
|
||||||
public PythonConfig PythonConfig { get; set; } = null!;
|
public InferenceClientConfig InferenceClientConfig { get; set; } = null!;
|
||||||
|
|
||||||
|
public GpsDeniedClientConfig GpsDeniedClientConfig { get; set; } = null!;
|
||||||
|
|
||||||
public QueueConfig QueueConfig { get; set; } = null!;
|
public QueueConfig QueueConfig { get; set; } = null!;
|
||||||
|
|
||||||
@@ -85,7 +87,8 @@ public class ConfigUpdater : IConfigUpdater
|
|||||||
//Save without sensitive info
|
//Save without sensitive info
|
||||||
var publicConfig = new
|
var publicConfig = new
|
||||||
{
|
{
|
||||||
PythonConfig = config.PythonConfig,
|
InferenceClientConfig = config.InferenceClientConfig,
|
||||||
|
GpsDeniedClientConfig = config.GpsDeniedClientConfig,
|
||||||
DirectoriesConfig = config.DirectoriesConfig,
|
DirectoriesConfig = config.DirectoriesConfig,
|
||||||
AnnotationConfig = config.AnnotationConfig,
|
AnnotationConfig = config.AnnotationConfig,
|
||||||
AIRecognitionConfig = config.AIRecognitionConfig,
|
AIRecognitionConfig = config.AIRecognitionConfig,
|
||||||
|
|||||||
@@ -100,26 +100,40 @@ public class FailsafeAnnotationsProducer
|
|||||||
.ToListAsync(token: cancellationToken);
|
.ToListAsync(token: cancellationToken);
|
||||||
|
|
||||||
var messages = new List<AnnotationCreatedMessage>();
|
var messages = new List<AnnotationCreatedMessage>();
|
||||||
|
var badImages = new List<string>();
|
||||||
foreach (var annotation in annotations)
|
foreach (var annotation in annotations)
|
||||||
{
|
{
|
||||||
var image = await File.ReadAllBytesAsync(annotation.ImagePath, cancellationToken);
|
try
|
||||||
var annCreateMessage = new AnnotationCreatedMessage
|
|
||||||
{
|
{
|
||||||
Name = annotation.Name,
|
var image = await File.ReadAllBytesAsync(annotation.ImagePath, cancellationToken);
|
||||||
OriginalMediaName = annotation.OriginalMediaName,
|
var annCreateMessage = new AnnotationCreatedMessage
|
||||||
Time = annotation.Time,
|
{
|
||||||
CreatedRole = annotation.CreatedRole,
|
Name = annotation.Name,
|
||||||
CreatedEmail = annotation.CreatedEmail,
|
OriginalMediaName = annotation.OriginalMediaName,
|
||||||
CreatedDate = annotation.CreatedDate,
|
Time = annotation.Time,
|
||||||
Status = annotation.AnnotationStatus,
|
CreatedRole = annotation.CreatedRole,
|
||||||
|
CreatedEmail = annotation.CreatedEmail,
|
||||||
|
CreatedDate = annotation.CreatedDate,
|
||||||
|
Status = annotation.AnnotationStatus,
|
||||||
|
|
||||||
ImageExtension = annotation.ImageExtension,
|
ImageExtension = annotation.ImageExtension,
|
||||||
Image = image,
|
Image = image,
|
||||||
Detections = JsonConvert.SerializeObject(annotation.Detections),
|
Detections = JsonConvert.SerializeObject(annotation.Detections),
|
||||||
Source = annotation.Source,
|
Source = annotation.Source,
|
||||||
|
};
|
||||||
|
messages.Add(annCreateMessage);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
badImages.Add(annotation.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
if (badImages.Any())
|
||||||
messages.Add(annCreateMessage);
|
{
|
||||||
|
await db.AnnotationsQueue.Where(x => badImages.Contains(x.Name)).DeleteAsync(token: cancellationToken);
|
||||||
|
_dbFactory.SaveToDisk();
|
||||||
}
|
}
|
||||||
return messages;
|
return messages;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
using Azaion.Common.Database;
|
using Azaion.Common.Database;
|
||||||
using Azaion.Common.DTO.Config;
|
using Azaion.Common.DTO.Config;
|
||||||
using Azaion.CommonSecurity;
|
using Azaion.CommonSecurity;
|
||||||
using Azaion.CommonSecurity.DTO;
|
|
||||||
using Azaion.CommonSecurity.DTO.Commands;
|
using Azaion.CommonSecurity.DTO.Commands;
|
||||||
|
using Azaion.CommonSecurity.Services;
|
||||||
|
using MessagePack;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using NetMQ;
|
|
||||||
using NetMQ.Sockets;
|
|
||||||
|
|
||||||
namespace Azaion.Common.Services;
|
namespace Azaion.Common.Services;
|
||||||
|
|
||||||
@@ -16,30 +16,29 @@ public interface IInferenceService
|
|||||||
Task RunInference(List<string> mediaPaths, Func<AnnotationImage, Task> processAnnotation, CancellationToken ct = default);
|
Task RunInference(List<string> mediaPaths, Func<AnnotationImage, Task> processAnnotation, CancellationToken ct = default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PythonInferenceService(ILogger<PythonInferenceService> logger, IOptions<PythonConfig> pythonConfigOptions, IOptions<AIRecognitionConfig> aiConfigOptions) : IInferenceService
|
public class InferenceService(ILogger<InferenceService> logger, [FromKeyedServices(SecurityConstants.EXTERNAL_INFERENCE_PATH)] IExternalClient externalClient, IOptions<AIRecognitionConfig> aiConfigOptions) : IInferenceService
|
||||||
{
|
{
|
||||||
public async Task RunInference(List<string> mediaPaths, Func<AnnotationImage, Task> processAnnotation, CancellationToken ct = default)
|
public async Task RunInference(List<string> mediaPaths, Func<AnnotationImage, Task> processAnnotation, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var pythonConfig = pythonConfigOptions.Value;
|
|
||||||
var aiConfig = aiConfigOptions.Value;
|
var aiConfig = aiConfigOptions.Value;
|
||||||
|
|
||||||
using var dealer = new DealerSocket();
|
|
||||||
var clientId = Guid.NewGuid();
|
|
||||||
dealer.Options.Identity = Encoding.UTF8.GetBytes(clientId.ToString("N"));
|
|
||||||
dealer.Connect($"tcp://{pythonConfig.ZeroMqHost}:{pythonConfig.ZeroMqPort}");
|
|
||||||
|
|
||||||
aiConfig.Paths = mediaPaths;
|
aiConfig.Paths = mediaPaths;
|
||||||
dealer.SendFrame(RemoteCommand.Serialize(CommandType.Inference, aiConfig));
|
externalClient.Send(RemoteCommand.Create(CommandType.Inference, aiConfig));
|
||||||
|
|
||||||
while (!ct.IsCancellationRequested)
|
while (!ct.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var annotationStream = dealer.Get<AnnotationImage>(bytes => bytes.Length == 4 && Encoding.UTF8.GetString(bytes) == "DONE", ct: ct);
|
var bytes = externalClient.GetBytes(ct: ct);
|
||||||
if (annotationStream == null)
|
if (bytes == null)
|
||||||
break;
|
throw new Exception("Can't get bytes from inference client");
|
||||||
|
|
||||||
await processAnnotation(annotationStream);
|
if (bytes.Length == 4 && Encoding.UTF8.GetString(bytes) == "DONE")
|
||||||
|
return;
|
||||||
|
|
||||||
|
var annotationImage = MessagePackSerializer.Deserialize<AnnotationImage>(bytes, cancellationToken: ct);
|
||||||
|
|
||||||
|
await processAnnotation(annotationImage);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MessagePack" Version="3.1.0" />
|
<PackageReference Include="MessagePack" Version="3.1.0" />
|
||||||
<PackageReference Include="MessagePack.Annotations" Version="3.1.0" />
|
<PackageReference Include="MessagePack.Annotations" Version="3.1.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
|
||||||
<PackageReference Include="NetMQ" Version="4.0.1.13" />
|
<PackageReference Include="NetMQ" Version="4.0.1.13" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.3.0" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.3.0" />
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ public class RemoteCommand(CommandType commandType, byte[]? data = null)
|
|||||||
[Key("Data")]
|
[Key("Data")]
|
||||||
public byte[]? Data { get; set; } = data;
|
public byte[]? Data { get; set; } = data;
|
||||||
|
|
||||||
public static byte[] Serialize<T>(CommandType commandType, T data) where T : class
|
public static RemoteCommand Create<T>(CommandType commandType, T data) where T : class
|
||||||
{
|
{
|
||||||
var dataBytes = MessagePackSerializer.Serialize(data);
|
var dataBytes = MessagePackSerializer.Serialize(data);
|
||||||
return MessagePackSerializer.Serialize(new RemoteCommand(commandType, dataBytes ));
|
return new RemoteCommand(commandType, dataBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -1,11 +1,16 @@
|
|||||||
namespace Azaion.CommonSecurity.DTO;
|
namespace Azaion.CommonSecurity.DTO;
|
||||||
|
|
||||||
public class PythonConfig
|
public abstract class ExternalClientConfig
|
||||||
{
|
{
|
||||||
public string ZeroMqHost { get; set; } = "";
|
public string ZeroMqHost { get; set; } = "";
|
||||||
public int ZeroMqPort { get; set; }
|
public int ZeroMqPort { get; set; }
|
||||||
public double OneTryTimeoutSeconds { get; set; }
|
public double OneTryTimeoutSeconds { get; set; }
|
||||||
public int RetryCount {get;set;}
|
public int RetryCount {get;set;}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InferenceClientConfig : ExternalClientConfig
|
||||||
|
{
|
||||||
public string ResourcesFolder { get; set; } = "";
|
public string ResourcesFolder { get; set; } = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class GpsDeniedClientConfig : ExternalClientConfig;
|
||||||
@@ -2,5 +2,6 @@
|
|||||||
|
|
||||||
public class SecureAppConfig
|
public class SecureAppConfig
|
||||||
{
|
{
|
||||||
public PythonConfig PythonConfig { get; set; } = null!;
|
public InferenceClientConfig InferenceClientConfig { get; set; } = null!;
|
||||||
|
public GpsDeniedClientConfig GpsDeniedClientConfig { get; set; } = null!;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace Azaion.CommonSecurity;
|
using Azaion.CommonSecurity.DTO;
|
||||||
|
|
||||||
|
namespace Azaion.CommonSecurity;
|
||||||
|
|
||||||
public class SecurityConstants
|
public class SecurityConstants
|
||||||
{
|
{
|
||||||
@@ -6,13 +8,36 @@ public class SecurityConstants
|
|||||||
|
|
||||||
public const string DUMMY_DIR = "dummy";
|
public const string DUMMY_DIR = "dummy";
|
||||||
|
|
||||||
#region PythonConfig
|
#region ExternalClientsConfig
|
||||||
public const string AZAION_INFERENCE_PATH = "azaion-inference.exe";
|
public const string EXTERNAL_INFERENCE_PATH = "azaion-inference.exe";
|
||||||
|
public const string EXTERNAL_GPS_DENIED_PATH = "image-matcher.exe";
|
||||||
|
|
||||||
|
public const string DEFAULT_ZMQ_INFERENCE_HOST = "127.0.0.1";
|
||||||
|
public const int DEFAULT_ZMQ_INFERENCE_PORT = 5227;
|
||||||
|
|
||||||
|
public const string DEFAULT_ZMQ_GPS_DENIED_HOST = "127.0.0.1";
|
||||||
|
public const int DEFAULT_ZMQ_GPS_DENIED_PORT = 5227;
|
||||||
|
|
||||||
public const string DEFAULT_ZMQ_HOST = "127.0.0.1";
|
|
||||||
public const int DEFAULT_ZMQ_PORT = 5127;
|
|
||||||
public const int DEFAULT_RETRY_COUNT = 25;
|
public const int DEFAULT_RETRY_COUNT = 25;
|
||||||
public const int DEFAULT_TIMEOUT_SECONDS = 5;
|
public const int DEFAULT_TIMEOUT_SECONDS = 5;
|
||||||
|
|
||||||
#endregion PythonConfig
|
public static readonly SecureAppConfig DefaultSecureAppConfig = new()
|
||||||
|
{
|
||||||
|
InferenceClientConfig = new InferenceClientConfig
|
||||||
|
{
|
||||||
|
ZeroMqHost = DEFAULT_ZMQ_INFERENCE_HOST,
|
||||||
|
ZeroMqPort = DEFAULT_ZMQ_INFERENCE_PORT,
|
||||||
|
OneTryTimeoutSeconds = DEFAULT_TIMEOUT_SECONDS,
|
||||||
|
RetryCount = DEFAULT_RETRY_COUNT,
|
||||||
|
ResourcesFolder = ""
|
||||||
|
},
|
||||||
|
GpsDeniedClientConfig = new GpsDeniedClientConfig
|
||||||
|
{
|
||||||
|
ZeroMqHost = DEFAULT_ZMQ_GPS_DENIED_HOST,
|
||||||
|
ZeroMqPort = DEFAULT_ZMQ_GPS_DENIED_PORT,
|
||||||
|
OneTryTimeoutSeconds = DEFAULT_TIMEOUT_SECONDS,
|
||||||
|
RetryCount = DEFAULT_RETRY_COUNT,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endregion ExternalClientsConfig
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using Azaion.CommonSecurity.DTO;
|
||||||
|
using Azaion.CommonSecurity.DTO.Commands;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Azaion.CommonSecurity.Services;
|
||||||
|
|
||||||
|
public interface IAuthProvider
|
||||||
|
{
|
||||||
|
void Login(ApiCredentials credentials);
|
||||||
|
User CurrentUser { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AuthProvider([FromKeyedServices(SecurityConstants.EXTERNAL_INFERENCE_PATH)] IExternalClient externalClient) : IAuthProvider
|
||||||
|
{
|
||||||
|
public User CurrentUser { get; private set; } = null!;
|
||||||
|
|
||||||
|
public void Login(ApiCredentials credentials)
|
||||||
|
{
|
||||||
|
externalClient.Send(RemoteCommand.Create(CommandType.Login, credentials));
|
||||||
|
var user = externalClient.Get<User>();
|
||||||
|
if (user == null)
|
||||||
|
throw new Exception("Can't get user from Auth provider");
|
||||||
|
|
||||||
|
CurrentUser = user;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
using Azaion.CommonSecurity.DTO;
|
||||||
|
using Azaion.CommonSecurity.DTO.Commands;
|
||||||
|
using MessagePack;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using NetMQ;
|
||||||
|
using NetMQ.Sockets;
|
||||||
|
|
||||||
|
namespace Azaion.CommonSecurity.Services;
|
||||||
|
|
||||||
|
public interface IExternalClient
|
||||||
|
{
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
void Send(RemoteCommand create);
|
||||||
|
T? Get<T>(int retries = 24, int tryTimeoutSeconds = 5, CancellationToken ct = default) where T : class;
|
||||||
|
byte[]? GetBytes(int retries = 24, int tryTimeoutSeconds = 5, CancellationToken ct = default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class BaseZeroMqExternalClient : IExternalClient
|
||||||
|
{
|
||||||
|
private readonly DealerSocket _dealer = new();
|
||||||
|
private readonly Guid _clientId = Guid.NewGuid();
|
||||||
|
|
||||||
|
private readonly ExternalClientConfig _externalClientConfig;
|
||||||
|
|
||||||
|
protected abstract string ClientPath { get; }
|
||||||
|
|
||||||
|
protected BaseZeroMqExternalClient(ExternalClientConfig config)
|
||||||
|
{
|
||||||
|
_externalClientConfig = config;
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var process = new Process();
|
||||||
|
process.StartInfo = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = ClientPath
|
||||||
|
//Arguments = $"-e {credentials.Email} -p {credentials.Password} -f {apiConfig.ResourcesFolder}",
|
||||||
|
//RedirectStandardOutput = true,
|
||||||
|
//RedirectStandardError = true,
|
||||||
|
//CreateNoWindow = true
|
||||||
|
};
|
||||||
|
|
||||||
|
process.OutputDataReceived += (_, e) => { if (e.Data != null) Console.WriteLine(e.Data); };
|
||||||
|
process.ErrorDataReceived += (_, e) => { if (e.Data != null) Console.WriteLine(e.Data); };
|
||||||
|
process.Start();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dealer.Options.Identity = Encoding.UTF8.GetBytes(_clientId.ToString("N"));
|
||||||
|
_dealer.Connect($"tcp://{_externalClientConfig.ZeroMqHost}:{_externalClientConfig.ZeroMqPort}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
if (!_dealer.IsDisposed)
|
||||||
|
{
|
||||||
|
_dealer.SendFrame(MessagePackSerializer.Serialize(new RemoteCommand(CommandType.Exit)));
|
||||||
|
_dealer.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Send(RemoteCommand command)
|
||||||
|
{
|
||||||
|
_dealer.SendFrame(MessagePackSerializer.Serialize(command));
|
||||||
|
}
|
||||||
|
|
||||||
|
public T? Get<T>(int retries = 24, int tryTimeoutSeconds = 5, CancellationToken ct = default) where T : class
|
||||||
|
{
|
||||||
|
var bytes = GetBytes(retries, tryTimeoutSeconds, ct);
|
||||||
|
return bytes != null ? MessagePackSerializer.Deserialize<T>(bytes, cancellationToken: ct) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[]? GetBytes(int retries = 24, int tryTimeoutSeconds = 5, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var tryNum = 0;
|
||||||
|
while (!ct.IsCancellationRequested && tryNum++ < retries)
|
||||||
|
{
|
||||||
|
if (!_dealer.TryReceiveFrameBytes(TimeSpan.FromSeconds(tryTimeoutSeconds), out var bytes))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ct.IsCancellationRequested)
|
||||||
|
throw new Exception($"Unable to get bytes after {tryNum} retries, {tryTimeoutSeconds} seconds each");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InferenceExternalClient(IOptions<InferenceClientConfig> inferenceClientConfig)
|
||||||
|
: BaseZeroMqExternalClient(inferenceClientConfig.Value)
|
||||||
|
{
|
||||||
|
protected override string ClientPath => SecurityConstants.EXTERNAL_INFERENCE_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GpsDeniedExternalClient(IOptions<GpsDeniedClientConfig> gpsDeniedClientConfig)
|
||||||
|
: BaseZeroMqExternalClient(gpsDeniedClientConfig.Value)
|
||||||
|
{
|
||||||
|
protected override string ClientPath => SecurityConstants.EXTERNAL_GPS_DENIED_PATH;
|
||||||
|
}
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using System.Text;
|
|
||||||
using Azaion.CommonSecurity.DTO;
|
|
||||||
using Azaion.CommonSecurity.DTO.Commands;
|
|
||||||
using MessagePack;
|
|
||||||
using NetMQ;
|
|
||||||
using NetMQ.Sockets;
|
|
||||||
|
|
||||||
namespace Azaion.CommonSecurity.Services;
|
|
||||||
|
|
||||||
public interface IResourceLoader
|
|
||||||
{
|
|
||||||
MemoryStream LoadFileFromPython(string fileName, string? folder = null);
|
|
||||||
void StopPython();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IAuthProvider
|
|
||||||
{
|
|
||||||
User CurrentUser { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PythonResourceLoader : IResourceLoader, IAuthProvider
|
|
||||||
{
|
|
||||||
private readonly DealerSocket _dealer = new();
|
|
||||||
private readonly Guid _clientId = Guid.NewGuid();
|
|
||||||
|
|
||||||
public User CurrentUser { get; set; } = null!;
|
|
||||||
|
|
||||||
public PythonResourceLoader(PythonConfig config)
|
|
||||||
{
|
|
||||||
StartPython();
|
|
||||||
_dealer.Options.Identity = Encoding.UTF8.GetBytes(_clientId.ToString("N"));
|
|
||||||
_dealer.Connect($"tcp://{config.ZeroMqHost}:{config.ZeroMqPort}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartPython()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var process = new Process();
|
|
||||||
process.StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = SecurityConstants.AZAION_INFERENCE_PATH,
|
|
||||||
//Arguments = $"-e {credentials.Email} -p {credentials.Password} -f {apiConfig.ResourcesFolder}",
|
|
||||||
//UseShellExecute = false,
|
|
||||||
//RedirectStandardOutput = true,
|
|
||||||
// RedirectStandardError = true,
|
|
||||||
//CreateNoWindow = true
|
|
||||||
};
|
|
||||||
|
|
||||||
process.OutputDataReceived += (_, e) => { if (e.Data != null) Console.WriteLine(e.Data); };
|
|
||||||
process.ErrorDataReceived += (_, e) => { if (e.Data != null) Console.WriteLine(e.Data); };
|
|
||||||
process.Start();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine(e);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Login(ApiCredentials credentials)
|
|
||||||
{
|
|
||||||
_dealer.SendFrame(RemoteCommand.Serialize(CommandType.Login, credentials));
|
|
||||||
var user = _dealer.Get<User>();
|
|
||||||
if (user == null)
|
|
||||||
throw new Exception("Can't get user from Auth provider");
|
|
||||||
|
|
||||||
CurrentUser = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StopPython()
|
|
||||||
{
|
|
||||||
if (!_dealer.IsDisposed)
|
|
||||||
{
|
|
||||||
_dealer.SendFrame(MessagePackSerializer.Serialize(new RemoteCommand(CommandType.Exit)));
|
|
||||||
_dealer.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public MemoryStream LoadFileFromPython(string fileName, string? folder = null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_dealer.SendFrame(RemoteCommand.Serialize(CommandType.Load, new LoadFileData(fileName, folder)));
|
|
||||||
|
|
||||||
if (!_dealer.TryReceiveFrameBytes(TimeSpan.FromSeconds(300), out var bytes))
|
|
||||||
throw new Exception($"Unable to receive {fileName}");
|
|
||||||
|
|
||||||
return new MemoryStream(bytes);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new Exception($"Failed to load fil0e '{fileName}': {ex.Message}", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using Azaion.CommonSecurity.DTO.Commands;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Azaion.CommonSecurity.Services;
|
||||||
|
|
||||||
|
public interface IResourceLoader
|
||||||
|
{
|
||||||
|
MemoryStream LoadFile(string fileName, string? folder = null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ResourceLoader([FromKeyedServices(SecurityConstants.EXTERNAL_INFERENCE_PATH)] IExternalClient externalClient) : IResourceLoader
|
||||||
|
{
|
||||||
|
public MemoryStream LoadFile(string fileName, string? folder = null)
|
||||||
|
{
|
||||||
|
externalClient.Send(RemoteCommand.Create(CommandType.Load, new LoadFileData(fileName, folder)));
|
||||||
|
var bytes = externalClient.GetBytes();
|
||||||
|
if (bytes == null)
|
||||||
|
throw new Exception($"Unable to receive {fileName}");
|
||||||
|
|
||||||
|
return new MemoryStream(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using MessagePack;
|
|
||||||
using NetMQ;
|
|
||||||
using NetMQ.Sockets;
|
|
||||||
|
|
||||||
namespace Azaion.CommonSecurity;
|
|
||||||
|
|
||||||
public static class ZeroMqExtensions
|
|
||||||
{
|
|
||||||
public static T? Get<T>(this DealerSocket dealer, Func<byte[], bool>? shouldInterceptFn = null, int retries = 24, int tryTimeoutSeconds = 5, CancellationToken ct = default) where T : class
|
|
||||||
{
|
|
||||||
var tryNum = 0;
|
|
||||||
while (!ct.IsCancellationRequested && tryNum++ < retries)
|
|
||||||
{
|
|
||||||
if (!dealer.TryReceiveFrameBytes(TimeSpan.FromSeconds(tryTimeoutSeconds), out var bytes))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (shouldInterceptFn != null && shouldInterceptFn(bytes))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return MessagePackSerializer.Deserialize<T>(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ct.IsCancellationRequested)
|
|
||||||
throw new Exception($"Unable to get {typeof(T).Name} after {tryNum} retries, {tryTimeoutSeconds} seconds each");
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,6 +9,7 @@ cdef class AIRecognitionConfig:
|
|||||||
|
|
||||||
cdef public bytes file_data
|
cdef public bytes file_data
|
||||||
cdef public list[str] paths
|
cdef public list[str] paths
|
||||||
|
cdef public int model_batch_size
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef from_msgpack(bytes data)
|
cdef from_msgpack(bytes data)
|
||||||
@@ -11,7 +11,8 @@ cdef class AIRecognitionConfig:
|
|||||||
tracking_intersection_threshold,
|
tracking_intersection_threshold,
|
||||||
|
|
||||||
file_data,
|
file_data,
|
||||||
paths
|
paths,
|
||||||
|
model_batch_size
|
||||||
):
|
):
|
||||||
self.frame_period_recognition = frame_period_recognition
|
self.frame_period_recognition = frame_period_recognition
|
||||||
self.frame_recognition_seconds = frame_recognition_seconds
|
self.frame_recognition_seconds = frame_recognition_seconds
|
||||||
@@ -23,26 +24,29 @@ cdef class AIRecognitionConfig:
|
|||||||
|
|
||||||
self.file_data = file_data
|
self.file_data = file_data
|
||||||
self.paths = paths
|
self.paths = paths
|
||||||
|
self.model_batch_size = model_batch_size
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return (f'frame_seconds : {self.frame_recognition_seconds}, distance_confidence : {self.tracking_distance_confidence}, '
|
return (f'frame_seconds : {self.frame_recognition_seconds}, distance_confidence : {self.tracking_distance_confidence}, '
|
||||||
f'probability_increase : {self.tracking_probability_increase}, '
|
f'probability_increase : {self.tracking_probability_increase}, '
|
||||||
f'intersection_threshold : {self.tracking_intersection_threshold}, '
|
f'intersection_threshold : {self.tracking_intersection_threshold}, '
|
||||||
f'frame_period_recognition : {self.frame_period_recognition}, '
|
f'frame_period_recognition : {self.frame_period_recognition}, '
|
||||||
f'paths: {self.paths}')
|
f'paths: {self.paths}, '
|
||||||
|
f'model_batch_size: {self.model_batch_size}')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef from_msgpack(bytes data):
|
cdef from_msgpack(bytes data):
|
||||||
unpacked = unpackb(data, strict_map_key=False)
|
unpacked = unpackb(data, strict_map_key=False)
|
||||||
return AIRecognitionConfig(
|
return AIRecognitionConfig(
|
||||||
unpacked.get("FramePeriodRecognition", 0),
|
unpacked.get("f_pr", 0),
|
||||||
unpacked.get("FrameRecognitionSeconds", 0.0),
|
unpacked.get("f_rs", 0.0),
|
||||||
unpacked.get("ProbabilityThreshold", 0.0),
|
unpacked.get("pt", 0.0),
|
||||||
|
|
||||||
unpacked.get("TrackingDistanceConfidence", 0.0),
|
unpacked.get("t_dc", 0.0),
|
||||||
unpacked.get("TrackingProbabilityIncrease", 0.0),
|
unpacked.get("t_pi", 0.0),
|
||||||
unpacked.get("TrackingIntersectionThreshold", 0.0),
|
unpacked.get("t_it", 0.0),
|
||||||
|
|
||||||
unpacked.get("Data", b''),
|
unpacked.get("d", b''),
|
||||||
unpacked.get("Paths", []),
|
unpacked.get("p", []),
|
||||||
|
unpacked.get("m_bs")
|
||||||
)
|
)
|
||||||
@@ -1 +1 @@
|
|||||||
zmq_port: 5128
|
zmq_port: 5127
|
||||||
@@ -10,7 +10,6 @@ cdef str AI_MODEL_FILE_BIG # AI Model file (BIG part)
|
|||||||
cdef str AI_MODEL_FILE_SMALL # AI Model file (small part)
|
cdef str AI_MODEL_FILE_SMALL # AI Model file (small part)
|
||||||
|
|
||||||
cdef bytes DONE_SIGNAL
|
cdef bytes DONE_SIGNAL
|
||||||
cdef int MODEL_BATCH_SIZE
|
|
||||||
|
|
||||||
|
|
||||||
cdef log(str log_message, bytes client_id=*)
|
cdef log(str log_message, bytes client_id=*)
|
||||||
@@ -12,7 +12,6 @@ cdef str AI_MODEL_FILE_BIG = "azaion.onnx.big"
|
|||||||
cdef str AI_MODEL_FILE_SMALL = "azaion.onnx.small"
|
cdef str AI_MODEL_FILE_SMALL = "azaion.onnx.small"
|
||||||
|
|
||||||
cdef bytes DONE_SIGNAL = b"DONE"
|
cdef bytes DONE_SIGNAL = b"DONE"
|
||||||
cdef int MODEL_BATCH_SIZE = 4
|
|
||||||
|
|
||||||
cdef log(str log_message, bytes client_id=None):
|
cdef log(str log_message, bytes client_id=None):
|
||||||
local_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
|
local_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ cdef class Inference:
|
|||||||
images.append(m)
|
images.append(m)
|
||||||
# images first, it's faster
|
# images first, it's faster
|
||||||
if len(images) > 0:
|
if len(images) > 0:
|
||||||
for chunk in self.split_list_extend(images, constants.MODEL_BATCH_SIZE):
|
for chunk in self.split_list_extend(images, ai_config.model_batch_size):
|
||||||
print(f'run inference on {" ".join(chunk)}...')
|
print(f'run inference on {" ".join(chunk)}...')
|
||||||
self._process_images(cmd, ai_config, chunk)
|
self._process_images(cmd, ai_config, chunk)
|
||||||
if len(videos) > 0:
|
if len(videos) > 0:
|
||||||
@@ -158,7 +158,7 @@ cdef class Inference:
|
|||||||
batch_frames.append(frame)
|
batch_frames.append(frame)
|
||||||
batch_timestamps.append(int(v_input.get(cv2.CAP_PROP_POS_MSEC)))
|
batch_timestamps.append(int(v_input.get(cv2.CAP_PROP_POS_MSEC)))
|
||||||
|
|
||||||
if len(batch_frames) == constants.MODEL_BATCH_SIZE:
|
if len(batch_frames) == ai_config.model_batch_size:
|
||||||
input_blob = self.preprocess(batch_frames)
|
input_blob = self.preprocess(batch_frames)
|
||||||
outputs = self.session.run(None, {self.model_input: input_blob})
|
outputs = self.session.run(None, {self.model_input: input_blob})
|
||||||
list_detections = self.postprocess(outputs, ai_config)
|
list_detections = self.postprocess(outputs, ai_config)
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ msgpack
|
|||||||
pyjwt
|
pyjwt
|
||||||
zmq
|
zmq
|
||||||
requests
|
requests
|
||||||
|
pyyaml
|
||||||
+36
-23
@@ -33,7 +33,10 @@ public partial class App
|
|||||||
private IMediator _mediator = null!;
|
private IMediator _mediator = null!;
|
||||||
private FormState _formState = null!;
|
private FormState _formState = null!;
|
||||||
|
|
||||||
private PythonResourceLoader _resourceLoader = null!;
|
private InferenceExternalClient _inferenceClient = null!;
|
||||||
|
private IResourceLoader _resourceLoader = null!;
|
||||||
|
private IAuthProvider _authProvider = null!;
|
||||||
|
|
||||||
private Stream _securedConfig = null!;
|
private Stream _securedConfig = null!;
|
||||||
private static readonly Guid KeyPressTaskId = Guid.NewGuid();
|
private static readonly Guid KeyPressTaskId = Guid.NewGuid();
|
||||||
|
|
||||||
@@ -55,41 +58,44 @@ public partial class App
|
|||||||
"Azaion.Dataset"
|
"Azaion.Dataset"
|
||||||
];
|
];
|
||||||
|
|
||||||
private static PythonConfig ReadPythonConfig()
|
private static SecureAppConfig ReadSecureAppConfig()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!File.Exists(SecurityConstants.CONFIG_PATH))
|
if (!File.Exists(SecurityConstants.CONFIG_PATH))
|
||||||
throw new FileNotFoundException(SecurityConstants.CONFIG_PATH);
|
throw new FileNotFoundException(SecurityConstants.CONFIG_PATH);
|
||||||
var configStr = File.ReadAllText(SecurityConstants.CONFIG_PATH);
|
var configStr = File.ReadAllText(SecurityConstants.CONFIG_PATH);
|
||||||
return JsonConvert.DeserializeObject<SecureAppConfig>(configStr)!.PythonConfig;
|
var config = JsonConvert.DeserializeObject<SecureAppConfig>(configStr);
|
||||||
|
|
||||||
|
return config ?? SecurityConstants.DefaultSecureAppConfig;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.WriteLine(e);
|
Console.WriteLine(e);
|
||||||
return new PythonConfig
|
return SecurityConstants.DefaultSecureAppConfig;
|
||||||
{
|
|
||||||
ZeroMqHost = SecurityConstants.DEFAULT_ZMQ_HOST,
|
|
||||||
ZeroMqPort = SecurityConstants.DEFAULT_ZMQ_PORT,
|
|
||||||
OneTryTimeoutSeconds = SecurityConstants.DEFAULT_TIMEOUT_SECONDS,
|
|
||||||
RetryCount = SecurityConstants.DEFAULT_RETRY_COUNT,
|
|
||||||
|
|
||||||
ResourcesFolder = ""
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartLogin()
|
private void StartLogin()
|
||||||
{
|
{
|
||||||
new ConfigUpdater().CheckConfig();
|
new ConfigUpdater().CheckConfig();
|
||||||
|
var secureAppConfig = ReadSecureAppConfig();
|
||||||
|
_inferenceClient = new InferenceExternalClient(new OptionsWrapper<InferenceClientConfig>(secureAppConfig.InferenceClientConfig));
|
||||||
|
_resourceLoader = new ResourceLoader(_inferenceClient);
|
||||||
|
_authProvider = new AuthProvider(_inferenceClient);
|
||||||
|
|
||||||
var login = new Login();
|
var login = new Login();
|
||||||
var pythonConfig = ReadPythonConfig();
|
login.Closed += (sender, args) =>
|
||||||
_resourceLoader = new PythonResourceLoader(pythonConfig);
|
{
|
||||||
|
if (!login.MainSuiteOpened)
|
||||||
|
_inferenceClient.Stop();
|
||||||
|
};
|
||||||
|
|
||||||
login.CredentialsEntered += (_, credentials) =>
|
login.CredentialsEntered += (_, credentials) =>
|
||||||
{
|
{
|
||||||
credentials.Folder = pythonConfig.ResourcesFolder;
|
credentials.Folder = secureAppConfig.InferenceClientConfig.ResourcesFolder;
|
||||||
_resourceLoader.Login(credentials);
|
_authProvider.Login(credentials);
|
||||||
_securedConfig = _resourceLoader.LoadFileFromPython("secured-config.json");
|
_securedConfig = _resourceLoader.LoadFile("secured-config.json");
|
||||||
|
|
||||||
AppDomain.CurrentDomain.AssemblyResolve += (_, a) =>
|
AppDomain.CurrentDomain.AssemblyResolve += (_, a) =>
|
||||||
{
|
{
|
||||||
@@ -98,7 +104,7 @@ public partial class App
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var stream = _resourceLoader.LoadFileFromPython($"{assemblyName}.dll");
|
var stream = _resourceLoader.LoadFile($"{assemblyName}.dll");
|
||||||
return Assembly.Load(stream.ToArray());
|
return Assembly.Load(stream.ToArray());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -147,18 +153,25 @@ public partial class App
|
|||||||
services.AddSingleton<MainSuite>();
|
services.AddSingleton<MainSuite>();
|
||||||
services.AddSingleton<IHardwareService, HardwareService>();
|
services.AddSingleton<IHardwareService, HardwareService>();
|
||||||
|
|
||||||
services.AddSingleton<IResourceLoader>(_resourceLoader);
|
|
||||||
services.AddSingleton<IAuthProvider>(_resourceLoader);
|
|
||||||
services.AddSingleton<IInferenceService, PythonInferenceService>();
|
|
||||||
|
|
||||||
services.Configure<AppConfig>(context.Configuration);
|
services.Configure<AppConfig>(context.Configuration);
|
||||||
services.ConfigureSection<PythonConfig>(context.Configuration);
|
|
||||||
services.ConfigureSection<QueueConfig>(context.Configuration);
|
services.ConfigureSection<QueueConfig>(context.Configuration);
|
||||||
services.ConfigureSection<DirectoriesConfig>(context.Configuration);
|
services.ConfigureSection<DirectoriesConfig>(context.Configuration);
|
||||||
services.ConfigureSection<AnnotationConfig>(context.Configuration);
|
services.ConfigureSection<AnnotationConfig>(context.Configuration);
|
||||||
services.ConfigureSection<AIRecognitionConfig>(context.Configuration);
|
services.ConfigureSection<AIRecognitionConfig>(context.Configuration);
|
||||||
services.ConfigureSection<ThumbnailConfig>(context.Configuration);
|
services.ConfigureSection<ThumbnailConfig>(context.Configuration);
|
||||||
|
|
||||||
|
#region External Services
|
||||||
|
|
||||||
|
services.ConfigureSection<InferenceClientConfig>(context.Configuration);
|
||||||
|
services.ConfigureSection<GpsDeniedClientConfig>(context.Configuration);
|
||||||
|
services.AddKeyedSingleton<IExternalClient>(SecurityConstants.EXTERNAL_INFERENCE_PATH, _inferenceClient);
|
||||||
|
services.AddKeyedSingleton<IExternalClient, GpsDeniedExternalClient>(SecurityConstants.EXTERNAL_GPS_DENIED_PATH);
|
||||||
|
services.AddSingleton<IResourceLoader>(_resourceLoader);
|
||||||
|
services.AddSingleton<IAuthProvider>(_authProvider);
|
||||||
|
services.AddSingleton<IInferenceService, InferenceService>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
services.AddSingleton<IConfigUpdater, ConfigUpdater>();
|
services.AddSingleton<IConfigUpdater, ConfigUpdater>();
|
||||||
services.AddSingleton<Annotator.Annotator>();
|
services.AddSingleton<Annotator.Annotator>();
|
||||||
services.AddSingleton<DatasetExplorer>();
|
services.AddSingleton<DatasetExplorer>();
|
||||||
|
|||||||
@@ -60,8 +60,8 @@
|
|||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="Build">
|
<Target Name="PostBuild" AfterTargets="Build">
|
||||||
<MakeDir Directories="$(TargetDir)dummy" />
|
<MakeDir Directories="$(TargetDir)dummy" />
|
||||||
<Move SourceFiles="$(TargetDir)Azaion.Annotator.dll" DestinationFolder="$(TargetDir)dummy" />
|
<Copy SourceFiles="$(TargetDir)Azaion.Annotator.dll" DestinationFolder="$(TargetDir)dummy" />
|
||||||
<Move SourceFiles="$(TargetDir)Azaion.Dataset.dll" DestinationFolder="$(TargetDir)dummy" />
|
<Copy SourceFiles="$(TargetDir)Azaion.Dataset.dll" DestinationFolder="$(TargetDir)dummy" />
|
||||||
<Exec Command="upload.cmd $(ConfigurationName) stage" />
|
<Exec Command="upload.cmd $(ConfigurationName) stage" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ namespace Azaion.Suite;
|
|||||||
|
|
||||||
public partial class Login
|
public partial class Login
|
||||||
{
|
{
|
||||||
|
public bool MainSuiteOpened { get; set; } = false;
|
||||||
|
|
||||||
public Login()
|
public Login()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -20,6 +22,7 @@ public partial class Login
|
|||||||
LoginBtn.Cursor = Cursors.Wait;
|
LoginBtn.Cursor = Cursors.Wait;
|
||||||
Cursor = Cursors.Wait;
|
Cursor = Cursors.Wait;
|
||||||
CredentialsEntered?.Invoke(this, new ApiCredentials(TbEmail.Text, TbPassword.Password));
|
CredentialsEntered?.Invoke(this, new ApiCredentials(TbEmail.Text, TbPassword.Password));
|
||||||
|
MainSuiteOpened = true;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public partial class MainSuite
|
|||||||
private readonly IDbFactory _dbFactory;
|
private readonly IDbFactory _dbFactory;
|
||||||
private readonly Dictionary<WindowEnum, Window> _openedWindows = new();
|
private readonly Dictionary<WindowEnum, Window> _openedWindows = new();
|
||||||
private readonly IResourceLoader _resourceLoader;
|
private readonly IResourceLoader _resourceLoader;
|
||||||
|
private readonly IEnumerable<IExternalClient> _externalClients;
|
||||||
private static readonly Guid SaveConfigTaskId = Guid.NewGuid();
|
private static readonly Guid SaveConfigTaskId = Guid.NewGuid();
|
||||||
|
|
||||||
public MainSuite(IOptions<AppConfig> appConfig,
|
public MainSuite(IOptions<AppConfig> appConfig,
|
||||||
@@ -33,7 +34,8 @@ public partial class MainSuite
|
|||||||
IServiceProvider sp,
|
IServiceProvider sp,
|
||||||
IGalleryService galleryService,
|
IGalleryService galleryService,
|
||||||
IDbFactory dbFactory,
|
IDbFactory dbFactory,
|
||||||
IResourceLoader resourceLoader)
|
IResourceLoader resourceLoader,
|
||||||
|
IEnumerable<IExternalClient> externalClients)
|
||||||
{
|
{
|
||||||
_configUpdater = configUpdater;
|
_configUpdater = configUpdater;
|
||||||
_modules = modules;
|
_modules = modules;
|
||||||
@@ -41,6 +43,7 @@ public partial class MainSuite
|
|||||||
_galleryService = galleryService;
|
_galleryService = galleryService;
|
||||||
_dbFactory = dbFactory;
|
_dbFactory = dbFactory;
|
||||||
_resourceLoader = resourceLoader;
|
_resourceLoader = resourceLoader;
|
||||||
|
_externalClients = externalClients;
|
||||||
_appConfig = appConfig.Value;
|
_appConfig = appConfig.Value;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Loaded += OnLoaded;
|
Loaded += OnLoaded;
|
||||||
@@ -111,10 +114,13 @@ public partial class MainSuite
|
|||||||
_openedWindows[module.WindowEnum] = window;
|
_openedWindows[module.WindowEnum] = window;
|
||||||
window.Closed += (_, _) =>
|
window.Closed += (_, _) =>
|
||||||
{
|
{
|
||||||
_resourceLoader.StopPython();
|
|
||||||
_openedWindows.Remove(module.WindowEnum);
|
_openedWindows.Remove(module.WindowEnum);
|
||||||
if (!_openedWindows.Any())
|
if (_openedWindows.Any())
|
||||||
Close();
|
return;
|
||||||
|
|
||||||
|
foreach (var client in _externalClients)
|
||||||
|
client.Stop();
|
||||||
|
Close();
|
||||||
};
|
};
|
||||||
window.Show();
|
window.Show();
|
||||||
window.Activate();
|
window.Activate();
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
{
|
{
|
||||||
"PythonConfig": {
|
"InferenceClientConfig": {
|
||||||
"ZeroMqHost": "127.0.0.1",
|
"ZeroMqHost": "127.0.0.1",
|
||||||
"ZeroMqPort": 5127,
|
"ZeroMqPort": 5127,
|
||||||
"RetryCount": 25,
|
"RetryCount": 25,
|
||||||
"TimeoutSeconds": 5,
|
"TimeoutSeconds": 5,
|
||||||
"ResourcesFolder": "stage"
|
"ResourcesFolder": "stage"
|
||||||
},
|
},
|
||||||
|
"GpsDeniedClientConfig": {
|
||||||
|
"ZeroMqHost": "127.0.0.1",
|
||||||
|
"ZeroMqPort": 5227,
|
||||||
|
"RetryCount": 25,
|
||||||
|
"TimeoutSeconds": 5
|
||||||
|
},
|
||||||
"DirectoriesConfig": {
|
"DirectoriesConfig": {
|
||||||
"VideosDirectory": "E:\\Azaion6",
|
"VideosDirectory": "E:\\Azaion6",
|
||||||
"LabelsDirectory": "E:\\labels",
|
"LabelsDirectory": "E:\\labels",
|
||||||
@@ -44,7 +50,9 @@
|
|||||||
|
|
||||||
"TrackingDistanceConfidence": 0.15,
|
"TrackingDistanceConfidence": 0.15,
|
||||||
"TrackingProbabilityIncrease": 15.0,
|
"TrackingProbabilityIncrease": 15.0,
|
||||||
"TrackingIntersectionThreshold": 0.8
|
"TrackingIntersectionThreshold": 0.8,
|
||||||
|
|
||||||
|
"ModelBatchSize": 2
|
||||||
},
|
},
|
||||||
"ThumbnailConfig": { "Size": "240,135", "Border": 10 },
|
"ThumbnailConfig": { "Size": "240,135", "Border": 10 },
|
||||||
"MapConfig":
|
"MapConfig":
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
{
|
{
|
||||||
"PythonConfig": {
|
"InferenceClientConfig": {
|
||||||
"ZeroMqHost": "127.0.0.1",
|
"ZeroMqHost": "127.0.0.1",
|
||||||
"ZeroMqPort": 5131,
|
"ZeroMqPort": 5131,
|
||||||
"RetryCount": 25,
|
"RetryCount": 25,
|
||||||
|
"TimeoutSeconds": 5,
|
||||||
|
"ResourcesFolder": "stage"
|
||||||
|
},
|
||||||
|
"GpsDeniedClientConfig": {
|
||||||
|
"ZeroMqHost": "127.0.0.1",
|
||||||
|
"ZeroMqPort": 5231,
|
||||||
|
"RetryCount": 25,
|
||||||
"TimeoutSeconds": 5
|
"TimeoutSeconds": 5
|
||||||
},
|
},
|
||||||
"DirectoriesConfig": {
|
"DirectoriesConfig": {
|
||||||
|
|||||||
Reference in New Issue
Block a user