GenAI: add ability to save JPGs sent to provider (#15643)

* GenAI: add ability to save JPGs sent to provider

* Remove mention from GenAI docs

* Change config name to debug_save_thumbnails

* Change  folder structure to clips/genai-requests/{event_id}/{1.jpg}
This commit is contained in:
leccelecce 2024-12-23 14:05:34 +00:00 committed by GitHub
parent 87e7b62c85
commit 00371546a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 36 additions and 1 deletions

View File

@ -760,6 +760,8 @@ cameras:
- cat - cat
# Optional: Restrict generation to objects that entered any of the listed zones (default: none, all zones qualify) # Optional: Restrict generation to objects that entered any of the listed zones (default: none, all zones qualify)
required_zones: [] required_zones: []
# Optional: Save thumbnails sent to generative AI for review/debugging purposes (default: shown below)
debug_save_thumbnails: False
# Optional # Optional
ui: ui:

View File

@ -38,6 +38,10 @@ class GenAICameraConfig(BaseModel):
default_factory=list, default_factory=list,
title="List of required zones to be entered in order to run generative AI.", title="List of required zones to be entered in order to run generative AI.",
) )
debug_save_thumbnails: bool = Field(
default=False,
title="Save thumbnails sent to generative AI for debugging purposes.",
)
@field_validator("required_zones", mode="before") @field_validator("required_zones", mode="before")
@classmethod @classmethod

View File

@ -5,6 +5,7 @@ import logging
import os import os
import threading import threading
from multiprocessing.synchronize import Event as MpEvent from multiprocessing.synchronize import Event as MpEvent
from pathlib import Path
from typing import Optional from typing import Optional
import cv2 import cv2
@ -217,6 +218,8 @@ class EmbeddingMaintainer(threading.Thread):
_, buffer = cv2.imencode(".jpg", cropped_image) _, buffer = cv2.imencode(".jpg", cropped_image)
snapshot_image = buffer.tobytes() snapshot_image = buffer.tobytes()
num_thumbnails = len(self.tracked_events.get(event_id, []))
embed_image = ( embed_image = (
[snapshot_image] [snapshot_image]
if event.has_snapshot and camera_config.genai.use_snapshot if event.has_snapshot and camera_config.genai.use_snapshot
@ -225,11 +228,37 @@ class EmbeddingMaintainer(threading.Thread):
data["thumbnail"] data["thumbnail"]
for data in self.tracked_events[event_id] for data in self.tracked_events[event_id]
] ]
if len(self.tracked_events.get(event_id, [])) > 0 if num_thumbnails > 0
else [thumbnail] else [thumbnail]
) )
) )
if camera_config.genai.debug_save_thumbnails and num_thumbnails > 0:
logger.debug(
f"Saving {num_thumbnails} thumbnails for event {event.id}"
)
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):
jpg_bytes: bytes = data["thumbnail"]
if jpg_bytes is None:
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",
),
"wb",
) as j:
j.write(jpg_bytes)
# Generate the description. Call happens in a thread since it is network bound. # Generate the description. Call happens in a thread since it is network bound.
threading.Thread( threading.Thread(
target=self._embed_description, target=self._embed_description,