diff --git a/frigate/embeddings/maintainer.py b/frigate/embeddings/maintainer.py index d169d2d88..a99ef72a2 100644 --- a/frigate/embeddings/maintainer.py +++ b/frigate/embeddings/maintainer.py @@ -397,7 +397,14 @@ class EmbeddingMaintainer(threading.Thread): source_type, _, camera, frame_name, data = update + logger.debug( + f"Received update - source_type: {source_type}, camera: {camera}, data label: {data.get('label') if data else 'None'}" + ) + if not camera or source_type != EventTypeEnum.tracked_object: + logger.debug( + f"Skipping update - camera: {camera}, source_type: {source_type}" + ) return if self.config.semantic_search.enabled: @@ -407,6 +414,9 @@ class EmbeddingMaintainer(threading.Thread): # no need to process updated objects if no processors are active if len(self.realtime_processors) == 0 and len(self.post_processors) == 0: + logger.debug( + f"No processors active - realtime: {len(self.realtime_processors)}, post: {len(self.post_processors)}" + ) return # Create our own thumbnail based on the bounding box and the frame time @@ -415,6 +425,7 @@ class EmbeddingMaintainer(threading.Thread): frame_name, camera_config.frame_shape_yuv ) except FileNotFoundError: + logger.debug(f"Frame {frame_name} not found for camera {camera}") pass if yuv_frame is None: @@ -423,7 +434,11 @@ class EmbeddingMaintainer(threading.Thread): ) return + logger.debug( + f"Processing {len(self.realtime_processors)} realtime processors for object {data.get('id')} (label: {data.get('label')})" + ) for processor in self.realtime_processors: + logger.debug(f"Calling process_frame on {processor.__class__.__name__}") processor.process_frame(data, yuv_frame) for processor in self.post_processors: diff --git a/frigate/object_detection/base.py b/frigate/object_detection/base.py index 9f4965111..bb5f83fab 100644 --- a/frigate/object_detection/base.py +++ b/frigate/object_detection/base.py @@ -9,6 +9,7 @@ from multiprocessing import Queue, Value from multiprocessing.synchronize import Event as MpEvent import numpy as np +import zmq from frigate.comms.object_detector_signaler import ( ObjectDetectorPublisher, @@ -377,6 +378,15 @@ class RemoteObjectDetector: if self.stop_event.is_set(): return detections + # Drain any stale detection results from the ZMQ buffer before making a new request + # This prevents reading detection results from a previous request + # NOTE: This should never happen, but can in some rare cases + while True: + try: + self.detector_subscriber.socket.recv_string(flags=zmq.NOBLOCK) + except zmq.Again: + break + # copy input to shared memory self.np_shm[:] = tensor_input[:] self.detection_queue.put(self.name) diff --git a/web/src/components/card/ClassificationCard.tsx b/web/src/components/card/ClassificationCard.tsx index 21f498fe4..6de418446 100644 --- a/web/src/components/card/ClassificationCard.tsx +++ b/web/src/components/card/ClassificationCard.tsx @@ -181,6 +181,7 @@ type GroupedClassificationCardProps = { selectedItems: string[]; i18nLibrary: string; objectType: string; + noClassificationLabel?: string; onClick: (data: ClassificationItemData | undefined) => void; children?: (data: ClassificationItemData) => React.ReactNode; }; @@ -190,6 +191,7 @@ export function GroupedClassificationCard({ threshold, selectedItems, i18nLibrary, + noClassificationLabel = "details.none", onClick, children, }: GroupedClassificationCardProps) { @@ -222,10 +224,14 @@ export function GroupedClassificationCard({ const bestTyped: ClassificationItemData = best; return { ...bestTyped, - name: event ? (event.sub_label ?? t("details.unknown")) : bestTyped.name, + name: event + ? event.sub_label && event.sub_label !== "none" + ? event.sub_label + : t(noClassificationLabel) + : bestTyped.name, score: event?.data?.sub_label_score || bestTyped.score, }; - }, [group, event, t]); + }, [group, event, noClassificationLabel, t]); const bestScoreStatus = useMemo(() => { if (!bestItem?.score || !threshold) { @@ -311,8 +317,10 @@ export function GroupedClassificationCard({ isMobile && "px-2", )} > - {event?.sub_label ? event.sub_label : t("details.unknown")} - {event?.sub_label && ( + {event?.sub_label && event.sub_label !== "none" + ? event.sub_label + : t(noClassificationLabel)} + {event?.sub_label && event.sub_label !== "none" && (