Compare commits

..

14 Commits

Author SHA1 Message Date
Josh Hawkins
6dfc9cbf0f fix ExportRecordingsBody to allow optional name field
fixes https://github.com/blakeblackshear/frigate/discussions/21413 because of https://github.com/blakeblackshear/frigate-hass-integration/pull/1021
2025-12-23 22:09:03 -06:00
Josh Hawkins
8c1071355c version bump on updating page 2025-12-23 12:06:43 -06:00
Josh Hawkins
46033cce8f clarify docs for none class 2025-12-23 11:43:36 -06:00
Nicolas Mowen
aaec0f6e92 Correctly catch JSONDecodeError 2025-12-23 06:57:12 -07:00
Nicolas Mowen
ec6fd2289c Ensure genai client exists 2025-12-23 06:10:36 -07:00
Josh Hawkins
92c6138feb add slovak 2025-12-22 22:07:52 -06:00
Josh Hawkins
d84aab09b1 add triggers to note 2025-12-22 18:33:17 -06:00
Josh Hawkins
2bf7ecb0b6 0.17 2025-12-22 17:56:00 -06:00
Josh Hawkins
bcc2d37a4c remove footnote about 0.17 2025-12-22 17:53:11 -06:00
Nicolas Mowen
bf4007d66a Reset the wizard state after closing with model 2025-12-22 16:01:20 -07:00
Josh Hawkins
6e1b2447ac only show allowed cameras and groups in camera filter button 2025-12-22 15:39:55 -06:00
Josh Hawkins
bf74e74696 fix weekday starting point on explore when set to monday in UI settings 2025-12-22 13:41:28 -06:00
Nicolas Mowen
3fb9abc97d Add review thumbnail URL to integration docs 2025-12-22 10:53:25 -07:00
Josh Hawkins
fb0838558f use fallback timeout for opening media source
covers the case where there is no active connection to the go2rtc stream and the camera takes a long time to start
2025-12-21 22:09:21 -06:00
14 changed files with 20 additions and 57 deletions

View File

@ -55,7 +55,7 @@ function setup_homekit_config() {
if [[ ! -f "${config_path}" ]]; then
echo "[INFO] Creating empty HomeKit config file..."
echo 'homekit: {}' > "${config_path}"
echo '{}' > "${config_path}"
fi
# Convert YAML to JSON for jq processing
@ -70,14 +70,12 @@ function setup_homekit_config() {
jq '
# Keep only the homekit section if it exists, otherwise empty object
if has("homekit") then {homekit: .homekit} else {homekit: {}} end
' "${temp_json}" > "${cleaned_json}" 2>/dev/null || {
echo '{"homekit": {}}' > "${cleaned_json}"
}
' "${temp_json}" > "${cleaned_json}" 2>/dev/null || echo '{"homekit": {}}' > "${cleaned_json}"
# Convert back to YAML and write to the config file
yq eval -P "${cleaned_json}" > "${config_path}" 2>/dev/null || {
echo "[WARNING] Failed to convert cleaned config to YAML, creating minimal config"
echo 'homekit: {}' > "${config_path}"
echo '{"homekit": {}}' > "${config_path}"
}
# Clean up temp files

View File

@ -16,13 +16,12 @@ Review summaries provide structured JSON responses that are saved for each revie
```
- `title` (string): A concise, direct title that describes the purpose or overall action (e.g., "Person taking out trash", "Joe walking dog").
- `scene` (string): A narrative description of what happens across the sequence from start to finish, including setting, detected objects, and their observable actions.
- `shortSummary` (string): A brief 2-sentence summary of the scene, suitable for notifications. This is a condensed version of the scene description.
- `confidence` (float): 0-1 confidence in the analysis. Higher confidence when objects/actions are clearly visible and context is unambiguous.
- `other_concerns` (list): List of user-defined concerns that may need additional investigation.
- `potential_threat_level` (integer): 0, 1, or 2 as defined below.
```
This will show in multiple places in the UI to give additional context about each activity, and allow viewing more details when extra attention is required. Frigate's built in notifications will automatically show the title and `shortSummary` when the data is available, while the full `scene` description is available in the UI for detailed review.
This will show in multiple places in the UI to give additional context about each activity, and allow viewing more details when extra attention is required. Frigate's built in notifications will also automatically show the title and description when the data is available.
### Defining Typical Activity

View File

@ -38,7 +38,3 @@ This is a fork (with fixed errors and new features) of [original Double Take](ht
## [Periscope](https://github.com/maksz42/periscope)
[Periscope](https://github.com/maksz42/periscope) is a lightweight Android app that turns old devices into live viewers for Frigate. It works on Android 2.2 and above, including Android TV. It supports authentication and HTTPS.
## [Scrypted - Frigate bridge plugin](https://github.com/apocaliss92/scrypted-frigate-bridge)
[Scrypted - Frigate bridge](https://github.com/apocaliss92/scrypted-frigate-bridge) is an plugin that allows to ingest Frigate detections, motion, videoclips on Scrypted as well as provide templates to export rebroadcast configurations on Frigate.

View File

@ -388,7 +388,7 @@ class WebPushClient(Communicator):
else:
title = base_title
message = payload["after"]["data"]["metadata"]["shortSummary"]
message = payload["after"]["data"]["metadata"]["scene"]
else:
zone_names = payload["after"]["data"]["zones"]
formatted_zone_names = []

View File

@ -28,7 +28,6 @@ from frigate.util.builtin import (
get_ffmpeg_arg_list,
)
from frigate.util.config import (
CURRENT_CONFIG_VERSION,
StreamInfoRetriever,
convert_area_to_pixels,
find_config_file,
@ -77,12 +76,11 @@ logger = logging.getLogger(__name__)
yaml = YAML()
DEFAULT_CONFIG = f"""
DEFAULT_CONFIG = """
mqtt:
enabled: False
cameras: {{}} # No cameras defined, UI wizard should be used
version: {CURRENT_CONFIG_VERSION}
cameras: {} # No cameras defined, UI wizard should be used
"""
DEFAULT_DETECTORS = {"cpu": {"type": "cpu"}}
@ -755,7 +753,8 @@ class FrigateConfig(FrigateBaseModel):
if new_config and f.tell() == 0:
f.write(DEFAULT_CONFIG)
logger.info(
"Created default config file, see the getting started docs for configuration: https://docs.frigate.video/guides/getting_started"
"Created default config file, see the getting started docs \
for configuration https://docs.frigate.video/guides/getting_started"
)
f.seek(0)

View File

@ -8,9 +8,6 @@ class ReviewMetadata(BaseModel):
scene: str = Field(
description="A comprehensive description of the setting and entities, including relevant context and plausible inferences if supported by visual evidence."
)
shortSummary: str = Field(
description="A brief 2-sentence summary of the scene, suitable for notifications. Should capture the key activity and context without full detail."
)
confidence: float = Field(
description="A float between 0 and 1 representing your overall confidence in this analysis."
)

View File

@ -633,7 +633,7 @@ class EmbeddingMaintainer(threading.Thread):
camera, frame_name, _, _, motion_boxes, _ = data
if not camera or len(motion_boxes) == 0 or camera not in self.config.cameras:
if not camera or len(motion_boxes) == 0:
return
camera_config = self.config.cameras[camera]

View File

@ -101,7 +101,6 @@ When forming your description:
Your response MUST be a flat JSON object with:
- `title` (string): A concise, direct title that describes the primary action or event in the sequence, not just what you literally see. Use spatial context when available to make titles more meaningful. When multiple objects/actions are present, prioritize whichever is most prominent or occurs first. Use names from "Objects in Scene" based on what you visually observe. If you see both a name and an unidentified object of the same type but visually observe only one person/object, use ONLY the name. Examples: "Joe walking dog", "Person taking out trash", "Vehicle arriving in driveway", "Joe accessing vehicle", "Person leaving porch for driveway".
- `scene` (string): A narrative description of what happens across the sequence from start to finish, in chronological order. Start by describing how the sequence begins, then describe the progression of events. **Describe all significant movements and actions in the order they occur.** For example, if a vehicle arrives and then a person exits, describe both actions sequentially. **Only describe actions you can actually observe happening in the frames provided.** Do not infer or assume actions that aren't visible (e.g., if you see someone walking but never see them sit, don't say they sat down). Include setting, detected objects, and their observable actions. Avoid speculation or filling in assumed behaviors. Your description should align with and support the threat level you assign.
- `shortSummary` (string): A brief 2-sentence summary of the scene, suitable for notifications. Should capture the key activity and context without full detail. This should be a condensed version of the scene description above.
- `confidence` (float): 0-1 confidence in your analysis. Higher confidence when objects/actions are clearly visible and context is unambiguous. Lower confidence when the sequence is unclear, objects are partially obscured, or context is ambiguous.
- `potential_threat_level` (integer): 0, 1, or 2 as defined in "Normal Activity Patterns for This Property" above. Your threat level must be consistent with your scene description and the guidance above.
{get_concern_prompt()}
@ -193,8 +192,6 @@ Input format: Each event is a JSON object with:
- "title", "scene", "confidence", "potential_threat_level" (0-2), "other_concerns", "camera", "time", "start_time", "end_time"
- "context": array of related events from other cameras that occurred during overlapping time periods
**Note: Use the "scene" field for event descriptions in the report. Ignore any "shortSummary" field if present.**
Report Structure - Use this EXACT format:
# Security Summary - {time_range}

View File

@ -3,7 +3,7 @@
import logging
from typing import Any, Optional
from httpx import RemoteProtocolError, TimeoutException
from httpx import TimeoutException
from ollama import Client as ApiClient
from ollama import ResponseError
@ -68,12 +68,7 @@ class OllamaClient(GenAIClient):
f"Ollama tokens used: eval_count={result.get('eval_count')}, prompt_eval_count={result.get('prompt_eval_count')}"
)
return result["response"].strip()
except (
TimeoutException,
ResponseError,
RemoteProtocolError,
ConnectionError,
) as e:
except (TimeoutException, ResponseError, ConnectionError) as e:
logger.warning("Ollama returned an error: %s", str(e))
return None

View File

@ -139,11 +139,9 @@ class OutputProcess(FrigateProcess):
if CameraConfigUpdateEnum.add in updates:
for camera in updates["add"]:
jsmpeg_cameras[camera] = JsmpegCamera(
self.config.cameras[camera], self.stop_event, websocket_server
)
preview_recorders[camera] = PreviewRecorder(
self.config.cameras[camera]
cam_config, self.stop_event, websocket_server
)
preview_recorders[camera] = PreviewRecorder(cam_config)
preview_write_times[camera] = 0
if (

View File

@ -54,7 +54,7 @@ export default function SetPasswordDialog({
config?.auth?.refresh_time ?? undefined;
const refreshTimeLabel = refreshSeconds
? formatSecondsToDuration(refreshSeconds)
: t("time.30minutes", { ns: "common" });
: "30 minutes";
// visibility toggles for password fields
const [showOldPassword, setShowOldPassword] = useState<boolean>(false);

View File

@ -31,8 +31,7 @@ type WizardState = {
type WizardAction =
| { type: "UPDATE_DATA"; payload: Partial<WizardFormData> }
| { type: "UPDATE_AND_NEXT"; payload: Partial<WizardFormData> }
| { type: "RESET_NAVIGATE" }
| { type: "RESET_ALL" };
| { type: "RESET_NAVIGATE" };
const wizardReducer = (
state: WizardState,
@ -51,11 +50,6 @@ const wizardReducer = (
};
case "RESET_NAVIGATE":
return { ...state, shouldNavigateNext: false };
case "RESET_ALL":
return {
wizardData: { streams: [] },
shouldNavigateNext: false,
};
default:
return state;
}
@ -90,13 +84,13 @@ export default function CameraWizardDialog({
useEffect(() => {
if (open) {
setCurrentStep(0);
dispatch({ type: "RESET_ALL" });
dispatch({ type: "UPDATE_DATA", payload: { streams: [] } });
}
}, [open]);
const handleClose = useCallback(() => {
setCurrentStep(0);
dispatch({ type: "RESET_ALL" });
dispatch({ type: "UPDATE_DATA", payload: { streams: [] } });
onClose();
}, [onClose]);

View File

@ -219,12 +219,12 @@ function Exports() {
/>
))}
</div>
) : exports !== undefined ? (
) : (
<div className="absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center text-center">
<LuFolderX className="size-16" />
{t("noExports")}
</div>
) : null}
)}
</div>
</div>
);

View File

@ -22,7 +22,6 @@ import { SearchTab } from "@/components/overlay/detail/SearchDetailDialog";
import { FrigateConfig } from "@/types/frigateConfig";
import { useTranslation } from "react-i18next";
import { getTranslatedLabel } from "@/utils/i18n";
import { LuSearchX } from "react-icons/lu";
type ExploreViewProps = {
setSearchDetail: (search: SearchResult | undefined) => void;
@ -87,15 +86,6 @@ export default function ExploreView({
);
}
if (eventsByLabel && Object.keys(eventsByLabel).length == 0 && !isLoading) {
return (
<div className="absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center text-center">
<LuSearchX className="size-16" />
{t("noTrackedObjects")}
</div>
);
}
return (
<div className="mx-2 space-y-4">
{Object.entries(eventsByLabel).map(([label, filteredEvents]) => (