add pxd headers for correct work

fixes definitions
can run until API call
This commit is contained in:
Alex Bezdieniezhnykh
2025-01-16 17:56:58 +02:00
parent 7439005ed7
commit e21dd7e70f
17 changed files with 207 additions and 165 deletions
+14 -17
View File
@@ -21,7 +21,7 @@ Windows
- [Install CUDA](https://developer.nvidia.com/cuda-12-1-0-download-archive) - [Install CUDA](https://developer.nvidia.com/cuda-12-1-0-download-archive)
Linux Linux
* ``` ```
sudo apt install nvidia-driver-535 sudo apt install nvidia-driver-535
wget https://developer.download.nvidia.com/compute/cudnn/9.2.0/local_installers/cudnn-local-repo-ubuntu2204-9.2.0_1.0-1_amd64.deb wget https://developer.download.nvidia.com/compute/cudnn/9.2.0/local_installers/cudnn-local-repo-ubuntu2204-9.2.0_1.0-1_amd64.deb
@@ -33,30 +33,27 @@ Linux
nvcc --version nvcc --version
``` ```
<h3>Install dependencies</h3>
```
Make sure that your virtual env is installed with links to the global python packages and headers, like this:
python -m venv --system-site-packages venv
This is crucial for the Build because build needs Python.h header and other files.
<h3>Install dependencies</h3>
Make sure that your virtual env is installed with links to the global python packages and headers, like this:
```
python -m venv --system-site-packages venv
```
This is crucial for the build because build needs Python.h header and other files.
```
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install --upgrade huggingface_hub pip install --upgrade huggingface_hub
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install git+https://github.com/airockchip/ultralytics_yolov8.git
- or
pip install ultralytics pip install ultralytics
pip install cython
pip uninstall -y opencv-python pip uninstall -y opencv-python
pip install opencv-python pip install opencv-python cython msgpack cryptography rstream
pip install msgpack ```
In case of fbgemm.dll error (Windows specific):
- copypaste libomp140.x86_64.dll to C:\Windows\System32
```
* fbgemm.dll error (Windows specific)
```
copypaste libomp140.x86_64.dll to C:\Windows\System32
```
<h3>Build</h3> <h3>Build</h3>
``` ```
+8
View File
@@ -0,0 +1,8 @@
cdef class Detection:
cdef double x, y, w, h
cdef int cls
cdef class Annotation:
cdef bytes image
cdef float time
cdef list[Detection] detections
+13
View File
@@ -0,0 +1,13 @@
cdef class Detection:
def __init__(self, double x, double y, double w, double h, int cls):
self.x = x
self.y = y
self.w = w
self.h = h
self.cls = cls
cdef class Annotation:
def __init__(self, bytes image_bytes, float time, list[Detection] detections):
self.image = image_bytes
self.time = time
self.detections = detections
+10
View File
@@ -0,0 +1,10 @@
from processor_command cimport FileCommand
cdef class ApiClient:
cdef str email, password, token, folder, token_file, api_url
cdef get_encryption_key(self, str hardware_hash)
cdef login(self, str email, str password, bint persist_token=*)
cdef bytes load_file(self, str filename, bint persist_token=*)
cdef bytes load_ai_model(self)
+13 -20
View File
@@ -1,47 +1,41 @@
# cython: language_level=3
import io import io
import os import os
from http import HTTPStatus from http import HTTPStatus
import requests import requests
import constants cimport constants
from hardware_service import HardwareService from hardware_service cimport HardwareService, HardwareInfo
from processor_command import FileCommand, CommandType
from security import Security from security import Security
cdef class ApiClient: cdef class ApiClient:
"""Handles API authentication and downloading of the AI model.""" """Handles API authentication and downloading of the AI model."""
cdef str email
cdef str password
cdef str token
cdef str folder
def __init__(self, str email, str password, str folder): def __init__(self, str email, str password, str folder):
self.email = email self.email = email
self.password = password self.password = password
self.folder = folder self.folder = folder
if os.path.exists(constants.TOKEN_FILE): if os.path.exists(<str>constants.TOKEN_FILE):
with open(constants.TOKEN_FILE, "r") as file: with open(<str>constants.TOKEN_FILE, "r") as file:
self.token = file.read().strip() self.token = file.read().strip()
else: else:
self.token = None self.token = None
cdef get_encryption_key(self, command: FileCommand, str hardware_hash): cdef get_encryption_key(self, str hardware_hash):
return f'{self.email}-{self.password}-{hardware_hash}-#%@AzaionKey@%#---' return f'{self.email}-{self.password}-{hardware_hash}-#%@AzaionKey@%#---'
cdef login(self, str email, str password, persist_token:bool=False): cdef login(self, str email, str password, bint persist_token=False):
response = requests.post(f"{constants.API_URL}/login", json={"email": email, "password": password}) response = requests.post(f"{constants.API_URL}/login", json={"email": email, "password": password})
response.raise_for_status() response.raise_for_status()
self.token = response.json()["token"] self.token = response.json()["token"]
print(f'')
if persist_token: if persist_token:
with open(constants.TOKEN_FILE, 'w') as file: with open(<str>constants.TOKEN_FILE, 'w') as file:
file.write(self.token) file.write(self.token)
cdef bytes load_file(self, command: FileCommand, persist_token:bool=False): cdef bytes load_file(self, str filename, bint persist_token=False):
hardware_service = HardwareService() hardware_service = HardwareService()
hardware = hardware_service.get_hardware_info() cdef HardwareInfo hardware = hardware_service.get_hardware_info()
if self.token is None: if self.token is None:
self.login(self.email, self.password, persist_token) self.login(self.email, self.password, persist_token)
@@ -51,7 +45,7 @@ cdef class ApiClient:
payload = { payload = {
"password": self.password, "password": self.password,
"hardware": hardware, "hardware": hardware,
"fileName": command.filename "fileName": filename
} }
response = requests.post(url, json=payload, headers=headers, stream=True) response = requests.post(url, json=payload, headers=headers, stream=True)
@@ -59,13 +53,12 @@ cdef class ApiClient:
self.login(self.email, self.password, persist_token) self.login(self.email, self.password, persist_token)
response = requests.post(url, json=payload, headers=headers, stream=True) response = requests.post(url, json=payload, headers=headers, stream=True)
key = self.get_encryption_key(command, hardware.hash) key = self.get_encryption_key(hardware.hash)
encrypted_stream = io.BytesIO(response.content) encrypted_stream = io.BytesIO(response.content)
decrypted_stream = io.BytesIO() decrypted_stream = io.BytesIO()
Security.decrypt_to(encrypted_stream, decrypted_stream, key) Security.decrypt_to(encrypted_stream, decrypted_stream, key)
return decrypted_stream return decrypted_stream
cdef bytes load_ai_model(self): cdef bytes load_ai_model(self):
file_command = FileCommand(CommandType.LOAD, constants.AI_MODEL_FILE) return self.load_file(constants.AI_MODEL_FILE, <bint>True)
return self.load_file(file_command, True)
+12
View File
@@ -0,0 +1,12 @@
cdef str SOCKET_HOST # Host for the socket server
cdef int SOCKET_PORT # Port for the socket server
cdef int SOCKET_BUFFER_SIZE # Buffer size for socket communication
cdef int QUEUE_MAXSIZE # Maximum size of the command queue
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
-5
View File
@@ -1,5 +1,3 @@
# cython: language_level=3
cdef str SOCKET_HOST = "127.0.0.1" # Host for the socket server cdef str SOCKET_HOST = "127.0.0.1" # Host for the socket server
cdef int SOCKET_PORT = 9127 # Port for the socket server cdef int SOCKET_PORT = 9127 # Port for the socket server
cdef int SOCKET_BUFFER_SIZE = 4096 # Buffer size for socket communication cdef int SOCKET_BUFFER_SIZE = 4096 # Buffer size for socket communication
@@ -8,10 +6,7 @@ cdef int QUEUE_MAXSIZE = 1000 # Maximum size of the command queue
cdef str COMMANDS_QUEUE = "azaion-commands" cdef str COMMANDS_QUEUE = "azaion-commands"
cdef str ANNOTATIONS_QUEUE = "azaion-annotations" cdef str ANNOTATIONS_QUEUE = "azaion-annotations"
cdef str API_URL = "https://api.azaion.com" # Base URL for the external API cdef str API_URL = "https://api.azaion.com" # Base URL for the external API
cdef str TOKEN_FILE = "token" cdef str TOKEN_FILE = "token"
cdef str QUEUE_CONFIG_FILENAME = "secured-config.json" cdef str QUEUE_CONFIG_FILENAME = "secured-config.json"
cdef str AI_MODEL_FILE = "azaion.pt" cdef str AI_MODEL_FILE = "azaion.pt"
+13
View File
@@ -0,0 +1,13 @@
import main
from main import ParsedArguments
def start_server():
args = ParsedArguments('admin@azaion.com', 'Az@1on1000Odm$n', 'stage', True)
processor = main.CommandProcessor(args)
try:
processor.start()
except Exception as e:
processor.stop()
if __name__ == "__main__":
start_server()
+9
View File
@@ -0,0 +1,9 @@
cdef class HardwareInfo:
cdef str cpu, gpu, memory, mac_address, hash
cdef class HardwareService:
cdef bint is_windows
cdef HardwareInfo get_hardware_info(self)
cdef str calc_hash(self, str s)
+3 -8
View File
@@ -1,15 +1,8 @@
# cython: language_level=3
import base64 import base64
import subprocess import subprocess
from hashlib import sha384 from hashlib import sha384
cdef class HardwareInfo: cdef class HardwareInfo:
cdef str cpu
cdef str gpu
cdef str memory
cdef str mac_address
cdef str hash
def __init__(self, str cpu, str gpu, str memory, str mac_address, str hw_hash): def __init__(self, str cpu, str gpu, str memory, str mac_address, str hw_hash):
self.cpu = cpu self.cpu = cpu
self.gpu = gpu self.gpu = gpu
@@ -25,11 +18,13 @@ cdef class HardwareService:
def __init__(self): def __init__(self):
try: try:
if subprocess.check_output("ver", shell=True).decode('utf-8').startswith("Microsoft"): res = subprocess.check_output("ver", shell=True).decode('utf-8')
if "Microsoft Windows" in res:
self.is_windows = True self.is_windows = True
else: else:
self.is_windows = False self.is_windows = False
except Exception: except Exception:
print('Error during os type checking')
self.is_windows = False self.is_windows = False
cdef HardwareInfo get_hardware_info(self): cdef HardwareInfo get_hardware_info(self):
+1 -23
View File
@@ -1,9 +1,9 @@
# cython: language_level=3
from ultralytics import YOLO from ultralytics import YOLO
import mimetypes import mimetypes
import cv2 import cv2
from ultralytics.engine.results import Boxes from ultralytics.engine.results import Boxes
from processor_command import FileCommand from processor_command import FileCommand
from annotation cimport Detection, Annotation
cdef class Inference: cdef class Inference:
"""Handles YOLO inference using the AI model.""" """Handles YOLO inference using the AI model."""
@@ -66,25 +66,3 @@ cdef class Inference:
_, encoded_image = cv2.imencode('.jpg', frame[0]) _, encoded_image = cv2.imencode('.jpg', frame[0])
image_bytes = encoded_image.tobytes() image_bytes = encoded_image.tobytes()
return Annotation(image_bytes, time, detections) return Annotation(image_bytes, time, detections)
cdef class Detection:
cdef double x
cdef double y
cdef double w
cdef double h
cdef int cls
def __init__(self, double x, double y, double w, double h, int cls):
self.x = x
self.y = y
self.w = w
self.h = h
self.cls = cls
cdef class Annotation:
def __init__(self, image_bytes: bytes, float time, detections: [Detection]):
self.image = image_bytes
self.time = time
self.detections = detections
+23 -26
View File
@@ -1,44 +1,43 @@
# cython: language_level=3
import queue import queue
import threading import threading
import constants cimport constants
from api_client import ApiClient from api_client cimport ApiClient
from inference import Inference, Annotation from annotation cimport Annotation
from processor_command import FileCommand, CommandType, ProcessorType from inference import Inference
from remote_handlers import SocketHandler, RabbitHandler from processor_command cimport FileCommand, CommandType, ProcessorType
from remote_handlers cimport SocketHandler, RabbitHandler
import argparse import argparse
cdef enum ListenOption:
SOCKET = 1
QUEUE = 2
cdef class ParsedArguments: cdef class ParsedArguments:
cdef ListenOption listen cdef str email, password, folder;
cdef str email
cdef str password
cdef str folder
cdef bint persist_token cdef bint persist_token
def __init__(self, ListenOption listen, str email, str password, str folder, bint persist_token): def __init__(self, str email, str password, str folder, bint persist_token):
self.listen = listen
self.email = email self.email = email
self.password = password self.password = password
self.folder = folder self.folder = folder
self.persist_token = persist_token self.persist_token = persist_token
cdef class CommandProcessor: cdef class CommandProcessor:
cdef ApiClient api_client
cdef SocketHandler socket_handler
cdef RabbitHandler rabbit_handler
cdef object command_queue
cdef bint running
def __init__(self, args: ParsedArguments): def __init__(self, args: ParsedArguments):
self.api_client = ApiClient(args.email, args.password, args.folder) self.api_client = ApiClient(args.email, args.password, args.folder)
self.socket_handler = SocketHandler(self.on_message) self.socket_handler = SocketHandler(self.on_message)
self.rabbit_handler = RabbitHandler(self.on_message) self.socket_handler.start()
self.rabbit_handler = RabbitHandler(self.api_client, self.on_message)
self.rabbit_handler.start()
self.command_queue = queue.Queue(maxsize=constants.QUEUE_MAXSIZE) self.command_queue = queue.Queue(maxsize=constants.QUEUE_MAXSIZE)
self.running = True self.running = True
def start(self): def start(self):
threading.Thread(target=self.process_queue, daemon=True).start() threading.Thread(target=self.process_queue, daemon=True).start()
cdef on_message(self, cmd: FileCommand): cdef on_message(self, FileCommand cmd):
try: try:
if cmd.command_type == CommandType.INFERENCE: if cmd.command_type == CommandType.INFERENCE:
self.command_queue.put(cmd) self.command_queue.put(cmd)
@@ -61,7 +60,7 @@ cdef class CommandProcessor:
except Exception as e: except Exception as e:
print(f"Error processing queue: {e}") print(f"Error processing queue: {e}")
cdef process_load(self, command: FileCommand): cdef process_load(self, FileCommand command):
response = self.api_client.load_file(command) response = self.api_client.load_file(command)
handler = self.socket_handler if command.processor_type == ProcessorType.SOCKET else self.rabbit_handler handler = self.socket_handler if command.processor_type == ProcessorType.SOCKET else self.rabbit_handler
handler.send(response) handler.send(response)
@@ -72,20 +71,18 @@ cdef class CommandProcessor:
def parse_arguments(): def parse_arguments():
parser = argparse.ArgumentParser(description="Command Processor") parser = argparse.ArgumentParser(description="Command Processor")
parser.add_argument("--listen", type=ListenOption, choices=[ListenOption.SOCKET, ListenOption.QUEUE], default=ListenOption.SOCKET, help="socket: Local communication, queue: remote. Default is socket") parser.add_argument("-e", "--email", type=str, default="", help="Email")
parser.add_argument("--email", type=str, default="", help="Email") parser.add_argument("-p", "--pw", type=str, default="", help="Password")
parser.add_argument("--pw", type=str, default="", help="Password") parser.add_argument("-f", "--folder", type=str, default="", help="Folder to API inner folder to download file from")
parser.add_argument("--folder", type=str, default="", help="Folder to API inner folder to download file from") parser.add_argument("-t", "--persist_token", type=bool, default=True, help="True for persisting token from API")
parser.add_argument("--persist_token", type=bool, default=True, help="True for persisting token from API")
cdef args = parser.parse_args() cdef args = parser.parse_args()
cdef ListenOption listen = ListenOption(args.listen)
cdef str email = args.email cdef str email = args.email
cdef str password = args.pw cdef str password = args.pw
cdef str folder = args.folder cdef str folder = args.folder
cdef bint persist_token = args.persist_token cdef bint persist_token = args.persist_token
return ParsedArguments(listen, email, password, folder, persist_token) return ParsedArguments(email, password, folder, persist_token)
if __name__ == '__main__': if __name__ == '__main__':
args = parse_arguments() args = parse_arguments()
+15
View File
@@ -0,0 +1,15 @@
cdef enum ProcessorType:
SOCKET = 1,
RABBIT = 2
cdef enum CommandType:
INFERENCE = 1
LOAD = 2
cdef class FileCommand:
cdef CommandType command_type
cdef ProcessorType processor_type
cdef str filename
@staticmethod
cdef from_msgpack(bytes data, ProcessorType processor_type)
+2 -12
View File
@@ -1,23 +1,13 @@
import msgpack import msgpack
cdef enum CommandType:
INFERENCE = 1
LOAD = 2
cdef enum ProcessorType:
SOCKET = 1,
RABBIT = 2
cdef class FileCommand: cdef class FileCommand:
cdef str filename def __init__(self, command_type: CommandType, ProcessorType processor_type, str filename):
def __init__(self, command_type: CommandType, processor_type: ProcessorType, str filename):
self.command_type = command_type self.command_type = command_type
self.processor_type = processor_type self.processor_type = processor_type
self.filename = filename self.filename = filename
@staticmethod @staticmethod
cdef from_msgpack(bytes data, processor_type: ProcessorType): cdef from_msgpack(bytes data, ProcessorType processor_type):
unpacked = msgpack.unpackb(data, strict_map_key=False) unpacked = msgpack.unpackb(data, strict_map_key=False)
return FileCommand(unpacked.get("CommandType"), processor_type, unpacked.get("Filename") return FileCommand(unpacked.get("CommandType"), processor_type, unpacked.get("Filename")
) )
+20
View File
@@ -0,0 +1,20 @@
from annotation cimport Annotation
cdef class SocketHandler:
cdef object on_message
cdef object _socket
cdef object _connection
cdef start(self)
cdef start_inner(self)
cdef send(self, list[Annotation] message)
cdef close(self)
cdef class RabbitHandler:
cdef object on_message
cdef object annotation_producer
cdef object command_consumer
cdef start(self)
cdef send(self, object message)
cdef close(self)
+27 -30
View File
@@ -1,4 +1,3 @@
# cython: language_level=3
import json import json
import socket import socket
import struct import struct
@@ -8,9 +7,10 @@ import msgpack
from msgpack import packb from msgpack import packb
from rstream import Producer, Consumer, AMQPMessage, ConsumerOffsetSpecification, OffsetType, MessageContext from rstream import Producer, Consumer, AMQPMessage, ConsumerOffsetSpecification, OffsetType, MessageContext
import constants cimport constants
from api_client import ApiClient from api_client cimport ApiClient
from processor_command import FileCommand, ProcessorType from processor_command cimport FileCommand, ProcessorType
from annotation cimport Annotation
cdef class QueueConfig: cdef class QueueConfig:
cdef str host cdef str host
@@ -35,15 +35,15 @@ cdef class QueueConfig:
cdef class SocketHandler: cdef class SocketHandler:
"""Handles socket communication with size-prefixed messages.""" """Handles socket communication with size-prefixed messages."""
def __init__(self, on_message): def __init__(self, object on_message):
self.on_message = on_message self.on_message = on_message
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.connect((constants.SOCKET_HOST, constants.SOCKET_PORT)) self._socket.bind((constants.SOCKET_HOST, constants.SOCKET_PORT))
self._socket.listen(1) self._socket.listen(1)
cdef start(self): cdef start(self):
threading.Thread(target=self.start, daemon=True).start() threading.Thread(target=self.start_inner, daemon=True).start()
cdef start_inner(self): cdef start_inner(self):
while True: while True:
@@ -62,53 +62,50 @@ cdef class SocketHandler:
cmd = FileCommand.from_msgpack(data, ProcessorType.SOCKET) cmd = FileCommand.from_msgpack(data, ProcessorType.SOCKET)
self.on_message(cmd) self.on_message(cmd)
async def send(self, object message): cdef send(self, list[Annotation] message):
data = msgpack.packb(message) data = msgpack.packb(message)
size_prefix = len(data).to_bytes(4, 'big') size_prefix = len(data).to_bytes(4, 'big')
self._connection.sendall(size_prefix + data) self._connection.sendall(size_prefix + data)
def close(self): cdef close(self):
if self._socket: if self._socket:
self._socket.close() self._socket.close()
self._socket = None self._socket = None
cdef class RabbitHandler: cdef class RabbitHandler:
cdef str hardware_hash def __init__(self, ApiClient api_client, object on_message):
def __init__(self, config_filename, on_message):
self.on_message = on_message self.on_message = on_message
cdef str config_str = ApiClient().load_file(constants.QUEUE_CONFIG_FILENAME).decode(encoding='utf-8') cdef str config_str = api_client.load_file(constants.QUEUE_CONFIG_FILENAME).decode(encoding='utf-8')
self.queue_config = QueueConfig.from_json(config_str) queue_config = QueueConfig.from_json(config_str)
self.annotation_producer = Producer( self.annotation_producer = Producer(
host=<str>self.queue_config.host, host=<str>queue_config.host,
port=self.queue_config.port, port=queue_config.port,
username=<str>self.queue_config.producer_user, username=<str>queue_config.producer_user,
password=<str>self.queue_config.producer_pw password=<str>queue_config.producer_pw
) )
self.command_consumer = Consumer( self.command_consumer = Consumer(
host=<str>self.queue_config.host, host=<str>queue_config.host,
port=self.queue_config.port, port=queue_config.port,
username=<str>self.queue_config.consumer_user, username=<str>queue_config.consumer_user,
password=<str>self.queue_config.consumer_pw password=<str>queue_config.consumer_pw
) )
cdef start(self): cdef start(self):
self.command_consumer.start() self.command_consumer.start()
self.command_consumer.subscribe(stream=constants.COMMANDS_QUEUE, callback=self.on_message_inner, self.command_consumer.subscribe(stream=<str>constants.COMMANDS_QUEUE, callback=self.on_message_inner,
offset_specification=ConsumerOffsetSpecification(OffsetType.FIRST, None)) # put real offset offset_specification=ConsumerOffsetSpecification(OffsetType.FIRST, None)) # put real offset
def on_message_inner(self, message: AMQPMessage, message_context: MessageContext):
cdef on_message_inner(self, message: AMQPMessage, message_context: MessageContext):
cdef bytes body = message.body cdef bytes body = message.body
cmd = FileCommand.from_msgpack(body, ProcessorType.RABBIT) cmd = FileCommand.from_msgpack(body, ProcessorType.RABBIT)
self.on_message(cmd) self.on_message(cmd)
cpdef send(self, object message): cdef send(self, object message):
packed_message = AMQPMessage(body=packb(message)) packed_message = AMQPMessage(body=packb(message))
self.annotation_producer.send(constants.ANNOTATIONS_QUEUE, packed_message) self.annotation_producer.send(<str>constants.ANNOTATIONS_QUEUE, packed_message)
async def close(self): cdef close(self):
if self.annotation_producer: if self.annotation_producer:
await self.annotation_producer.close() self.annotation_producer.close()
if self.command_consumer: if self.command_consumer:
await self.command_consumer.close() self.command_consumer.close()
+7 -7
View File
@@ -2,14 +2,15 @@ from setuptools import setup, Extension
from Cython.Build import cythonize from Cython.Build import cythonize
extensions = [ extensions = [
Extension('main', ['main.pyx']),
Extension('api_client', ['api_client.pyx']),
Extension('constants', ['constants.pyx']), Extension('constants', ['constants.pyx']),
Extension('hardware_service', ['hardware_service.pyx']), Extension('annotation', ['annotation.pyx']),
Extension('inference', ['inference.pyx']), Extension('hardware_service', ['hardware_service.pyx'], extra_compile_args=["-g"], extra_link_args=["-g"]),
Extension('processor_command', ['processor_command.pyx']), Extension('processor_command', ['processor_command.pyx']),
Extension('api_client', ['api_client.pyx']),
Extension('inference', ['inference.pyx']),
Extension('remote_handlers', ['remote_handlers.pyx']), Extension('remote_handlers', ['remote_handlers.pyx']),
Extension('security', ['security.pyx']) Extension('security', ['security.pyx']),
Extension('main', ['main.pyx']),
] ]
setup( setup(
@@ -20,8 +21,7 @@ setup(
"language_level": 3, "language_level": 3,
"emit_code_comments" : False, "emit_code_comments" : False,
"binding": True "binding": True
}, }
gdb_debug=True
), ),
zip_safe=False zip_safe=False
) )