matrice-inference 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of matrice-inference might be problematic. Click here for more details.
- matrice_inference/__init__.py +72 -0
- matrice_inference/py.typed +0 -0
- matrice_inference/server/__init__.py +23 -0
- matrice_inference/server/inference_interface.py +176 -0
- matrice_inference/server/model/__init__.py +1 -0
- matrice_inference/server/model/model_manager.py +274 -0
- matrice_inference/server/model/model_manager_wrapper.py +550 -0
- matrice_inference/server/model/triton_model_manager.py +290 -0
- matrice_inference/server/model/triton_server.py +1248 -0
- matrice_inference/server/proxy_interface.py +371 -0
- matrice_inference/server/server.py +1004 -0
- matrice_inference/server/stream/__init__.py +0 -0
- matrice_inference/server/stream/app_deployment.py +228 -0
- matrice_inference/server/stream/consumer_worker.py +201 -0
- matrice_inference/server/stream/frame_cache.py +127 -0
- matrice_inference/server/stream/inference_worker.py +163 -0
- matrice_inference/server/stream/post_processing_worker.py +230 -0
- matrice_inference/server/stream/producer_worker.py +147 -0
- matrice_inference/server/stream/stream_pipeline.py +451 -0
- matrice_inference/server/stream/utils.py +23 -0
- matrice_inference/tmp/abstract_model_manager.py +58 -0
- matrice_inference/tmp/aggregator/__init__.py +18 -0
- matrice_inference/tmp/aggregator/aggregator.py +330 -0
- matrice_inference/tmp/aggregator/analytics.py +906 -0
- matrice_inference/tmp/aggregator/ingestor.py +438 -0
- matrice_inference/tmp/aggregator/latency.py +597 -0
- matrice_inference/tmp/aggregator/pipeline.py +968 -0
- matrice_inference/tmp/aggregator/publisher.py +431 -0
- matrice_inference/tmp/aggregator/synchronizer.py +594 -0
- matrice_inference/tmp/batch_manager.py +239 -0
- matrice_inference/tmp/overall_inference_testing.py +338 -0
- matrice_inference/tmp/triton_utils.py +638 -0
- matrice_inference-0.1.2.dist-info/METADATA +28 -0
- matrice_inference-0.1.2.dist-info/RECORD +37 -0
- matrice_inference-0.1.2.dist-info/WHEEL +5 -0
- matrice_inference-0.1.2.dist-info/licenses/LICENSE.txt +21 -0
- matrice_inference-0.1.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Ultra-optimized streaming pipeline using MatriceStream and updated inference interface:
|
|
3
|
+
Direct processing with priority queues, dynamic camera configuration
|
|
4
|
+
|
|
5
|
+
Architecture:
|
|
6
|
+
Consumer workers (threading) -> Priority Queue -> Inference workers (threading) ->
|
|
7
|
+
Priority Queue -> Post-processing workers (threading) -> Priority Queue -> Producer workers (threading)
|
|
8
|
+
|
|
9
|
+
Features:
|
|
10
|
+
- Start without initial configuration
|
|
11
|
+
- Dynamic camera configuration while running
|
|
12
|
+
- Support for both Kafka and Redis streams
|
|
13
|
+
- Integration with updated InferenceInterface and PostProcessor
|
|
14
|
+
- Maximum throughput with direct processing
|
|
15
|
+
- Low latency with no batching delays
|
|
16
|
+
- Multi-camera support with topic routing
|
|
17
|
+
- Thread-based parallelism for inference and post-processing
|
|
18
|
+
- Non-blocking threading for consumers/producers
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import asyncio
|
|
22
|
+
import json
|
|
23
|
+
import time
|
|
24
|
+
import logging
|
|
25
|
+
import threading
|
|
26
|
+
import queue
|
|
27
|
+
import signal
|
|
28
|
+
import copy
|
|
29
|
+
from dataclasses import dataclass, field
|
|
30
|
+
from typing import Any, Dict, Optional, List, Union
|
|
31
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
32
|
+
|
|
33
|
+
from matrice_common.stream.matrice_stream import MatriceStream, StreamType
|
|
34
|
+
from matrice_analytics.post_processing.post_processor import PostProcessor
|
|
35
|
+
|
|
36
|
+
from matrice_inference.server.inference_interface import InferenceInterface
|
|
37
|
+
from matrice_inference.server.model.model_manager_wrapper import ModelManagerWrapper
|
|
38
|
+
from matrice_inference.server.stream.utils import CameraConfig, StreamMessage
|
|
39
|
+
from matrice_inference.server.stream.consumer_worker import ConsumerWorker
|
|
40
|
+
from matrice_inference.server.stream.inference_worker import InferenceWorker
|
|
41
|
+
from matrice_inference.server.stream.post_processing_worker import PostProcessingWorker
|
|
42
|
+
from matrice_inference.server.stream.producer_worker import ProducerWorker
|
|
43
|
+
# from matrice_inference.server.stream.frame_cache import RedisFrameCache
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class StreamingPipeline:
|
|
48
|
+
"""Ultra-optimized streaming pipeline with dynamic camera configuration."""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
inference_interface: InferenceInterface,
|
|
53
|
+
post_processor: PostProcessor,
|
|
54
|
+
consumer_threads=1,
|
|
55
|
+
producer_threads=1,
|
|
56
|
+
inference_threads=1,
|
|
57
|
+
postprocessing_threads=1,
|
|
58
|
+
inference_queue_maxsize=5000,
|
|
59
|
+
postproc_queue_maxsize=5000,
|
|
60
|
+
output_queue_maxsize=5000,
|
|
61
|
+
message_timeout=10.0,
|
|
62
|
+
inference_timeout=30.0,
|
|
63
|
+
shutdown_timeout=30.0,
|
|
64
|
+
camera_configs: Optional[Dict[str, CameraConfig]] = None,
|
|
65
|
+
):
|
|
66
|
+
self.inference_interface = inference_interface
|
|
67
|
+
self.post_processor = post_processor
|
|
68
|
+
self.consumer_threads = consumer_threads
|
|
69
|
+
self.producer_threads = producer_threads
|
|
70
|
+
self.inference_threads = inference_threads
|
|
71
|
+
self.postprocessing_threads = postprocessing_threads
|
|
72
|
+
self.inference_queue_maxsize = inference_queue_maxsize
|
|
73
|
+
self.postproc_queue_maxsize = postproc_queue_maxsize
|
|
74
|
+
self.output_queue_maxsize = output_queue_maxsize
|
|
75
|
+
self.message_timeout = message_timeout
|
|
76
|
+
self.inference_timeout = inference_timeout
|
|
77
|
+
self.shutdown_timeout = shutdown_timeout
|
|
78
|
+
|
|
79
|
+
# Camera configurations (can be empty initially)
|
|
80
|
+
self.camera_configs: Dict[str, CameraConfig] = camera_configs or {}
|
|
81
|
+
|
|
82
|
+
# Priority queues for pipeline stages
|
|
83
|
+
self.inference_queue = queue.PriorityQueue(maxsize=self.inference_queue_maxsize)
|
|
84
|
+
self.postproc_queue = queue.PriorityQueue(maxsize=self.postproc_queue_maxsize)
|
|
85
|
+
self.output_queue = queue.PriorityQueue(maxsize=self.output_queue_maxsize)
|
|
86
|
+
|
|
87
|
+
# Thread pools for CPU/GPU intensive work
|
|
88
|
+
self.inference_executor = ThreadPoolExecutor(self.inference_threads)
|
|
89
|
+
self.postprocessing_executor = ThreadPoolExecutor(self.postprocessing_threads)
|
|
90
|
+
|
|
91
|
+
# No centralized stream management - each worker creates its own streams
|
|
92
|
+
|
|
93
|
+
# Worker instances
|
|
94
|
+
self.consumer_workers: Dict[str, List[ConsumerWorker]] = {}
|
|
95
|
+
self.inference_workers = []
|
|
96
|
+
self.postproc_workers = []
|
|
97
|
+
self.producer_workers = []
|
|
98
|
+
|
|
99
|
+
# Worker threads
|
|
100
|
+
self.worker_threads = []
|
|
101
|
+
|
|
102
|
+
# Control state
|
|
103
|
+
self.running = False
|
|
104
|
+
|
|
105
|
+
self.logger = logging.getLogger(__name__)
|
|
106
|
+
|
|
107
|
+
# Frame cache disabled (commented out)
|
|
108
|
+
# self.frame_cache_config = frame_cache_config or {}
|
|
109
|
+
# self.frame_cache: Optional[RedisFrameCache] = None
|
|
110
|
+
|
|
111
|
+
# Removed set_global_instances method - now passing interfaces as parameters to worker functions
|
|
112
|
+
|
|
113
|
+
async def start(self):
|
|
114
|
+
"""Start the pipeline."""
|
|
115
|
+
if self.running:
|
|
116
|
+
self.logger.warning("Pipeline already running")
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
self.running = True
|
|
120
|
+
self.logger.info("Starting ultra-optimized streaming pipeline...")
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
# Frame cache initialization disabled
|
|
124
|
+
# fc = dict(self.frame_cache_config)
|
|
125
|
+
# if not fc.get("host"):
|
|
126
|
+
# for cfg in self.camera_configs.values():
|
|
127
|
+
# sc = cfg.stream_config
|
|
128
|
+
# if sc.get("stream_type", "kafka").lower() == "redis":
|
|
129
|
+
# fc.setdefault("host", sc.get("host", "localhost"))
|
|
130
|
+
# fc.setdefault("port", sc.get("port", 6379))
|
|
131
|
+
# fc.setdefault("password", sc.get("password"))
|
|
132
|
+
# fc.setdefault("username", sc.get("username"))
|
|
133
|
+
# fc.setdefault("db", sc.get("db", 0))
|
|
134
|
+
# break
|
|
135
|
+
# try:
|
|
136
|
+
# self.frame_cache = RedisFrameCache(
|
|
137
|
+
# host=fc.get("host", "localhost"),
|
|
138
|
+
# port=fc.get("port", 6379),
|
|
139
|
+
# db=fc.get("db", 0),
|
|
140
|
+
# password=fc.get("password"),
|
|
141
|
+
# username=fc.get("username"),
|
|
142
|
+
# ttl_seconds=fc.get("ttl_seconds", 300),
|
|
143
|
+
# prefix=fc.get("prefix", "stream:frames:"),
|
|
144
|
+
# )
|
|
145
|
+
# self.frame_cache.start()
|
|
146
|
+
# except Exception as _:
|
|
147
|
+
# self.frame_cache = None
|
|
148
|
+
# self.logger.warning("Frame cache initialization failed; proceeding without cache")
|
|
149
|
+
|
|
150
|
+
# Initialize streams for existing camera configs
|
|
151
|
+
await self._initialize_streams()
|
|
152
|
+
|
|
153
|
+
# Create and start workers
|
|
154
|
+
await self._create_workers()
|
|
155
|
+
self._start_workers()
|
|
156
|
+
|
|
157
|
+
self.logger.info(
|
|
158
|
+
f"Pipeline started with {len(self.camera_configs)} cameras, "
|
|
159
|
+
f"{sum(len(workers) for workers in self.consumer_workers.values())} consumer workers, "
|
|
160
|
+
f"{len(self.inference_workers)} inference workers, "
|
|
161
|
+
f"{len(self.postproc_workers)} post-processing workers, "
|
|
162
|
+
f"{len(self.producer_workers)} producer workers"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
except Exception as e:
|
|
166
|
+
self.logger.error(f"Failed to start pipeline: {e}")
|
|
167
|
+
await self.stop()
|
|
168
|
+
raise
|
|
169
|
+
|
|
170
|
+
async def stop(self):
|
|
171
|
+
"""Stop the pipeline gracefully."""
|
|
172
|
+
if not self.running:
|
|
173
|
+
return
|
|
174
|
+
|
|
175
|
+
self.logger.info("Stopping pipeline...")
|
|
176
|
+
self.running = False
|
|
177
|
+
|
|
178
|
+
# Stop all workers
|
|
179
|
+
self._stop_workers()
|
|
180
|
+
|
|
181
|
+
# Wait for all threads to complete
|
|
182
|
+
for thread in self.worker_threads:
|
|
183
|
+
if thread.is_alive():
|
|
184
|
+
thread.join(timeout=self.shutdown_timeout)
|
|
185
|
+
|
|
186
|
+
# Close streams
|
|
187
|
+
await self._close_streams()
|
|
188
|
+
|
|
189
|
+
# Shutdown executors
|
|
190
|
+
self.inference_executor.shutdown(wait=False)
|
|
191
|
+
self.postprocessing_executor.shutdown(wait=False)
|
|
192
|
+
|
|
193
|
+
# Frame cache stop disabled
|
|
194
|
+
# try:
|
|
195
|
+
# if self.frame_cache:
|
|
196
|
+
# self.frame_cache.stop()
|
|
197
|
+
# except Exception:
|
|
198
|
+
# pass
|
|
199
|
+
|
|
200
|
+
self.logger.info("Pipeline stopped")
|
|
201
|
+
|
|
202
|
+
async def add_camera_config(self, camera_config: CameraConfig) -> bool:
|
|
203
|
+
"""
|
|
204
|
+
Add a camera configuration dynamically while pipeline is running.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
camera_config: Camera configuration to add
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
bool: True if successfully added, False otherwise
|
|
211
|
+
"""
|
|
212
|
+
try:
|
|
213
|
+
camera_id = camera_config.camera_id
|
|
214
|
+
|
|
215
|
+
if camera_id in self.camera_configs:
|
|
216
|
+
self.logger.warning(f"Camera {camera_id} already exists, updating configuration")
|
|
217
|
+
# Stop existing workers for this camera
|
|
218
|
+
await self._stop_camera_workers(camera_id)
|
|
219
|
+
|
|
220
|
+
# Add camera config
|
|
221
|
+
self.camera_configs[camera_id] = camera_config
|
|
222
|
+
|
|
223
|
+
# Create workers for this camera if pipeline is running
|
|
224
|
+
if self.running:
|
|
225
|
+
await self._create_camera_workers(camera_config)
|
|
226
|
+
self._start_camera_workers(camera_id)
|
|
227
|
+
|
|
228
|
+
self.logger.info(f"Successfully added camera configuration for {camera_id}")
|
|
229
|
+
return True
|
|
230
|
+
|
|
231
|
+
except Exception as e:
|
|
232
|
+
self.logger.error(f"Failed to add camera config for {camera_config.camera_id}: {str(e)}")
|
|
233
|
+
return False
|
|
234
|
+
|
|
235
|
+
async def remove_camera_config(self, camera_id: str) -> bool:
|
|
236
|
+
"""
|
|
237
|
+
Remove a camera configuration dynamically.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
camera_id: ID of camera to remove
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
bool: True if successfully removed, False otherwise
|
|
244
|
+
"""
|
|
245
|
+
try:
|
|
246
|
+
if camera_id not in self.camera_configs:
|
|
247
|
+
self.logger.warning(f"Camera {camera_id} does not exist")
|
|
248
|
+
return False
|
|
249
|
+
|
|
250
|
+
# Stop workers for this camera
|
|
251
|
+
await self._stop_camera_workers(camera_id)
|
|
252
|
+
|
|
253
|
+
# Remove camera config
|
|
254
|
+
del self.camera_configs[camera_id]
|
|
255
|
+
|
|
256
|
+
self.logger.info(f"Successfully removed camera configuration for {camera_id}")
|
|
257
|
+
return True
|
|
258
|
+
|
|
259
|
+
except Exception as e:
|
|
260
|
+
self.logger.error(f"Failed to remove camera config for {camera_id}: {str(e)}")
|
|
261
|
+
return False
|
|
262
|
+
|
|
263
|
+
async def update_camera_config(self, camera_config: CameraConfig) -> bool:
|
|
264
|
+
"""
|
|
265
|
+
Update an existing camera configuration.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
camera_config: Updated camera configuration
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
bool: True if successfully updated, False otherwise
|
|
272
|
+
"""
|
|
273
|
+
return await self.add_camera_config(camera_config)
|
|
274
|
+
|
|
275
|
+
def enable_camera(self, camera_id: str) -> bool:
|
|
276
|
+
"""Enable a camera."""
|
|
277
|
+
if camera_id in self.camera_configs:
|
|
278
|
+
self.camera_configs[camera_id].enabled = True
|
|
279
|
+
self.logger.info(f"Camera {camera_id} enabled")
|
|
280
|
+
return True
|
|
281
|
+
return False
|
|
282
|
+
|
|
283
|
+
def disable_camera(self, camera_id: str) -> bool:
|
|
284
|
+
"""Disable a camera."""
|
|
285
|
+
if camera_id in self.camera_configs:
|
|
286
|
+
self.camera_configs[camera_id].enabled = False
|
|
287
|
+
self.logger.info(f"Camera {camera_id} disabled")
|
|
288
|
+
return True
|
|
289
|
+
return False
|
|
290
|
+
|
|
291
|
+
async def _initialize_streams(self):
|
|
292
|
+
"""No centralized stream initialization - workers create their own streams."""
|
|
293
|
+
pass
|
|
294
|
+
|
|
295
|
+
async def _initialize_camera_streams(self, camera_config: CameraConfig):
|
|
296
|
+
"""No centralized camera stream initialization - workers create their own streams."""
|
|
297
|
+
pass
|
|
298
|
+
|
|
299
|
+
async def _close_streams(self):
|
|
300
|
+
"""No centralized streams to close - workers manage their own streams."""
|
|
301
|
+
pass
|
|
302
|
+
|
|
303
|
+
async def _close_camera_streams(self, camera_id: str):
|
|
304
|
+
"""No centralized camera streams to close - workers manage their own streams."""
|
|
305
|
+
pass
|
|
306
|
+
|
|
307
|
+
async def _create_workers(self):
|
|
308
|
+
"""Create all worker instances."""
|
|
309
|
+
# Create consumer workers (per camera)
|
|
310
|
+
for camera_config in self.camera_configs.values():
|
|
311
|
+
await self._create_camera_workers(camera_config)
|
|
312
|
+
|
|
313
|
+
# Create inference workers
|
|
314
|
+
for i in range(self.inference_threads):
|
|
315
|
+
worker = InferenceWorker(
|
|
316
|
+
worker_id=i,
|
|
317
|
+
inference_queue=self.inference_queue,
|
|
318
|
+
postproc_queue=self.postproc_queue,
|
|
319
|
+
inference_executor=self.inference_executor,
|
|
320
|
+
message_timeout=self.message_timeout,
|
|
321
|
+
inference_timeout=self.inference_timeout,
|
|
322
|
+
inference_interface=self.inference_interface
|
|
323
|
+
)
|
|
324
|
+
self.inference_workers.append(worker)
|
|
325
|
+
|
|
326
|
+
# Create post-processing workers
|
|
327
|
+
for i in range(self.postprocessing_threads):
|
|
328
|
+
worker = PostProcessingWorker(
|
|
329
|
+
worker_id=i,
|
|
330
|
+
postproc_queue=self.postproc_queue,
|
|
331
|
+
output_queue=self.output_queue,
|
|
332
|
+
postprocessing_executor=self.postprocessing_executor,
|
|
333
|
+
message_timeout=self.message_timeout,
|
|
334
|
+
inference_timeout=self.inference_timeout,
|
|
335
|
+
post_processor=self.post_processor,
|
|
336
|
+
# frame_cache=self.frame_cache,
|
|
337
|
+
)
|
|
338
|
+
self.postproc_workers.append(worker)
|
|
339
|
+
|
|
340
|
+
# Create producer workers
|
|
341
|
+
for i in range(self.producer_threads):
|
|
342
|
+
worker = ProducerWorker(
|
|
343
|
+
worker_id=i,
|
|
344
|
+
output_queue=self.output_queue,
|
|
345
|
+
camera_configs=self.camera_configs,
|
|
346
|
+
message_timeout=self.message_timeout
|
|
347
|
+
)
|
|
348
|
+
self.producer_workers.append(worker)
|
|
349
|
+
|
|
350
|
+
async def _create_camera_workers(self, camera_config: CameraConfig):
|
|
351
|
+
"""Create consumer workers for a specific camera."""
|
|
352
|
+
camera_id = camera_config.camera_id
|
|
353
|
+
|
|
354
|
+
# Create consumer workers for this camera - each worker will create its own stream
|
|
355
|
+
camera_workers = []
|
|
356
|
+
for i in range(self.consumer_threads):
|
|
357
|
+
worker = ConsumerWorker(
|
|
358
|
+
camera_id=camera_id,
|
|
359
|
+
worker_id=i,
|
|
360
|
+
stream_config=camera_config.stream_config,
|
|
361
|
+
input_topic=camera_config.input_topic,
|
|
362
|
+
inference_queue=self.inference_queue,
|
|
363
|
+
message_timeout=self.message_timeout,
|
|
364
|
+
camera_config=camera_config
|
|
365
|
+
)
|
|
366
|
+
camera_workers.append(worker)
|
|
367
|
+
|
|
368
|
+
self.consumer_workers[camera_id] = camera_workers
|
|
369
|
+
|
|
370
|
+
def _start_workers(self):
|
|
371
|
+
"""Start all worker instances."""
|
|
372
|
+
# Start consumer workers
|
|
373
|
+
for camera_id in self.consumer_workers:
|
|
374
|
+
self._start_camera_workers(camera_id)
|
|
375
|
+
|
|
376
|
+
# Start inference workers
|
|
377
|
+
for worker in self.inference_workers:
|
|
378
|
+
thread = worker.start()
|
|
379
|
+
self.worker_threads.append(thread)
|
|
380
|
+
|
|
381
|
+
# Start post-processing workers
|
|
382
|
+
for worker in self.postproc_workers:
|
|
383
|
+
thread = worker.start()
|
|
384
|
+
self.worker_threads.append(thread)
|
|
385
|
+
|
|
386
|
+
# Start producer workers
|
|
387
|
+
for worker in self.producer_workers:
|
|
388
|
+
thread = worker.start()
|
|
389
|
+
self.worker_threads.append(thread)
|
|
390
|
+
|
|
391
|
+
def _start_camera_workers(self, camera_id: str):
|
|
392
|
+
"""Start consumer workers for a specific camera."""
|
|
393
|
+
if camera_id in self.consumer_workers:
|
|
394
|
+
for worker in self.consumer_workers[camera_id]:
|
|
395
|
+
thread = worker.start()
|
|
396
|
+
self.worker_threads.append(thread)
|
|
397
|
+
|
|
398
|
+
def _stop_workers(self):
|
|
399
|
+
"""Stop all worker instances."""
|
|
400
|
+
# Stop all workers
|
|
401
|
+
for workers in self.consumer_workers.values():
|
|
402
|
+
for worker in workers:
|
|
403
|
+
worker.stop()
|
|
404
|
+
|
|
405
|
+
for worker in (self.inference_workers + self.postproc_workers + self.producer_workers):
|
|
406
|
+
worker.stop()
|
|
407
|
+
|
|
408
|
+
async def _stop_camera_workers(self, camera_id: str):
|
|
409
|
+
"""Stop consumer workers for a specific camera."""
|
|
410
|
+
if camera_id in self.consumer_workers:
|
|
411
|
+
for worker in self.consumer_workers[camera_id]:
|
|
412
|
+
worker.stop()
|
|
413
|
+
# Remove from tracking
|
|
414
|
+
del self.consumer_workers[camera_id]
|
|
415
|
+
|
|
416
|
+
def get_metrics(self) -> Dict[str, Any]:
|
|
417
|
+
"""Get pipeline metrics."""
|
|
418
|
+
return {
|
|
419
|
+
"running": self.running,
|
|
420
|
+
"camera_count": len(self.camera_configs),
|
|
421
|
+
"enabled_cameras": sum(1 for config in self.camera_configs.values() if config.enabled),
|
|
422
|
+
"queue_sizes": {
|
|
423
|
+
"inference": self.inference_queue.qsize(),
|
|
424
|
+
"postproc": self.postproc_queue.qsize(),
|
|
425
|
+
"output": self.output_queue.qsize(),
|
|
426
|
+
},
|
|
427
|
+
"worker_counts": {
|
|
428
|
+
"consumers": sum(len(workers) for workers in self.consumer_workers.values()),
|
|
429
|
+
"inference_workers": len(self.inference_workers),
|
|
430
|
+
"postproc_workers": len(self.postproc_workers),
|
|
431
|
+
"producers": len(self.producer_workers),
|
|
432
|
+
},
|
|
433
|
+
"thread_counts": {
|
|
434
|
+
"total_threads": len(self.worker_threads),
|
|
435
|
+
"active_threads": len([t for t in self.worker_threads if t.is_alive()]),
|
|
436
|
+
},
|
|
437
|
+
"thread_pool_sizes": {
|
|
438
|
+
"inference_threads": self.inference_threads,
|
|
439
|
+
"postprocessing_threads": self.postprocessing_threads,
|
|
440
|
+
},
|
|
441
|
+
"camera_configs": {
|
|
442
|
+
camera_id: {
|
|
443
|
+
"input_topic": config.input_topic,
|
|
444
|
+
"output_topic": config.output_topic,
|
|
445
|
+
"enabled": config.enabled,
|
|
446
|
+
"stream_type": config.stream_config.get("stream_type", "kafka")
|
|
447
|
+
}
|
|
448
|
+
for camera_id, config in self.camera_configs.items()
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Dict, Any, Optional
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class CameraConfig:
|
|
8
|
+
"""Configuration for a camera stream."""
|
|
9
|
+
camera_id: str
|
|
10
|
+
input_topic: str
|
|
11
|
+
output_topic: str
|
|
12
|
+
stream_config: Dict[str, Any] = field(default_factory=dict)
|
|
13
|
+
enabled: bool = True
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class StreamMessage:
|
|
18
|
+
"""Raw message from stream."""
|
|
19
|
+
camera_id: str
|
|
20
|
+
message_key: str
|
|
21
|
+
data: Any
|
|
22
|
+
timestamp: datetime
|
|
23
|
+
priority: int = 1
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Tuple, Dict, Any, Optional, List
|
|
3
|
+
|
|
4
|
+
class AbstractModelManager(ABC):
|
|
5
|
+
"""Abstract base class for model management."""
|
|
6
|
+
|
|
7
|
+
@abstractmethod
|
|
8
|
+
def __init__(
|
|
9
|
+
self,
|
|
10
|
+
model_id: str,
|
|
11
|
+
internal_server_type: str,
|
|
12
|
+
internal_port: int,
|
|
13
|
+
internal_host: str,
|
|
14
|
+
action_tracker: Any,
|
|
15
|
+
num_model_instances: int = 1,
|
|
16
|
+
):
|
|
17
|
+
"""Initialize the model manager.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
model_id: ID of the model.
|
|
21
|
+
internal_server_type: Type of internal server.
|
|
22
|
+
internal_port: Internal port number.
|
|
23
|
+
internal_host: Internal host address.
|
|
24
|
+
action_tracker: Tracker for monitoring actions.
|
|
25
|
+
num_model_instances: Number of model instances to create.
|
|
26
|
+
"""
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def get_model(self) -> Any:
|
|
31
|
+
"""Get a model instance for inference."""
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def inference(
|
|
36
|
+
self,
|
|
37
|
+
input1: Any,
|
|
38
|
+
input2: Optional[Any] = None,
|
|
39
|
+
extra_params: Optional[Dict[str, Any]] = None,
|
|
40
|
+
stream_key: Optional[str] = None,
|
|
41
|
+
stream_info: Optional[Dict[str, Any]] = None,
|
|
42
|
+
input_hash: Optional[str] = None,
|
|
43
|
+
) -> Tuple[Any, bool]:
|
|
44
|
+
"""Perform single inference."""
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def batch_inference(
|
|
49
|
+
self,
|
|
50
|
+
input1: List[Any],
|
|
51
|
+
input2: Optional[List[Any]] = None,
|
|
52
|
+
extra_params: Optional[Dict[str, Any]] = None,
|
|
53
|
+
stream_key: Optional[str] = None,
|
|
54
|
+
stream_info: Optional[Dict[str, Any]] = None,
|
|
55
|
+
input_hash: Optional[str] = None,
|
|
56
|
+
) -> Tuple[List[Any], bool]:
|
|
57
|
+
"""Perform batch inference."""
|
|
58
|
+
pass
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Aggregator package for handling deployment streaming and results aggregation.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
# Import modules to make them available for external use
|
|
6
|
+
from matrice_inference.tmp.aggregator.pipeline import ResultsAggregationPipeline
|
|
7
|
+
from matrice_inference.tmp.aggregator.synchronizer import ResultsSynchronizer
|
|
8
|
+
from matrice_inference.tmp.aggregator.ingestor import ResultsIngestor
|
|
9
|
+
from matrice_inference.tmp.aggregator.aggregator import ResultsAggregator
|
|
10
|
+
from matrice_inference.tmp.aggregator.publisher import ResultsPublisher
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"ResultsAggregationPipeline",
|
|
14
|
+
"ResultsSynchronizer",
|
|
15
|
+
"ResultsIngestor",
|
|
16
|
+
"ResultsAggregator",
|
|
17
|
+
"ResultsPublisher",
|
|
18
|
+
]
|