More mypy cleanup (#22658)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / ARM Extra Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions

* Halfway point for fixing data processing

* Fix mixin types missing

* Cleanup LPR mypy

* Cleanup audio mypy

* Cleanup bird mypy

* Cleanup mypy for custom classification

* remove whisper

* Fix DB typing

* Cleanup events mypy

* Clenaup

* fix type evaluation

* Cleanup

* Fix broken imports
This commit is contained in:
Nicolas Mowen
2026-03-26 12:54:12 -06:00
committed by GitHub
parent 4772e6a2ab
commit 03d0139497
22 changed files with 398 additions and 274 deletions
@@ -24,7 +24,7 @@ from frigate.util.file import get_event_thumbnail_bytes, load_event_snapshot_ima
from frigate.util.image import create_thumbnail, ensure_jpeg_bytes
if TYPE_CHECKING:
from frigate.embeddings import Embeddings
from frigate.embeddings.embeddings import Embeddings
from ..post.api import PostProcessorApi
from ..types import DataProcessorMetrics
@@ -139,7 +139,7 @@ class ObjectDescriptionProcessor(PostProcessorApi):
):
self._process_genai_description(event, camera_config, thumbnail)
else:
self.cleanup_event(event.id)
self.cleanup_event(str(event.id))
def __regenerate_description(self, event_id: str, source: str, force: bool) -> None:
"""Regenerate the description for an event."""
@@ -149,17 +149,17 @@ class ObjectDescriptionProcessor(PostProcessorApi):
logger.error(f"Event {event_id} not found for description regeneration")
return
if self.genai_client is None:
logger.error("GenAI not enabled")
return
camera_config = self.config.cameras[event.camera]
camera_config = self.config.cameras[str(event.camera)]
if not camera_config.objects.genai.enabled and not force:
logger.error(f"GenAI not enabled for camera {event.camera}")
return
thumbnail = get_event_thumbnail_bytes(event)
if thumbnail is None:
logger.error("No thumbnail available for %s", event.id)
return
# ensure we have a jpeg to pass to the model
thumbnail = ensure_jpeg_bytes(thumbnail)
@@ -187,7 +187,9 @@ class ObjectDescriptionProcessor(PostProcessorApi):
)
)
self._genai_embed_description(event, embed_image)
self._genai_embed_description(
event, [img for img in embed_image if img is not None]
)
def process_data(self, frame_data: dict, data_type: PostProcessDataEnum) -> None:
"""Process a frame update."""
@@ -241,7 +243,7 @@ class ObjectDescriptionProcessor(PostProcessorApi):
# Crop snapshot based on region
# provide full image if region doesn't exist (manual events)
height, width = img.shape[:2]
x1_rel, y1_rel, width_rel, height_rel = event.data.get(
x1_rel, y1_rel, width_rel, height_rel = event.data.get( # type: ignore[attr-defined]
"region", [0, 0, 1, 1]
)
x1, y1 = int(x1_rel * width), int(y1_rel * height)
@@ -258,14 +260,16 @@ class ObjectDescriptionProcessor(PostProcessorApi):
return None
def _process_genai_description(
self, event: Event, camera_config: CameraConfig, thumbnail
self, event: Event, camera_config: CameraConfig, thumbnail: bytes
) -> None:
event_id = str(event.id)
if event.has_snapshot and camera_config.objects.genai.use_snapshot:
snapshot_image = self._read_and_crop_snapshot(event)
if not snapshot_image:
return
num_thumbnails = len(self.tracked_events.get(event.id, []))
num_thumbnails = len(self.tracked_events.get(event_id, []))
# ensure we have a jpeg to pass to the model
thumbnail = ensure_jpeg_bytes(thumbnail)
@@ -277,7 +281,7 @@ class ObjectDescriptionProcessor(PostProcessorApi):
else (
[
data["thumbnail"][:] if data.get("thumbnail") else None
for data in self.tracked_events[event.id]
for data in self.tracked_events[event_id]
if data.get("thumbnail")
]
if num_thumbnails > 0
@@ -286,22 +290,22 @@ class ObjectDescriptionProcessor(PostProcessorApi):
)
if camera_config.objects.genai.debug_save_thumbnails and num_thumbnails > 0:
logger.debug(f"Saving {num_thumbnails} thumbnails for event {event.id}")
logger.debug(f"Saving {num_thumbnails} thumbnails for event {event_id}")
Path(os.path.join(CLIPS_DIR, f"genai-requests/{event.id}")).mkdir(
Path(os.path.join(CLIPS_DIR, f"genai-requests/{event_id}")).mkdir(
parents=True, exist_ok=True
)
for idx, data in enumerate(self.tracked_events[event.id], 1):
for idx, data in enumerate(self.tracked_events[event_id], 1):
jpg_bytes: bytes | None = data["thumbnail"]
if jpg_bytes is None:
logger.warning(f"Unable to save thumbnail {idx} for {event.id}.")
logger.warning(f"Unable to save thumbnail {idx} for {event_id}.")
else:
with open(
os.path.join(
CLIPS_DIR,
f"genai-requests/{event.id}/{idx}.jpg",
f"genai-requests/{event_id}/{idx}.jpg",
),
"wb",
) as j:
@@ -310,7 +314,7 @@ class ObjectDescriptionProcessor(PostProcessorApi):
# Generate the description. Call happens in a thread since it is network bound.
threading.Thread(
target=self._genai_embed_description,
name=f"_genai_embed_description_{event.id}",
name=f"_genai_embed_description_{event_id}",
daemon=True,
args=(
event,
@@ -319,12 +323,12 @@ class ObjectDescriptionProcessor(PostProcessorApi):
).start()
# Clean up tracked events and early request state
self.cleanup_event(event.id)
self.cleanup_event(event_id)
def _genai_embed_description(self, event: Event, thumbnails: list[bytes]) -> None:
"""Embed the description for an event."""
start = datetime.datetime.now().timestamp()
camera_config = self.config.cameras[event.camera]
camera_config = self.config.cameras[str(event.camera)]
description = self.genai_client.generate_object_description(
camera_config, thumbnails, event
)
@@ -346,7 +350,7 @@ class ObjectDescriptionProcessor(PostProcessorApi):
# Embed the description
if self.config.semantic_search.enabled:
self.embeddings.embed_description(event.id, description)
self.embeddings.embed_description(str(event.id), description)
# Check semantic trigger for this description
if self.semantic_trigger_processor is not None: