matrice-analytics 0.1.56__py3-none-any.whl → 0.1.58__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-analytics might be problematic. Click here for more details.
- matrice_analytics/post_processing/face_reg/embedding_manager.py +71 -6
- matrice_analytics/post_processing/face_reg/face_recognition.py +93 -6
- {matrice_analytics-0.1.56.dist-info → matrice_analytics-0.1.58.dist-info}/METADATA +1 -1
- {matrice_analytics-0.1.56.dist-info → matrice_analytics-0.1.58.dist-info}/RECORD +7 -7
- {matrice_analytics-0.1.56.dist-info → matrice_analytics-0.1.58.dist-info}/WHEEL +0 -0
- {matrice_analytics-0.1.56.dist-info → matrice_analytics-0.1.58.dist-info}/licenses/LICENSE.txt +0 -0
- {matrice_analytics-0.1.56.dist-info → matrice_analytics-0.1.58.dist-info}/top_level.txt +0 -0
|
@@ -56,7 +56,26 @@ class EmbeddingConfig:
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
class EmbeddingManager:
|
|
59
|
-
"""
|
|
59
|
+
"""
|
|
60
|
+
Manages face embeddings, search operations, and caching.
|
|
61
|
+
|
|
62
|
+
CRITICAL INITIALIZATION FLOW:
|
|
63
|
+
1. __init__() creates the manager but does NOT load embeddings or start background refresh
|
|
64
|
+
2. External caller MUST call await _load_staff_embeddings() to load embeddings synchronously
|
|
65
|
+
3. After successful load, caller SHOULD call start_background_refresh() for periodic updates
|
|
66
|
+
4. The _embeddings_loaded flag tracks whether embeddings are ready for use
|
|
67
|
+
5. All search operations check _embeddings_loaded before proceeding
|
|
68
|
+
|
|
69
|
+
This design prevents race conditions where:
|
|
70
|
+
- Background thread tries to load while main thread is loading
|
|
71
|
+
- Search operations are called before embeddings are loaded
|
|
72
|
+
- Multiple threads compete for the embeddings_lock during initialization
|
|
73
|
+
|
|
74
|
+
Thread Safety:
|
|
75
|
+
- _embeddings_lock protects embeddings_matrix and embedding_metadata
|
|
76
|
+
- _cache_lock protects track_id_cache
|
|
77
|
+
- _embeddings_loaded is set only after successful load under lock
|
|
78
|
+
"""
|
|
60
79
|
|
|
61
80
|
def __init__(self, config: EmbeddingConfig, face_client: FacialRecognitionClient = None):
|
|
62
81
|
self.config = config
|
|
@@ -89,11 +108,47 @@ class EmbeddingManager:
|
|
|
89
108
|
self._is_running = False
|
|
90
109
|
self._stop_event = threading.Event()
|
|
91
110
|
|
|
92
|
-
#
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
111
|
+
# Initialization status flag
|
|
112
|
+
self._embeddings_loaded = False
|
|
113
|
+
|
|
114
|
+
# DON'T start background refresh yet - wait for initial load in initialize()
|
|
115
|
+
# This prevents race conditions where background thread interferes with main init
|
|
116
|
+
self.logger.info(f"EmbeddingManager created - background refresh will start after initial load (interval: {self.config.background_refresh_interval}s)")
|
|
96
117
|
|
|
118
|
+
def is_ready(self) -> bool:
|
|
119
|
+
"""
|
|
120
|
+
Check if embeddings are loaded and ready for use.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
True if embeddings are loaded and matrix is valid, False otherwise
|
|
124
|
+
"""
|
|
125
|
+
return (
|
|
126
|
+
self._embeddings_loaded
|
|
127
|
+
and self.embeddings_matrix is not None
|
|
128
|
+
and len(self.embedding_metadata) > 0
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
def get_status(self) -> Dict[str, Any]:
|
|
132
|
+
"""
|
|
133
|
+
Get detailed status of embedding manager for debugging and health checks.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
Dictionary with status information
|
|
137
|
+
"""
|
|
138
|
+
with self._embeddings_lock:
|
|
139
|
+
matrix_shape = self.embeddings_matrix.shape if self.embeddings_matrix is not None else None
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
"embeddings_loaded": self._embeddings_loaded,
|
|
143
|
+
"embeddings_count": len(self.staff_embeddings),
|
|
144
|
+
"matrix_shape": matrix_shape,
|
|
145
|
+
"metadata_count": len(self.embedding_metadata),
|
|
146
|
+
"cache_size": len(self.track_id_cache),
|
|
147
|
+
"last_update": self.staff_embeddings_last_update,
|
|
148
|
+
"is_running": self._is_running,
|
|
149
|
+
"is_ready": self.is_ready(),
|
|
150
|
+
}
|
|
151
|
+
|
|
97
152
|
def set_face_client(self, face_client: FacialRecognitionClient):
|
|
98
153
|
"""Set the face recognition client."""
|
|
99
154
|
self.face_client = face_client
|
|
@@ -272,6 +327,8 @@ class EmbeddingManager:
|
|
|
272
327
|
|
|
273
328
|
self.embedding_metadata = self.staff_embeddings.copy()
|
|
274
329
|
self.staff_embeddings_last_update = time.time()
|
|
330
|
+
self._embeddings_loaded = True # Mark as successfully loaded
|
|
331
|
+
|
|
275
332
|
self.logger.info(f"Successfully loaded and cached {len(self.staff_embeddings)} staff embeddings (dim={self.embeddings_matrix.shape[1]})")
|
|
276
333
|
print(f"=============== SUCCESS: LOADED {len(self.staff_embeddings)} EMBEDDINGS, MATRIX SHAPE: {self.embeddings_matrix.shape} ===============")
|
|
277
334
|
try:
|
|
@@ -336,9 +393,16 @@ class EmbeddingManager:
|
|
|
336
393
|
|
|
337
394
|
def _find_best_local_match(self, query_embedding: List[float]) -> Optional[Tuple[StaffEmbedding, float]]:
|
|
338
395
|
"""Find best matching staff member using optimized matrix operations (thread-safe)."""
|
|
396
|
+
# Check if embeddings are loaded at all
|
|
397
|
+
if not self._embeddings_loaded:
|
|
398
|
+
print(f"ERROR: _find_best_local_match called but embeddings not loaded yet (_embeddings_loaded={self._embeddings_loaded})")
|
|
399
|
+
self.logger.error("Embeddings not loaded - _find_best_local_match cannot proceed")
|
|
400
|
+
return None
|
|
401
|
+
|
|
339
402
|
with self._embeddings_lock:
|
|
340
403
|
if self.embeddings_matrix is None or len(self.embedding_metadata) == 0:
|
|
341
|
-
print(f"ERROR: _find_best_local_match - embeddings_matrix is None={self.embeddings_matrix is None}, metadata_len={len(self.embedding_metadata)}")
|
|
404
|
+
print(f"ERROR: _find_best_local_match - embeddings_matrix is None={self.embeddings_matrix is None}, metadata_len={len(self.embedding_metadata)}, _embeddings_loaded={self._embeddings_loaded}")
|
|
405
|
+
self.logger.error(f"Embeddings matrix is None despite _embeddings_loaded={self._embeddings_loaded}")
|
|
342
406
|
return None
|
|
343
407
|
|
|
344
408
|
# Create local copies to avoid issues with concurrent modifications
|
|
@@ -346,6 +410,7 @@ class EmbeddingManager:
|
|
|
346
410
|
embedding_metadata = self.embedding_metadata.copy()
|
|
347
411
|
|
|
348
412
|
if embeddings_matrix is None:
|
|
413
|
+
print("ERROR: _find_best_local_match - embeddings_matrix copy is None")
|
|
349
414
|
return None
|
|
350
415
|
|
|
351
416
|
try:
|
|
@@ -143,6 +143,13 @@ class TemporalIdentityManager:
|
|
|
143
143
|
|
|
144
144
|
# PRIMARY PATH: Local similarity search using EmbeddingManager (FAST - ~1-5ms)
|
|
145
145
|
if self.embedding_manager:
|
|
146
|
+
# Defensive check: ensure embeddings are loaded before attempting search
|
|
147
|
+
if not self.embedding_manager.is_ready():
|
|
148
|
+
status = self.embedding_manager.get_status()
|
|
149
|
+
self.logger.error(f"EmbeddingManager not ready for search - status: {status}")
|
|
150
|
+
print(f"ERROR: _compute_best_identity - embeddings not ready. Status: {status}")
|
|
151
|
+
return None, "Unknown", 0.0, None, {}, "unknown"
|
|
152
|
+
|
|
146
153
|
try:
|
|
147
154
|
local_match = self.embedding_manager._find_best_local_match(emb)
|
|
148
155
|
|
|
@@ -540,11 +547,30 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
540
547
|
Async initialization method to set up face client and all components.
|
|
541
548
|
Must be called after __init__ before process() can be called.
|
|
542
549
|
|
|
550
|
+
CRITICAL INITIALIZATION SEQUENCE:
|
|
551
|
+
1. Initialize face client and update deployment
|
|
552
|
+
2. Create EmbeddingManager (does NOT load embeddings yet)
|
|
553
|
+
3. Synchronously load embeddings with _load_staff_embeddings() - MUST succeed
|
|
554
|
+
4. Verify embeddings are actually loaded (fail-fast if not)
|
|
555
|
+
5. Start background refresh thread (only after successful load)
|
|
556
|
+
6. Initialize TemporalIdentityManager with loaded EmbeddingManager
|
|
557
|
+
7. Final verification of all components
|
|
558
|
+
|
|
559
|
+
This sequence ensures:
|
|
560
|
+
- No race conditions between main load and background thread
|
|
561
|
+
- Fail-fast behavior if embeddings can't be loaded
|
|
562
|
+
- All components have verified embeddings before use
|
|
563
|
+
|
|
543
564
|
Args:
|
|
544
565
|
config: Optional config to use. If not provided, uses config from __init__.
|
|
566
|
+
|
|
567
|
+
Raises:
|
|
568
|
+
RuntimeError: If embeddings fail to load or verification fails
|
|
545
569
|
"""
|
|
570
|
+
print("=============== INITIALIZE() CALLED ===============")
|
|
546
571
|
if self._initialized:
|
|
547
572
|
self.logger.debug("Use case already initialized, skipping")
|
|
573
|
+
print("=============== ALREADY INITIALIZED, SKIPPING ===============")
|
|
548
574
|
return
|
|
549
575
|
|
|
550
576
|
# Use provided config or fall back to default config from __init__
|
|
@@ -558,10 +584,12 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
558
584
|
raise TypeError(f"Invalid config type for initialization: {type(init_config)}, expected FaceRecognitionEmbeddingConfig")
|
|
559
585
|
|
|
560
586
|
self.logger.info("Initializing face recognition use case with provided config")
|
|
587
|
+
print("=============== STEP 1: INITIALIZING FACE CLIENT ===============")
|
|
561
588
|
|
|
562
589
|
# Initialize face client (includes deployment update)
|
|
563
590
|
try:
|
|
564
591
|
self.face_client = await self._get_facial_recognition_client(init_config)
|
|
592
|
+
print(f"=============== FACE CLIENT INITIALIZED: {self.face_client is not None} ===============")
|
|
565
593
|
|
|
566
594
|
# Initialize People activity logging if enabled
|
|
567
595
|
if init_config.enable_people_activity_logging:
|
|
@@ -570,7 +598,9 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
570
598
|
self.logger.info("People activity logging enabled and started")
|
|
571
599
|
|
|
572
600
|
# Initialize EmbeddingManager
|
|
601
|
+
print("=============== STEP 2: INITIALIZING EMBEDDING MANAGER ===============")
|
|
573
602
|
if not init_config.embedding_config:
|
|
603
|
+
print("=============== CREATING EMBEDDING CONFIG ===============")
|
|
574
604
|
init_config.embedding_config = EmbeddingConfig(
|
|
575
605
|
similarity_threshold=init_config.similarity_threshold,
|
|
576
606
|
confidence_threshold=init_config.confidence_threshold,
|
|
@@ -581,16 +611,42 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
581
611
|
staff_embeddings_cache_ttl=43200,
|
|
582
612
|
)
|
|
583
613
|
self.embedding_manager = EmbeddingManager(init_config.embedding_config, self.face_client)
|
|
614
|
+
print(f"=============== EMBEDDING MANAGER CREATED: {self.embedding_manager is not None} ===============")
|
|
584
615
|
self.logger.info("Embedding manager initialized")
|
|
585
616
|
|
|
586
617
|
# Load staff embeddings immediately for fast startup (avoid race conditions)
|
|
618
|
+
# This MUST succeed before we can proceed - fail fast if it doesn't
|
|
619
|
+
print("=============== STEP 3: CALLING _load_staff_embeddings() ===============")
|
|
587
620
|
embeddings_loaded = await self.embedding_manager._load_staff_embeddings()
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
621
|
+
print(f"=============== EMBEDDINGS LOADED: {embeddings_loaded} ===============")
|
|
622
|
+
|
|
623
|
+
if not embeddings_loaded:
|
|
624
|
+
error_msg = "CRITICAL: Failed to load staff embeddings at initialization - cannot proceed without embeddings"
|
|
625
|
+
print(f"=============== {error_msg} ===============")
|
|
626
|
+
self.logger.error(error_msg)
|
|
627
|
+
raise RuntimeError(error_msg)
|
|
628
|
+
|
|
629
|
+
# Verify embeddings are actually loaded using is_ready() method
|
|
630
|
+
if not self.embedding_manager.is_ready():
|
|
631
|
+
status = self.embedding_manager.get_status()
|
|
632
|
+
error_msg = f"CRITICAL: Embeddings not ready after load - status: {status}"
|
|
633
|
+
print(f"=============== {error_msg} ===============")
|
|
634
|
+
self.logger.error(error_msg)
|
|
635
|
+
raise RuntimeError(error_msg)
|
|
636
|
+
|
|
637
|
+
print(f"=============== STAFF EMBEDDINGS COUNT: {len(self.embedding_manager.staff_embeddings)} ===============")
|
|
638
|
+
print(f"=============== EMBEDDINGS MATRIX SHAPE: {self.embedding_manager.embeddings_matrix.shape} ===============")
|
|
639
|
+
print(f"=============== EMBEDDINGS LOADED FLAG: {self.embedding_manager._embeddings_loaded} ===============")
|
|
640
|
+
self.logger.info(f"Successfully loaded {len(self.embedding_manager.staff_embeddings)} staff embeddings at initialization")
|
|
641
|
+
|
|
642
|
+
# NOW start background refresh after successful initial load (prevents race conditions)
|
|
643
|
+
if init_config.embedding_config.enable_background_refresh:
|
|
644
|
+
print("=============== STEP 4: STARTING BACKGROUND REFRESH ===============")
|
|
645
|
+
self.embedding_manager.start_background_refresh()
|
|
646
|
+
self.logger.info("Background embedding refresh started after successful initial load")
|
|
592
647
|
|
|
593
648
|
# Initialize TemporalIdentityManager with EmbeddingManager for fast local search
|
|
649
|
+
print("=============== STEP 5: INITIALIZING TEMPORAL IDENTITY MANAGER ===============")
|
|
594
650
|
self.temporal_identity_manager = TemporalIdentityManager(
|
|
595
651
|
face_client=self.face_client,
|
|
596
652
|
embedding_manager=self.embedding_manager,
|
|
@@ -602,8 +658,26 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
602
658
|
)
|
|
603
659
|
self.logger.info("Temporal identity manager initialized with embedding manager for local similarity search")
|
|
604
660
|
|
|
661
|
+
# Final verification before marking as initialized
|
|
662
|
+
print("=============== STEP 6: FINAL VERIFICATION ===============")
|
|
663
|
+
if not self.embedding_manager.is_ready():
|
|
664
|
+
status = self.embedding_manager.get_status()
|
|
665
|
+
error_msg = f"CRITICAL: Final verification failed - embeddings not ready. Status: {status}"
|
|
666
|
+
print(f"=============== {error_msg} ===============")
|
|
667
|
+
self.logger.error(error_msg)
|
|
668
|
+
raise RuntimeError(error_msg)
|
|
669
|
+
|
|
670
|
+
# Log detailed status for debugging
|
|
671
|
+
status = self.embedding_manager.get_status()
|
|
672
|
+
print(f"=============== FINAL CHECKS PASSED ===============")
|
|
673
|
+
print(f" - Face client: {self.face_client is not None}")
|
|
674
|
+
print(f" - Embedding manager: {self.embedding_manager is not None}")
|
|
675
|
+
print(f" - Embedding manager status: {status}")
|
|
676
|
+
print(f" - Temporal identity manager: {self.temporal_identity_manager is not None}")
|
|
677
|
+
|
|
605
678
|
self._initialized = True
|
|
606
|
-
self.logger.info("Face recognition use case fully initialized")
|
|
679
|
+
self.logger.info("Face recognition use case fully initialized and verified")
|
|
680
|
+
print("=============== INITIALIZATION COMPLETE ===============")
|
|
607
681
|
|
|
608
682
|
except Exception as e:
|
|
609
683
|
self.logger.error(f"Error during use case initialization: {e}", exc_info=True)
|
|
@@ -747,7 +821,7 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
747
821
|
self.logger.debug("Applied category filtering")
|
|
748
822
|
|
|
749
823
|
print("------------------TILL TRACKER MS----------------------------")
|
|
750
|
-
print("LATENCY:",(time.time() - processing_start)*1000,"| Throughput fps:",(1.0 / (time.time() - processing_start)) if (time.time() - processing_start) > 0 else None)
|
|
824
|
+
print(self._initialized,"LATENCY:",(time.time() - processing_start)*1000,"| Throughput fps:",(1.0 / (time.time() - processing_start)) if (time.time() - processing_start) > 0 else None)
|
|
751
825
|
print("------------------TILL TRACKER MS----------------------------")
|
|
752
826
|
# Advanced tracking (BYTETracker-like) - only if enabled
|
|
753
827
|
if config.enable_face_tracking:
|
|
@@ -794,6 +868,19 @@ class FaceRecognitionEmbeddingUseCase(BaseProcessor):
|
|
|
794
868
|
|
|
795
869
|
# Process face recognition for each detection (if enabled)
|
|
796
870
|
if config.enable_face_recognition:
|
|
871
|
+
# Additional safety check: verify embeddings are still loaded and ready
|
|
872
|
+
if not self.embedding_manager or not self.embedding_manager.is_ready():
|
|
873
|
+
status = self.embedding_manager.get_status() if self.embedding_manager else {}
|
|
874
|
+
error_msg = f"CRITICAL: Cannot process face recognition - embeddings not ready. Status: {status}"
|
|
875
|
+
self.logger.error(error_msg)
|
|
876
|
+
print(f"ERROR: {error_msg}")
|
|
877
|
+
return self.create_error_result(
|
|
878
|
+
error_msg,
|
|
879
|
+
usecase=self.name,
|
|
880
|
+
category=self.category,
|
|
881
|
+
context=context,
|
|
882
|
+
)
|
|
883
|
+
|
|
797
884
|
face_recognition_result = await self._process_face_recognition(
|
|
798
885
|
processed_data, config, stream_info, input_bytes
|
|
799
886
|
)
|
|
@@ -28,8 +28,8 @@ matrice_analytics/post_processing/core/config.py,sha256=uyxWndO-DE9PeGD_h5K3TeB0
|
|
|
28
28
|
matrice_analytics/post_processing/core/config_utils.py,sha256=QuAS-_JKSoNOtfUWgr7Alf_wsqODzN2rHlQu-cHRK0s,34311
|
|
29
29
|
matrice_analytics/post_processing/face_reg/__init__.py,sha256=yntaiGlW9vdjBpPZQXNuovALihJPzRlFyUE88l3MhBA,1364
|
|
30
30
|
matrice_analytics/post_processing/face_reg/compare_similarity.py,sha256=NlFc8b2a74k0PqSFAbuM_fUbA1BT3pr3VUgvSqRpJzQ,23396
|
|
31
|
-
matrice_analytics/post_processing/face_reg/embedding_manager.py,sha256=
|
|
32
|
-
matrice_analytics/post_processing/face_reg/face_recognition.py,sha256=
|
|
31
|
+
matrice_analytics/post_processing/face_reg/embedding_manager.py,sha256=zd4KIqZijRssPzA7QJsg9-DCJ983aIyUPoo8WuRW2rs,44956
|
|
32
|
+
matrice_analytics/post_processing/face_reg/face_recognition.py,sha256=qkFl7f3EkyK9V6nWVCCC61ODV8R2sRffp1OB-ZVPjSU,109247
|
|
33
33
|
matrice_analytics/post_processing/face_reg/face_recognition_client.py,sha256=eF2NYju1uWKXhILndI1rh4_VhWrKSGidui2jjbPQXgM,27596
|
|
34
34
|
matrice_analytics/post_processing/face_reg/people_activity_logging.py,sha256=vZbIvkK1h3h58ROeF0_ygF3lqr19O2h5222bN8XyIis,13675
|
|
35
35
|
matrice_analytics/post_processing/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -189,8 +189,8 @@ matrice_analytics/post_processing/utils/format_utils.py,sha256=UTF7A5h9j0_S12xH9
|
|
|
189
189
|
matrice_analytics/post_processing/utils/geometry_utils.py,sha256=BWfdM6RsdJTTLR1GqkWfdwpjMEjTCJyuBxA4zVGKdfk,9623
|
|
190
190
|
matrice_analytics/post_processing/utils/smoothing_utils.py,sha256=78U-yucAcjUiZ0NIAc9NOUSIT0PWP1cqyIPA_Fdrjp0,14699
|
|
191
191
|
matrice_analytics/post_processing/utils/tracking_utils.py,sha256=rWxuotnJ3VLMHIBOud2KLcu4yZfDp7hVPWUtNAq_2xw,8288
|
|
192
|
-
matrice_analytics-0.1.
|
|
193
|
-
matrice_analytics-0.1.
|
|
194
|
-
matrice_analytics-0.1.
|
|
195
|
-
matrice_analytics-0.1.
|
|
196
|
-
matrice_analytics-0.1.
|
|
192
|
+
matrice_analytics-0.1.58.dist-info/licenses/LICENSE.txt,sha256=_uQUZpgO0mRYL5-fPoEvLSbNnLPv6OmbeEDCHXhK6Qc,1066
|
|
193
|
+
matrice_analytics-0.1.58.dist-info/METADATA,sha256=K3BFU6zoK1DBwLnrxRRi0bM8biLmRcJ2rHbuzPVinsI,14378
|
|
194
|
+
matrice_analytics-0.1.58.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
195
|
+
matrice_analytics-0.1.58.dist-info/top_level.txt,sha256=STAPEU-e-rWTerXaspdi76T_eVRSrEfFpURSP7_Dt8E,18
|
|
196
|
+
matrice_analytics-0.1.58.dist-info/RECORD,,
|
|
File without changes
|
{matrice_analytics-0.1.56.dist-info → matrice_analytics-0.1.58.dist-info}/licenses/LICENSE.txt
RENAMED
|
File without changes
|
|
File without changes
|