make python app load a bit eariler, making startup a bit faster

This commit is contained in:
Alex Bezdieniezhnykh
2025-02-13 18:13:15 +02:00
parent e329e5bb67
commit cfd5483a18
31 changed files with 183 additions and 124 deletions
+2 -2
View File
@@ -148,13 +148,13 @@
Grid.Column="0"
Name="LvFiles"
Background="Black"
SelectedItem="{Binding Path=SelectedVideo}" Foreground="#FFA4AFCC"
SelectedItem="{Binding Path=SelectedVideo}" Foreground="#FFEEEEEE"
>
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding HasAnnotations}" Value="true">
<Setter Property="Background" Value="Gray"/>
<Setter Property="Background" Value="#FF505050"/>
</DataTrigger>
</Style.Triggers>
<EventSetter Event="ContextMenuOpening" Handler="LvFilesContextOpening"></EventSetter>
+3 -8
View File
@@ -41,7 +41,6 @@ public partial class Annotator
private readonly AnnotationService _annotationService;
private readonly IDbFactory _dbFactory;
private readonly IInferenceService _inferenceService;
private readonly IResourceLoader _resourceLoader;
private ObservableCollection<DetectionClass> AnnotationClasses { get; set; } = new();
private bool _suspendLayout;
@@ -71,8 +70,7 @@ public partial class Annotator
ILogger<Annotator> logger,
AnnotationService annotationService,
IDbFactory dbFactory,
IInferenceService inferenceService,
IResourceLoader resourceLoader)
IInferenceService inferenceService)
{
InitializeComponent();
_appConfig = appConfig.Value;
@@ -86,7 +84,6 @@ public partial class Annotator
_annotationService = annotationService;
_dbFactory = dbFactory;
_inferenceService = inferenceService;
_resourceLoader = resourceLoader;
Loaded += OnLoaded;
Closed += OnFormClosed;
@@ -401,7 +398,6 @@ public partial class Annotator
private void OnFormClosed(object? sender, EventArgs e)
{
_resourceLoader.StopPython();
MainCancellationSource.Cancel();
DetectionCancellationSource.Cancel();
_mediaPlayer.Stop();
@@ -454,6 +450,7 @@ public partial class Annotator
_appConfig.DirectoriesConfig.VideosDirectory = dlg.FileName;
TbFolder.Text = dlg.FileName;
await Task.CompletedTask;
}
private void TbFilter_OnTextChanged(object sender, TextChangedEventArgs e)
@@ -497,8 +494,6 @@ public partial class Annotator
LvFilesContextMenu.DataContext = listItem!.DataContext;
}
private (TimeSpan Time, List<Detection> Detections)? _previousDetection;
public void AutoDetect(object sender, RoutedEventArgs e)
{
if (IsInferenceNow)
@@ -560,7 +555,7 @@ public partial class Annotator
try
{
var annotation = await _annotationService.SaveAnnotation(annotationImage);
if (annotation.OriginalMediaName != _formState.CurrentMedia.FName)
if (annotation.OriginalMediaName != _formState.CurrentMedia?.FName)
return;
AddAnnotation(annotation);
@@ -14,4 +14,5 @@ public class AIRecognitionConfig
[Key(nameof(TrackingIntersectionThreshold))] public double TrackingIntersectionThreshold { get; set; }
[Key(nameof(Data))] public byte[] Data { get; set; }
[Key(nameof(Paths))] public List<string> Paths { get; set; }
}
+3 -3
View File
@@ -26,9 +26,9 @@ public class PythonInferenceService(ILogger<PythonInferenceService> logger, IOpt
dealer.Options.Identity = Encoding.UTF8.GetBytes(clientId.ToString("N"));
dealer.Connect($"tcp://{SecurityConstants.ZMQ_HOST}:{SecurityConstants.ZMQ_PORT}");
var data = MessagePackSerializer.Serialize(aiConfigOptions.Value);
var filename = JsonConvert.SerializeObject(mediaPaths);
dealer.SendFrame(MessagePackSerializer.Serialize(new RemoteCommand(CommandType.Inference, filename, data)));
var aiConfig = aiConfigOptions.Value;
aiConfig.Paths = mediaPaths;
dealer.SendFrame(RemoteCommand.Serialize(CommandType.Inference, aiConfig));
while (!ct.IsCancellationRequested)
{
+10 -1
View File
@@ -1,7 +1,16 @@
namespace Azaion.CommonSecurity.DTO;
using MessagePack;
namespace Azaion.CommonSecurity.DTO;
[MessagePackObject]
public class ApiCredentials(string email, string password) : EventArgs
{
[Key(nameof(Email))]
public string Email { get; set; } = email;
[Key(nameof(Password))]
public string Password { get; set; } = password;
[Key(nameof(Folder))]
public string Folder { get; set; } = null!;
}
@@ -3,22 +3,36 @@
namespace Azaion.CommonSecurity.DTO.Commands;
[MessagePackObject]
public class RemoteCommand(CommandType commandType, string? filename = null, byte[]? data = null)
public class RemoteCommand(CommandType commandType, byte[]? data = null)
{
[Key("CommandType")]
public CommandType CommandType { get; set; } = commandType;
[Key("Filename")]
public string? Filename { get; set; } = filename;
[Key("Data")]
public byte[]? Data { get; set; } = data;
public static byte[] Serialize<T>(CommandType commandType, T data) where T : class
{
var dataBytes = MessagePackSerializer.Serialize(data);
return MessagePackSerializer.Serialize(new RemoteCommand(commandType, dataBytes ));
}
}
[MessagePackObject]
public class LoadFileData(string filename, string? folder = null )
{
[Key(nameof(Folder))]
public string? Folder { get; set; } = folder;
[Key(nameof(Filename))]
public string Filename { get; set; } = filename;
}
public enum CommandType
{
None = 0,
GetUser = 10,
Login = 10,
Load = 20,
Inference = 30,
StopInference = 40,
+2 -2
View File
@@ -6,8 +6,8 @@ namespace Azaion.CommonSecurity.DTO;
[MessagePackObject]
public class User
{
[Key("i")]public string Id { get; set; }
[Key("e")]public string Email { get; set; }
[Key("i")] public string Id { get; set; } = "";
[Key("e")] public string Email { get; set; } = "";
[Key("r")]public RoleEnum Role { get; set; }
//For deserializing
@@ -10,7 +10,7 @@ namespace Azaion.CommonSecurity.Services;
public interface IResourceLoader
{
MemoryStream LoadFileFromPython(string fileName);
MemoryStream LoadFileFromPython(string fileName, string? folder = null);
void StopPython();
}
@@ -25,29 +25,22 @@ public class PythonResourceLoader : IResourceLoader, IAuthProvider
private readonly DealerSocket _dealer = new();
private readonly Guid _clientId = Guid.NewGuid();
public User CurrentUser { get; }
public User CurrentUser { get; set; }
public PythonResourceLoader(ApiConfig apiConfig, ApiCredentials credentials, AzaionApiClient api)
public PythonResourceLoader()
{
StartPython(apiConfig, credentials);
StartPython();
_dealer.Options.Identity = Encoding.UTF8.GetBytes(_clientId.ToString("N"));
_dealer.Connect($"tcp://{SecurityConstants.ZMQ_HOST}:{SecurityConstants.ZMQ_PORT}");
_dealer.SendFrame(MessagePackSerializer.Serialize(new RemoteCommand(CommandType.GetUser)));
var user = _dealer.Get<User>();
if (user == null)
throw new Exception("Can't get user from Auth provider");
CurrentUser = user;
}
private void StartPython( ApiConfig apiConfig, ApiCredentials credentials)
private void StartPython()
{
using var process = new Process();
process.StartInfo = new ProcessStartInfo
{
FileName = SecurityConstants.AZAION_INFERENCE_PATH,
Arguments = $"-e {credentials.Email} -p {credentials.Password} -f {apiConfig.ResourcesFolder}",
//Arguments = $"-e {credentials.Email} -p {credentials.Password} -f {apiConfig.ResourcesFolder}",
//UseShellExecute = false,
//RedirectStandardOutput = true,
// RedirectStandardError = true,
@@ -59,17 +52,27 @@ public class PythonResourceLoader : IResourceLoader, IAuthProvider
process.Start();
}
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()
{
_dealer.SendFrame(MessagePackSerializer.Serialize(new RemoteCommand(CommandType.Exit)));
_dealer?.Close();
_dealer.Close();
}
public MemoryStream LoadFileFromPython(string fileName)
public MemoryStream LoadFileFromPython(string fileName, string? folder = null)
{
try
{
_dealer.SendFrame(MessagePackSerializer.Serialize(new RemoteCommand(CommandType.Load, fileName)));
_dealer.SendFrame(RemoteCommand.Serialize(CommandType.Load, new LoadFileData(fileName, folder)));
if (!_dealer.TryReceiveFrameBytes(TimeSpan.FromSeconds(3), out var bytes))
throw new Exception($"Unable to receive {fileName}");
+5 -2
View File
@@ -1,7 +1,10 @@
from user cimport User
from credentials cimport Credentials
from file_data cimport FileData
cdef class ApiClient:
cdef str email, password, token, folder, token_file, api_url
cdef public Credentials credentials
cdef str token, folder, api_url
cdef User user
cdef get_encryption_key(self, str hardware_hash)
@@ -9,7 +12,7 @@ cdef class ApiClient:
cdef set_token(self, str token)
cdef get_user(self)
cdef load_bytes(self, str filename)
cdef load_bytes(self, FileData file_data)
cdef load_ai_model(self)
cdef load_queue_config(self)
+11 -18
View File
@@ -9,33 +9,25 @@ from hardware_service cimport HardwareService, HardwareInfo
from security cimport Security
from io import BytesIO
from user cimport User, RoleEnum
from file_data cimport FileData
cdef class ApiClient:
"""Handles API authentication and downloading of the AI model."""
def __init__(self, str email, str password, str folder):
self.email = email
self.password = password
self.folder = folder
def __init__(self):
self.credentials = None
self.user = None
if os.path.exists(<str>constants.TOKEN_FILE):
with open(<str>constants.TOKEN_FILE, "r") as file:
self.set_token(<str>file.read().strip())
else:
self.token = None
cdef get_encryption_key(self, str hardware_hash):
cdef str key = f'{self.email}-{self.password}-{hardware_hash}-#%@AzaionKey@%#---'
cdef str key = f'{self.credentials.email}-{self.credentials.password}-{hardware_hash}-#%@AzaionKey@%#---'
return Security.calc_hash(key)
cdef login(self):
response = requests.post(f"{constants.API_URL}/login",
json={"email": self.email, "password": self.password})
json={"email": self.credentials.email, "password": self.credentials.password})
response.raise_for_status()
token = response.json()["token"]
self.set_token(token)
with open(<str>constants.TOKEN_FILE, 'w') as file:
file.write(token)
cdef set_token(self, str token):
self.token = token
@@ -68,14 +60,15 @@ cdef class ApiClient:
self.login()
return self.user
cdef load_bytes(self, str filename):
cdef load_bytes(self, FileData file_data):
folder = file_data.folder or self.credentials.folder
hardware_service = HardwareService()
cdef HardwareInfo hardware = hardware_service.get_hardware_info()
if self.token is None:
self.login()
url = f"{constants.API_URL}/resources/get/{self.folder}"
url = f"{constants.API_URL}/resources/get/{folder}"
headers = {
"Authorization": f"Bearer {self.token}",
"Content-Type": "application/json"
@@ -83,9 +76,9 @@ cdef class ApiClient:
payload = json.dumps(
{
"password": self.password,
"password": self.credentials.password,
"hardware": hardware.to_json_object(),
"fileName": filename
"fileName": file_data.filename
}, indent=4)
response = requests.post(url, data=payload, headers=headers, stream=True)
@@ -104,7 +97,7 @@ cdef class ApiClient:
stream = BytesIO(response.raw.read())
data = Security.decrypt_to(stream, key)
print(f'loaded file: {filename}, {len(data)} bytes')
print(f'loaded file: {file_data.filename}, {len(data)} bytes')
return data
cdef load_ai_model(self):
+4 -2
View File
@@ -7,13 +7,15 @@ pyinstaller --onefile ^
--collect-all cryptography ^
--collect-all cv2 ^
--collect-all onnxruntime ^
--hidden-import constants ^
--hidden-import annotation ^
--hidden-import credentials ^
--hidden-import file_data ^
--hidden-import user ^
--hidden-import security ^
--hidden-import secure_model ^
--hidden-import api_client ^
--hidden-import hardware_service ^
--hidden-import constants ^
--hidden-import annotation ^
--hidden-import remote_command ^
--hidden-import ai_config ^
--hidden-import inference ^
-1
View File
@@ -5,7 +5,6 @@ cdef str COMMANDS_QUEUE # Name of the commands queue in rabbit
cdef str ANNOTATIONS_QUEUE # Name of the annotations queue in rabbit
cdef str API_URL # Base URL for the external API
cdef str TOKEN_FILE # Name of the token file where temporary token would be stored
cdef str QUEUE_CONFIG_FILENAME # queue config filename to load from api
cdef str AI_MODEL_FILE # AI Model file
-1
View File
@@ -5,7 +5,6 @@ cdef str COMMANDS_QUEUE = "azaion-commands"
cdef str ANNOTATIONS_QUEUE = "azaion-annotations"
cdef str API_URL = "https://api.azaion.com" # Base URL for the external API
cdef str TOKEN_FILE = "token"
cdef str QUEUE_CONFIG_FILENAME = "secured-config.json"
cdef str AI_MODEL_FILE = "azaion.onnx"
+7
View File
@@ -0,0 +1,7 @@
cdef class Credentials:
cdef public str email
cdef public str password
cdef public str folder
@staticmethod
cdef from_msgpack(bytes data)
+17
View File
@@ -0,0 +1,17 @@
from msgpack import unpackb
cdef class Credentials:
def __init__(self, str email, str password, str folder):
self.email = email
self.password = password
self.folder = folder
@staticmethod
cdef from_msgpack(bytes data):
unpacked = unpackb(data, strict_map_key=False)
return Credentials(
unpacked.get("Email"),
unpacked.get("Password"),
unpacked.get("Folder"))
+6
View File
@@ -0,0 +1,6 @@
cdef class FileData:
cdef public str folder
cdef public str filename
@staticmethod
cdef from_msgpack(bytes data)
+14
View File
@@ -0,0 +1,14 @@
from msgpack import unpackb
cdef class FileData:
def __init__(self, str folder, str filename):
self.folder = folder
self.filename = filename
@staticmethod
cdef from_msgpack(bytes data):
unpacked = unpackb(data, strict_map_key=False)
return FileData(
unpacked.get("Folder"),
unpacked.get("Filename"))
+15 -15
View File
@@ -9,16 +9,10 @@ from annotation cimport Annotation
from inference cimport Inference
from remote_command cimport RemoteCommand, CommandType
from remote_command_handler cimport RemoteCommandHandler
from credentials cimport Credentials
from file_data cimport FileData
from user cimport User
cdef class ParsedArguments:
cdef str email, password, folder;
def __init__(self, str email, str password, str folder):
self.email = email
self.password = password
self.folder = folder
cdef class CommandProcessor:
cdef ApiClient api_client
cdef RemoteCommandHandler remote_handler
@@ -26,8 +20,8 @@ cdef class CommandProcessor:
cdef bint running
cdef Inference inference
def __init__(self, args: ParsedArguments):
self.api_client = ApiClient(args.email, args.password, args.folder)
def __init__(self):
self.api_client = ApiClient()
self.remote_handler = RemoteCommandHandler(self.on_command)
self.inference_queue = Queue(maxsize=constants.QUEUE_MAXSIZE)
self.remote_handler.start()
@@ -49,11 +43,10 @@ cdef class CommandProcessor:
cdef on_command(self, RemoteCommand command):
try:
if command.command_type == CommandType.GET_USER:
self.get_user(command, self.api_client.get_user())
if command.command_type == CommandType.LOGIN:
self.login(command)
elif command.command_type == CommandType.LOAD:
response = self.api_client.load_bytes(command.filename)
self.remote_handler.send(command.client_id, response)
self.load_file(command)
elif command.command_type == CommandType.INFERENCE:
self.inference_queue.put(command)
elif command.command_type == CommandType.STOP_INFERENCE:
@@ -66,9 +59,16 @@ cdef class CommandProcessor:
except Exception as e:
print(f"Error handling client: {e}")
cdef get_user(self, RemoteCommand command, User user):
cdef login(self, RemoteCommand command):
cdef User user
self.api_client.credentials = Credentials.from_msgpack(command.data)
user = self.api_client.get_user()
self.remote_handler.send(command.client_id, user.serialize())
cdef load_file(self, RemoteCommand command):
response = self.api_client.load_bytes(FileData.from_msgpack(command.data))
self.remote_handler.send(command.client_id, response)
cdef on_annotation(self, RemoteCommand cmd, Annotation annotation):
data = annotation.serialize()
self.remote_handler.send(cmd.client_id, data)
+1 -2
View File
@@ -1,5 +1,5 @@
cdef enum CommandType:
GET_USER = 10
LOGIN = 10
LOAD = 20
INFERENCE = 30
STOP_INFERENCE = 40
@@ -8,7 +8,6 @@ cdef enum CommandType:
cdef class RemoteCommand:
cdef public bytes client_id
cdef CommandType command_type
cdef str filename
cdef bytes data
@staticmethod
+4 -5
View File
@@ -1,23 +1,22 @@
import msgpack
cdef class RemoteCommand:
def __init__(self, CommandType command_type, str filename, bytes data):
def __init__(self, CommandType command_type, bytes data):
self.command_type = command_type
self.filename = filename
self.data = data
def __str__(self):
command_type_names = {
10: "GET_USER",
10: "LOGIN",
20: "LOAD",
30: "INFERENCE",
40: "STOP_INFERENCE",
100: "EXIT"
}
data_str = f'. Data: {len(self.data)} bytes' if self.data else ''
return f'{command_type_names[self.command_type]}: {self.filename}{data_str}'
return f'{command_type_names[self.command_type]}: {data_str}'
@staticmethod
cdef from_msgpack(bytes data):
unpacked = msgpack.unpackb(data, strict_map_key=False)
return RemoteCommand(unpacked.get("CommandType"), unpacked.get("Filename"), unpacked.get("Data"))
return RemoteCommand(unpacked.get("CommandType"), unpacked.get("Data"))
+2
View File
@@ -5,6 +5,8 @@ import numpy as np
extensions = [
Extension('constants', ['constants.pyx']),
Extension('annotation', ['annotation.pyx']),
Extension('credentials', ['credentials.pyx']),
Extension('file_data', ['file_data.pyx']),
Extension('security', ['security.pyx']),
Extension('hardware_service', ['hardware_service.pyx'], extra_compile_args=["-g"], extra_link_args=["-g"]),
Extension('remote_command', ['remote_command.pyx']),
+5 -14
View File
@@ -1,22 +1,13 @@
import argparse
from main import ParsedArguments, CommandProcessor
from main import CommandProcessor
def parse_arguments():
parser = argparse.ArgumentParser(description="Command Processor")
parser.add_argument("-e", "--email", type=str, default="", help="Email")
parser.add_argument("-p", "--pw", type=str, default="", help="Password")
parser.add_argument("-f", "--folder", type=str, default="", help="Folder to API inner folder to download file from")
args = parser.parse_args()
return ParsedArguments(args.email, args.pw, args.folder)
def start(args: ParsedArguments):
processor = CommandProcessor(args)
def start():
processor = CommandProcessor()
try:
processor.start()
except KeyboardInterrupt:
processor.stop()
if __name__ == '__main__':
start(parse_arguments())
start()
+1 -1
View File
@@ -3,7 +3,7 @@ from PyInstaller.utils.hooks import collect_all
datas = []
binaries = []
hiddenimports = ['user', 'security', 'secure_model', 'api_client', 'hardware_service', 'constants', 'annotation', 'remote_command', 'ai_config', 'inference', 'remote_command_handler']
hiddenimports = ['constants', 'annotation', 'credentials', 'file_data', 'user', 'security', 'secure_model', 'api_client', 'hardware_service', 'remote_command', 'ai_config', 'inference', 'remote_command_handler']
tmp_ret = collect_all('jwt')
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
tmp_ret = collect_all('requests')
+6
View File
@@ -32,22 +32,27 @@ Global
{8E0809AF-2920-4267-B14D-84BAB334A46F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E0809AF-2920-4267-B14D-84BAB334A46F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E0809AF-2920-4267-B14D-84BAB334A46F}.Release|Any CPU.Build.0 = Release|Any CPU
{8E0809AF-2920-4267-B14D-84BAB334A46F}.Release|Any CPU.Deploy.0 = Release|Any CPU
{85359558-FB59-4542-A597-FD9E1B04C8E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85359558-FB59-4542-A597-FD9E1B04C8E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85359558-FB59-4542-A597-FD9E1B04C8E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85359558-FB59-4542-A597-FD9E1B04C8E7}.Release|Any CPU.Build.0 = Release|Any CPU
{85359558-FB59-4542-A597-FD9E1B04C8E7}.Release|Any CPU.Deploy.0 = Release|Any CPU
{BA77500E-8B66-4F31-81B0-E831FC12EDFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BA77500E-8B66-4F31-81B0-E831FC12EDFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA77500E-8B66-4F31-81B0-E831FC12EDFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA77500E-8B66-4F31-81B0-E831FC12EDFB}.Release|Any CPU.Build.0 = Release|Any CPU
{BA77500E-8B66-4F31-81B0-E831FC12EDFB}.Release|Any CPU.Deploy.0 = Release|Any CPU
{1D8E6F44-C64E-4DBE-8665-2101EC5BE36E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D8E6F44-C64E-4DBE-8665-2101EC5BE36E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D8E6F44-C64E-4DBE-8665-2101EC5BE36E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D8E6F44-C64E-4DBE-8665-2101EC5BE36E}.Release|Any CPU.Build.0 = Release|Any CPU
{1D8E6F44-C64E-4DBE-8665-2101EC5BE36E}.Release|Any CPU.Deploy.0 = Release|Any CPU
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Release|Any CPU.Build.0 = Release|Any CPU
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Release|Any CPU.Deploy.0 = Release|Any CPU
{32C4747F-F700-44FD-B4ED-21B4A66B5FAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32C4747F-F700-44FD-B4ED-21B4A66B5FAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32C4747F-F700-44FD-B4ED-21B4A66B5FAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -60,6 +65,7 @@ Global
{E0C7176D-2E91-4928-B3C1-55CC91C8F77D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0C7176D-2E91-4928-B3C1-55CC91C8F77D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0C7176D-2E91-4928-B3C1-55CC91C8F77D}.Release|Any CPU.Build.0 = Release|Any CPU
{E0C7176D-2E91-4928-B3C1-55CC91C8F77D}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{32C4747F-F700-44FD-B4ED-21B4A66B5FAB} = {C307BE2E-FFCC-4BD7-AD89-C82D40B65D03}
+8 -8
View File
@@ -33,7 +33,7 @@ public partial class App
private IMediator _mediator = null!;
private FormState _formState = null!;
private PythonResourceLoader _resourceLoader = null!;
private readonly PythonResourceLoader _resourceLoader = new();
private Stream _securedConfig = null!;
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
@@ -54,7 +54,7 @@ public partial class App
"Azaion.Dataset"
];
private ApiConfig ReadConfig()
private static ApiConfig ReadConfig()
{
try
{
@@ -69,8 +69,9 @@ public partial class App
return new ApiConfig
{
Url = SecurityConstants.DEFAULT_API_URL,
RetryCount = SecurityConstants.DEFAULT_API_RETRY_COUNT ,
TimeoutSeconds = SecurityConstants.DEFAULT_API_TIMEOUT_SECONDS
RetryCount = SecurityConstants.DEFAULT_API_RETRY_COUNT,
TimeoutSeconds = SecurityConstants.DEFAULT_API_TIMEOUT_SECONDS,
ResourcesFolder = ""
};
}
}
@@ -81,10 +82,9 @@ public partial class App
var login = new Login();
login.CredentialsEntered += (_, credentials) =>
{
var apiConfig = ReadConfig();
var api = AzaionApiClient.Create(credentials, apiConfig);
_resourceLoader = new PythonResourceLoader(apiConfig, credentials, api);
var config = ReadConfig();
credentials.Folder = config.ResourcesFolder;
_resourceLoader.Login(credentials);
_securedConfig = _resourceLoader.LoadFileFromPython("secured-config.json");
AppDomain.CurrentDomain.AssemblyResolve += (_, a) =>
+5 -5
View File
@@ -30,9 +30,9 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Azaion.Annotator\Azaion.Annotator.csproj" />
<ProjectReference Include="..\Azaion.Common\Azaion.Common.csproj" />
<ProjectReference Include="..\Azaion.Dataset\Azaion.Dataset.csproj" />
<ProjectReference Include="..\Dummy\Azaion.Annotator\Azaion.Annotator.csproj" />
<ProjectReference Include="..\Dummy\Azaion.Dataset\Azaion.Dataset.csproj" />
</ItemGroup>
<ItemGroup>
@@ -54,9 +54,9 @@
</ItemGroup>
<Target Name="PostBuild" AfterTargets="Build">
<MakeDir Directories="$(TargetDir)secure" />
<Move SourceFiles="$(TargetDir)Azaion.Annotator.dll" DestinationFolder="$(TargetDir)secure" />
<Move SourceFiles="$(TargetDir)Azaion.Dataset.dll" DestinationFolder="$(TargetDir)secure" />
<MakeDir Directories="$(TargetDir)dummy" />
<Move SourceFiles="$(TargetDir)Azaion.Annotator.dll" DestinationFolder="$(TargetDir)dummy" />
<Move SourceFiles="$(TargetDir)Azaion.Dataset.dll" DestinationFolder="$(TargetDir)dummy" />
<Exec Command="upload.cmd $(ConfigurationName)" />
</Target>
+6 -2
View File
@@ -8,6 +8,7 @@ using Azaion.Common.DTO;
using Azaion.Common.DTO.Config;
using Azaion.Common.Extensions;
using Azaion.Common.Services;
using Azaion.CommonSecurity.Services;
using Azaion.Dataset;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
@@ -24,20 +25,22 @@ public partial class MainSuite
private readonly IGalleryService _galleryService;
private readonly IDbFactory _dbFactory;
private readonly Dictionary<WindowEnum, Window> _openedWindows = new();
private readonly IResourceLoader _resourceLoader;
public MainSuite(IOptions<AppConfig> appConfig,
IConfigUpdater configUpdater,
IEnumerable<IAzaionModule> modules,
IServiceProvider sp,
IGalleryService galleryService,
IDbFactory dbFactory
)
IDbFactory dbFactory,
IResourceLoader resourceLoader)
{
_configUpdater = configUpdater;
_modules = modules;
_sp = sp;
_galleryService = galleryService;
_dbFactory = dbFactory;
_resourceLoader = resourceLoader;
_appConfig = appConfig.Value;
InitializeComponent();
Loaded += OnLoaded;
@@ -107,6 +110,7 @@ public partial class MainSuite
_openedWindows[module.WindowEnum] = window;
window.Closed += (_, _) =>
{
_resourceLoader.StopPython();
_openedWindows.Remove(module.WindowEnum);
if (!_openedWindows.Any())
Close();
+2 -5
View File
@@ -1,10 +1,7 @@
{
"ApiConfig": {
"Url": "https://api.azaion.com/",
"RetryCount": 3,
"TimeoutSeconds": 40.0,
"ResourcesFolder": "stage",
"TokenFile": "token.txt"
"TimeoutSeconds": 20.0,
"ResourcesFolder": "stage"
},
"DirectoriesConfig": {
"VideosDirectory": "E:\\Azaion6",
+3 -2
View File
@@ -7,11 +7,12 @@ set RESOURCES_FOLDER=stage
set EMAIL=uploader@azaion.com
set PASSWORD=Az@1on_10Upl0@der
echo %cd%
set FILE1_TO_UPLOAD=%cd%\bin\%CONFIG%\net8.0-windows\secure\Azaion.Annotator.dll
set FILE1_TO_UPLOAD=%cd%\..\Azaion.Annotator\bin\%CONFIG%\net8.0-windows\Azaion.Annotator.dll
set "FILE1_TO_UPLOAD=%FILE1_TO_UPLOAD:\=/%"
set FILE2_TO_UPLOAD=%cd%\bin\%CONFIG%\net8.0-windows\secure\Azaion.Dataset.dll
set FILE2_TO_UPLOAD=%cd%\..\Azaion.Dataset\bin\%CONFIG%\net8.0-windows\Azaion.Dataset.dll
set "FILE2_TO_UPLOAD=%FILE2_TO_UPLOAD:\=/%"
-1
View File
@@ -20,7 +20,6 @@ public class DictTest
}
[Theory]
[InlineData(null, 0)]
[InlineData(new int[]{}, 0)]
[InlineData(new int[]{1, 2, 5}, 1)]
[InlineData(new int[]{3, -2, 5}, -2)]
@@ -27,7 +27,6 @@
<PackageReference Include="SkiaSharp" Version="2.88.9" />
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.21" />
<PackageReference Include="WindowsAPICodePack" Version="7.0.4" />
<PackageReference Include="YoloV8.Gpu" Version="5.0.4" />
</ItemGroup>
<ItemGroup>