From e656913316a760647d51823a50aab4a280f6c75b Mon Sep 17 00:00:00 2001 From: Jason Hunter Date: Sun, 16 Jun 2024 00:37:30 -0400 Subject: [PATCH] use IPC to write description, update docs for reindex --- docs/docs/configuration/reference.md | 2 ++ docs/docs/configuration/semantic_search.md | 3 ++- frigate/comms/dispatcher.py | 7 ++++++- frigate/config.py | 6 +++--- frigate/const.py | 1 + frigate/embeddings/__init__.py | 2 +- frigate/embeddings/maintainer.py | 17 ++++++++++++++--- 7 files changed, 29 insertions(+), 9 deletions(-) diff --git a/docs/docs/configuration/reference.md b/docs/docs/configuration/reference.md index e9d93e979..ff7a741b9 100644 --- a/docs/docs/configuration/reference.md +++ b/docs/docs/configuration/reference.md @@ -469,6 +469,8 @@ snapshots: semantic_search: # Optional: Enable semantic search (default: shown below) enabled: False + # Optional: Re-index embeddings database from historical events (default: shown below) + reindex: False # Optional: Configuration for AI generated event descriptions # NOTE: Semantic Search must be enabled for this to do anything. diff --git a/docs/docs/configuration/semantic_search.md b/docs/docs/configuration/semantic_search.md index 6e876dc3a..d8ab61d41 100644 --- a/docs/docs/configuration/semantic_search.md +++ b/docs/docs/configuration/semantic_search.md @@ -12,11 +12,12 @@ Semantic Search is a global configuration setting. ```yaml semantic_search: enabled: True + reindex: False ``` :::tip -The embeddings database can be re-indexed from the existing detections in your database by adding an empty file named `.reindex` to the root of your configuration directory. Depending on the number of detections you have, it can take up to 30 minutes to complete and may max out your CPU while indexing. +The embeddings database can be re-indexed from the existing detections in your database by adding `reindex: True` to your `semantic_search` configuration. Depending on the number of detections you have, it can take up to 30 minutes to complete and may max out your CPU while indexing. Make sure to set the config back to `False` before restarting Frigate again. ::: diff --git a/frigate/comms/dispatcher.py b/frigate/comms/dispatcher.py index db6c44c11..2369a9a3c 100644 --- a/frigate/comms/dispatcher.py +++ b/frigate/comms/dispatcher.py @@ -14,9 +14,10 @@ from frigate.const import ( INSERT_PREVIEW, REQUEST_REGION_GRID, UPDATE_CAMERA_ACTIVITY, + UPDATE_EVENT_DESCRIPTION, UPSERT_REVIEW_SEGMENT, ) -from frigate.models import Previews, Recordings, ReviewSegment +from frigate.models import Event, Previews, Recordings, ReviewSegment from frigate.ptz.onvif import OnvifCommandEnum, OnvifController from frigate.types import PTZMetricsTypes from frigate.util.object import get_camera_regions_grid @@ -128,6 +129,10 @@ class Dispatcher: ).execute() elif topic == UPDATE_CAMERA_ACTIVITY: self.camera_activity = payload + elif topic == UPDATE_EVENT_DESCRIPTION: + event: Event = Event.get(Event.id == payload["id"]) + event.data["description"] = payload["description"] + event.save() elif topic == "onConnect": self.publish("camera_activity", json.dumps(self.camera_activity)) else: diff --git a/frigate/config.py b/frigate/config.py index 8e39a9653..2da39aea4 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -725,6 +725,9 @@ class ReviewConfig(FrigateBaseModel): class SemanticSearchConfig(FrigateBaseModel): enabled: bool = Field(default=True, title="Enable semantic search.") + reindex: Optional[bool] = Field( + default=False, title="Reindex all detections on startup." + ) class GenAIProviderEnum(str, Enum): @@ -746,9 +749,6 @@ class GenAIConfig(FrigateBaseModel): title="Default caption prompt.", ) object_prompts: Dict[str, str] = Field(default={}, title="Object specific prompts.") - reindex: Optional[bool] = Field( - default=False, title="Reindex all detections on startup." - ) class GenAICameraConfig(FrigateBaseModel): diff --git a/frigate/const.py b/frigate/const.py index 0ba8d6f64..16d86f6aa 100644 --- a/frigate/const.py +++ b/frigate/const.py @@ -81,6 +81,7 @@ REQUEST_REGION_GRID = "request_region_grid" UPSERT_REVIEW_SEGMENT = "upsert_review_segment" CLEAR_ONGOING_REVIEW_SEGMENTS = "clear_ongoing_review_segments" UPDATE_CAMERA_ACTIVITY = "update_camera_activity" +UPDATE_EVENT_DESCRIPTION = "update_event_description" # Autotracking diff --git a/frigate/embeddings/__init__.py b/frigate/embeddings/__init__.py index 8a8663d51..41af73c01 100644 --- a/frigate/embeddings/__init__.py +++ b/frigate/embeddings/__init__.py @@ -57,7 +57,7 @@ def manage_embeddings(config: FrigateConfig) -> None: embeddings = Embeddings() # Check if we need to re-index events - if config.genai.reindex: + if config.semantic_search.reindex: embeddings.reindex() maintainer = EmbeddingMaintainer( diff --git a/frigate/embeddings/maintainer.py b/frigate/embeddings/maintainer.py index 019cc7a25..aac85c01a 100644 --- a/frigate/embeddings/maintainer.py +++ b/frigate/embeddings/maintainer.py @@ -13,7 +13,9 @@ from peewee import DoesNotExist from PIL import Image from frigate.comms.events_updater import EventEndSubscriber, EventUpdateSubscriber +from frigate.comms.inter_process import InterProcessRequestor from frigate.config import FrigateConfig +from frigate.const import UPDATE_EVENT_DESCRIPTION from frigate.events.types import EventTypeEnum from frigate.genai import get_genai_client from frigate.models import Event @@ -39,6 +41,8 @@ class EmbeddingMaintainer(threading.Thread): self.event_subscriber = EventUpdateSubscriber() self.event_end_subscriber = EventEndSubscriber() self.frame_manager = SharedMemoryFrameManager() + # create communication for updating event descriptions + self.requestor = InterProcessRequestor() self.stop_event = stop_event self.tracked_events = {} self.genai_client = get_genai_client(config.genai) @@ -49,6 +53,11 @@ class EmbeddingMaintainer(threading.Thread): self._process_updates() self._process_finalized() + self.event_subscriber.stop() + self.event_end_subscriber.stop() + self.requestor.stop() + logger.info("Exiting embeddings maintenance...") + def _process_updates(self) -> None: """Process event updates""" update = self.event_subscriber.check_for_update() @@ -167,9 +176,11 @@ class EmbeddingMaintainer(threading.Thread): logger.debug("Failed to generate description for %s", event.id) return - # Update the event to add the description - event.data["description"] = description - event.save() + # fire and forget description update + self.requestor.send_data( + UPDATE_EVENT_DESCRIPTION, + {"id": event.id, "description": description}, + ) # Encode the description self.embeddings.description.upsert(