Compare commits

...

8 Commits

Author SHA1 Message Date
dependabot[bot]
f39322566e Update scipy requirement from ==1.13.* to ==1.15.* in /docker/main
Updates the requirements on [scipy](https://github.com/scipy/scipy) to permit the latest version.
- [Release notes](https://github.com/scipy/scipy/releases)
- [Commits](https://github.com/scipy/scipy/compare/v1.13.0rc1...v1.15.0)

---
updated-dependencies:
- dependency-name: scipy
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-06 11:31:30 +00:00
Nicolas Mowen
e7ad38d827 Update model docs (#15779) 2025-01-02 10:04:16 -06:00
Josh Hawkins
a1ce9aacf2 Tracked object details pane bugfix (#15736)
* restore save button in tracked object details pane

* conditionally show save button
2024-12-30 08:23:25 -06:00
Nicolas Mowen
322b847356 Fix event cleanup (#15724) 2024-12-29 14:47:40 -06:00
Josh Hawkins
98338e4c7f Ensure object lifecycle ratio is re-normalized to camera aspect (#15717) 2024-12-28 13:37:39 -07:00
Josh Hawkins
171a89f37b Language consistency - use Explore instead of Search (#15709) 2024-12-27 17:38:43 -07:00
Josh Hawkins
8114b541a8 Sort camera group edit screen by ui config values (#15705) 2024-12-27 14:30:27 -06:00
Josh Hawkins
c48396c5c6 Fix crash when streams are undefined in go2rtc config password cleaning (#15695) 2024-12-27 08:36:21 -06:00
12 changed files with 82 additions and 66 deletions

View File

@@ -27,7 +27,7 @@ ruamel.yaml == 0.18.*
tzlocal == 5.2 tzlocal == 5.2
requests == 2.32.* requests == 2.32.*
types-requests == 2.32.* types-requests == 2.32.*
scipy == 1.13.* scipy == 1.15.*
norfair == 2.2.* norfair == 2.2.*
setproctitle == 1.3.* setproctitle == 1.3.*
ws4py == 0.5.* ws4py == 0.5.*

View File

@@ -144,7 +144,9 @@ detectors:
#### SSDLite MobileNet v2 #### SSDLite MobileNet v2
An OpenVINO model is provided in the container at `/openvino-model/ssdlite_mobilenet_v2.xml` and is used by this detector type by default. The model comes from Intel's Open Model Zoo [SSDLite MobileNet V2](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/ssdlite_mobilenet_v2) and is converted to an FP16 precision IR model. Use the model configuration shown below when using the OpenVINO detector with the default model. An OpenVINO model is provided in the container at `/openvino-model/ssdlite_mobilenet_v2.xml` and is used by this detector type by default. The model comes from Intel's Open Model Zoo [SSDLite MobileNet V2](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/ssdlite_mobilenet_v2) and is converted to an FP16 precision IR model.
Use the model configuration shown below when using the OpenVINO detector with the default OpenVINO model:
```yaml ```yaml
detectors: detectors:
@@ -254,6 +256,7 @@ yolov4x-mish-640
yolov7-tiny-288 yolov7-tiny-288
yolov7-tiny-416 yolov7-tiny-416
yolov7-640 yolov7-640
yolov7-416
yolov7-320 yolov7-320
yolov7x-640 yolov7x-640
yolov7x-320 yolov7x-320
@@ -282,6 +285,8 @@ The TensorRT detector can be selected by specifying `tensorrt` as the model type
The TensorRT detector uses `.trt` model files that are located in `/config/model_cache/tensorrt` by default. These model path and dimensions used will depend on which model you have generated. The TensorRT detector uses `.trt` model files that are located in `/config/model_cache/tensorrt` by default. These model path and dimensions used will depend on which model you have generated.
Use the config below to work with generated TRT models:
```yaml ```yaml
detectors: detectors:
tensorrt: tensorrt:

View File

@@ -117,25 +117,27 @@ auth:
hash_iterations: 600000 hash_iterations: 600000
# Optional: model modifications # Optional: model modifications
# NOTE: The default values are for the EdgeTPU detector.
# Other detectors will require the model config to be set.
model: model:
# Optional: path to the model (default: automatic based on detector) # Required: path to the model (default: automatic based on detector)
path: /edgetpu_model.tflite path: /edgetpu_model.tflite
# Optional: path to the labelmap (default: shown below) # Required: path to the labelmap (default: shown below)
labelmap_path: /labelmap.txt labelmap_path: /labelmap.txt
# Required: Object detection model input width (default: shown below) # Required: Object detection model input width (default: shown below)
width: 320 width: 320
# Required: Object detection model input height (default: shown below) # Required: Object detection model input height (default: shown below)
height: 320 height: 320
# Optional: Object detection model input colorspace # Required: Object detection model input colorspace
# Valid values are rgb, bgr, or yuv. (default: shown below) # Valid values are rgb, bgr, or yuv. (default: shown below)
input_pixel_format: rgb input_pixel_format: rgb
# Optional: Object detection model input tensor format # Required: Object detection model input tensor format
# Valid values are nhwc or nchw (default: shown below) # Valid values are nhwc or nchw (default: shown below)
input_tensor: nhwc input_tensor: nhwc
# Optional: Object detection model type, currently only used with the OpenVINO detector # Required: Object detection model type, currently only used with the OpenVINO detector
# Valid values are ssd, yolox, yolonas (default: shown below) # Valid values are ssd, yolox, yolonas (default: shown below)
model_type: ssd model_type: ssd
# Optional: Label name modifications. These are merged into the standard labelmap. # Required: Label name modifications. These are merged into the standard labelmap.
labelmap: labelmap:
2: vehicle 2: vehicle
# Optional: Map of object labels to their attribute labels (default: depends on model) # Optional: Map of object labels to their attribute labels (default: depends on model)

View File

@@ -139,6 +139,8 @@ def config(request: Request):
mode="json", warnings="none", exclude_none=True mode="json", warnings="none", exclude_none=True
) )
for stream_name, stream in go2rtc.get("streams", {}).items(): for stream_name, stream in go2rtc.get("streams", {}).items():
if stream is None:
continue
if isinstance(stream, str): if isinstance(stream, str):
cleaned = clean_camera_user_pass(stream) cleaned = clean_camera_user_pass(stream)
else: else:

View File

@@ -121,8 +121,8 @@ class EventCleanup(threading.Thread):
events_to_update = [] events_to_update = []
for batch in query.iterator(): for event in query.iterator():
events_to_update.extend([event.id for event in batch]) events_to_update.append(event.id)
if len(events_to_update) >= CHUNK_SIZE: if len(events_to_update) >= CHUNK_SIZE:
logger.debug( logger.debug(
f"Updating {update_params} for {len(events_to_update)} events" f"Updating {update_params} for {len(events_to_update)} events"
@@ -257,7 +257,7 @@ class EventCleanup(threading.Thread):
events_to_update = [] events_to_update = []
for event in query.iterator(): for event in query.iterator():
events_to_update.append(event) events_to_update.append(event.id)
if len(events_to_update) >= CHUNK_SIZE: if len(events_to_update) >= CHUNK_SIZE:
logger.debug( logger.debug(

View File

@@ -755,7 +755,11 @@ export function CameraGroupEdit({
<FormMessage /> <FormMessage />
{[ {[
...(birdseyeConfig?.enabled ? ["birdseye"] : []), ...(birdseyeConfig?.enabled ? ["birdseye"] : []),
...Object.keys(config?.cameras ?? {}), ...Object.keys(config?.cameras ?? {}).sort(
(a, b) =>
(config?.cameras[a]?.ui?.order ?? 0) -
(config?.cameras[b]?.ui?.order ?? 0),
),
].map((camera) => ( ].map((camera) => (
<FormControl key={camera}> <FormControl key={camera}>
<FilterSwitch <FilterSwitch

View File

@@ -477,7 +477,10 @@ export default function ObjectLifecycle({
</p> </p>
{Array.isArray(item.data.box) && {Array.isArray(item.data.box) &&
item.data.box.length >= 4 item.data.box.length >= 4
? (item.data.box[2] / item.data.box[3]).toFixed(2) ? (
aspectRatio *
(item.data.box[2] / item.data.box[3])
).toFixed(2)
: "N/A"} : "N/A"}
</div> </div>
</div> </div>

View File

@@ -505,45 +505,46 @@ function ObjectDetailsTab({
<div className="flex w-full flex-row justify-end gap-2"> <div className="flex w-full flex-row justify-end gap-2">
{config?.cameras[search.camera].genai.enabled && search.end_time && ( {config?.cameras[search.camera].genai.enabled && search.end_time && (
<> <div className="flex items-start">
<div className="flex items-start"> <Button
<Button className="rounded-r-none border-r-0"
className="rounded-r-none border-r-0" aria-label="Regenerate tracked object description"
aria-label="Regenerate tracked object description" onClick={() => regenerateDescription("thumbnails")}
onClick={() => regenerateDescription("thumbnails")} >
> Regenerate
Regenerate </Button>
</Button> {search.has_snapshot && (
{search.has_snapshot && ( <DropdownMenu>
<DropdownMenu> <DropdownMenuTrigger asChild>
<DropdownMenuTrigger asChild> <Button
<Button className="rounded-l-none border-l-0 px-2"
className="rounded-l-none border-l-0 px-2" aria-label="Expand regeneration menu"
aria-label="Expand regeneration menu" >
> <FaChevronDown className="size-3" />
<FaChevronDown className="size-3" /> </Button>
</Button> </DropdownMenuTrigger>
</DropdownMenuTrigger> <DropdownMenuContent>
<DropdownMenuContent> <DropdownMenuItem
<DropdownMenuItem className="cursor-pointer"
className="cursor-pointer" aria-label="Regenerate from snapshot"
aria-label="Regenerate from snapshot" onClick={() => regenerateDescription("snapshot")}
onClick={() => regenerateDescription("snapshot")} >
> Regenerate from Snapshot
Regenerate from Snapshot </DropdownMenuItem>
</DropdownMenuItem> <DropdownMenuItem
<DropdownMenuItem className="cursor-pointer"
className="cursor-pointer" aria-label="Regenerate from thumbnails"
aria-label="Regenerate from thumbnails" onClick={() => regenerateDescription("thumbnails")}
onClick={() => regenerateDescription("thumbnails")} >
> Regenerate from Thumbnails
Regenerate from Thumbnails </DropdownMenuItem>
</DropdownMenuItem> </DropdownMenuContent>
</DropdownMenuContent> </DropdownMenu>
</DropdownMenu> )}
)} </div>
</div> )}
{(config?.cameras[search.camera].genai.enabled && search.end_time) ||
(!config?.cameras[search.camera].genai.enabled && (
<Button <Button
variant="select" variant="select"
aria-label="Save" aria-label="Save"
@@ -551,8 +552,7 @@ function ObjectDetailsTab({
> >
Save Save
</Button> </Button>
</> ))}
)}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -46,7 +46,7 @@ export default function SearchSettings({
const trigger = ( const trigger = (
<Button <Button
className="flex items-center gap-2" className="flex items-center gap-2"
aria-label="Search Settings" aria-label="Explore Settings"
size="sm" size="sm"
> >
<FaCog className="text-secondary-foreground" /> <FaCog className="text-secondary-foreground" />

View File

@@ -328,12 +328,12 @@ export default function Explore() {
<div className="flex max-w-96 flex-col items-center justify-center space-y-3 rounded-lg bg-background/50 p-5"> <div className="flex max-w-96 flex-col items-center justify-center space-y-3 rounded-lg bg-background/50 p-5">
<div className="my-5 flex flex-col items-center gap-2 text-xl"> <div className="my-5 flex flex-col items-center gap-2 text-xl">
<TbExclamationCircle className="mb-3 size-10" /> <TbExclamationCircle className="mb-3 size-10" />
<div>Search Unavailable</div> <div>Explore is Unavailable</div>
</div> </div>
{embeddingsReindexing && allModelsLoaded && ( {embeddingsReindexing && allModelsLoaded && (
<> <>
<div className="text-center text-primary-variant"> <div className="text-center text-primary-variant">
Search can be used after tracked object embeddings have Explore can be used after tracked object embeddings have
finished reindexing. finished reindexing.
</div> </div>
<div className="pt-5 text-center"> <div className="pt-5 text-center">
@@ -384,8 +384,8 @@ export default function Explore() {
<> <>
<div className="text-center text-primary-variant"> <div className="text-center text-primary-variant">
Frigate is downloading the necessary embeddings models to Frigate is downloading the necessary embeddings models to
support semantic searching. This may take several minutes support the Semantic Search feature. This may take several
depending on the speed of your network connection. minutes depending on the speed of your network connection.
</div> </div>
<div className="flex w-96 flex-col gap-2 py-5"> <div className="flex w-96 flex-col gap-2 py-5">
<div className="flex flex-row items-center justify-center gap-2"> <div className="flex flex-row items-center justify-center gap-2">

View File

@@ -40,7 +40,7 @@ import UiSettingsView from "@/views/settings/UiSettingsView";
const allSettingsViews = [ const allSettingsViews = [
"UI settings", "UI settings",
"search settings", "explore settings",
"camera settings", "camera settings",
"masks / zones", "masks / zones",
"motion tuner", "motion tuner",
@@ -175,7 +175,7 @@ export default function Settings() {
</div> </div>
<div className="mt-2 flex h-full w-full flex-col items-start md:h-dvh md:pb-24"> <div className="mt-2 flex h-full w-full flex-col items-start md:h-dvh md:pb-24">
{page == "UI settings" && <UiSettingsView />} {page == "UI settings" && <UiSettingsView />}
{page == "search settings" && ( {page == "explore settings" && (
<SearchSettingsView setUnsavedChanges={setUnsavedChanges} /> <SearchSettingsView setUnsavedChanges={setUnsavedChanges} />
)} )}
{page == "debug" && ( {page == "debug" && (

View File

@@ -91,7 +91,7 @@ export default function SearchSettingsView({
) )
.then((res) => { .then((res) => {
if (res.status === 200) { if (res.status === 200) {
toast.success("Search settings have been saved.", { toast.success("Explore settings have been saved.", {
position: "top-center", position: "top-center",
}); });
setChangedValue(false); setChangedValue(false);
@@ -128,7 +128,7 @@ export default function SearchSettingsView({
if (changedValue) { if (changedValue) {
addMessage( addMessage(
"search_settings", "search_settings",
`Unsaved search settings changes`, `Unsaved Explore settings changes`,
undefined, undefined,
"search_settings", "search_settings",
); );
@@ -140,7 +140,7 @@ export default function SearchSettingsView({
}, [changedValue]); }, [changedValue]);
useEffect(() => { useEffect(() => {
document.title = "Search Settings - Frigate"; document.title = "Explore Settings - Frigate";
}, []); }, []);
if (!config) { if (!config) {
@@ -152,7 +152,7 @@ export default function SearchSettingsView({
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0"> <div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0">
<Heading as="h3" className="my-2"> <Heading as="h3" className="my-2">
Search Settings Explore Settings
</Heading> </Heading>
<Separator className="my-2 flex bg-secondary" /> <Separator className="my-2 flex bg-secondary" />
<Heading as="h4" className="my-2"> <Heading as="h4" className="my-2">
@@ -221,7 +221,7 @@ export default function SearchSettingsView({
<div className="text-md">Model Size</div> <div className="text-md">Model Size</div>
<div className="space-y-1 text-sm text-muted-foreground"> <div className="space-y-1 text-sm text-muted-foreground">
<p> <p>
The size of the model used for semantic search embeddings. The size of the model used for Semantic Search embeddings.
</p> </p>
<ul className="list-disc pl-5 text-sm"> <ul className="list-disc pl-5 text-sm">
<li> <li>