separate load functionality from inference client to loader client. Call loader client from inference to get the model.

remove dummy dlls, remove resource loader from c#.

TODO: Load dlls separately by Loader UI and loader client

WIP
This commit is contained in:
Alex Bezdieniezhnykh
2025-06-06 20:04:03 +03:00
parent 500db31142
commit 7750025631
54 changed files with 353 additions and 571 deletions
+2 -2
View File
@@ -17,5 +17,5 @@ cdef class ApiClient:
cdef load_bytes(self, str filename, str folder)
cdef upload_file(self, str filename, bytes resource, str folder)
cdef load_big_file_cdn(self, str folder, str big_part)
cdef load_big_small_resource(self, str resource_name, str folder, str key)
cdef upload_big_small_resource(self, bytes resource, str resource_name, str folder, str key)
cdef load_big_small_resource(self, str resource_name, str folder)
cdef upload_big_small_resource(self, bytes resource, str resource_name, str folder)
+18 -10
View File
@@ -8,7 +8,7 @@ import requests
cimport constants
import yaml
from requests import HTTPError
from credentials cimport Credentials
from cdn_manager cimport CDNManager, CDNCredentials
from hardware_service cimport HardwareService
from security cimport Security
@@ -98,8 +98,10 @@ cdef class ApiClient:
constants.log(f"Upload fail: {e}")
cdef load_bytes(self, str filename, str folder):
hardware_service = HardwareService()
cdef str hardware = hardware_service.get_hardware_info()
cdef str hardware = HardwareService.get_hardware_info()
hw_hash = Security.get_hw_hash(hardware)
key = Security.get_api_encryption_key(self.credentials, hw_hash)
if self.token is None:
self.login()
url = f"{self.api_url}/resources/get/{folder}"
@@ -124,10 +126,12 @@ cdef class ApiClient:
response = requests.post(url, data=payload, headers=headers, stream=True)
if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR:
print('500!')
hw_hash = Security.get_hw_hash(hardware)
key = Security.get_api_encryption_key(self.credentials, hw_hash)
raise Exception(f'Internal API error! {response.text}')
if response.status_code == HTTPStatus.CONFLICT:
res = response.json()
err_code = res['ErrorCode']
err_msg = res['Message']
raise Exception(f"Error {err_code}: {err_msg}")
resp_bytes = response.raw.read()
data = Security.decrypt_to(resp_bytes, key)
@@ -142,28 +146,32 @@ cdef class ApiClient:
else:
return None
cdef load_big_small_resource(self, str resource_name, str folder, str key):
cdef load_big_small_resource(self, str resource_name, str folder):
cdef str big_part = f'{resource_name}.big'
cdef str small_part = f'{resource_name}.small'
encrypted_bytes_small = self.load_bytes(small_part, folder)
key = Security.get_resource_encryption_key()
print(f'checking on existence for {folder}\\{big_part}')
if os.path.exists(os.path.join(<str> folder, big_part)):
with open(path.join(<str> folder, big_part), 'rb') as binary_file:
local_bytes_big = binary_file.read()
print(f'local file {folder}\\{big_part} is found!')
try:
return Security.decrypt_to(encrypted_bytes_small + local_bytes_big, key)
resource = Security.decrypt_to(encrypted_bytes_small + local_bytes_big, key)
return resource
except Exception as ex:
print('Local file doesnt match with api file, old version')
remote_bytes_big = self.load_big_file_cdn(folder, big_part)
return Security.decrypt_to(encrypted_bytes_small + remote_bytes_big, key)
cdef upload_big_small_resource(self, bytes resource, str resource_name, str folder, str key):
cdef upload_big_small_resource(self, bytes resource, str resource_name, str folder):
cdef str big_part_name = f'{resource_name}.big'
cdef str small_part_name = f'{resource_name}.small'
key = Security.get_resource_encryption_key()
resource_encrypted = Security.encrypt_to(<bytes>resource, key)
part_small_size = min(constants.SMALL_SIZE_KB * 1024, int(0.3 * len(resource_encrypted)))
+19 -1
View File
@@ -21,4 +21,22 @@ venv\Scripts\python setup.py build_ext --inplace
echo install azaion-loader
venv\Scripts\pyinstaller --name=azaion-loader ^
--collect-all boto3 ^
--collect-all requests ^
--collect-all boto3 ^
--collect-all msgpack ^
--collect-all zmq ^
--collect-all jwt ^
--collect-all boto3 ^
--collect-all cryptography ^
--collect-all yaml ^
--hidden-import constants ^
--hidden-import file_data ^
--hidden-import remote_command ^
--hidden-import remote_command_handler ^
--hidden-import user ^
--hidden-import security ^
--hidden-import cdn_manager ^
--hidden-import credentials ^
--hidden-import api_client ^
--hidden-import hardware_service ^
start.py
+3
View File
@@ -13,3 +13,6 @@ cdef class Credentials:
unpacked.get("Email"),
unpacked.get("Password"))
def __str__(self):
return f'{self.email}: {self.password}'
+10
View File
@@ -4,3 +4,13 @@ cdef class FileData:
@staticmethod
cdef from_msgpack(bytes data)
cdef bytes serialize(self)
cdef class UploadFileData(FileData):
cdef public bytes resource
@staticmethod
cdef from_msgpack(bytes data)
cdef bytes serialize(self)
+28 -2
View File
@@ -1,7 +1,6 @@
from msgpack import unpackb
from msgpack import unpackb, packb
cdef class FileData:
def __init__(self, str folder, str filename):
self.folder = folder
self.filename = filename
@@ -12,3 +11,30 @@ cdef class FileData:
return FileData(
unpacked.get("Folder"),
unpacked.get("Filename"))
cdef bytes serialize(self):
return packb({
"Folder": self.folder,
"Filename": self.filename
})
cdef class UploadFileData(FileData):
def __init__(self, bytes resource, str folder, str filename):
super().__init__(folder, filename)
self.resource = resource
@staticmethod
cdef from_msgpack(bytes data):
unpacked = unpackb(data, strict_map_key=False)
return UploadFileData(
unpacked.get("Resource"),
unpacked.get("Folder"),
unpacked.get("Filename"))
cdef bytes serialize(self):
return packb({
"Resource": self.resource,
"Folder": self.folder,
"Filename": self.filename
})
+1 -2
View File
@@ -1,5 +1,4 @@
cdef class HardwareService:
@staticmethod
cdef has_nvidia_gpu()
cdef str get_hardware_info(self)
cdef str get_hardware_info()
+1 -26
View File
@@ -1,34 +1,9 @@
import os
import subprocess
import pynvml
cdef class HardwareService:
@staticmethod
cdef has_nvidia_gpu():
try:
pynvml.nvmlInit()
device_count = pynvml.nvmlDeviceGetCount()
if device_count > 0:
print(f"Found NVIDIA GPU(s).")
return True
else:
print("No NVIDIA GPUs found by NVML.")
return False
except pynvml.NVMLError as error:
print(f"Failed to find NVIDIA GPU")
return False
finally:
try:
pynvml.nvmlShutdown()
except:
print('Failed to shutdown pynvml cause probably no NVidia GPU')
pass
cdef str get_hardware_info(self):
cdef str get_hardware_info():
if os.name == 'nt': # windows
os_command = (
"powershell -Command \""
+25 -18
View File
@@ -4,7 +4,7 @@ import traceback
from credentials cimport Credentials
from remote_command cimport RemoteCommand, CommandType
from remote_command_handler cimport RemoteCommandHandler
from file_data cimport FileData
from file_data cimport FileData, UploadFileData
from api_client cimport ApiClient
cdef class CommandProcessor:
@@ -12,6 +12,7 @@ cdef class CommandProcessor:
cdef ApiClient api_client
cdef bint running
cdef object shutdown_event
cdef RemoteCommand ok_response
def __init__(self, int zmq_port, str api_url):
self.api_client = ApiClient(api_url)
@@ -19,6 +20,7 @@ cdef class CommandProcessor:
self.remote_handler = RemoteCommandHandler(zmq_port, self.on_command)
self.remote_handler.start()
self.running = True
self.ok_response = RemoteCommand(CommandType.OK)
def start(self):
while self.running:
@@ -29,31 +31,36 @@ cdef class CommandProcessor:
traceback.print_exc()
print('EXIT!')
cdef on_command(self, RemoteCommand command):
try:
if command.command_type == CommandType.LOGIN:
self.api_client.set_credentials(Credentials.from_msgpack(command.data))
elif command.command_type == CommandType.LOAD:
self.load_file(command)
elif command.command_type == CommandType.EXIT:
if command.command_type == CommandType.EXIT:
self.remote_handler.send(command.client_id, self.ok_response.serialize())
t = Thread(target=self.stop) # non-block worker:
t.start()
return
if command.command_type == CommandType.LOGIN:
self.api_client.set_credentials(Credentials.from_msgpack(command.data))
self.remote_handler.send(command.client_id, self.ok_response.serialize())
elif command.command_type == CommandType.LOAD:
file_data = FileData.from_msgpack(command.data)
file_bytes = self.api_client.load_bytes(file_data.filename, file_data.folder)
self.remote_handler.send(command.client_id, RemoteCommand(CommandType.DATA_BYTES, file_bytes).serialize())
elif command.command_type == CommandType.LOAD_BIG_SMALL:
data = FileData.from_msgpack(command.data)
file_bytes = self.api_client.load_big_small_resource(data.filename, data.folder)
self.remote_handler.send(command.client_id, RemoteCommand(CommandType.DATA_BYTES, file_bytes).serialize())
elif command.command_type == CommandType.UPLOAD_BIG_SMALL:
data = UploadFileData.from_msgpack(command.data)
file_bytes = self.api_client.upload_big_small_resource(data.resource, data.filename, data.folder)
self.remote_handler.send(command.client_id, RemoteCommand(CommandType.OK).serialize())
else:
pass
except Exception as e:
print(f"Error handling client: {e}")
cdef load_file(self, RemoteCommand command):
cdef RemoteCommand response
cdef FileData file_data
cdef bytes file_bytes
try:
file_data = FileData.from_msgpack(command.data)
file_bytes = self.api_client.load_bytes(file_data.filename, file_data.folder)
response = RemoteCommand(CommandType.DATA_BYTES, file_bytes)
except Exception as e:
response = RemoteCommand(CommandType.DATA_BYTES, None, str(e))
self.remote_handler.send(command.client_id, response.serialize())
err_command = RemoteCommand(CommandType.ERROR, None, str(e))
self.remote_handler.send(command.client_id, err_command.serialize())
def stop(self):
self.shutdown_event.set()
+3
View File
@@ -1,6 +1,9 @@
cdef enum CommandType:
OK = 3
LOGIN = 10
LOAD = 20
LOAD_BIG_SMALL = 22
UPLOAD_BIG_SMALL = 24
DATA_BYTES = 25
INFERENCE = 30
INFERENCE_DATA = 35
+4 -1
View File
@@ -1,15 +1,18 @@
import msgpack
cdef class RemoteCommand:
def __init__(self, CommandType command_type, bytes data, str message=None):
def __init__(self, CommandType command_type, bytes data=None, str message=None):
self.command_type = command_type
self.data = data
self.message = message
def __str__(self):
command_type_names = {
3: "OK",
10: "LOGIN",
20: "LOAD",
22: "LOAD_BIG_SMALL",
24: "UPLOAD_BIG_SMALL",
25: "DATA_BYTES",
30: "INFERENCE",
35: "INFERENCE_DATA",
+1 -1
View File
@@ -3,7 +3,7 @@ import zmq
from threading import Thread, Event
from remote_command cimport RemoteCommand
cimport constants
import yaml
cdef class RemoteCommandHandler:
def __init__(self, int zmq_port, object on_command):
+1
View File
@@ -7,3 +7,4 @@ zmq
requests
pyyaml
boto3
cryptography==44.0.2
+1 -1
View File
@@ -14,7 +14,7 @@ cdef class Security:
cdef get_api_encryption_key(Credentials credentials, str hardware_hash)
@staticmethod
cdef get_model_encryption_key()
cdef get_resource_encryption_key()
@staticmethod
cdef calc_hash(str key)
+1 -1
View File
@@ -56,7 +56,7 @@ cdef class Security:
return Security.calc_hash(key)
@staticmethod
cdef get_model_encryption_key():
cdef get_resource_encryption_key():
cdef str key = '-#%@AzaionKey@%#---234sdfklgvhjbnn'
return Security.calc_hash(key)