mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-05 21:17:43 +03:00
api for search queries
This commit is contained in:
parent
4c12420cf8
commit
a3b37f79fa
@ -619,6 +619,39 @@ def get_sub_labels(split_joined: Optional[int] = None):
|
|||||||
return JSONResponse(content=sub_labels)
|
return JSONResponse(content=sub_labels)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/identifiers")
|
||||||
|
def get_identifiers(split_joined: Optional[int] = None):
|
||||||
|
try:
|
||||||
|
events = Event.select(Event.data).distinct()
|
||||||
|
except Exception:
|
||||||
|
return JSONResponse(
|
||||||
|
content=({"success": False, "message": "Failed to get identifiers"}),
|
||||||
|
status_code=404,
|
||||||
|
)
|
||||||
|
|
||||||
|
identifiers = []
|
||||||
|
for e in events:
|
||||||
|
if e.data is not None and "identifier" in e.data:
|
||||||
|
identifiers.append(e.data["identifier"])
|
||||||
|
|
||||||
|
while None in identifiers:
|
||||||
|
identifiers.remove(None)
|
||||||
|
|
||||||
|
if split_joined:
|
||||||
|
original_identifiers = identifiers.copy()
|
||||||
|
for identifier in original_identifiers:
|
||||||
|
if identifier and "," in identifier:
|
||||||
|
identifiers.remove(identifier)
|
||||||
|
parts = identifier.split(",")
|
||||||
|
for part in parts:
|
||||||
|
if part.strip() not in identifiers:
|
||||||
|
identifiers.append(part.strip())
|
||||||
|
|
||||||
|
identifiers = list(set(identifiers))
|
||||||
|
identifiers.sort()
|
||||||
|
return JSONResponse(content=identifiers)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/timeline")
|
@router.get("/timeline")
|
||||||
def timeline(camera: str = "all", limit: int = 100, source_id: Optional[str] = None):
|
def timeline(camera: str = "all", limit: int = 100, source_id: Optional[str] = None):
|
||||||
clauses = []
|
clauses = []
|
||||||
|
|||||||
@ -27,6 +27,7 @@ class EventsQueryParams(BaseModel):
|
|||||||
max_score: Optional[float] = None
|
max_score: Optional[float] = None
|
||||||
min_speed: Optional[float] = None
|
min_speed: Optional[float] = None
|
||||||
max_speed: Optional[float] = None
|
max_speed: Optional[float] = None
|
||||||
|
identifier: Optional[str] = "all"
|
||||||
is_submitted: Optional[int] = None
|
is_submitted: Optional[int] = None
|
||||||
min_length: Optional[float] = None
|
min_length: Optional[float] = None
|
||||||
max_length: Optional[float] = None
|
max_length: Optional[float] = None
|
||||||
@ -55,6 +56,7 @@ class EventsSearchQueryParams(BaseModel):
|
|||||||
max_score: Optional[float] = None
|
max_score: Optional[float] = None
|
||||||
min_speed: Optional[float] = None
|
min_speed: Optional[float] = None
|
||||||
max_speed: Optional[float] = None
|
max_speed: Optional[float] = None
|
||||||
|
identifier: Optional[str] = "all"
|
||||||
sort: Optional[str] = None
|
sort: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -101,6 +101,7 @@ def events(params: EventsQueryParams = Depends()):
|
|||||||
min_length = params.min_length
|
min_length = params.min_length
|
||||||
max_length = params.max_length
|
max_length = params.max_length
|
||||||
event_id = params.event_id
|
event_id = params.event_id
|
||||||
|
identifier = params.identifier
|
||||||
|
|
||||||
sort = params.sort
|
sort = params.sort
|
||||||
|
|
||||||
@ -158,6 +159,39 @@ def events(params: EventsQueryParams = Depends()):
|
|||||||
sub_label_clause = reduce(operator.or_, sub_label_clauses)
|
sub_label_clause = reduce(operator.or_, sub_label_clauses)
|
||||||
clauses.append((sub_label_clause))
|
clauses.append((sub_label_clause))
|
||||||
|
|
||||||
|
if identifier != "all":
|
||||||
|
# use matching so joined identifiers are included
|
||||||
|
# for example an identifier 'ABC123' would get events
|
||||||
|
# with identifiers 'ABC123' and 'ABC123, XYZ789'
|
||||||
|
# also supports regex with slashes before and after the pattern
|
||||||
|
identifier_clauses = []
|
||||||
|
filtered_identifiers = identifier.split(",")
|
||||||
|
|
||||||
|
if "None" in filtered_identifiers:
|
||||||
|
filtered_identifiers.remove("None")
|
||||||
|
identifier_clauses.append((Event.data["identifier"].is_null()))
|
||||||
|
|
||||||
|
for identifier in filtered_identifiers:
|
||||||
|
if identifier.startswith("r:"): # Regex pattern
|
||||||
|
pattern = identifier[2:] # Strip the "r:" prefix
|
||||||
|
identifier_clauses.append(
|
||||||
|
(Event.data["identifier"].cast("text").regexp(pattern))
|
||||||
|
)
|
||||||
|
print(pattern)
|
||||||
|
else: # Regular exact matching plus list inclusion
|
||||||
|
identifier_clauses.append(
|
||||||
|
(Event.data["identifier"].cast("text") == identifier)
|
||||||
|
)
|
||||||
|
identifier_clauses.append(
|
||||||
|
(Event.data["identifier"].cast("text") % f"*{identifier},*")
|
||||||
|
)
|
||||||
|
identifier_clauses.append(
|
||||||
|
(Event.data["identifier"].cast("text") % f"*, {identifier}*")
|
||||||
|
)
|
||||||
|
|
||||||
|
identifier_clause = reduce(operator.or_, identifier_clauses)
|
||||||
|
clauses.append((identifier_clause))
|
||||||
|
|
||||||
if zones != "all":
|
if zones != "all":
|
||||||
# use matching so events with multiple zones
|
# use matching so events with multiple zones
|
||||||
# still match on a search where any zone matches
|
# still match on a search where any zone matches
|
||||||
@ -399,6 +433,7 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends())
|
|||||||
has_clip = params.has_clip
|
has_clip = params.has_clip
|
||||||
has_snapshot = params.has_snapshot
|
has_snapshot = params.has_snapshot
|
||||||
is_submitted = params.is_submitted
|
is_submitted = params.is_submitted
|
||||||
|
identifier = params.identifier
|
||||||
|
|
||||||
# for similarity search
|
# for similarity search
|
||||||
event_id = params.event_id
|
event_id = params.event_id
|
||||||
@ -468,6 +503,39 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends())
|
|||||||
|
|
||||||
event_filters.append((reduce(operator.or_, zone_clauses)))
|
event_filters.append((reduce(operator.or_, zone_clauses)))
|
||||||
|
|
||||||
|
if identifier != "all":
|
||||||
|
# use matching so joined identifiers are included
|
||||||
|
# for example an identifier 'ABC123' would get events
|
||||||
|
# with identifiers 'ABC123' and 'ABC123, XYZ789'
|
||||||
|
# also supports regex with slashes before and after the pattern
|
||||||
|
identifier_clauses = []
|
||||||
|
filtered_identifiers = identifier.split(",")
|
||||||
|
|
||||||
|
if "None" in filtered_identifiers:
|
||||||
|
filtered_identifiers.remove("None")
|
||||||
|
identifier_clauses.append((Event.data["identifier"].is_null()))
|
||||||
|
|
||||||
|
for identifier in filtered_identifiers:
|
||||||
|
if identifier.startswith("r:"): # Regex pattern
|
||||||
|
pattern = identifier[2:] # Strip the "r:" prefix
|
||||||
|
identifier_clauses.append(
|
||||||
|
(Event.data["identifier"].cast("text").regexp(pattern))
|
||||||
|
)
|
||||||
|
print(pattern)
|
||||||
|
else: # Regular exact matching plus list inclusion
|
||||||
|
identifier_clauses.append(
|
||||||
|
(Event.data["identifier"].cast("text") == identifier)
|
||||||
|
)
|
||||||
|
identifier_clauses.append(
|
||||||
|
(Event.data["identifier"].cast("text") % f"*{identifier},*")
|
||||||
|
)
|
||||||
|
identifier_clauses.append(
|
||||||
|
(Event.data["identifier"].cast("text") % f"*, {identifier}*")
|
||||||
|
)
|
||||||
|
|
||||||
|
identifier_clause = reduce(operator.or_, identifier_clauses)
|
||||||
|
event_filters.append((identifier_clause))
|
||||||
|
|
||||||
if after:
|
if after:
|
||||||
event_filters.append((Event.start_time > after))
|
event_filters.append((Event.start_time > after))
|
||||||
|
|
||||||
@ -685,6 +753,7 @@ def events_summary(params: EventsSummaryQueryParams = Depends()):
|
|||||||
Event.camera,
|
Event.camera,
|
||||||
Event.label,
|
Event.label,
|
||||||
Event.sub_label,
|
Event.sub_label,
|
||||||
|
Event.data,
|
||||||
fn.strftime(
|
fn.strftime(
|
||||||
"%Y-%m-%d",
|
"%Y-%m-%d",
|
||||||
fn.datetime(
|
fn.datetime(
|
||||||
@ -699,6 +768,7 @@ def events_summary(params: EventsSummaryQueryParams = Depends()):
|
|||||||
Event.camera,
|
Event.camera,
|
||||||
Event.label,
|
Event.label,
|
||||||
Event.sub_label,
|
Event.sub_label,
|
||||||
|
Event.data,
|
||||||
(Event.start_time + seconds_offset).cast("int") / (3600 * 24),
|
(Event.start_time + seconds_offset).cast("int") / (3600 * 24),
|
||||||
Event.zones,
|
Event.zones,
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user