This commit is contained in:
Nicolas Mowen 2026-03-08 07:36:29 -06:00
parent 6a77ee6db6
commit a773fef74b
2 changed files with 15 additions and 59 deletions

View File

@ -61,6 +61,7 @@ from .classification import (
FaceRecognitionConfig, FaceRecognitionConfig,
LicensePlateRecognitionConfig, LicensePlateRecognitionConfig,
SemanticSearchConfig, SemanticSearchConfig,
SemanticSearchModelEnum,
) )
from .database import DatabaseConfig from .database import DatabaseConfig
from .env import EnvVars from .env import EnvVars
@ -595,7 +596,7 @@ class FrigateConfig(FrigateBaseModel):
# validate semantic_search.model when it is a GenAI provider name # validate semantic_search.model when it is a GenAI provider name
if self.semantic_search.enabled and isinstance( if self.semantic_search.enabled and isinstance(
self.semantic_search.model, str self.semantic_search.model, str
): ) and not isinstance(self.semantic_search.model, SemanticSearchModelEnum):
if self.semantic_search.model not in self.genai: if self.semantic_search.model not in self.genai:
raise ValueError( raise ValueError(
f"semantic_search.model '{self.semantic_search.model}' is not a " f"semantic_search.model '{self.semantic_search.model}' is not a "

View File

@ -80,7 +80,6 @@ class Embeddings:
self.db = db self.db = db
self.metrics = metrics self.metrics = metrics
self.requestor = InterProcessRequestor() self.requestor = InterProcessRequestor()
self.genai_manager = genai_manager
self.image_inference_speed = InferenceSpeed(self.metrics.image_embeddings_speed) self.image_inference_speed = InferenceSpeed(self.metrics.image_embeddings_speed)
self.image_eps = EventsPerSecond() self.image_eps = EventsPerSecond()
@ -108,9 +107,9 @@ class Embeddings:
) )
model_cfg = self.config.semantic_search.model model_cfg = self.config.semantic_search.model
is_genai_model = isinstance(model_cfg, str)
if is_genai_model: if not isinstance(model_cfg, SemanticSearchModelEnum):
# GenAI provider
embeddings_client = ( embeddings_client = (
genai_manager.embeddings_client if genai_manager else None genai_manager.embeddings_client if genai_manager else None
) )
@ -161,7 +160,7 @@ class Embeddings:
def get_model_definitions(self): def get_model_definitions(self):
model_cfg = self.config.semantic_search.model model_cfg = self.config.semantic_search.model
if isinstance(model_cfg, str): if not isinstance(model_cfg, SemanticSearchModelEnum):
# GenAI provider: no ONNX models to download # GenAI provider: no ONNX models to download
models = [] models = []
elif model_cfg == SemanticSearchModelEnum.jinav2: elif model_cfg == SemanticSearchModelEnum.jinav2:
@ -251,14 +250,6 @@ class Embeddings:
embeddings = self.vision_embedding(valid_thumbs) embeddings = self.vision_embedding(valid_thumbs)
if len(embeddings) != len(valid_ids):
logger.warning(
"Batch embed returned %d embeddings for %d thumbnails; skipping batch",
len(embeddings),
len(valid_ids),
)
return []
if upsert: if upsert:
items = [] items = []
for i in range(len(valid_ids)): for i in range(len(valid_ids)):
@ -281,15 +272,9 @@ class Embeddings:
def embed_description( def embed_description(
self, event_id: str, description: str, upsert: bool = True self, event_id: str, description: str, upsert: bool = True
) -> np.ndarray | None: ) -> np.ndarray:
start = datetime.datetime.now().timestamp() start = datetime.datetime.now().timestamp()
embeddings = self.text_embedding([description]) embedding = self.text_embedding([description])[0]
if not embeddings:
logger.warning(
"Failed to generate description embedding for event %s", event_id
)
return None
embedding = embeddings[0]
if upsert: if upsert:
self.db.execute_sql( self.db.execute_sql(
@ -312,32 +297,8 @@ class Embeddings:
# upsert embeddings one by one to avoid token limit # upsert embeddings one by one to avoid token limit
embeddings = [] embeddings = []
for eid, desc in event_descriptions.items(): for desc in event_descriptions.values():
result = self.text_embedding([desc]) embeddings.append(self.text_embedding([desc])[0])
if not result:
logger.warning(
"Failed to generate description embedding for event %s", eid
)
continue
embeddings.append(result[0])
if not embeddings:
logger.warning("No description embeddings generated in batch")
return np.array([])
# Build ids list for only successful embeddings - we need to track which succeeded
ids = list(event_descriptions.keys())
if len(embeddings) != len(ids):
# Rebuild ids/embeddings for only successful ones (match by order)
ids = []
embeddings_filtered = []
for eid, desc in event_descriptions.items():
result = self.text_embedding([desc])
if result:
ids.append(eid)
embeddings_filtered.append(result[0])
ids = ids
embeddings = embeddings_filtered
if upsert: if upsert:
ids = list(event_descriptions.keys()) ids = list(event_descriptions.keys())
@ -377,14 +338,12 @@ class Embeddings:
# Get total count of events to process # Get total count of events to process
total_events = Event.select().count() total_events = Event.select().count()
batch_size = ( if not isinstance(self.config.semantic_search.model, SemanticSearchModelEnum):
4 batch_size = 1
if ( elif self.config.semantic_search.model == SemanticSearchModelEnum.jinav2:
isinstance(self.config.semantic_search.model, str) batch_size = 4
or self.config.semantic_search.model == SemanticSearchModelEnum.jinav2 else:
) batch_size = 32
else 32
)
current_page = 1 current_page = 1
totals = { totals = {
@ -669,8 +628,6 @@ class Embeddings:
if trigger.type == "description": if trigger.type == "description":
logger.debug(f"Generating embedding for trigger description {trigger_name}") logger.debug(f"Generating embedding for trigger description {trigger_name}")
embedding = self.embed_description(None, trigger.data, upsert=False) embedding = self.embed_description(None, trigger.data, upsert=False)
if embedding is None:
return b""
return embedding.astype(np.float32).tobytes() return embedding.astype(np.float32).tobytes()
elif trigger.type == "thumbnail": elif trigger.type == "thumbnail":
@ -706,8 +663,6 @@ class Embeddings:
embedding = self.embed_thumbnail( embedding = self.embed_thumbnail(
str(trigger.data), thumbnail, upsert=False str(trigger.data), thumbnail, upsert=False
) )
if embedding is None:
return b""
return embedding.astype(np.float32).tobytes() return embedding.astype(np.float32).tobytes()
else: else: