mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-11-13 00:53:02 +03:00
Fix sub label filter for non-ascii names (#24953)
* fix sub label filter for non-ascii names The sub_labels filter lowercased the requested name in Python but the stored value with SQLite's LOWER(), which only folds ASCII. Cyrillic and other non-ASCII names never matched, so filtering by a face name returned no events. Both sides are now lowered in SQLite, which keeps ASCII matching case-insensitive and non-ASCII matching exact. * cover events/search in sub label filter test
This commit is contained in:
+14
-22
@@ -199,18 +199,14 @@ def events(
|
||||
sub_label_clauses.append(Event.sub_label.is_null())
|
||||
|
||||
for label in filtered_sub_labels:
|
||||
lowered = label.lower()
|
||||
sub_label_clauses.append(
|
||||
fn.LOWER(Event.sub_label.cast("text")) == lowered
|
||||
) # include exact matches (case-insensitive)
|
||||
# SQLite LOWER() only folds ASCII, so lower both sides in SQL to
|
||||
# keep non-ASCII names matching exactly
|
||||
stored = fn.LOWER(Event.sub_label.cast("text"))
|
||||
sub_label_clauses.append(stored == fn.LOWER(label))
|
||||
|
||||
# include this label when part of a list (LIKE is case-insensitive in sqlite for ASCII)
|
||||
sub_label_clauses.append(
|
||||
fn.LOWER(Event.sub_label.cast("text")) % f"*{lowered},*"
|
||||
)
|
||||
sub_label_clauses.append(
|
||||
fn.LOWER(Event.sub_label.cast("text")) % f"*, {lowered}*"
|
||||
)
|
||||
# include this label when part of a list
|
||||
sub_label_clauses.append(stored % fn.LOWER(f"*{label},*"))
|
||||
sub_label_clauses.append(stored % fn.LOWER(f"*, {label}*"))
|
||||
|
||||
sub_label_clause = reduce(operator.or_, sub_label_clauses)
|
||||
clauses.append(sub_label_clause)
|
||||
@@ -633,18 +629,14 @@ def events_search(
|
||||
sub_label_clauses.append(Event.sub_label.is_null())
|
||||
|
||||
for label in filtered_sub_labels:
|
||||
lowered = label.lower()
|
||||
sub_label_clauses.append(
|
||||
fn.LOWER(Event.sub_label.cast("text")) == lowered
|
||||
) # include exact matches (case-insensitive)
|
||||
# SQLite LOWER() only folds ASCII, so lower both sides in SQL to
|
||||
# keep non-ASCII names matching exactly
|
||||
stored = fn.LOWER(Event.sub_label.cast("text"))
|
||||
sub_label_clauses.append(stored == fn.LOWER(label))
|
||||
|
||||
# include this label when part of a list (LIKE is case-insensitive in sqlite for ASCII)
|
||||
sub_label_clauses.append(
|
||||
fn.LOWER(Event.sub_label.cast("text")) % f"*{lowered},*"
|
||||
)
|
||||
sub_label_clauses.append(
|
||||
fn.LOWER(Event.sub_label.cast("text")) % f"*, {lowered}*"
|
||||
)
|
||||
# include this label when part of a list
|
||||
sub_label_clauses.append(stored % fn.LOWER(f"*{label},*"))
|
||||
sub_label_clauses.append(stored % fn.LOWER(f"*, {label}*"))
|
||||
|
||||
event_filters.append(reduce(operator.or_, sub_label_clauses))
|
||||
|
||||
|
||||
@@ -485,6 +485,40 @@ class TestHttpApp(BaseTestHttp):
|
||||
assert sub_labels
|
||||
assert sub_labels == [sub_label]
|
||||
|
||||
def test_get_event_list_filter_sub_labels(self):
|
||||
sub_labels = {
|
||||
"1.cyrillic": "Кузнецова Ира",
|
||||
"2.joined": "Ира, Bob",
|
||||
"3.ascii": "Alice",
|
||||
"4.none": None,
|
||||
}
|
||||
mock_embeddings = Mock()
|
||||
mock_embeddings.search_thumbnail.return_value = [(id, 0.1) for id in sub_labels]
|
||||
|
||||
self.app.frigate_config.semantic_search.enabled = True
|
||||
self.app.embeddings = mock_embeddings
|
||||
|
||||
with AuthTestClient(self.app) as client:
|
||||
for id, sub_label in sub_labels.items():
|
||||
super().insert_mock_event(id)
|
||||
Event.update(sub_label=sub_label).where(Event.id == id).execute()
|
||||
|
||||
search_params = {"search_type": "similarity", "event_id": "1.cyrillic"}
|
||||
|
||||
for path, params in (("/events", {}), ("/events/search", search_params)):
|
||||
|
||||
def ids(query: str) -> set[str]:
|
||||
events = client.get(
|
||||
path, params={**params, "sub_labels": query}
|
||||
).json()
|
||||
return {event["id"] for event in events}
|
||||
|
||||
assert ids("Кузнецова Ира") == {"1.cyrillic"}
|
||||
assert ids("Ира") == {"2.joined"}
|
||||
assert ids("bob") == {"2.joined"}
|
||||
assert ids("ALICE") == {"3.ascii"}
|
||||
assert ids("None") == {"4.none"}
|
||||
|
||||
####################################################################################################################
|
||||
################################### GET /metrics Endpoint #########################################################
|
||||
####################################################################################################################
|
||||
|
||||
Reference in New Issue
Block a user