Compare commits

...

8 Commits

Author SHA1 Message Date
Nicolas Mowen
290da87075 Ensure that cache dir exists for Frigate+ 2025-05-08 17:39:56 -06:00
Josh Hawkins
23d719d271 copy path data 2025-05-08 16:52:52 -05:00
Nicolas Mowen
58b2ad9c8f Fix incorrectly copying zones 2025-05-08 15:27:16 -06:00
Josh Hawkins
309638323a webpush debugging logs 2025-05-08 15:51:37 -05:00
Nicolas Mowen
6849ee06f5 Don't delete train tab 2025-05-08 14:04:01 -06:00
Josh Hawkins
d3821fc706 settings i18n fixes 2025-05-08 14:48:22 -05:00
Nicolas Mowen
31051e4835 GPU is required 2025-05-08 13:37:00 -06:00
Nicolas Mowen
7d775def31 Force GPU for large embedding model 2025-05-08 13:34:47 -06:00
13 changed files with 49 additions and 37 deletions

View File

@ -34,7 +34,7 @@ All of these features run locally on your system.
The `small` model is optimized for efficiency and runs on the CPU, most CPUs should run the model efficiently.
The `large` model is optimized for accuracy, an integrated or discrete GPU is highly recommended. See the [Hardware Accelerated Enrichments](/configuration/hardware_acceleration_enrichments.md) documentation.
The `large` model is optimized for accuracy, an integrated or discrete GPU is required. See the [Hardware Accelerated Enrichments](/configuration/hardware_acceleration_enrichments.md) documentation.
## Configuration

View File

@ -303,6 +303,9 @@ class WebPushClient(Communicator): # type: ignore[misc]
and len(payload["before"]["data"]["zones"])
== len(payload["after"]["data"]["zones"])
):
logger.debug(
f"Skipping notification for {camera} - message is an update and important fields don't have an update"
)
return
self.last_camera_notification_time[camera] = current_time
@ -325,6 +328,8 @@ class WebPushClient(Communicator): # type: ignore[misc]
direct_url = f"/review?id={reviewId}" if state == "end" else f"/#{camera}"
ttl = 3600 if state == "end" else 0
logger.debug(f"Sending push notification for {camera}, review ID {reviewId}")
for user in self.web_pushers:
self.send_push_notification(
user=user,

View File

@ -126,6 +126,10 @@ class ModelConfig(BaseModel):
if not self.path or not self.path.startswith("plus://"):
return
# ensure that model cache dir exists
if not os.path.exists(MODEL_CACHE_DIR):
os.makedirs(MODEL_CACHE_DIR)
model_id = self.path[7:]
self.path = os.path.join(MODEL_CACHE_DIR, model_id)
model_info_path = f"{self.path}.json"

View File

@ -235,7 +235,7 @@ class EmbeddingsContext:
if os.path.isfile(file_path):
os.unlink(file_path)
if len(os.listdir(folder)) == 0:
if face != "train" and len(os.listdir(folder)) == 0:
os.rmdir(folder)
self.requestor.send_data(

View File

@ -23,10 +23,7 @@ FACENET_INPUT_SIZE = 160
class FaceNetEmbedding(BaseEmbedding):
def __init__(
self,
device: str = "AUTO",
):
def __init__(self):
super().__init__(
model_name="facedet",
model_file="facenet.tflite",
@ -34,7 +31,6 @@ class FaceNetEmbedding(BaseEmbedding):
"facenet.tflite": "https://github.com/NickM-27/facenet-onnx/releases/download/v1.0/facenet.tflite",
},
)
self.device = device
self.download_path = os.path.join(MODEL_CACHE_DIR, self.model_name)
self.tokenizer = None
self.feature_extractor = None
@ -113,10 +109,7 @@ class FaceNetEmbedding(BaseEmbedding):
class ArcfaceEmbedding(BaseEmbedding):
def __init__(
self,
device: str = "AUTO",
):
def __init__(self):
super().__init__(
model_name="facedet",
model_file="arcface.onnx",
@ -124,7 +117,6 @@ class ArcfaceEmbedding(BaseEmbedding):
"arcface.onnx": "https://github.com/NickM-27/facenet-onnx/releases/download/v1.0/arcface.onnx",
},
)
self.device = device
self.download_path = os.path.join(MODEL_CACHE_DIR, self.model_name)
self.tokenizer = None
self.feature_extractor = None
@ -154,7 +146,7 @@ class ArcfaceEmbedding(BaseEmbedding):
self.runner = ONNXModelRunner(
os.path.join(self.download_path, self.model_file),
self.device,
"GPU",
)
def _preprocess_inputs(self, raw_inputs):

View File

@ -1,5 +1,6 @@
"""Maintain review segments in db."""
import copy
import json
import logging
import os
@ -119,21 +120,23 @@ class PendingReviewSegment:
)
def get_data(self, ended: bool) -> dict:
return {
ReviewSegment.id.name: self.id,
ReviewSegment.camera.name: self.camera,
ReviewSegment.start_time.name: self.start_time,
ReviewSegment.end_time.name: self.last_update if ended else None,
ReviewSegment.severity.name: self.severity.value,
ReviewSegment.thumb_path.name: self.frame_path,
ReviewSegment.data.name: {
"detections": list(set(self.detections.keys())),
"objects": list(set(self.detections.values())),
"sub_labels": list(self.sub_labels.values()),
"zones": self.zones,
"audio": list(self.audio),
},
}.copy()
return copy.deepcopy(
{
ReviewSegment.id.name: self.id,
ReviewSegment.camera.name: self.camera,
ReviewSegment.start_time.name: self.start_time,
ReviewSegment.end_time.name: self.last_update if ended else None,
ReviewSegment.severity.name: self.severity.value,
ReviewSegment.thumb_path.name: self.frame_path,
ReviewSegment.data.name: {
"detections": list(set(self.detections.keys())),
"objects": list(set(self.detections.values())),
"sub_labels": list(self.sub_labels.values()),
"zones": self.zones,
"audio": list(self.audio),
},
}
)
class ReviewSegmentMaintainer(threading.Thread):

View File

@ -154,7 +154,7 @@ class TrackedObject:
"attributes": obj_data["attributes"],
"current_estimated_speed": self.current_estimated_speed,
"velocity_angle": self.velocity_angle,
"path_data": self.path_data,
"path_data": self.path_data.copy(),
"recognized_license_plate": obj_data.get(
"recognized_license_plate"
),
@ -378,7 +378,7 @@ class TrackedObject:
"current_estimated_speed": self.current_estimated_speed,
"average_estimated_speed": self.average_estimated_speed,
"velocity_angle": self.velocity_angle,
"path_data": self.path_data,
"path_data": self.path_data.copy(),
"recognized_license_plate": self.obj_data.get("recognized_license_plate"),
}

View File

@ -84,6 +84,7 @@
},
"classification": {
"title": "Classification Settings",
"unsavedChanges": "Unsaved Classification settings changes",
"birdClassification": {
"title": "Bird Classification",
"desc": "Bird classification identifies known birds using a quantized Tensorflow model. When a known bird is recognized, its common name will be added as a sub_label. This information is included in the UI, filters, as well as in notifications."
@ -168,11 +169,12 @@
"notSelectDetections": "All {{detectionsLabels}} objects detected in {{zone}} on {{cameraName}} not categorized as Alerts will be shown as Detections regardless of which zone they are in.",
"regardlessOfZoneObjectDetectionsTips": "All {{detectionsLabels}} objects not categorized on {{cameraName}} will be shown as Detections regardless of which zone they are in."
},
"unsavedChanges": "Unsaved Review Classification settings for {{camera}}",
"selectAlertsZones": "Select zones for Alerts",
"selectDetectionsZones": "Select zones for Detections",
"limitDetections": "Limit detections to specific zones",
"toast": {
"success": "Review classification configuration has been saved. Restart Frigate to apply changes."
"success": "Review Classification configuration has been saved. Restart Frigate to apply changes."
}
}
},
@ -338,6 +340,7 @@
},
"motionDetectionTuner": {
"title": "Motion Detection Tuner",
"unsavedChanges": "Unsaved Motion Tuner changes ({{camera}})",
"desc": {
"title": "Frigate uses motion detection as a first line check to see if there is anything happening in the frame worth checking with object detection.",
"documentation": "Read the Motion Tuning Guide"
@ -527,6 +530,8 @@
"registerDevice": "Register This Device",
"unregisterDevice": "Unregister This Device",
"sendTestNotification": "Send a test notification",
"unsavedRegistrations": "Unsaved Notification registrations",
"unsavedChanges": "Unsaved Notification changes",
"active": "Notifications Active",
"suspended": "Notifications suspended {{time}}",
"suspendTime": {
@ -587,6 +592,7 @@
"loadingAvailableModels": "Loading available models…",
"modelSelect": "Your available models on Frigate+ can be selected here. Note that only models compatible with your current detector configuration can be selected."
},
"unsavedChanges": "Unsaved Frigate+ settings changes",
"restart_required": "Restart required (Frigate+ model changed)",
"toast": {
"success": "Frigate+ settings have been saved. Restart Frigate to apply changes.",

View File

@ -230,7 +230,9 @@ export default function CameraSettingsView({
if (changedValue) {
addMessage(
"camera_settings",
`Unsaved review classification settings for ${capitalizeFirstLetter(selectedCamera)}`,
t("camera.reviewClassification.unsavedChanges", {
camera: selectedCamera,
}),
undefined,
`review_classification_settings_${selectedCamera}`,
);

View File

@ -220,7 +220,7 @@ export default function ClassificationSettingsView({
if (changedValue) {
addMessage(
"search_settings",
`Unsaved Classification settings changes`,
t("classification.unsavedChanges"),
undefined,
"search_settings",
);

View File

@ -176,7 +176,7 @@ export default function FrigatePlusSettingsView({
if (changedValue) {
addMessage(
"plus_settings",
`Unsaved Frigate+ settings changes`,
t("frigatePlus.unsavedChanges"),
undefined,
"plus_settings",
);

View File

@ -167,7 +167,7 @@ export default function MotionTunerView({
if (changedValue) {
addMessage(
"motion_tuner",
`Unsaved motion tuner changes (${selectedCamera})`,
t("motionDetectionTuner.unsavedChanges", { camera: selectedCamera }),
undefined,
`motion_tuner_${selectedCamera}`,
);

View File

@ -105,7 +105,7 @@ export default function NotificationView({
if (changedValue) {
addMessage(
"notification_settings",
`Unsaved notification settings`,
t("notification.unsavedChanges"),
undefined,
`notification_settings`,
);
@ -128,7 +128,7 @@ export default function NotificationView({
if (registration) {
addMessage(
"notification_settings",
"Unsaved Notification Registrations",
t("notification.unsavedRegistrations"),
undefined,
"registration",
);