mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-07-21 03:09:02 +03:00
Compare commits
23
Commits
@@ -72,7 +72,7 @@ This does not affect using hardware for accelerating other tasks such as [semant
|
||||
|
||||
# Officially Supported Detectors
|
||||
|
||||
Frigate provides a number of builtin detector types. By default, Frigate will use a single CPU detector. Other detectors may require additional configuration as described below. When using multiple detectors they will run in dedicated processes, but pull from a common queue of detection requests from across all cameras.
|
||||
Frigate provides a number of builtin detector types. By default, Frigate will use a single OpenVINO detector running on the CPU. Other detectors may require additional configuration as described below. When using multiple detectors they will run in dedicated processes, but pull from a common queue of detection requests from across all cameras.
|
||||
|
||||
## Edge TPU Detector
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ cameras:
|
||||
|
||||
### Step 4: Configure detectors
|
||||
|
||||
By default, Frigate will use a single CPU detector.
|
||||
By default, Frigate will use a single OpenVINO detector running on the CPU.
|
||||
|
||||
In many cases, the integrated graphics on Intel CPUs provides sufficient performance for typical Frigate setups. If you have an Intel processor, you can follow the configuration below.
|
||||
|
||||
|
||||
Generated
+3
-3
@@ -10971,9 +10971,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
|
||||
@@ -499,6 +499,40 @@ def config_save(save_option: str, body: Any = Body(media_type="text/plain")):
|
||||
)
|
||||
|
||||
|
||||
def _restore_masked_camera_paths(config_data: dict, config: FrigateConfig) -> None:
|
||||
"""Substitute incoming `*:*` masked credentials with the in-memory ones.
|
||||
|
||||
The /config response masks ffmpeg input credentials, so the settings UI
|
||||
sends the masked path back when sibling fields (e.g. hwaccel_args) are
|
||||
edited. Without this we'd write `rtsp://*:*@host` into YAML and lose
|
||||
the real credentials. Mutates `config_data` in place.
|
||||
"""
|
||||
cameras = config_data.get("cameras")
|
||||
if not isinstance(cameras, dict):
|
||||
return
|
||||
|
||||
for camera_name, camera_data in cameras.items():
|
||||
if not isinstance(camera_data, dict):
|
||||
continue
|
||||
inputs = camera_data.get("ffmpeg", {}).get("inputs")
|
||||
if not isinstance(inputs, list):
|
||||
continue
|
||||
existing = config.cameras.get(camera_name)
|
||||
if existing is None:
|
||||
continue
|
||||
existing_paths = [inp.path for inp in existing.ffmpeg.inputs]
|
||||
for index, input_obj in enumerate(inputs):
|
||||
if not isinstance(input_obj, dict):
|
||||
continue
|
||||
path = input_obj.get("path")
|
||||
if not isinstance(path, str):
|
||||
continue
|
||||
if ("://*:*@" in path or "user=*&password=*" in path) and index < len(
|
||||
existing_paths
|
||||
):
|
||||
input_obj["path"] = existing_paths[index]
|
||||
|
||||
|
||||
def _config_set_in_memory(request: Request, body: AppConfigSetBody) -> JSONResponse:
|
||||
"""Apply config changes in-memory only, without writing to YAML.
|
||||
|
||||
@@ -509,6 +543,7 @@ def _config_set_in_memory(request: Request, body: AppConfigSetBody) -> JSONRespo
|
||||
try:
|
||||
updates = {}
|
||||
if body.config_data:
|
||||
_restore_masked_camera_paths(body.config_data, request.app.frigate_config)
|
||||
updates = flatten_config_data(body.config_data)
|
||||
updates = {k: ("" if v is None else v) for k, v in updates.items()}
|
||||
|
||||
@@ -615,6 +650,9 @@ def config_set(request: Request, body: AppConfigSetBody):
|
||||
if query_string:
|
||||
updates = process_config_query_string(query_string)
|
||||
elif body.config_data:
|
||||
_restore_masked_camera_paths(
|
||||
body.config_data, request.app.frigate_config
|
||||
)
|
||||
updates = flatten_config_data(body.config_data)
|
||||
# Convert None values to empty strings for deletion (e.g., when deleting masks)
|
||||
updates = {k: ("" if v is None else v) for k, v in updates.items()}
|
||||
|
||||
+24
-10
@@ -26,6 +26,7 @@ from frigate.api.defs.request.app_body import (
|
||||
AppPutRoleBody,
|
||||
)
|
||||
from frigate.api.defs.tags import Tags
|
||||
from frigate.api.media_auth import check_camera_access, deny_response_for_media_uri
|
||||
from frigate.config import AuthConfig, NetworkingConfig, ProxyConfig
|
||||
from frigate.const import CONFIG_DIR, JWT_SECRET_ENV_VAR, PASSWORD_HASH_ALGORITHM
|
||||
from frigate.models import User
|
||||
@@ -633,6 +634,9 @@ def auth(request: Request):
|
||||
logger.debug("X-Proxy-Secret header does not match configured secret value")
|
||||
return fail_response
|
||||
|
||||
original_url = request.headers.get("x-original-url")
|
||||
frigate_config = request.app.frigate_config
|
||||
|
||||
# if auth is disabled, just apply the proxy header map and return success
|
||||
if not auth_config.enabled:
|
||||
# pass the user header value from the upstream proxy if a mapping is specified
|
||||
@@ -649,6 +653,11 @@ def auth(request: Request):
|
||||
role = resolve_role(request.headers, proxy_config, config_roles_set)
|
||||
|
||||
success_response.headers["remote-role"] = role
|
||||
|
||||
deny_status = deny_response_for_media_uri(original_url, role, frigate_config)
|
||||
if deny_status is not None:
|
||||
return Response("", status_code=deny_status)
|
||||
|
||||
return success_response
|
||||
|
||||
# now apply authentication
|
||||
@@ -743,6 +752,11 @@ def auth(request: Request):
|
||||
|
||||
success_response.headers["remote-user"] = user
|
||||
success_response.headers["remote-role"] = role
|
||||
|
||||
deny_status = deny_response_for_media_uri(original_url, role, frigate_config)
|
||||
if deny_status is not None:
|
||||
return Response("", status_code=deny_status)
|
||||
|
||||
return success_response
|
||||
except Exception as e:
|
||||
logger.error(f"Error parsing jwt: {e}")
|
||||
@@ -1069,19 +1083,19 @@ async def require_camera_access(
|
||||
raise HTTPException(status_code=current_user.status_code, detail=detail)
|
||||
|
||||
role = current_user["role"]
|
||||
all_camera_names = set(request.app.frigate_config.cameras.keys())
|
||||
roles_dict = request.app.frigate_config.auth.roles
|
||||
allowed_cameras = User.get_allowed_cameras(role, roles_dict, all_camera_names)
|
||||
frigate_config = request.app.frigate_config
|
||||
|
||||
# Admin or full access bypasses
|
||||
if role == "admin" or not roles_dict.get(role):
|
||||
if check_camera_access(role, camera_name, frigate_config):
|
||||
return
|
||||
|
||||
if camera_name not in allowed_cameras:
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail=f"Access denied to camera '{camera_name}'. Allowed: {allowed_cameras}",
|
||||
)
|
||||
all_camera_names = set(frigate_config.cameras.keys())
|
||||
allowed_cameras = User.get_allowed_cameras(
|
||||
role, frigate_config.auth.roles, all_camera_names
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail=f"Access denied to camera '{camera_name}'. Allowed: {allowed_cameras}",
|
||||
)
|
||||
|
||||
|
||||
def _get_stream_owner_cameras(request: Request, stream_name: str) -> set[str]:
|
||||
|
||||
+14
-1
@@ -37,6 +37,7 @@ from frigate.api.defs.response.chat_response import (
|
||||
from frigate.api.defs.tags import Tags
|
||||
from frigate.api.event import events
|
||||
from frigate.config import FrigateConfig
|
||||
from frigate.config.ui import UnitSystemEnum
|
||||
from frigate.genai.utils import build_assistant_message_for_conversation
|
||||
from frigate.jobs.vlm_watch import (
|
||||
get_vlm_watch_job,
|
||||
@@ -1301,6 +1302,7 @@ async def chat_completion(
|
||||
|
||||
cameras_info = []
|
||||
config = request.app.frigate_config
|
||||
has_speed_zone = False
|
||||
for camera_id in allowed_cameras:
|
||||
if camera_id not in config.cameras:
|
||||
continue
|
||||
@@ -1311,6 +1313,10 @@ async def chat_completion(
|
||||
else camera_id.replace("_", " ").title()
|
||||
)
|
||||
zone_names = list(camera_config.zones.keys())
|
||||
if not has_speed_zone:
|
||||
has_speed_zone = any(
|
||||
zone.distances for zone in camera_config.zones.values()
|
||||
)
|
||||
if zone_names:
|
||||
cameras_info.append(
|
||||
f" - {friendly_name} (ID: {camera_id}, zones: {', '.join(zone_names)})"
|
||||
@@ -1326,6 +1332,13 @@ async def chat_completion(
|
||||
+ "\n\nWhen users refer to cameras by their friendly name (e.g., 'Back Deck Camera'), use the corresponding camera ID (e.g., 'back_deck_cam') in tool calls."
|
||||
)
|
||||
|
||||
speed_units_section = ""
|
||||
if has_speed_zone:
|
||||
speed_unit = (
|
||||
"mph" if config.ui.unit_system == UnitSystemEnum.imperial else "km/h"
|
||||
)
|
||||
speed_units_section = f"\n\nReport object speeds to the user in {speed_unit}."
|
||||
|
||||
system_prompt = f"""You are a helpful assistant for Frigate, a security camera NVR system. You help users answer questions about their cameras, detected objects, and events.
|
||||
|
||||
Current server local date and time: {current_date_str} at {current_time_str}
|
||||
@@ -1337,7 +1350,7 @@ When users ask about "today", "yesterday", "this week", etc., use the current da
|
||||
When searching for objects or events, use ISO 8601 format for dates (e.g., {current_date_str}T00:00:00Z for the start of today).
|
||||
Always be accurate with time calculations based on the current date provided.
|
||||
|
||||
When a user refers to a specific object they have seen or describe with identifying details ("that green car", "the person in the red jacket", "a package left today"), prefer the find_similar_objects tool over search_objects. Use search_objects first only to locate the anchor event, then pass its id to find_similar_objects. For generic queries like "show me all cars today", keep using search_objects. If a user message begins with [attached_event:<id>], treat that event id as the anchor for any similarity or "tell me more" request in the same message and call find_similar_objects with that id.{cameras_section}"""
|
||||
When a user refers to a specific object they have seen or describe with identifying details ("that green car", "the person in the red jacket", "a package left today"), prefer the find_similar_objects tool over search_objects. Use search_objects first only to locate the anchor event, then pass its id to find_similar_objects. For generic queries like "show me all cars today", keep using search_objects. If a user message begins with [attached_event:<id>], treat that event id as the anchor for any similarity or "tell me more" request in the same message and call find_similar_objects with that id.{cameras_section}{speed_units_section}"""
|
||||
|
||||
conversation.append(
|
||||
{
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
"""URI-aware authorization for nginx-served static media.
|
||||
|
||||
The `/auth` endpoint (used as nginx `auth_request` target) calls into this
|
||||
module to classify the requested URI from the `X-Original-URL` header and, for
|
||||
camera-scoped resources, decide whether the current role may access them.
|
||||
|
||||
Without this, `auth_request` only verifies the JWT — every authenticated user
|
||||
could read clips, recordings, and exports for *any* camera, bypassing the
|
||||
per-camera authorization the regular API enforces via `require_camera_access`.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
from urllib.parse import unquote, urlparse
|
||||
|
||||
from peewee import DoesNotExist
|
||||
|
||||
from frigate.config import FrigateConfig
|
||||
from frigate.const import EXPORT_DIR
|
||||
from frigate.models import Export, User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MediaAuthResolution(str, Enum):
|
||||
"""Classification of an `X-Original-URL` path for media-auth purposes."""
|
||||
|
||||
CAMERA = "camera"
|
||||
ADMIN_ONLY = "admin_only"
|
||||
LISTING_MULTI_CAMERA = "listing_multi_camera"
|
||||
LISTING_NEUTRAL = "listing_neutral"
|
||||
# Under a recognized media root (/clips, /recordings, /exports) but
|
||||
# unclassifiable (unknown subtree, no matching DB row, DB error).
|
||||
# Restricted users are denied; admins/full-access roles are allowed
|
||||
# (nginx will likely return 404 if the file genuinely doesn't exist).
|
||||
UNRESOLVED_MEDIA = "unresolved_media"
|
||||
# Not a media URI at all (e.g. /api/events, /login).
|
||||
UNKNOWN = "unknown"
|
||||
|
||||
|
||||
def extract_path(original_url: Optional[str]) -> Optional[str]:
|
||||
"""Return the decoded path component of nginx's `X-Original-URL` header.
|
||||
|
||||
nginx forwards the *raw* request URI (with `..` segments intact) via
|
||||
`$request_uri`. nginx normalizes the path before serving the file, so a
|
||||
request like `/recordings/.../allowed_cam/../forbidden_cam/file.mp4`
|
||||
would (1) parse as the allowed camera in our auth check, (2) be served
|
||||
as the forbidden camera by nginx. To close the bypass we reject any URI
|
||||
whose path contains `.` or `..` segments outright.
|
||||
"""
|
||||
if not original_url:
|
||||
return None
|
||||
|
||||
parsed = urlparse(original_url)
|
||||
raw_path = parsed.path or original_url
|
||||
decoded = unquote(raw_path)
|
||||
if not decoded:
|
||||
return None
|
||||
|
||||
if not decoded.startswith("/"):
|
||||
decoded = "/" + decoded
|
||||
|
||||
segments = decoded.split("/")
|
||||
if ".." in segments or "." in segments:
|
||||
return None
|
||||
|
||||
return decoded
|
||||
|
||||
|
||||
def resolve_media_uri(
|
||||
uri: str, frigate_config: Optional[FrigateConfig] = None
|
||||
) -> tuple[MediaAuthResolution, Optional[str]]:
|
||||
"""Classify a URI and return the owning camera if applicable.
|
||||
|
||||
`frigate_config` is used to disambiguate clip/review filenames whose
|
||||
camera name contains hyphens by matching against the longest configured
|
||||
camera-name prefix.
|
||||
"""
|
||||
if not uri:
|
||||
return MediaAuthResolution.UNKNOWN, None
|
||||
|
||||
parts = [p for p in uri.split("/") if p]
|
||||
if not parts:
|
||||
return MediaAuthResolution.UNKNOWN, None
|
||||
|
||||
root = parts[0]
|
||||
if root == "recordings":
|
||||
return _resolve_recording(parts)
|
||||
if root == "clips":
|
||||
return _resolve_clip(parts, frigate_config)
|
||||
if root == "exports":
|
||||
return _resolve_export(parts)
|
||||
|
||||
return MediaAuthResolution.UNKNOWN, None
|
||||
|
||||
|
||||
def _resolve_recording(
|
||||
parts: list[str],
|
||||
) -> tuple[MediaAuthResolution, Optional[str]]:
|
||||
# /recordings → neutral
|
||||
# /recordings/{date} → neutral
|
||||
# /recordings/{date}/{hour} → multi-camera listing
|
||||
# /recordings/{date}/{hour}/{cam}/... → camera
|
||||
if len(parts) <= 2:
|
||||
return MediaAuthResolution.LISTING_NEUTRAL, None
|
||||
if len(parts) == 3:
|
||||
return MediaAuthResolution.LISTING_MULTI_CAMERA, None
|
||||
return MediaAuthResolution.CAMERA, parts[3]
|
||||
|
||||
|
||||
def _resolve_clip(
|
||||
parts: list[str], frigate_config: Optional[FrigateConfig]
|
||||
) -> tuple[MediaAuthResolution, Optional[str]]:
|
||||
# /clips → multi-camera listing
|
||||
# /clips/thumbs/{cam}/... → camera
|
||||
# /clips/previews/{cam}/... → camera
|
||||
# /clips/review/thumb-{cam}-{review_id}.webp → camera (parsed)
|
||||
# /clips/faces/... → admin-only
|
||||
# /clips/genai-requests/... → admin-only
|
||||
# /clips/preview_restart_cache/... → admin-only
|
||||
# /clips/{model}/train|dataset/... → admin-only
|
||||
# /clips/{cam}-{event_id}[-clean].{ext} → camera (parsed)
|
||||
# other /clips/{subdir}/... → unresolved (deny restricted)
|
||||
if len(parts) == 1:
|
||||
return MediaAuthResolution.LISTING_MULTI_CAMERA, None
|
||||
|
||||
second = parts[1]
|
||||
|
||||
if second in ("thumbs", "previews"):
|
||||
if len(parts) == 2:
|
||||
return MediaAuthResolution.LISTING_MULTI_CAMERA, None
|
||||
return MediaAuthResolution.CAMERA, parts[2]
|
||||
|
||||
if second == "review":
|
||||
if len(parts) == 2:
|
||||
return MediaAuthResolution.LISTING_MULTI_CAMERA, None
|
||||
camera = _camera_from_thumb_filename(parts[2], frigate_config)
|
||||
if camera:
|
||||
return MediaAuthResolution.CAMERA, camera
|
||||
return MediaAuthResolution.UNRESOLVED_MEDIA, None
|
||||
|
||||
if second in ("faces", "genai-requests", "preview_restart_cache"):
|
||||
return MediaAuthResolution.ADMIN_ONLY, None
|
||||
|
||||
if len(parts) >= 3 and parts[2] in ("train", "dataset"):
|
||||
return MediaAuthResolution.ADMIN_ONLY, None
|
||||
|
||||
if len(parts) == 2:
|
||||
camera = _camera_from_clip_filename(second, frigate_config)
|
||||
if camera:
|
||||
return MediaAuthResolution.CAMERA, camera
|
||||
return MediaAuthResolution.UNRESOLVED_MEDIA, None
|
||||
|
||||
return MediaAuthResolution.UNRESOLVED_MEDIA, None
|
||||
|
||||
|
||||
def _longest_prefix_camera(
|
||||
stem: str, frigate_config: Optional[FrigateConfig]
|
||||
) -> Optional[str]:
|
||||
if frigate_config is None:
|
||||
return None
|
||||
for cam in sorted(frigate_config.cameras.keys(), key=len, reverse=True):
|
||||
if stem.startswith(cam + "-"):
|
||||
return cam
|
||||
return None
|
||||
|
||||
|
||||
def _camera_from_clip_filename(
|
||||
filename: str, frigate_config: Optional[FrigateConfig]
|
||||
) -> Optional[str]:
|
||||
"""Match a flat clip filename `{camera}-{event_id}[-clean].{ext}` against
|
||||
configured camera names. Longest-prefix wins so camera names containing
|
||||
hyphens (e.g. `front-door`) resolve correctly.
|
||||
"""
|
||||
dot = filename.rfind(".")
|
||||
stem = filename[:dot] if dot > 0 else filename
|
||||
return _longest_prefix_camera(stem, frigate_config)
|
||||
|
||||
|
||||
def _camera_from_thumb_filename(
|
||||
filename: str, frigate_config: Optional[FrigateConfig]
|
||||
) -> Optional[str]:
|
||||
"""Match a review thumbnail filename `thumb-{camera}-{review_id}.webp`."""
|
||||
if not filename.startswith("thumb-"):
|
||||
return None
|
||||
dot = filename.rfind(".")
|
||||
stem = filename[len("thumb-") : dot] if dot > 0 else filename[len("thumb-") :]
|
||||
return _longest_prefix_camera(stem, frigate_config)
|
||||
|
||||
|
||||
def _resolve_export(
|
||||
parts: list[str],
|
||||
) -> tuple[MediaAuthResolution, Optional[str]]:
|
||||
# /exports → multi-camera listing
|
||||
# /exports/{filename}.mp4 → camera (DB lookup by exact path)
|
||||
if len(parts) == 1:
|
||||
return MediaAuthResolution.LISTING_MULTI_CAMERA, None
|
||||
if len(parts) != 2:
|
||||
return MediaAuthResolution.UNRESOLVED_MEDIA, None
|
||||
|
||||
filename = parts[1]
|
||||
full_path = os.path.join(EXPORT_DIR, filename)
|
||||
try:
|
||||
export = Export.get(Export.video_path == full_path)
|
||||
return MediaAuthResolution.CAMERA, export.camera
|
||||
except DoesNotExist:
|
||||
return MediaAuthResolution.UNRESOLVED_MEDIA, None
|
||||
except Exception as e:
|
||||
logger.warning("Export DB lookup failed for %s: %s", filename, e)
|
||||
return MediaAuthResolution.UNRESOLVED_MEDIA, None
|
||||
|
||||
|
||||
def check_camera_access(role: str, camera: str, frigate_config: FrigateConfig) -> bool:
|
||||
"""Return True iff `role` may access `camera`.
|
||||
|
||||
Mirrors the gating logic in `require_camera_access`: admin and any role
|
||||
without a non-empty allow-list bypass the check.
|
||||
"""
|
||||
if role == "admin":
|
||||
return True
|
||||
|
||||
roles_dict = frigate_config.auth.roles
|
||||
if not roles_dict.get(role):
|
||||
return True
|
||||
|
||||
all_camera_names = set(frigate_config.cameras.keys())
|
||||
allowed = User.get_allowed_cameras(role, roles_dict, all_camera_names)
|
||||
return camera in allowed
|
||||
|
||||
|
||||
def is_role_restricted(role: str, frigate_config: FrigateConfig) -> bool:
|
||||
"""True if `role` has a non-empty allow-list (i.e. not full-access)."""
|
||||
if role == "admin":
|
||||
return False
|
||||
return bool(frigate_config.auth.roles.get(role))
|
||||
|
||||
|
||||
def deny_response_for_media_uri(
|
||||
original_url: Optional[str], role: Optional[str], frigate_config: FrigateConfig
|
||||
) -> Optional[int]:
|
||||
"""Decide whether the current role should be blocked from `original_url`.
|
||||
|
||||
Returns an HTTP status code (403) when access should be denied, or `None`
|
||||
when the request is allowed.
|
||||
"""
|
||||
if not original_url:
|
||||
return None
|
||||
|
||||
path = extract_path(original_url)
|
||||
|
||||
# `extract_path` returns None for URIs containing `.` or `..` segments.
|
||||
# For media-root URIs that's a traversal attempt — deny outright. For
|
||||
# non-media URIs, pass through (nginx / the backend handle them).
|
||||
if path is None:
|
||||
raw = urlparse(original_url).path or original_url
|
||||
decoded = unquote(raw)
|
||||
first = decoded.lstrip("/").split("/", 1)[0] if decoded else ""
|
||||
if first in ("clips", "recordings", "exports"):
|
||||
return 403
|
||||
return None
|
||||
|
||||
resolution, camera = resolve_media_uri(path, frigate_config)
|
||||
if resolution == MediaAuthResolution.UNKNOWN:
|
||||
return None
|
||||
|
||||
if not role or role == "admin":
|
||||
return None
|
||||
|
||||
if not is_role_restricted(role, frigate_config):
|
||||
return None
|
||||
|
||||
if resolution == MediaAuthResolution.LISTING_NEUTRAL:
|
||||
return None
|
||||
|
||||
if resolution in (
|
||||
MediaAuthResolution.LISTING_MULTI_CAMERA,
|
||||
MediaAuthResolution.ADMIN_ONLY,
|
||||
MediaAuthResolution.UNRESOLVED_MEDIA,
|
||||
):
|
||||
return 403
|
||||
|
||||
if resolution == MediaAuthResolution.CAMERA:
|
||||
if camera and check_camera_access(role, camera, frigate_config):
|
||||
return None
|
||||
return 403
|
||||
|
||||
return 403
|
||||
+5
-12
@@ -428,18 +428,11 @@ class FrigateApp:
|
||||
self.camera_maintainer.start()
|
||||
|
||||
def start_audio_processor(self) -> None:
|
||||
audio_cameras = [
|
||||
c
|
||||
for c in self.config.cameras.values()
|
||||
if c.enabled and c.audio.enabled_in_config
|
||||
]
|
||||
|
||||
if audio_cameras:
|
||||
self.audio_process = AudioProcessor(
|
||||
self.config, audio_cameras, self.camera_metrics, self.stop_event
|
||||
)
|
||||
self.audio_process.start()
|
||||
self.processes["audio_detector"] = self.audio_process.pid or 0
|
||||
self.audio_process = AudioProcessor(
|
||||
self.config, self.camera_metrics, self.stop_event
|
||||
)
|
||||
self.audio_process.start()
|
||||
self.processes["audio_detector"] = self.audio_process.pid or 0
|
||||
|
||||
def start_timeline_processor(self) -> None:
|
||||
self.timeline_processor = TimelineProcessor(
|
||||
|
||||
@@ -76,7 +76,7 @@ class CameraConfig(FrigateBaseModel):
|
||||
# Options with global fallback
|
||||
audio: AudioConfig = Field(
|
||||
default_factory=AudioConfig,
|
||||
title="Audio events",
|
||||
title="Audio detection",
|
||||
description="Settings for audio-based event detection for this camera.",
|
||||
)
|
||||
audio_transcription: CameraAudioTranscriptionConfig = Field(
|
||||
|
||||
@@ -41,8 +41,7 @@ class GenAIConfig(FrigateBaseModel):
|
||||
title="Model",
|
||||
description="The model to use from the provider for generating descriptions or summaries.",
|
||||
)
|
||||
provider: GenAIProviderEnum | None = Field(
|
||||
default=None,
|
||||
provider: GenAIProviderEnum = Field(
|
||||
title="Provider",
|
||||
description="The GenAI provider to use (for example: ollama, gemini, openai).",
|
||||
)
|
||||
|
||||
@@ -121,7 +121,10 @@ class CameraConfigUpdateSubscriber:
|
||||
elif update_type == CameraConfigUpdateEnum.objects:
|
||||
config.objects = updated_config
|
||||
elif update_type == CameraConfigUpdateEnum.record:
|
||||
old_enabled_in_config = config.record.enabled_in_config
|
||||
config.record = updated_config
|
||||
if old_enabled_in_config != updated_config.enabled_in_config:
|
||||
config.recreate_ffmpeg_cmds()
|
||||
elif update_type == CameraConfigUpdateEnum.review:
|
||||
config.review = updated_config
|
||||
elif update_type == CameraConfigUpdateEnum.review_genai:
|
||||
|
||||
@@ -26,6 +26,11 @@ class EnrichmentsDeviceEnum(str, Enum):
|
||||
CPU = "CPU"
|
||||
|
||||
|
||||
class ModelSizeEnum(str, Enum):
|
||||
small = "small"
|
||||
large = "large"
|
||||
|
||||
|
||||
class TriggerType(str, Enum):
|
||||
THUMBNAIL = "thumbnail"
|
||||
DESCRIPTION = "description"
|
||||
@@ -53,13 +58,13 @@ class AudioTranscriptionConfig(FrigateBaseModel):
|
||||
title="Transcription language",
|
||||
description="Language code used for transcription/translation (for example 'en' for English). See https://whisper-api.com/docs/languages/ for supported language codes.",
|
||||
)
|
||||
device: Optional[EnrichmentsDeviceEnum] = Field(
|
||||
device: EnrichmentsDeviceEnum = Field(
|
||||
default=EnrichmentsDeviceEnum.CPU,
|
||||
title="Transcription device",
|
||||
description="Device key (CPU/GPU) to run the transcription model on. Only NVIDIA CUDA GPUs are currently supported for transcription.",
|
||||
)
|
||||
model_size: str = Field(
|
||||
default="small",
|
||||
model_size: ModelSizeEnum = Field(
|
||||
default=ModelSizeEnum.small,
|
||||
title="Model size",
|
||||
description="Model size to use for offline audio event transcription.",
|
||||
)
|
||||
@@ -189,8 +194,8 @@ class SemanticSearchConfig(FrigateBaseModel):
|
||||
return v
|
||||
return v
|
||||
|
||||
model_size: str = Field(
|
||||
default="small",
|
||||
model_size: ModelSizeEnum = Field(
|
||||
default=ModelSizeEnum.small,
|
||||
title="Model size",
|
||||
description="Select model size; 'small' runs on CPU and 'large' typically requires GPU.",
|
||||
)
|
||||
@@ -253,8 +258,8 @@ class FaceRecognitionConfig(FrigateBaseModel):
|
||||
title="Enable face recognition",
|
||||
description="Enable or disable face recognition for all cameras; can be overridden per-camera.",
|
||||
)
|
||||
model_size: str = Field(
|
||||
default="small",
|
||||
model_size: ModelSizeEnum = Field(
|
||||
default=ModelSizeEnum.small,
|
||||
title="Model size",
|
||||
description="Model size to use for face embeddings (small/large); larger may require GPU.",
|
||||
)
|
||||
@@ -335,8 +340,8 @@ class LicensePlateRecognitionConfig(FrigateBaseModel):
|
||||
title="Enable LPR",
|
||||
description="Enable or disable license plate recognition for all cameras; can be overridden per-camera.",
|
||||
)
|
||||
model_size: str = Field(
|
||||
default="small",
|
||||
model_size: ModelSizeEnum = Field(
|
||||
default=ModelSizeEnum.small,
|
||||
title="Model size",
|
||||
description="Model size used for text detection/recognition. Most users should use 'small'.",
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
@@ -80,17 +81,40 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
yaml = YAML()
|
||||
|
||||
DEFAULT_DETECTORS = {
|
||||
"ov": {
|
||||
"type": "openvino",
|
||||
"device": "CPU",
|
||||
}
|
||||
}
|
||||
DEFAULT_MODEL = {
|
||||
"width": 300,
|
||||
"height": 300,
|
||||
"input_tensor": "nhwc",
|
||||
"input_pixel_format": "bgr",
|
||||
"path": "/openvino-model/ssdlite_mobilenet_v2.xml",
|
||||
"labelmap_path": "/openvino-model/coco_91cl_bkgr.txt",
|
||||
}
|
||||
DEFAULT_DETECT_DIMENSIONS = {"width": 1280, "height": 720}
|
||||
|
||||
|
||||
def _render_default_yaml(data: dict) -> str:
|
||||
buf = io.StringIO()
|
||||
_yaml_writer = YAML()
|
||||
_yaml_writer.indent(mapping=2, sequence=4, offset=2)
|
||||
_yaml_writer.dump(data, buf)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
DEFAULT_CONFIG = f"""
|
||||
mqtt:
|
||||
enabled: False
|
||||
|
||||
{_render_default_yaml({"detectors": DEFAULT_DETECTORS, "model": DEFAULT_MODEL})}
|
||||
cameras: {{}} # No cameras defined, UI wizard should be used
|
||||
version: {CURRENT_CONFIG_VERSION}
|
||||
"""
|
||||
|
||||
DEFAULT_DETECTORS = {"cpu": {"type": "cpu"}}
|
||||
DEFAULT_DETECT_DIMENSIONS = {"width": 1280, "height": 720}
|
||||
|
||||
# stream info handler
|
||||
stream_info_retriever = StreamInfoRetriever()
|
||||
|
||||
@@ -453,7 +477,7 @@ class FrigateConfig(FrigateBaseModel):
|
||||
cameras: Dict[str, CameraConfig] = Field(title="Cameras", description="Cameras")
|
||||
audio: AudioConfig = Field(
|
||||
default_factory=AudioConfig,
|
||||
title="Audio events",
|
||||
title="Audio detection",
|
||||
description="Settings for audio-based event detection for all cameras; can be overridden per-camera.",
|
||||
)
|
||||
birdseye: BirdseyeConfig = Field(
|
||||
@@ -679,6 +703,9 @@ class FrigateConfig(FrigateBaseModel):
|
||||
model_config["path"] = "/cpu_model.tflite"
|
||||
elif detector_config.type == "edgetpu":
|
||||
model_config["path"] = "/edgetpu_model.tflite"
|
||||
elif detector_config.type == "openvino":
|
||||
for default_key, default_value in DEFAULT_MODEL.items():
|
||||
model_config.setdefault(default_key, default_value)
|
||||
|
||||
model = ModelConfig.model_validate(model_config)
|
||||
model.check_and_load_plus_model(self.plus_api, detector_config.type)
|
||||
@@ -835,7 +862,9 @@ class FrigateConfig(FrigateBaseModel):
|
||||
if mask_config:
|
||||
coords = mask_config.coordinates
|
||||
relative_coords = get_relative_coordinates(
|
||||
coords, camera_config.frame_shape
|
||||
coords,
|
||||
camera_config.frame_shape,
|
||||
camera_name=camera_config.name,
|
||||
)
|
||||
# Create a new ObjectMaskConfig with raw_coordinates set
|
||||
processed_global_masks[mask_id] = ObjectMaskConfig(
|
||||
|
||||
@@ -269,7 +269,9 @@ class ObjectDescriptionProcessor(PostProcessorApi):
|
||||
|
||||
if event.has_snapshot and camera_config.objects.genai.use_snapshot:
|
||||
snapshot_image = self._read_and_crop_snapshot(event)
|
||||
|
||||
if not snapshot_image:
|
||||
self.cleanup_event(event_id)
|
||||
return
|
||||
|
||||
num_thumbnails = len(self.tracked_events.get(event_id, []))
|
||||
|
||||
@@ -2,7 +2,7 @@ from typing import Annotated
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, StringConstraints
|
||||
|
||||
ObservationItem = Annotated[str, StringConstraints(min_length=20, max_length=160)]
|
||||
ObservationItem = Annotated[str, StringConstraints(min_length=20, max_length=200)]
|
||||
|
||||
|
||||
class ReviewMetadata(BaseModel):
|
||||
@@ -11,33 +11,22 @@ class ReviewMetadata(BaseModel):
|
||||
observations: list[ObservationItem] = Field(
|
||||
...,
|
||||
min_length=3,
|
||||
max_length=15,
|
||||
description=(
|
||||
"Enumerate the significant observations across all frames, in "
|
||||
"chronological order, BEFORE composing the scene narrative. "
|
||||
"Include the very start of the activity — for example, a vehicle "
|
||||
"entering the frame or pulling into the driveway — even if it "
|
||||
"lasts only a few frames and the rest of the clip is dominated "
|
||||
"by a longer activity. Include each arrival, departure, motion "
|
||||
"event, object handled, and notable change in position or state. "
|
||||
"Each item is a single concrete fact written as a complete "
|
||||
"sentence. Do not summarize, interpret, or assign meaning here — "
|
||||
"that belongs in the scene field."
|
||||
),
|
||||
)
|
||||
title: str = Field(
|
||||
max_length=80,
|
||||
description="Under 10 words. Name the apparent purpose or outcome of the activity together with the location involved. Do not narrate or list the sequence of actions step by step.",
|
||||
max_length=8,
|
||||
description="Enumerate the significant observations across all frames, in chronological order.",
|
||||
)
|
||||
scene: str = Field(
|
||||
min_length=150,
|
||||
max_length=600,
|
||||
description="A chronological narrative of what happens from start to finish, drawing directly from the items in observations.",
|
||||
)
|
||||
title: str = Field(
|
||||
max_length=80,
|
||||
description="Title for the activity.",
|
||||
)
|
||||
shortSummary: str = Field(
|
||||
min_length=70,
|
||||
max_length=120,
|
||||
description="A brief 2-sentence summary of the scene, suitable for notifications.",
|
||||
max_length=140,
|
||||
description="A brief summary for the activity.",
|
||||
)
|
||||
confidence: float = Field(
|
||||
ge=0.0,
|
||||
|
||||
@@ -229,9 +229,10 @@ class FaceRealTimeProcessor(RealTimeProcessorApi):
|
||||
logger.debug(f"No person box available for {id}")
|
||||
return
|
||||
|
||||
rgb = cv2.cvtColor(frame, cv2.COLOR_YUV2RGB_I420)
|
||||
# YuNet (cv2.FaceDetectorYN) is trained on BGR
|
||||
bgr = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420)
|
||||
left, top, right, bottom = person_box
|
||||
person = rgb[top:bottom, left:right]
|
||||
person = bgr[top:bottom, left:right]
|
||||
face_box = self.__detect_face(person, self.face_config.detection_threshold)
|
||||
|
||||
if not face_box:
|
||||
@@ -250,11 +251,6 @@ class FaceRealTimeProcessor(RealTimeProcessorApi):
|
||||
)
|
||||
return
|
||||
|
||||
try:
|
||||
face_frame = cv2.cvtColor(face_frame, cv2.COLOR_RGB2BGR)
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to convert face frame color for {id}: {e}")
|
||||
return
|
||||
else:
|
||||
# don't run for object without attributes
|
||||
if not obj_data.get("current_attributes"):
|
||||
|
||||
@@ -60,7 +60,11 @@ from frigate.data_processing.real_time.license_plate import (
|
||||
)
|
||||
from frigate.data_processing.types import DataProcessorMetrics, PostProcessDataEnum
|
||||
from frigate.db.sqlitevecq import SqliteVecQueueDatabase
|
||||
from frigate.events.types import EventTypeEnum, RegenerateDescriptionEnum
|
||||
from frigate.events.types import (
|
||||
EventStateEnum,
|
||||
EventTypeEnum,
|
||||
RegenerateDescriptionEnum,
|
||||
)
|
||||
from frigate.genai import GenAIClientManager
|
||||
from frigate.models import Event, Recordings, ReviewSegment, Trigger
|
||||
from frigate.types import TrackedObjectUpdateTypesEnum
|
||||
@@ -435,7 +439,7 @@ class EmbeddingMaintainer(threading.Thread):
|
||||
if update is None:
|
||||
return
|
||||
|
||||
source_type, _, camera, frame_name, data = update
|
||||
source_type, event_type, camera, frame_name, data = update
|
||||
|
||||
logger.debug(
|
||||
f"Received update - source_type: {source_type}, camera: {camera}, data label: {data.get('label') if data else 'None'}"
|
||||
@@ -485,6 +489,12 @@ class EmbeddingMaintainer(threading.Thread):
|
||||
|
||||
for processor in self.post_processors:
|
||||
if isinstance(processor, ObjectDescriptionProcessor):
|
||||
# skip end events — _process_finalized handles them via event_end_subscriber.
|
||||
# processing them here can re-create tracked_events entries after cleanup
|
||||
# when the event_subscriber queue is backlogged behind event_end_subscriber.
|
||||
if event_type == EventStateEnum.end:
|
||||
continue
|
||||
|
||||
processor.process_data(
|
||||
{
|
||||
"camera": camera,
|
||||
|
||||
+35
-13
@@ -84,7 +84,6 @@ class AudioProcessor(FrigateProcess):
|
||||
def __init__(
|
||||
self,
|
||||
config: FrigateConfig,
|
||||
cameras: list[CameraConfig],
|
||||
camera_metrics: DictProxy,
|
||||
stop_event: MpEvent,
|
||||
):
|
||||
@@ -93,12 +92,11 @@ class AudioProcessor(FrigateProcess):
|
||||
)
|
||||
|
||||
self.camera_metrics = camera_metrics
|
||||
self.cameras = cameras
|
||||
self.config = config
|
||||
|
||||
def run(self) -> None:
|
||||
self.pre_run_setup(self.config.logger)
|
||||
audio_threads: list[AudioEventMaintainer] = []
|
||||
audio_threads: dict[str, AudioEventMaintainer] = {}
|
||||
|
||||
threading.current_thread().name = "process:audio_manager"
|
||||
|
||||
@@ -112,32 +110,56 @@ class AudioProcessor(FrigateProcess):
|
||||
else:
|
||||
self.transcription_model_runner = None
|
||||
|
||||
if len(self.cameras) == 0:
|
||||
return
|
||||
config_subscriber = CameraConfigUpdateSubscriber(
|
||||
self.config,
|
||||
self.config.cameras,
|
||||
[
|
||||
CameraConfigUpdateEnum.add,
|
||||
CameraConfigUpdateEnum.audio,
|
||||
CameraConfigUpdateEnum.ffmpeg,
|
||||
],
|
||||
)
|
||||
|
||||
for camera in self.cameras:
|
||||
audio_thread = AudioEventMaintainer(
|
||||
def spawn_if_needed(camera: CameraConfig) -> None:
|
||||
name = camera.name
|
||||
if name is None or name in audio_threads:
|
||||
return
|
||||
if not camera.enabled or not camera.audio.enabled:
|
||||
return
|
||||
# ffmpeg update may not have arrived yet; wait for next poll
|
||||
if not any("audio" in i.roles for i in camera.ffmpeg.inputs):
|
||||
return
|
||||
thread = AudioEventMaintainer(
|
||||
camera,
|
||||
self.config,
|
||||
self.camera_metrics,
|
||||
self.transcription_model_runner,
|
||||
self.stop_event, # type: ignore[arg-type]
|
||||
)
|
||||
audio_threads.append(audio_thread)
|
||||
audio_thread.start()
|
||||
audio_threads[name] = thread
|
||||
thread.start()
|
||||
self.logger.info(f"Audio maintainer started for {name}")
|
||||
|
||||
for camera in self.config.cameras.values():
|
||||
spawn_if_needed(camera)
|
||||
|
||||
self.logger.info(f"Audio processor started (pid: {self.pid})")
|
||||
|
||||
while not self.stop_event.wait():
|
||||
pass
|
||||
# poll for newly added cameras or cameras flipped to audio.enabled at runtime
|
||||
while not self.stop_event.wait(timeout=1.0):
|
||||
config_subscriber.check_for_updates()
|
||||
for camera in self.config.cameras.values():
|
||||
spawn_if_needed(camera)
|
||||
|
||||
for thread in audio_threads:
|
||||
config_subscriber.stop()
|
||||
|
||||
for thread in audio_threads.values():
|
||||
thread.join(1)
|
||||
if thread.is_alive():
|
||||
self.logger.info(f"Waiting for thread {thread.name:s} to exit")
|
||||
thread.join(10)
|
||||
|
||||
for thread in audio_threads:
|
||||
for thread in audio_threads.values():
|
||||
if thread.is_alive():
|
||||
self.logger.warning(f"Thread {thread.name} is still alive")
|
||||
|
||||
|
||||
@@ -108,10 +108,11 @@ When forming your description:
|
||||
## Response Field Guidelines
|
||||
|
||||
Respond with a JSON object matching the provided schema. Field-specific guidance:
|
||||
- `observations`: Include the very start of the activity — for example, a vehicle entering the frame or pulling into the driveway — even if it lasts only a few frames and the rest of the clip is dominated by a longer activity. Include each arrival, departure, object handled, and notable change in position or state. Each item is a single concrete fact written as a complete sentence.
|
||||
- `scene`: Describe how the sequence begins, then the progression of events — all significant movements and actions in order. For example, if a vehicle arrives and then a person exits, describe both sequentially. For named subjects (those with a `←` separator in "Objects in Scene"), always use their name — do not replace them with generic terms. For unnamed objects (e.g., "person", "car"), refer to them naturally with articles (e.g., "a person", "the car"). Your description should align with and support the threat level you assign.
|
||||
- `title`: Characterize **what took place and where** — interpret the overall purpose or outcome, do not simply compress the scene description into fewer words. Include the relevant location (zone, area, or entry point). For named subjects, always use their name. For unnamed objects, refer to them naturally with articles. No editorial qualifiers like "routine" or "suspicious."
|
||||
- `title`: Name the primary activity across the observations, together with the location. An activity is what is being done with objects, tools, or surfaces; locomotion through the scene qualifies as the activity only when no other interaction is observed. For named subjects, always use their name. For unnamed objects, refer to them naturally with articles.
|
||||
- `shortSummary`: Briefly summarize the primary activity across the observations.
|
||||
- `potential_threat_level`: Must be consistent with your scene description and the activity patterns above.
|
||||
{get_concern_prompt()}
|
||||
|
||||
## Sequence Details
|
||||
|
||||
|
||||
+108
-39
@@ -18,6 +18,17 @@ from frigate.genai.utils import parse_tool_calls_from_message
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _parse_launch_arg(args: list[str], flag: str) -> str | None:
|
||||
"""Return the value following `flag` in a positional argv list, or None."""
|
||||
try:
|
||||
idx = args.index(flag)
|
||||
except ValueError:
|
||||
return None
|
||||
if idx + 1 >= len(args):
|
||||
return None
|
||||
return args[idx + 1]
|
||||
|
||||
|
||||
def _to_jpeg(img_bytes: bytes) -> bytes | None:
|
||||
"""Convert image bytes to JPEG. llama.cpp/STB does not support WebP."""
|
||||
try:
|
||||
@@ -67,28 +78,73 @@ class LlamaCppClient(GenAIClient):
|
||||
|
||||
if base_url is None:
|
||||
return None
|
||||
else:
|
||||
base_url = base_url.replace("/v1", "") # Strip /v1 if included in base_url
|
||||
|
||||
configured_model = self.genai_config.model
|
||||
info = self._get_model_info(base_url, configured_model)
|
||||
|
||||
# Query /v1/models to validate the configured model exists
|
||||
if info is None:
|
||||
return None
|
||||
|
||||
self._context_size = info["context_size"]
|
||||
self._supports_vision = info["supports_vision"]
|
||||
self._supports_audio = info["supports_audio"]
|
||||
self._supports_tools = info["supports_tools"]
|
||||
self._media_marker = info["media_marker"]
|
||||
|
||||
logger.info(
|
||||
"llama.cpp model '%s' initialized — context: %s, vision: %s, audio: %s, tools: %s",
|
||||
configured_model,
|
||||
self._context_size or "unknown",
|
||||
self._supports_vision,
|
||||
self._supports_audio,
|
||||
self._supports_tools,
|
||||
)
|
||||
|
||||
return base_url
|
||||
|
||||
def _get_model_info(
|
||||
self, base_url: str, configured_model: str
|
||||
) -> dict[str, Any] | None:
|
||||
"""Resolve model metadata from /v1/models with /props fallback.
|
||||
|
||||
Returns a dict of capability fields, or None if the server's model
|
||||
registry was reachable and reported the configured model as missing.
|
||||
A reachable-but-unparseable /v1/models is treated as soft-pass and
|
||||
falls through to /props, matching prior behavior.
|
||||
|
||||
After ggml-org/llama.cpp#22952, /v1/models exposes per-model
|
||||
`architecture.input_modalities` (text/image/audio) — the primary
|
||||
source. When proxied through llama-swap, the same entry carries
|
||||
`status.args` (server launch argv) and, for the loaded model,
|
||||
`meta.n_ctx`. /props remains the only source for `media_marker`,
|
||||
which the server randomizes per startup unless LLAMA_MEDIA_MARKER
|
||||
is set.
|
||||
"""
|
||||
info: dict[str, Any] = {
|
||||
"context_size": None,
|
||||
"supports_vision": False,
|
||||
"supports_audio": False,
|
||||
"supports_tools": False,
|
||||
"media_marker": "<__media__>",
|
||||
}
|
||||
|
||||
model_entry: dict[str, Any] | None = None
|
||||
try:
|
||||
response = requests.get(
|
||||
f"{base_url}/v1/models",
|
||||
timeout=10,
|
||||
)
|
||||
response = requests.get(f"{base_url}/v1/models", timeout=10)
|
||||
response.raise_for_status()
|
||||
models_data = response.json()
|
||||
|
||||
model_found = False
|
||||
for model in models_data.get("data", []):
|
||||
model_ids = {model.get("id")}
|
||||
for alias in model.get("aliases", []):
|
||||
model_ids.add(alias)
|
||||
if configured_model in model_ids:
|
||||
model_found = True
|
||||
model_entry = model
|
||||
break
|
||||
|
||||
if not model_found:
|
||||
if model_entry is None:
|
||||
available = []
|
||||
for m in models_data.get("data", []):
|
||||
available.append(m.get("id", "unknown"))
|
||||
@@ -107,10 +163,35 @@ class LlamaCppClient(GenAIClient):
|
||||
e,
|
||||
)
|
||||
|
||||
# Query /props for context size, modalities, and tool support.
|
||||
# The standard /props?model=<name> endpoint works with llama-server.
|
||||
# If it fails, try the llama-swap per-model passthrough endpoint which
|
||||
# returns props for a specific model without requiring it to be loaded.
|
||||
if model_entry is not None:
|
||||
architecture = model_entry.get("architecture") or {}
|
||||
input_modalities = architecture.get("input_modalities") or []
|
||||
|
||||
if isinstance(input_modalities, list):
|
||||
info["supports_vision"] = "image" in input_modalities
|
||||
info["supports_audio"] = "audio" in input_modalities
|
||||
|
||||
status = model_entry.get("status") or {}
|
||||
launch_args = status.get("args") if isinstance(status, dict) else None
|
||||
if not isinstance(launch_args, list):
|
||||
launch_args = []
|
||||
|
||||
meta = model_entry.get("meta") if isinstance(model_entry, dict) else None
|
||||
n_ctx = meta.get("n_ctx") if isinstance(meta, dict) else None
|
||||
|
||||
if not n_ctx:
|
||||
n_ctx = _parse_launch_arg(launch_args, "--ctx-size")
|
||||
|
||||
if n_ctx:
|
||||
try:
|
||||
info["context_size"] = int(n_ctx)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
|
||||
# Tool calling on llama-server requires --jinja.
|
||||
if "--jinja" in launch_args:
|
||||
info["supports_tools"] = True
|
||||
|
||||
try:
|
||||
try:
|
||||
response = requests.get(
|
||||
@@ -128,44 +209,32 @@ class LlamaCppClient(GenAIClient):
|
||||
response.raise_for_status()
|
||||
props = response.json()
|
||||
|
||||
# Context size from server runtime config
|
||||
default_settings = props.get("default_generation_settings", {})
|
||||
n_ctx = default_settings.get("n_ctx")
|
||||
if n_ctx:
|
||||
self._context_size = int(n_ctx)
|
||||
if info["context_size"] is None:
|
||||
default_settings = props.get("default_generation_settings", {})
|
||||
n_ctx = default_settings.get("n_ctx")
|
||||
if n_ctx:
|
||||
info["context_size"] = int(n_ctx)
|
||||
|
||||
# Modalities (vision, audio)
|
||||
modalities = props.get("modalities", {})
|
||||
self._supports_vision = modalities.get("vision", False)
|
||||
self._supports_audio = modalities.get("audio", False)
|
||||
if not (info["supports_vision"] or info["supports_audio"]):
|
||||
modalities = props.get("modalities", {})
|
||||
info["supports_vision"] = bool(modalities.get("vision", False))
|
||||
info["supports_audio"] = bool(modalities.get("audio", False))
|
||||
|
||||
# Tool support from chat template capabilities
|
||||
chat_caps = props.get("chat_template_caps", {})
|
||||
self._supports_tools = chat_caps.get("supports_tools", False)
|
||||
if not info["supports_tools"]:
|
||||
chat_caps = props.get("chat_template_caps", {})
|
||||
info["supports_tools"] = bool(chat_caps.get("supports_tools", False))
|
||||
|
||||
# Media marker for multimodal embeddings; the server randomizes this
|
||||
# per startup unless LLAMA_MEDIA_MARKER is set, so we must read it
|
||||
# from /props rather than hardcoding "<__media__>".
|
||||
media_marker = props.get("media_marker")
|
||||
if isinstance(media_marker, str) and media_marker:
|
||||
self._media_marker = media_marker
|
||||
|
||||
logger.info(
|
||||
"llama.cpp model '%s' initialized — context: %s, vision: %s, audio: %s, tools: %s",
|
||||
configured_model,
|
||||
self._context_size or "unknown",
|
||||
self._supports_vision,
|
||||
self._supports_audio,
|
||||
self._supports_tools,
|
||||
)
|
||||
info["media_marker"] = media_marker
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"Failed to query llama.cpp /props endpoint: %s. "
|
||||
"Using defaults for context size and capabilities.",
|
||||
"Image embeddings may fail if the server randomized its media marker.",
|
||||
e,
|
||||
)
|
||||
|
||||
return base_url
|
||||
return info
|
||||
|
||||
def _send(
|
||||
self,
|
||||
|
||||
+42
-2
@@ -1,5 +1,7 @@
|
||||
"""Ollama Provider for Frigate AI."""
|
||||
|
||||
import base64
|
||||
import binascii
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, AsyncGenerator, Optional
|
||||
@@ -16,6 +18,41 @@ from frigate.genai.utils import parse_tool_calls_from_message
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _normalize_multimodal_content(
|
||||
content: Any,
|
||||
) -> tuple[Optional[str], Optional[list[bytes]]]:
|
||||
"""Convert OpenAI-style multimodal content to Ollama's (text, images) shape.
|
||||
|
||||
The chat API constructs user messages with content as a list of
|
||||
``{"type": "text"}`` and ``{"type": "image_url"}`` parts when a tool
|
||||
returns a live frame. Ollama's SDK requires content to be a string and
|
||||
images to be passed in a separate field, so we extract each.
|
||||
"""
|
||||
if not isinstance(content, list):
|
||||
return content, None
|
||||
|
||||
text_parts: list[str] = []
|
||||
images: list[bytes] = []
|
||||
for part in content:
|
||||
if not isinstance(part, dict):
|
||||
continue
|
||||
part_type = part.get("type")
|
||||
if part_type == "text":
|
||||
text = part.get("text")
|
||||
if text:
|
||||
text_parts.append(str(text))
|
||||
elif part_type == "image_url":
|
||||
url = (part.get("image_url") or {}).get("url", "")
|
||||
if isinstance(url, str) and url.startswith("data:"):
|
||||
try:
|
||||
encoded = url.split(",", 1)[1]
|
||||
images.append(base64.b64decode(encoded, validate=True))
|
||||
except (ValueError, IndexError, binascii.Error) as e:
|
||||
logger.debug("Failed to decode multimodal image url: %s", e)
|
||||
|
||||
return ("\n".join(text_parts) if text_parts else None), (images or None)
|
||||
|
||||
|
||||
@register_genai_provider(GenAIProviderEnum.ollama)
|
||||
class OllamaClient(GenAIClient):
|
||||
"""Generative AI client for Frigate using Ollama."""
|
||||
@@ -207,10 +244,13 @@ class OllamaClient(GenAIClient):
|
||||
"""Build request_messages and params for chat (sync or stream)."""
|
||||
request_messages = []
|
||||
for msg in messages:
|
||||
msg_dict = {
|
||||
content, images = _normalize_multimodal_content(msg.get("content", ""))
|
||||
msg_dict: dict[str, Any] = {
|
||||
"role": msg.get("role"),
|
||||
"content": msg.get("content", ""),
|
||||
"content": content if content is not None else "",
|
||||
}
|
||||
if images:
|
||||
msg_dict["images"] = images
|
||||
if msg.get("tool_call_id"):
|
||||
msg_dict["tool_call_id"] = msg["tool_call_id"]
|
||||
if msg.get("name"):
|
||||
|
||||
@@ -62,8 +62,10 @@ def get_canvas_shape(width: int, height: int) -> tuple[int, int]:
|
||||
if round(a_w / a_h, 2) != round(width / height, 2):
|
||||
canvas_width = int(width // 4 * 4)
|
||||
canvas_height = int((canvas_width / a_w * a_h) // 4 * 4)
|
||||
logger.warning(
|
||||
f"The birdseye resolution is a non-standard aspect ratio, forcing birdseye resolution to {canvas_width} x {canvas_height}"
|
||||
logger.error(
|
||||
f"Birdseye resolution {width}x{height} is not a supported aspect ratio "
|
||||
f"and may cause visual distortion; falling back to {canvas_width}x{canvas_height}. "
|
||||
f"Set width and height to a supported aspect ratio (16:9, 20:10, 16:6, 32:9, 12:9, 22:15, 9:16, 9:12, 16:3, or 1:1)"
|
||||
)
|
||||
|
||||
return (canvas_width, canvas_height)
|
||||
@@ -796,15 +798,18 @@ class Birdseye:
|
||||
websocket_server: Any,
|
||||
) -> None:
|
||||
self.config = config
|
||||
canvas_width, canvas_height = get_canvas_shape(
|
||||
config.birdseye.width, config.birdseye.height
|
||||
)
|
||||
self.input: queue.Queue[bytes] = queue.Queue(maxsize=10)
|
||||
self.converter = FFMpegConverter(
|
||||
config.ffmpeg,
|
||||
self.input,
|
||||
stop_event,
|
||||
config.birdseye.width,
|
||||
config.birdseye.height,
|
||||
config.birdseye.width,
|
||||
config.birdseye.height,
|
||||
canvas_width,
|
||||
canvas_height,
|
||||
canvas_width,
|
||||
canvas_height,
|
||||
config.birdseye.quality,
|
||||
config.birdseye.restream,
|
||||
)
|
||||
|
||||
@@ -351,9 +351,11 @@ class RecordingCleanup(threading.Thread):
|
||||
)
|
||||
.where(
|
||||
ReviewSegment.camera == camera,
|
||||
# need to ensure segments for all reviews starting
|
||||
# before the expire date are included
|
||||
ReviewSegment.start_time < motion_expire_date,
|
||||
# candidate recordings can extend up to continuous_expire_date
|
||||
# (the no-motion no-audio branch of the recordings query),
|
||||
# so reviews must cover that full range to avoid deleting
|
||||
# segments that overlap recent alerts/detections.
|
||||
ReviewSegment.start_time < continuous_expire_date,
|
||||
)
|
||||
.order_by(ReviewSegment.start_time)
|
||||
.namedtuples()
|
||||
|
||||
@@ -380,9 +380,14 @@ class RecordingExporter(threading.Thread):
|
||||
if label and label not in labels:
|
||||
labels.append(label)
|
||||
|
||||
title = str(review.severity).capitalize()
|
||||
if labels:
|
||||
title = f"{title}: {', '.join(labels)}"
|
||||
metadata = data.get("metadata") or {}
|
||||
title = metadata.get("title")
|
||||
|
||||
if not title:
|
||||
title = str(review.severity).capitalize()
|
||||
|
||||
if labels:
|
||||
title = f"{title}: {', '.join(labels)}"
|
||||
|
||||
chapter_blocks.append(
|
||||
"[CHAPTER]\n"
|
||||
|
||||
@@ -64,9 +64,9 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
def test_config_class(self):
|
||||
frigate_config = FrigateConfig(**self.minimal)
|
||||
assert "cpu" in frigate_config.detectors.keys()
|
||||
assert frigate_config.detectors["cpu"].type == DetectorTypeEnum.cpu
|
||||
assert frigate_config.detectors["cpu"].model.width == 320
|
||||
assert "ov" in frigate_config.detectors.keys()
|
||||
assert frigate_config.detectors["ov"].type == DetectorTypeEnum.openvino
|
||||
assert frigate_config.detectors["ov"].model.width == 300
|
||||
|
||||
@patch("frigate.detectors.detector_config.load_labels")
|
||||
def test_detector_custom_model_path(self, mock_labels):
|
||||
@@ -1005,6 +1005,7 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
config = {
|
||||
"mqtt": {"host": "mqtt"},
|
||||
"detectors": {"cpu": {"type": "cpu"}},
|
||||
"model": {"path": "plus://test"},
|
||||
"cameras": {
|
||||
"back": {
|
||||
|
||||
@@ -0,0 +1,381 @@
|
||||
"""Unit tests for `frigate.api.media_auth`.
|
||||
|
||||
Covers URI classification, the role-vs-camera decision matrix, and the export
|
||||
DB-lookup path. These are pure functions/DB lookups — no HTTP stack involved.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from peewee_migrate import Router
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from playhouse.sqliteq import SqliteQueueDatabase
|
||||
|
||||
from frigate.api.media_auth import (
|
||||
MediaAuthResolution,
|
||||
deny_response_for_media_uri,
|
||||
extract_path,
|
||||
resolve_media_uri,
|
||||
)
|
||||
from frigate.config import FrigateConfig
|
||||
from frigate.models import Event, Export, Recordings, ReviewSegment
|
||||
from frigate.test.const import TEST_DB, TEST_DB_CLEANUPS
|
||||
|
||||
_CONFIG = {
|
||||
"mqtt": {"host": "mqtt"},
|
||||
"auth": {"roles": {"limited_user": ["front_door"]}},
|
||||
"cameras": {
|
||||
"front_door": {
|
||||
"ffmpeg": {
|
||||
"inputs": [{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}]
|
||||
},
|
||||
"detect": {"height": 1080, "width": 1920, "fps": 5},
|
||||
},
|
||||
"back_door": {
|
||||
"ffmpeg": {
|
||||
"inputs": [{"path": "rtsp://10.0.0.2:554/video", "roles": ["detect"]}]
|
||||
},
|
||||
"detect": {"height": 1080, "width": 1920, "fps": 5},
|
||||
},
|
||||
# Camera name with a hyphen — exercises longest-prefix match.
|
||||
"back-yard": {
|
||||
"ffmpeg": {
|
||||
"inputs": [{"path": "rtsp://10.0.0.3:554/video", "roles": ["detect"]}]
|
||||
},
|
||||
"detect": {"height": 1080, "width": 1920, "fps": 5},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class TestExtractPath(unittest.TestCase):
|
||||
def test_full_url(self):
|
||||
self.assertEqual(
|
||||
extract_path("http://host:8971/clips/front_door-1.jpg"),
|
||||
"/clips/front_door-1.jpg",
|
||||
)
|
||||
|
||||
def test_strips_query_string(self):
|
||||
self.assertEqual(
|
||||
extract_path("http://h/recordings/2026-05-11/14/front_door/00.00.mp4?t=1"),
|
||||
"/recordings/2026-05-11/14/front_door/00.00.mp4",
|
||||
)
|
||||
|
||||
def test_path_only(self):
|
||||
self.assertEqual(extract_path("/exports/x.mp4"), "/exports/x.mp4")
|
||||
|
||||
def test_percent_decoded(self):
|
||||
self.assertEqual(
|
||||
extract_path("http://h/clips/front%20door-1.jpg"),
|
||||
"/clips/front door-1.jpg",
|
||||
)
|
||||
|
||||
def test_empty(self):
|
||||
self.assertIsNone(extract_path(None))
|
||||
self.assertIsNone(extract_path(""))
|
||||
|
||||
|
||||
class TestResolveMediaUri(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.config = FrigateConfig(**_CONFIG)
|
||||
|
||||
def _assert(self, uri, resolution, camera=None):
|
||||
got_resolution, got_camera = resolve_media_uri(uri, self.config)
|
||||
self.assertEqual(got_resolution, resolution, uri)
|
||||
self.assertEqual(got_camera, camera, uri)
|
||||
|
||||
def test_unknown_paths(self):
|
||||
self._assert("/api/events", MediaAuthResolution.UNKNOWN)
|
||||
self._assert("/", MediaAuthResolution.UNKNOWN)
|
||||
self._assert("", MediaAuthResolution.UNKNOWN)
|
||||
|
||||
def test_recordings(self):
|
||||
self._assert("/recordings/", MediaAuthResolution.LISTING_NEUTRAL)
|
||||
self._assert("/recordings/2026-05-11/", MediaAuthResolution.LISTING_NEUTRAL)
|
||||
self._assert(
|
||||
"/recordings/2026-05-11/14/", MediaAuthResolution.LISTING_MULTI_CAMERA
|
||||
)
|
||||
self._assert(
|
||||
"/recordings/2026-05-11/14/front_door/",
|
||||
MediaAuthResolution.CAMERA,
|
||||
camera="front_door",
|
||||
)
|
||||
self._assert(
|
||||
"/recordings/2026-05-11/14/back_door/00.00.mp4",
|
||||
MediaAuthResolution.CAMERA,
|
||||
camera="back_door",
|
||||
)
|
||||
|
||||
def test_clip_flat_filename_resolves_camera(self):
|
||||
self._assert(
|
||||
"/clips/front_door-1234.jpg",
|
||||
MediaAuthResolution.CAMERA,
|
||||
camera="front_door",
|
||||
)
|
||||
self._assert(
|
||||
"/clips/back_door-1234-clean.webp",
|
||||
MediaAuthResolution.CAMERA,
|
||||
camera="back_door",
|
||||
)
|
||||
|
||||
def test_clip_filename_with_hyphenated_camera_name(self):
|
||||
# Camera name "back-yard" itself contains a hyphen; longest-prefix
|
||||
# match must pick `back-yard`, not the bogus `back` prefix.
|
||||
self._assert(
|
||||
"/clips/back-yard-1234.jpg",
|
||||
MediaAuthResolution.CAMERA,
|
||||
camera="back-yard",
|
||||
)
|
||||
|
||||
def test_clip_filename_no_matching_camera(self):
|
||||
# Looks like a media path but couldn't classify — fail closed for
|
||||
# restricted users (UNRESOLVED_MEDIA), not pass-through.
|
||||
self._assert(
|
||||
"/clips/nonexistent-1234.jpg", MediaAuthResolution.UNRESOLVED_MEDIA
|
||||
)
|
||||
|
||||
def test_clip_thumbs(self):
|
||||
self._assert("/clips/thumbs/", MediaAuthResolution.LISTING_MULTI_CAMERA)
|
||||
self._assert(
|
||||
"/clips/thumbs/front_door/",
|
||||
MediaAuthResolution.CAMERA,
|
||||
camera="front_door",
|
||||
)
|
||||
self._assert(
|
||||
"/clips/thumbs/back_door/abc.webp",
|
||||
MediaAuthResolution.CAMERA,
|
||||
camera="back_door",
|
||||
)
|
||||
|
||||
def test_clip_previews(self):
|
||||
self._assert("/clips/previews/", MediaAuthResolution.LISTING_MULTI_CAMERA)
|
||||
self._assert(
|
||||
"/clips/previews/front_door/",
|
||||
MediaAuthResolution.CAMERA,
|
||||
camera="front_door",
|
||||
)
|
||||
self._assert(
|
||||
"/clips/previews/back_door/segment.mp4",
|
||||
MediaAuthResolution.CAMERA,
|
||||
camera="back_door",
|
||||
)
|
||||
|
||||
def test_clip_review_thumbs(self):
|
||||
# Format: /clips/review/thumb-{camera}-{review_id}.webp (frigate/review/maintainer.py).
|
||||
self._assert(
|
||||
"/clips/review/thumb-front_door-abc123.webp",
|
||||
MediaAuthResolution.CAMERA,
|
||||
camera="front_door",
|
||||
)
|
||||
# Hyphenated camera name — longest-prefix match.
|
||||
self._assert(
|
||||
"/clips/review/thumb-back-yard-abc123.webp",
|
||||
MediaAuthResolution.CAMERA,
|
||||
camera="back-yard",
|
||||
)
|
||||
# Unknown camera prefix → unresolved, not allowed for restricted users.
|
||||
self._assert(
|
||||
"/clips/review/thumb-unknown-cam-abc123.webp",
|
||||
MediaAuthResolution.UNRESOLVED_MEDIA,
|
||||
)
|
||||
|
||||
def test_clip_admin_only_subtrees(self):
|
||||
self._assert("/clips/faces/train/foo.webp", MediaAuthResolution.ADMIN_ONLY)
|
||||
self._assert("/clips/faces/", MediaAuthResolution.ADMIN_ONLY)
|
||||
self._assert("/clips/genai-requests/x/0.webp", MediaAuthResolution.ADMIN_ONLY)
|
||||
self._assert(
|
||||
"/clips/preview_restart_cache/x.mp4", MediaAuthResolution.ADMIN_ONLY
|
||||
)
|
||||
self._assert("/clips/some_model/train/x.jpg", MediaAuthResolution.ADMIN_ONLY)
|
||||
self._assert("/clips/some_model/dataset/x.jpg", MediaAuthResolution.ADMIN_ONLY)
|
||||
|
||||
def test_clip_unknown_subtree_is_unresolved(self):
|
||||
# Unknown /clips/{x}/{y}/... subtree falls through as unresolved (not
|
||||
# admin-only) so restricted users get 403 without admins being denied
|
||||
# access to legitimate but unrecognized resources.
|
||||
self._assert("/clips/random_dir/foo.jpg", MediaAuthResolution.UNRESOLVED_MEDIA)
|
||||
|
||||
def test_clip_top_level_listing(self):
|
||||
self._assert("/clips/", MediaAuthResolution.LISTING_MULTI_CAMERA)
|
||||
|
||||
def test_exports_listing(self):
|
||||
self._assert("/exports/", MediaAuthResolution.LISTING_MULTI_CAMERA)
|
||||
|
||||
|
||||
class TestExportResolution(unittest.TestCase):
|
||||
"""Export resolution requires a DB lookup."""
|
||||
|
||||
def setUp(self):
|
||||
migrate_db = SqliteExtDatabase("test.db")
|
||||
del logging.getLogger("peewee_migrate").handlers[:]
|
||||
Router(migrate_db).run()
|
||||
migrate_db.close()
|
||||
self.db = SqliteQueueDatabase(TEST_DB)
|
||||
self.db.bind([Event, ReviewSegment, Recordings, Export])
|
||||
self.config = FrigateConfig(**_CONFIG)
|
||||
|
||||
def tearDown(self):
|
||||
if not self.db.is_closed():
|
||||
self.db.close()
|
||||
for f in TEST_DB_CLEANUPS:
|
||||
try:
|
||||
os.remove(f)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def _insert_export(self, export_id, camera, filename):
|
||||
Export.insert(
|
||||
id=export_id,
|
||||
camera=camera,
|
||||
name=f"export-{export_id}",
|
||||
date=datetime.datetime.now(),
|
||||
video_path=f"/media/frigate/exports/{filename}",
|
||||
thumb_path=f"/media/frigate/exports/{filename}.jpg",
|
||||
in_progress=False,
|
||||
).execute()
|
||||
|
||||
def test_export_resolves_camera(self):
|
||||
self._insert_export(
|
||||
"exp1", "back_door", "back_door_20260511_140000-20260511_150000_abc123.mp4"
|
||||
)
|
||||
resolution, camera = resolve_media_uri(
|
||||
"/exports/back_door_20260511_140000-20260511_150000_abc123.mp4",
|
||||
self.config,
|
||||
)
|
||||
self.assertEqual(resolution, MediaAuthResolution.CAMERA)
|
||||
self.assertEqual(camera, "back_door")
|
||||
|
||||
def test_unknown_export_is_unresolved(self):
|
||||
# No matching row → UNRESOLVED_MEDIA (fail closed for restricted users),
|
||||
# not UNKNOWN (which would pass-through).
|
||||
resolution, camera = resolve_media_uri(
|
||||
"/exports/does_not_exist.mp4", self.config
|
||||
)
|
||||
self.assertEqual(resolution, MediaAuthResolution.UNRESOLVED_MEDIA)
|
||||
self.assertIsNone(camera)
|
||||
|
||||
def test_export_anchored_match_not_endswith(self):
|
||||
# Anchored exact-path equality must NOT match by filename suffix.
|
||||
# A request like /exports/clip.mp4 must not authorize against a row at
|
||||
# /media/frigate/exports/back_door_clip.mp4 just because the suffix matches.
|
||||
self._insert_export("exp_bd", "back_door", "back_door_clip.mp4")
|
||||
self._insert_export("exp_fd", "front_door", "front_door_clip.mp4")
|
||||
resolution, _ = resolve_media_uri("/exports/clip.mp4", self.config)
|
||||
self.assertEqual(resolution, MediaAuthResolution.UNRESOLVED_MEDIA)
|
||||
|
||||
|
||||
class TestDenyResponseForMediaUri(unittest.TestCase):
|
||||
"""End-to-end decision check used by /auth."""
|
||||
|
||||
def setUp(self):
|
||||
self.config = FrigateConfig(**_CONFIG)
|
||||
|
||||
def _deny(self, url, role):
|
||||
return deny_response_for_media_uri(url, role, self.config)
|
||||
|
||||
def test_admin_always_allowed(self):
|
||||
self.assertIsNone(self._deny("/clips/back_door-1.jpg", "admin"))
|
||||
self.assertIsNone(self._deny("/clips/", "admin"))
|
||||
self.assertIsNone(self._deny("/clips/faces/x.webp", "admin"))
|
||||
self.assertIsNone(
|
||||
self._deny("/recordings/2026-05-11/14/back_door/00.00.mp4", "admin")
|
||||
)
|
||||
|
||||
def test_unrestricted_role_allowed(self):
|
||||
# "viewer" role has no entry in roles_dict → full access (matches the
|
||||
# behavior of require_camera_access).
|
||||
self.assertIsNone(self._deny("/clips/back_door-1.jpg", "viewer"))
|
||||
self.assertIsNone(self._deny("/clips/", "viewer"))
|
||||
|
||||
def test_restricted_role_allowed_camera(self):
|
||||
self.assertIsNone(self._deny("/clips/front_door-1.jpg", "limited_user"))
|
||||
self.assertIsNone(
|
||||
self._deny("/recordings/2026-05-11/14/front_door/00.00.mp4", "limited_user")
|
||||
)
|
||||
self.assertIsNone(
|
||||
self._deny("/clips/thumbs/front_door/abc.webp", "limited_user")
|
||||
)
|
||||
|
||||
def test_restricted_role_blocked_other_camera(self):
|
||||
self.assertEqual(self._deny("/clips/back_door-1.jpg", "limited_user"), 403)
|
||||
self.assertEqual(
|
||||
self._deny("/recordings/2026-05-11/14/back_door/00.00.mp4", "limited_user"),
|
||||
403,
|
||||
)
|
||||
self.assertEqual(
|
||||
self._deny("/clips/thumbs/back_door/abc.webp", "limited_user"), 403
|
||||
)
|
||||
|
||||
def test_restricted_role_blocked_admin_only(self):
|
||||
self.assertEqual(self._deny("/clips/faces/train/foo.webp", "limited_user"), 403)
|
||||
|
||||
def test_restricted_role_blocked_multi_camera_listing(self):
|
||||
self.assertEqual(self._deny("/clips/", "limited_user"), 403)
|
||||
self.assertEqual(self._deny("/exports/", "limited_user"), 403)
|
||||
self.assertEqual(self._deny("/recordings/2026-05-11/14/", "limited_user"), 403)
|
||||
|
||||
def test_restricted_role_allowed_neutral_listing(self):
|
||||
self.assertIsNone(self._deny("/recordings/", "limited_user"))
|
||||
self.assertIsNone(self._deny("/recordings/2026-05-11/", "limited_user"))
|
||||
|
||||
def test_non_media_uri_passes_through(self):
|
||||
self.assertIsNone(self._deny("/api/events", "limited_user"))
|
||||
self.assertIsNone(self._deny("http://h/login", "limited_user"))
|
||||
|
||||
def test_missing_header(self):
|
||||
self.assertIsNone(self._deny(None, "limited_user"))
|
||||
self.assertIsNone(self._deny("", "limited_user"))
|
||||
|
||||
def test_traversal_in_media_uri_denied_for_all_roles(self):
|
||||
# Bypass attempt: parts[3] looks like an allowed camera, but the
|
||||
# normalized path nginx would serve points at a forbidden camera.
|
||||
# Both restricted and admin should be denied — the URI is malformed
|
||||
# and we refuse to make an auth decision against it.
|
||||
traversal_uris = [
|
||||
"/recordings/2026-05-11/14/front_door/../back_door/00.00.mp4",
|
||||
"/clips/front_door-1.jpg/../back_door-1.jpg",
|
||||
"/exports/../recordings/2026-05-11/14/back_door/00.00.mp4",
|
||||
"/clips/./back_door-1.jpg",
|
||||
]
|
||||
for uri in traversal_uris:
|
||||
self.assertEqual(self._deny(uri, "limited_user"), 403, uri)
|
||||
self.assertEqual(self._deny(uri, "admin"), 403, uri)
|
||||
self.assertEqual(self._deny(uri, "viewer"), 403, uri)
|
||||
|
||||
def test_traversal_outside_media_passes_through(self):
|
||||
# `..` in non-media URIs is not our problem; the backend handles it.
|
||||
self.assertIsNone(self._deny("/api/foo/../bar", "limited_user"))
|
||||
|
||||
def test_percent_encoded_traversal_denied(self):
|
||||
# nginx may decode percent-encoded `%2E%2E` to `..` before serving;
|
||||
# we must apply the same denial after percent-decoding.
|
||||
self.assertEqual(
|
||||
self._deny(
|
||||
"/recordings/2026-05-11/14/front_door/%2E%2E/back_door/00.mp4",
|
||||
"limited_user",
|
||||
),
|
||||
403,
|
||||
)
|
||||
|
||||
def test_unresolved_media_fails_closed_for_restricted(self):
|
||||
# Restricted user requesting a media URI we can't classify (no DB row,
|
||||
# unknown clip prefix, unknown clip subtree) must be denied.
|
||||
self.assertEqual(self._deny("/clips/nonexistent-1.jpg", "limited_user"), 403)
|
||||
self.assertEqual(self._deny("/clips/random_dir/foo.jpg", "limited_user"), 403)
|
||||
self.assertEqual(
|
||||
self._deny("/clips/review/thumb-unknown_cam-1.webp", "limited_user"),
|
||||
403,
|
||||
)
|
||||
|
||||
def test_unresolved_media_allowed_for_admin(self):
|
||||
# Admin and full-access roles are *not* denied on UNRESOLVED_MEDIA —
|
||||
# nginx returns 404 if the file doesn't exist on disk anyway, and we
|
||||
# don't want a stale DB to lock out admins.
|
||||
self.assertIsNone(self._deny("/clips/nonexistent-1.jpg", "admin"))
|
||||
self.assertIsNone(self._deny("/clips/nonexistent-1.jpg", "viewer"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -773,7 +773,9 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
logger.debug(f"Camera {camera} disabled, skipping update")
|
||||
continue
|
||||
|
||||
camera_state = self.camera_states[camera]
|
||||
camera_state = self.camera_states.get(camera)
|
||||
if camera_state is None:
|
||||
continue
|
||||
|
||||
camera_state.update(
|
||||
frame_name, frame_time, current_tracked_objects, motion_boxes, regions
|
||||
|
||||
@@ -330,7 +330,12 @@ class TrackedObject:
|
||||
if self.obj_data["position_changes"] != obj_data["position_changes"]:
|
||||
significant_change = True
|
||||
|
||||
if self.obj_data["attributes"] != obj_data["attributes"]:
|
||||
# disappearance of a per-frame attribute can be caused by detection
|
||||
# skipping the object on a frame (stationary objects on non-interval
|
||||
# frames), so only flag when a new attribute label appears
|
||||
prev_labels = {a["label"] for a in self.obj_data["attributes"]}
|
||||
curr_labels = {a["label"] for a in obj_data["attributes"]}
|
||||
if curr_labels - prev_labels:
|
||||
significant_change = True
|
||||
|
||||
# if the state changed between stationary and active
|
||||
|
||||
@@ -492,7 +492,7 @@ def migrate_018_0(config: dict[str, dict[str, Any]]) -> dict[str, dict[str, Any]
|
||||
genai = new_config.get("genai")
|
||||
|
||||
if genai and genai.get("provider"):
|
||||
genai["roles"] = ["embeddings", "vision", "tools"]
|
||||
genai["roles"] = ["embeddings", "descriptions", "chat"]
|
||||
new_config["genai"] = {"default": genai}
|
||||
|
||||
# Remove deprecated sync_recordings from global record config
|
||||
@@ -608,11 +608,14 @@ def migrate_018_0(config: dict[str, dict[str, Any]]) -> dict[str, dict[str, Any]
|
||||
|
||||
|
||||
def get_relative_coordinates(
|
||||
mask: Optional[Union[str, list]], frame_shape: tuple[int, int]
|
||||
mask: Optional[Union[str, list]],
|
||||
frame_shape: tuple[int, int],
|
||||
camera_name: str = "",
|
||||
) -> Union[str, list]:
|
||||
# masks and zones are saved as relative coordinates
|
||||
# we know if any points are > 1 then it is using the
|
||||
# old native resolution coordinates
|
||||
where = f" for camera {camera_name}" if camera_name else ""
|
||||
if mask:
|
||||
if isinstance(mask, list) and any(x > "1.0" for x in mask[0].split(",")):
|
||||
relative_masks = []
|
||||
@@ -627,7 +630,7 @@ def get_relative_coordinates(
|
||||
|
||||
if x > frame_shape[1] or y > frame_shape[0]:
|
||||
logger.error(
|
||||
f"Not applying mask due to invalid coordinates. {x},{y} is outside of the detection resolution {frame_shape[1]}x{frame_shape[0]}. Use the editor in the UI to correct the mask."
|
||||
f"Not applying mask due to invalid coordinates{where}. {x},{y} is outside of the detection resolution {frame_shape[1]}x{frame_shape[0]}. Use the editor in the UI to correct the mask."
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -650,7 +653,7 @@ def get_relative_coordinates(
|
||||
|
||||
if x > frame_shape[1] or y > frame_shape[0]:
|
||||
logger.error(
|
||||
f"Not applying mask due to invalid coordinates. {x},{y} is outside of the detection resolution {frame_shape[1]}x{frame_shape[0]}. Use the editor in the UI to correct the mask."
|
||||
f"Not applying mask due to invalid coordinates{where}. {x},{y} is outside of the detection resolution {frame_shape[1]}x{frame_shape[0]}. Use the editor in the UI to correct the mask."
|
||||
)
|
||||
return []
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ def remove_empty_directories(root: Path, paths: Iterable[Path]) -> None:
|
||||
|
||||
paths = parents
|
||||
|
||||
logger.debug("Removed {count} empty directories")
|
||||
logger.debug(f"Removed {count} empty directories")
|
||||
|
||||
|
||||
def sync_recordings(
|
||||
|
||||
+19
-21
@@ -438,34 +438,32 @@ def process_frames(
|
||||
else:
|
||||
object_tracker.update_frame_times(frame_name, frame_time)
|
||||
|
||||
# group the attribute detections based on what label they apply to
|
||||
attribute_detections: dict[str, list[TrackedObjectAttribute]] = {}
|
||||
for label, attribute_labels in attributes_map.items():
|
||||
attribute_detections[label] = [
|
||||
TrackedObjectAttribute(d)
|
||||
for d in consolidated_detections
|
||||
if d[0] in attribute_labels
|
||||
]
|
||||
|
||||
# build detections
|
||||
detections = {}
|
||||
for obj in object_tracker.tracked_objects.values():
|
||||
detections[obj["id"]] = {**obj, "attributes": []}
|
||||
|
||||
# find the best object for each attribute to be assigned to
|
||||
# assign each detected attribute to the best matching object.
|
||||
# iterate consolidated_detections once so attributes that appear under
|
||||
# multiple parent labels in attributes_map (e.g. license_plate is in
|
||||
# both "car" and "motorcycle") are not appended more than once
|
||||
all_objects: list[dict[str, Any]] = object_tracker.tracked_objects.values()
|
||||
for attributes in attribute_detections.values():
|
||||
for attribute in attributes:
|
||||
filtered_objects = filter(
|
||||
lambda o: attribute.label in attributes_map.get(o["label"], []),
|
||||
all_objects,
|
||||
)
|
||||
selected_object_id = attribute.find_best_object(filtered_objects)
|
||||
detected_attributes = [
|
||||
TrackedObjectAttribute(d)
|
||||
for d in consolidated_detections
|
||||
if d[0] in all_attributes
|
||||
]
|
||||
for attribute in detected_attributes:
|
||||
filtered_objects = filter(
|
||||
lambda o: attribute.label in attributes_map.get(o["label"], []),
|
||||
all_objects,
|
||||
)
|
||||
selected_object_id = attribute.find_best_object(filtered_objects)
|
||||
|
||||
if selected_object_id is not None:
|
||||
detections[selected_object_id]["attributes"].append(
|
||||
attribute.get_tracking_data()
|
||||
)
|
||||
if selected_object_id is not None:
|
||||
detections[selected_object_id]["attributes"].append(
|
||||
attribute.get_tracking_data()
|
||||
)
|
||||
|
||||
# debug object tracking
|
||||
if False:
|
||||
|
||||
@@ -174,6 +174,7 @@ class CameraWatchdog(threading.Thread):
|
||||
)
|
||||
self.requestor = InterProcessRequestor()
|
||||
self.was_enabled = self.config.enabled
|
||||
self.was_record_enabled_in_config = self.config.record.enabled_in_config
|
||||
|
||||
self.segment_subscriber = RecordingsDataSubscriber(RecordingsDataTypeEnum.all)
|
||||
self.latest_valid_segment_time: float = 0
|
||||
@@ -323,6 +324,22 @@ class CameraWatchdog(threading.Thread):
|
||||
self.was_enabled = enabled
|
||||
continue
|
||||
|
||||
record_enabled_in_config = self.config.record.enabled_in_config
|
||||
if record_enabled_in_config != self.was_record_enabled_in_config:
|
||||
if record_enabled_in_config and enabled:
|
||||
self.logger.debug(
|
||||
f"Record enabled in config for {self.config.name}, restarting ffmpeg"
|
||||
)
|
||||
self.stop_all_ffmpeg()
|
||||
self.start_all_ffmpeg()
|
||||
self.latest_valid_segment_time = 0
|
||||
self.latest_invalid_segment_time = 0
|
||||
self.latest_cache_segment_time = 0
|
||||
self.record_enable_time = datetime.now().astimezone(timezone.utc)
|
||||
last_restart_time = datetime.now().timestamp()
|
||||
self.was_record_enabled_in_config = record_enabled_in_config
|
||||
continue
|
||||
|
||||
if not enabled:
|
||||
continue
|
||||
|
||||
|
||||
@@ -150,29 +150,51 @@ def extract_translations_from_schema(
|
||||
# Handle anyOf cases
|
||||
elif "anyOf" in field_schema:
|
||||
for item in field_schema["anyOf"]:
|
||||
nested = None
|
||||
if item.get("type") == "null":
|
||||
continue
|
||||
if "properties" in item:
|
||||
nested = extract_translations_from_schema(item, defs=defs)
|
||||
elif "$ref" in item:
|
||||
ref_path = item["$ref"]
|
||||
if ref_path.startswith("#/$defs/"):
|
||||
ref_name = ref_path.split("/")[-1]
|
||||
if ref_name in defs:
|
||||
nested = extract_translations_from_schema(
|
||||
defs[ref_name], defs=defs
|
||||
)
|
||||
elif (
|
||||
"additionalProperties" in item
|
||||
and isinstance(item["additionalProperties"], dict)
|
||||
and "$ref" in item["additionalProperties"]
|
||||
):
|
||||
ref_path = item["additionalProperties"]["$ref"]
|
||||
if ref_path.startswith("#/$defs/"):
|
||||
ref_name = ref_path.split("/")[-1]
|
||||
if ref_name in defs:
|
||||
nested = extract_translations_from_schema(
|
||||
defs[ref_name], defs=defs
|
||||
)
|
||||
elif (
|
||||
"items" in item
|
||||
and isinstance(item["items"], dict)
|
||||
and ("$ref" in item["items"])
|
||||
):
|
||||
ref_path = item["items"]["$ref"]
|
||||
if ref_path.startswith("#/$defs/"):
|
||||
ref_name = ref_path.split("/")[-1]
|
||||
if ref_name in defs:
|
||||
nested = extract_translations_from_schema(
|
||||
defs[ref_name], defs=defs
|
||||
)
|
||||
|
||||
if nested:
|
||||
nested_without_root = {
|
||||
k: v
|
||||
for k, v in nested.items()
|
||||
if k not in ("label", "description")
|
||||
}
|
||||
field_translations.update(nested_without_root)
|
||||
elif "$ref" in item:
|
||||
ref_path = item["$ref"]
|
||||
if ref_path.startswith("#/$defs/"):
|
||||
ref_name = ref_path.split("/")[-1]
|
||||
if ref_name in defs:
|
||||
ref_schema = defs[ref_name]
|
||||
nested = extract_translations_from_schema(
|
||||
ref_schema, defs=defs
|
||||
)
|
||||
nested_without_root = {
|
||||
k: v
|
||||
for k, v in nested.items()
|
||||
if k not in ("label", "description")
|
||||
}
|
||||
field_translations.update(nested_without_root)
|
||||
|
||||
if field_translations:
|
||||
translations[field_name] = field_translations
|
||||
|
||||
Generated
+34
-44
@@ -35,7 +35,7 @@
|
||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@rjsf/core": "^6.4.1",
|
||||
"@rjsf/shadcn": "^6.5.2",
|
||||
"@rjsf/shadcn": "^6.4.1",
|
||||
"@rjsf/utils": "^6.4.1",
|
||||
"@rjsf/validator-ajv8": "^6.4.1",
|
||||
"apexcharts": "^3.52.0",
|
||||
@@ -4887,13 +4887,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rjsf/core": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/core/-/core-6.5.2.tgz",
|
||||
"integrity": "sha512-Fx+aVNQRYQyoY0vM8zYDZkuOiNe+5PLsxUySUdHfjljlT23mJnTCpPKMkxWJwh4UEWeSN0xjmknW9LfIwuQmOg==",
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/core/-/core-6.4.1.tgz",
|
||||
"integrity": "sha512-+QaiSgQnOuO6ghIsohH2u/QcylkN+Da2968a75g/i4oARYJRYVxXDm2u3JR5aXndpMb4t4jTFrYyG8cNIv6oEg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"lodash": "^4.18.1",
|
||||
"lodash-es": "^4.18.1",
|
||||
"lodash": "^4.17.23",
|
||||
"lodash-es": "^4.17.23",
|
||||
"markdown-to-jsx": "^8.0.0",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
@@ -4901,14 +4901,14 @@
|
||||
"node": ">=20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@rjsf/utils": "^6.5.x",
|
||||
"@rjsf/utils": "^6.4.x",
|
||||
"react": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@rjsf/shadcn": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/shadcn/-/shadcn-6.5.2.tgz",
|
||||
"integrity": "sha512-h3FsGRy07Gw4MrORlxNTuSb7icuyiUM0KXimg1jgtlYLhYvMKaHzJgdL/SrAyBWiUtXIsxuBhPU3rFxnA9Ml6Q==",
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/shadcn/-/shadcn-6.4.1.tgz",
|
||||
"integrity": "sha512-WzwXW3XY7K1jo9XrBv6M41ScdHrnQDKpSxip5i1N6xCgEE6hiyX+wn7pDO689OoidvL3lWQmtnoqMdcoJvEWjw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
@@ -4925,19 +4925,19 @@
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"lodash": "^4.18.1",
|
||||
"lodash-es": "^4.18.1",
|
||||
"lodash": "^4.17.23",
|
||||
"lodash-es": "^4.17.23",
|
||||
"lucide-react": "^0.548.0",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"uuid": "^14.0.0"
|
||||
"uuid": "^13.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@rjsf/core": "^6.5.x",
|
||||
"@rjsf/utils": "^6.5.x",
|
||||
"@rjsf/core": "^6.4.x",
|
||||
"@rjsf/utils": "^6.4.x",
|
||||
"react": ">=18"
|
||||
}
|
||||
},
|
||||
@@ -4951,9 +4951,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rjsf/shadcn/node_modules/tailwind-merge": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz",
|
||||
"integrity": "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==",
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
|
||||
"integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -4961,17 +4961,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rjsf/utils": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-6.5.2.tgz",
|
||||
"integrity": "sha512-qBVQ5qf9BKMOQy/DjMl/IjD5s6akRDx18cgiSYunKt/CYc+kPzHyCVA2TU0rXCsigNlhgnfM8piC3LEHye6vpA==",
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-6.4.1.tgz",
|
||||
"integrity": "sha512-5NL3jwt3rIS5/WRTrKt++y40FS/ScKGVwYJ3jIrHSQHSwBdLnd4cHf2zcnA97L1Klj8I6tvS/ugh+blf/Diwuw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@x0k/json-schema-merge": "^1.0.3",
|
||||
"fast-equals": "^6.0.0",
|
||||
"@x0k/json-schema-merge": "^1.0.2",
|
||||
"fast-uri": "^3.1.0",
|
||||
"jsonpointer": "^5.0.1",
|
||||
"lodash": "^4.18.1",
|
||||
"lodash-es": "^4.18.1",
|
||||
"lodash": "^4.17.23",
|
||||
"lodash-es": "^4.17.23",
|
||||
"react-is": "^18.3.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -4981,15 +4980,6 @@
|
||||
"react": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@rjsf/utils/node_modules/fast-equals": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-6.0.0.tgz",
|
||||
"integrity": "sha512-PFhhIGgdM79r5Uztdj9Zb6Tt1zKafqVfdMGwVca1z5z6fbX7DmsySSuJd8HiP6I1j505DCS83cLxo5rmSNeVEA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rjsf/validator-ajv8": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-6.4.1.tgz",
|
||||
@@ -6183,9 +6173,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@x0k/json-schema-merge": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@x0k/json-schema-merge/-/json-schema-merge-1.0.3.tgz",
|
||||
"integrity": "sha512-lerJC4sI9CNUQWdff3PnU1YJOqazD6TjMcvxZIPXUBjn4j1cUiXE0LvzhMnGYzKKr271TkvXJtH7gEwksrtn+w==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@x0k/json-schema-merge/-/json-schema-merge-1.0.2.tgz",
|
||||
"integrity": "sha512-1734qiJHNX3+cJGDMMw2yz7R+7kpbAtl5NdPs1c/0gO5kYT6s4dMbLXiIfpZNsOYhGZI3aH7FWrj4Zxz7epXNg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.15"
|
||||
@@ -7985,9 +7975,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fast-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -13987,9 +13977,9 @@
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz",
|
||||
"integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==",
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz",
|
||||
"integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@
|
||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@rjsf/core": "^6.4.1",
|
||||
"@rjsf/shadcn": "^6.5.2",
|
||||
"@rjsf/shadcn": "^6.4.1",
|
||||
"@rjsf/utils": "^6.4.1",
|
||||
"@rjsf/validator-ajv8": "^6.4.1",
|
||||
"apexcharts": "^3.52.0",
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
"title": "يتم إعادة تشغيل فرايجيت",
|
||||
"content": "العد التنازلي",
|
||||
"button": "فرض إعادة التحميل الآن"
|
||||
}
|
||||
},
|
||||
"description": "هذا سيؤدي لإيقاف Frigate مؤقتا أثناء إعادة تشغيلها"
|
||||
},
|
||||
"explore": {
|
||||
"plus": {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
{
|
||||
"label": "اعدادات الكاميرا"
|
||||
"label": "اعدادات الكاميرا",
|
||||
"name": {
|
||||
"label": "إسم الكاميرا"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
{}
|
||||
{
|
||||
"version": {
|
||||
"label": "إصدار الإعدادات الحالية",
|
||||
"description": "نسحة عددية أو نصية من الإعدادات الحالية الفعالة للمساعدة على اكتشاف الانتقال أو التغير في الصِّيَغ"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"audio": {
|
||||
"global": {
|
||||
"detection": "التحري العام"
|
||||
"detection": "التحري العام",
|
||||
"sensitivity": "الحساسية العامة"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
{}
|
||||
{
|
||||
"minimum": "يجب أن تكون {{limit}} على الأقل",
|
||||
"maximum": "يجب أن تكون {{limit}} كحد أقصى"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"documentTitle": "المحادثات - Frigate"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"documentTitle": "البحث عن الحركة - Frigate"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,503 @@
|
||||
{
|
||||
"speech": "Govor",
|
||||
"babbling": "Babavljanje",
|
||||
"bicycle": "Kolo",
|
||||
"yell": "Vik",
|
||||
"bellow": "Bubanj",
|
||||
"whoop": "Vrisak",
|
||||
"whispering": "Šaputanje",
|
||||
"laughter": "Smijeh",
|
||||
"snicker": "Prijem",
|
||||
"crying": "Plač",
|
||||
"sigh": "Usklik",
|
||||
"singing": "Pjevanje",
|
||||
"choir": "Hors",
|
||||
"yodeling": "Jodelanje",
|
||||
"chant": "Pjevanje",
|
||||
"mantra": "Mantra",
|
||||
"child_singing": "Dječje pjevanje",
|
||||
"synthetic_singing": "Sintetičko pjevanje",
|
||||
"rapping": "Rap",
|
||||
"humming": "Hum",
|
||||
"groan": "Grokot",
|
||||
"grunt": "Groktanje",
|
||||
"whistling": "Pucanje",
|
||||
"breathing": "Disanje",
|
||||
"wheeze": "Pijuckanje",
|
||||
"snoring": "Kicanje",
|
||||
"gasp": "Udah",
|
||||
"pant": "Pantanje",
|
||||
"snort": "Snortanje",
|
||||
"cough": "Kašljanje",
|
||||
"throat_clearing": "Očišćavanje grla",
|
||||
"sneeze": "Prašanje",
|
||||
"sniff": "Njuhanje",
|
||||
"run": "Trčanje",
|
||||
"shuffle": "Prelazak",
|
||||
"footsteps": "Koraci",
|
||||
"chewing": "Zubljanje",
|
||||
"biting": "Gubitak",
|
||||
"gargling": "Peranje grla",
|
||||
"stomach_rumble": "Grušenje",
|
||||
"burping": "Puknutje",
|
||||
"hiccup": "Kikot",
|
||||
"fart": "Pucanje",
|
||||
"hands": "Ruke",
|
||||
"finger_snapping": "Prašanje prstiju",
|
||||
"clapping": "Ključanje",
|
||||
"heartbeat": "Taktilno",
|
||||
"heart_murmur": "Šum srca",
|
||||
"cheering": "Pozdrav",
|
||||
"applause": "Pozdravljati",
|
||||
"chatter": "Šaputanje",
|
||||
"crowd": "Gomila",
|
||||
"children_playing": "Dječja igra",
|
||||
"animal": "Životinja",
|
||||
"pets": "Hrana",
|
||||
"dog": "Pas",
|
||||
"bark": "Glavu",
|
||||
"yip": "Jauk",
|
||||
"howl": "Vijuk",
|
||||
"bow_wow": "Vau vau",
|
||||
"growling": "Gručenje",
|
||||
"whimper_dog": "Pijuckanje psa",
|
||||
"cat": "Mačka",
|
||||
"purr": "Mrmor",
|
||||
"meow": "Mjau",
|
||||
"hiss": "Zujanje",
|
||||
"caterwaul": "Krik",
|
||||
"livestock": "Stoke",
|
||||
"horse": "Konj",
|
||||
"clip_clop": "Klik klok",
|
||||
"neigh": "Kijanje",
|
||||
"cattle": "Stoke",
|
||||
"moo": "Muu",
|
||||
"cowbell": "Kovčeg",
|
||||
"pig": "Svinja",
|
||||
"oink": "Roktanje",
|
||||
"goat": "Koza",
|
||||
"bleat": "Blejkanje",
|
||||
"sheep": "Ovca",
|
||||
"fowl": "Ptica",
|
||||
"chicken": "Pilica",
|
||||
"cluck": "Kukanje",
|
||||
"cock_a_doodle_doo": "Kukavica",
|
||||
"turkey": "Gusa",
|
||||
"gobble": "Gubljanje",
|
||||
"duck": "Kuja",
|
||||
"quack": "Kvaka",
|
||||
"goose": "Guska",
|
||||
"honk": "Trubljenje",
|
||||
"wild_animals": "Divlja životinja",
|
||||
"roaring_cats": "Vrišćeći mački",
|
||||
"roar": "Vrištanje",
|
||||
"bird": "Ptica",
|
||||
"chirp": "Pijuckanje",
|
||||
"squawk": "Krik",
|
||||
"pigeon": "Papiga",
|
||||
"coo": "Kukanje",
|
||||
"crow": "Vran",
|
||||
"caw": "Vranje",
|
||||
"owl": "Kukavica",
|
||||
"hoot": "Kukavica",
|
||||
"flapping_wings": "Mahanje krilima",
|
||||
"dogs": "Psi",
|
||||
"rats": "Štakori",
|
||||
"mouse": "Miš",
|
||||
"patter": "Topotanje",
|
||||
"insect": "Insekt",
|
||||
"cricket": "Cvrčak",
|
||||
"mosquito": "Komarac",
|
||||
"fly": "Muha",
|
||||
"buzz": "Zujanje",
|
||||
"frog": "Žaba",
|
||||
"croak": "Kreketanje",
|
||||
"snake": "Zmija",
|
||||
"rattle": "Zveckanje",
|
||||
"whale_vocalization": "Glasanje kita",
|
||||
"music": "Muzika",
|
||||
"musical_instrument": "Muzički instrument",
|
||||
"plucked_string_instrument": "Plucked String Instrument",
|
||||
"guitar": "Gitara",
|
||||
"electric_guitar": "Električna gitara",
|
||||
"bass_guitar": "Bas gitara",
|
||||
"acoustic_guitar": "Akustična gitara",
|
||||
"steel_guitar": "Steel gitara",
|
||||
"tapping": "Tapping",
|
||||
"strum": "Strum",
|
||||
"banjo": "Bendžo",
|
||||
"sitar": "Sitar",
|
||||
"mandolin": "Mandolina",
|
||||
"zither": "Citra",
|
||||
"ukulele": "Ukulele",
|
||||
"keyboard": "Klaviatura",
|
||||
"piano": "Klavir",
|
||||
"electric_piano": "Električni piano",
|
||||
"organ": "Orgulje",
|
||||
"electronic_organ": "Elektronski organ",
|
||||
"hammond_organ": "Hammond organ",
|
||||
"synthesizer": "Sintetizator",
|
||||
"sampler": "Sampler",
|
||||
"harpsichord": "Harfura",
|
||||
"percussion": "Percuzija",
|
||||
"drum_kit": "Set bubnjeva",
|
||||
"drum_machine": "Mašina za bubnjeve",
|
||||
"drum": "Bubanj",
|
||||
"snare_drum": "Bubanj sa zavojima",
|
||||
"rimshot": "Rimshot",
|
||||
"drum_roll": "Bubanj za roliranje",
|
||||
"bass_drum": "Bubanj za bas",
|
||||
"timpani": "Timpani",
|
||||
"tabla": "Tabla",
|
||||
"cymbal": "Cimbale",
|
||||
"hi_hat": "Hi-Hat",
|
||||
"wood_block": "Drveni blok",
|
||||
"tambourine": "Tamburina",
|
||||
"maraca": "Maraka",
|
||||
"gong": "Gong",
|
||||
"tubular_bells": "Cijevasti zvoni",
|
||||
"mallet_percussion": "Percusija s mljevima",
|
||||
"marimba": "Marimba",
|
||||
"glockenspiel": "Glockenspiel",
|
||||
"vibraphone": "Vibrafon",
|
||||
"steelpan": "Stelpan",
|
||||
"orchestra": "Orkestar",
|
||||
"brass_instrument": "Bronski instrument",
|
||||
"french_horn": "Francuski rog",
|
||||
"trumpet": "Truba",
|
||||
"trombone": "Trombon",
|
||||
"bowed_string_instrument": "Užadno strunski instrument",
|
||||
"string_section": "Strunski sekcija",
|
||||
"violin": "Violina",
|
||||
"pizzicato": "Pizzicato",
|
||||
"cello": "Celula",
|
||||
"double_bass": "Dvostruki bas",
|
||||
"wind_instrument": "Vjetreni instrument",
|
||||
"flute": "Flauta",
|
||||
"saxophone": "Saksafon",
|
||||
"clarinet": "Klarinet",
|
||||
"harp": "Harfa",
|
||||
"bell": "Zvono",
|
||||
"church_bell": "Crkveno zvono",
|
||||
"jingle_bell": "Zvono za igračke",
|
||||
"bicycle_bell": "Zvono za bicikl",
|
||||
"tuning_fork": "Zvučnik",
|
||||
"chime": "Zvono",
|
||||
"wind_chime": "Vjetrenjac",
|
||||
"harmonica": "Harmonika",
|
||||
"accordion": "Akkordon",
|
||||
"bagpipes": "Bogovina",
|
||||
"didgeridoo": "Didgeridoo",
|
||||
"theremin": "Teremin",
|
||||
"singing_bowl": "Pjevni čaša",
|
||||
"scratching": "Skrečing",
|
||||
"pop_music": "Pop muzika",
|
||||
"hip_hop_music": "Hip-Hop muzika",
|
||||
"beatboxing": "Bitboksing",
|
||||
"rock_music": "Rock muzika",
|
||||
"heavy_metal": "Heavy metal",
|
||||
"punk_rock": "Punk rock",
|
||||
"grunge": "Grandž",
|
||||
"progressive_rock": "Progressivni rock",
|
||||
"rock_and_roll": "Rock and roll",
|
||||
"psychedelic_rock": "Psihederički rock",
|
||||
"rhythm_and_blues": "Ritam i blues",
|
||||
"soul_music": "Soul glazba",
|
||||
"reggae": "Rege",
|
||||
"country": "Kantri",
|
||||
"swing_music": "Swing glazba",
|
||||
"bluegrass": "Bluegrass",
|
||||
"funk": "Fank",
|
||||
"folk_music": "Folklorno glazba",
|
||||
"middle_eastern_music": "Glazba Bliskog istoka",
|
||||
"jazz": "Džez",
|
||||
"disco": "Disko",
|
||||
"classical_music": "Klasična glazba",
|
||||
"opera": "Opera",
|
||||
"electronic_music": "Elektronska glazba",
|
||||
"house_music": "House glazba",
|
||||
"techno": "Tehno",
|
||||
"dubstep": "Dubstep",
|
||||
"drum_and_bass": "Drum i bass",
|
||||
"electronica": "Elektronika",
|
||||
"electronic_dance_music": "Elektronska plesna glazba",
|
||||
"ambient_music": "Ambient glazba",
|
||||
"trance_music": "Trance glazba",
|
||||
"music_of_latin_america": "Glazba Latinske Amerike",
|
||||
"salsa_music": "Salsa glazba",
|
||||
"flamenco": "Flamenko",
|
||||
"blues": "Bluz",
|
||||
"music_for_children": "Muzika za djecu",
|
||||
"new-age_music": "Muzika novog doba",
|
||||
"vocal_music": "Vokalna muzika",
|
||||
"a_capella": "A Capella",
|
||||
"music_of_africa": "Afrička muzika",
|
||||
"afrobeat": "Afrobeat",
|
||||
"christian_music": "Kršćanska muzika",
|
||||
"gospel_music": "Gospel muzika",
|
||||
"music_of_asia": "Azijatska muzika",
|
||||
"carnatic_music": "Karnatička muzika",
|
||||
"music_of_bollywood": "Bollywood muzika",
|
||||
"ska": "Ska",
|
||||
"traditional_music": "Tradicionalna muzika",
|
||||
"independent_music": "Nezavisna muzika",
|
||||
"song": "Pjesma",
|
||||
"background_music": "Pozadinska muzika",
|
||||
"theme_music": "Tema muzika",
|
||||
"jingle": "Jingle",
|
||||
"soundtrack_music": "Soundtrack muzika",
|
||||
"lullaby": "Pjesma za uspavanje",
|
||||
"video_game_music": "Muzika za video igre",
|
||||
"christmas_music": "Božićna muzika",
|
||||
"dance_music": "Dance muzika",
|
||||
"wedding_music": "Venčanska glazba",
|
||||
"happy_music": "Sretna glazba",
|
||||
"sad_music": "Tužna glazba",
|
||||
"tender_music": "Tenderna glazba",
|
||||
"exciting_music": "Uzbudljiva glazba",
|
||||
"angry_music": "Zlobna glazba",
|
||||
"scary_music": "Strašna glazba",
|
||||
"wind": "Vjetar",
|
||||
"rustling_leaves": "Šum listova",
|
||||
"wind_noise": "Šum vjetra",
|
||||
"thunderstorm": "Grmljavina",
|
||||
"thunder": "Grmljavac",
|
||||
"water": "Voda",
|
||||
"rain": "Kisa",
|
||||
"raindrop": "Kap kise",
|
||||
"rain_on_surface": "Kisa na površini",
|
||||
"stream": "Tok",
|
||||
"waterfall": "Padina",
|
||||
"ocean": "Okean",
|
||||
"waves": "Valovi",
|
||||
"steam": "Par",
|
||||
"gurgling": "Gurkanje",
|
||||
"fire": "Vatra",
|
||||
"crackle": "Krik",
|
||||
"vehicle": "Vozilo",
|
||||
"boat": "Brod",
|
||||
"sailboat": "Jedrilica",
|
||||
"rowboat": "Čamac",
|
||||
"motorboat": "Motorni čamac",
|
||||
"ship": "Brod",
|
||||
"motor_vehicle": "Motorno vozilo",
|
||||
"car": "Automobil",
|
||||
"toot": "Zvuk klaksona",
|
||||
"car_alarm": "Automobilski alarm",
|
||||
"power_windows": "Električna prozora",
|
||||
"skidding": "Klizanje",
|
||||
"tire_squeal": "Krik kotača",
|
||||
"car_passing_by": "Automobil prolazi",
|
||||
"race_car": "Racing automobil",
|
||||
"truck": "Kamion",
|
||||
"air_brake": "Vazdušni kočnici",
|
||||
"air_horn": "Vazdušni signal",
|
||||
"reversing_beeps": "Zvukovi za odlazak unazad",
|
||||
"ice_cream_truck": "Kamion za sladoled",
|
||||
"bus": "Autobus",
|
||||
"emergency_vehicle": "Hitni vozilo",
|
||||
"police_car": "Policijski automobil",
|
||||
"ambulance": "Ambulansa",
|
||||
"fire_engine": "Pogonski automobil",
|
||||
"motorcycle": "Motocikl",
|
||||
"traffic_noise": "Prometni šum",
|
||||
"rail_transport": "Željeznički transport",
|
||||
"train": "Vlak",
|
||||
"train_whistle": "Vlakovni svirac",
|
||||
"train_horn": "Vlakovni rohorn",
|
||||
"railroad_car": "Željeznički vagon",
|
||||
"train_wheels_squealing": "Vlakove točkove koje zavijaju",
|
||||
"subway": "Metropolitena",
|
||||
"aircraft": "Avion",
|
||||
"aircraft_engine": "Avionski motor",
|
||||
"jet_engine": "Reaktivni motor",
|
||||
"propeller": "Vijak",
|
||||
"helicopter": "Heličopter",
|
||||
"fixed-wing_aircraft": "Avion s krilima",
|
||||
"skateboard": "Skejtbord",
|
||||
"engine": "Motor",
|
||||
"light_engine": "Lagani motor",
|
||||
"dental_drill's_drill": "Stomatološki bušilica",
|
||||
"lawn_mower": "Kosilica",
|
||||
"chainsaw": "Pilica",
|
||||
"medium_engine": "Srednji motor",
|
||||
"heavy_engine": "Teški motor",
|
||||
"engine_knocking": "Kloping motora",
|
||||
"engine_starting": "Pokretanje motora",
|
||||
"idling": "Miris",
|
||||
"accelerating": "Ubrzavanje",
|
||||
"door": "Vrata",
|
||||
"doorbell": "Zvonce",
|
||||
"ding-dong": "Ding-dong",
|
||||
"sliding_door": "Klizna vrata",
|
||||
"slam": "Zatvaranje",
|
||||
"knock": "Kucanje",
|
||||
"tap": "Kucanje",
|
||||
"squeak": "Krik",
|
||||
"cupboard_open_or_close": "Otvorenje ili zatvaranje police",
|
||||
"drawer_open_or_close": "Otvorenje ili zatvaranje vunca",
|
||||
"dishes": "Posuđe",
|
||||
"cutlery": "Posuđe za jelo",
|
||||
"chopping": "Rezanje",
|
||||
"frying": "Praženje",
|
||||
"microwave_oven": "Mikrotalasna pećnica",
|
||||
"blender": "Miksere",
|
||||
"water_tap": "Kran",
|
||||
"sink": "Lavabo",
|
||||
"bathtub": "Kupatilo",
|
||||
"hair_dryer": "Sušilac za kosu",
|
||||
"toilet_flush": "Očišćavanje toaleta",
|
||||
"toothbrush": "Šetka za zube",
|
||||
"electric_toothbrush": "Električna šetka za zube",
|
||||
"vacuum_cleaner": "Praškoljac",
|
||||
"zipper": "Zatvarac",
|
||||
"keys_jangling": "Ključevi koji se škripi",
|
||||
"coin": "Novčanik",
|
||||
"scissors": "Škare",
|
||||
"electric_shaver": "Električni šavac",
|
||||
"shuffling_cards": "Premještanje karata",
|
||||
"typing": "Kucanje",
|
||||
"typewriter": "Tipkovnica",
|
||||
"computer_keyboard": "Računalna tipkovnica",
|
||||
"writing": "Pisanje",
|
||||
"alarm": "Alarm",
|
||||
"telephone": "Telefon",
|
||||
"telephone_bell_ringing": "Zvono telefona",
|
||||
"ringtone": "Ton za poziv",
|
||||
"telephone_dialing": "Pozivanje telefona",
|
||||
"dial_tone": "Ton za poziv",
|
||||
"busy_signal": "Signal zauzetosti",
|
||||
"alarm_clock": "Budilica",
|
||||
"siren": "Sirena",
|
||||
"civil_defense_siren": "Sirena za civilnu zaštitu",
|
||||
"buzzer": "Buzer",
|
||||
"smoke_detector": "Detektor dima",
|
||||
"fire_alarm": "Pozar alarm",
|
||||
"foghorn": "Mlazni svirac",
|
||||
"whistle": "Štiklja",
|
||||
"steam_whistle": "Parni zvono",
|
||||
"mechanisms": "Mehanizmi",
|
||||
"ratchet": "Ratchet",
|
||||
"clock": "Sat",
|
||||
"tick": "Tik",
|
||||
"tick-tock": "Tik-tak",
|
||||
"gears": "Zupčanici",
|
||||
"pulleys": "Koturači",
|
||||
"sewing_machine": "Šitna mašina",
|
||||
"mechanical_fan": "Mehanički ventilator",
|
||||
"air_conditioning": "Klima uređaj",
|
||||
"cash_register": "Gotovinska kasica",
|
||||
"printer": "Štampač",
|
||||
"camera": "Kamera",
|
||||
"single-lens_reflex_camera": "Kamera s jednim objektivom",
|
||||
"tools": "Alati",
|
||||
"hammer": "Klubica",
|
||||
"jackhammer": "Betonomijak",
|
||||
"sawing": "Sečenje",
|
||||
"filing": "Flešanje",
|
||||
"sanding": "Šljokanje",
|
||||
"power_tool": "Električni alat",
|
||||
"drill": "Bušilica",
|
||||
"explosion": "Eksplozija",
|
||||
"gunshot": "Pucanj",
|
||||
"machine_gun": "Automatska puška",
|
||||
"fusillade": "Fusiladža",
|
||||
"artillery_fire": "Pucanj topovima",
|
||||
"cap_gun": "Pistolj za pucanje",
|
||||
"fireworks": "Pucanje svjetiljki",
|
||||
"firecracker": "Svjetiljka",
|
||||
"burst": "Izbič",
|
||||
"eruption": "Eruptija",
|
||||
"boom": "Tutnjava",
|
||||
"wood": "Drvo",
|
||||
"chop": "Rezanje",
|
||||
"splinter": "Razlomak",
|
||||
"crack": "Klackanje",
|
||||
"glass": "Staklo",
|
||||
"chink": "Prozor",
|
||||
"shatter": "Razbijanje",
|
||||
"silence": "Tišina",
|
||||
"sound_effect": "Zvučni efekt",
|
||||
"environmental_noise": "Okolišni šum",
|
||||
"static": "Statički šum",
|
||||
"white_noise": "Bijeli šum",
|
||||
"pink_noise": "Rumeni šum",
|
||||
"television": "Televizija",
|
||||
"radio": "Radio",
|
||||
"field_recording": "Snimka na terenu",
|
||||
"scream": "Vrisak",
|
||||
"sodeling": "Sodeling",
|
||||
"chird": "Chird",
|
||||
"change_ringing": "Promjena zvona",
|
||||
"shofar": "Šofar",
|
||||
"liquid": "Tekućina",
|
||||
"splash": "Pljuskanje",
|
||||
"slosh": "Sloš",
|
||||
"squish": "Škripanje",
|
||||
"drip": "Kapanje",
|
||||
"pour": "Prelivanje",
|
||||
"trickle": "Tijek",
|
||||
"gush": "Gusenje",
|
||||
"fill": "Popunjavanje",
|
||||
"spray": "Sprajanje",
|
||||
"pump": "Pumpa",
|
||||
"stir": "Miješanje",
|
||||
"boiling": "Vrećenje",
|
||||
"sonar": "Sonar",
|
||||
"arrow": "Strela",
|
||||
"whoosh": "Šum",
|
||||
"thump": "Tupanje",
|
||||
"thunk": "Tunk",
|
||||
"electronic_tuner": "Elektronski tuner",
|
||||
"effects_unit": "Jedinica efekata",
|
||||
"chorus_effect": "Efekt korusa",
|
||||
"basketball_bounce": "Košarkaški skok",
|
||||
"bang": "Bum",
|
||||
"slap": "Pljeska",
|
||||
"whack": "Perc",
|
||||
"smash": "Sprem",
|
||||
"breaking": "Raskidanje",
|
||||
"bouncing": "Skakanje",
|
||||
"whip": "Škripanje",
|
||||
"flap": "Klizanje",
|
||||
"scratch": "Oštećenje",
|
||||
"scrape": "Prašenje",
|
||||
"rub": "Trenje",
|
||||
"roll": "Kotrljanje",
|
||||
"crushing": "Stiskanje",
|
||||
"crumpling": "Sklapanje",
|
||||
"tearing": "Raskidanje",
|
||||
"beep": "Bip",
|
||||
"ping": "Poziv",
|
||||
"ding": "Ding",
|
||||
"clang": "Zveket",
|
||||
"squeal": "Cika",
|
||||
"creak": "Škripa",
|
||||
"rustle": "Šuškanje",
|
||||
"whir": "Brujanje",
|
||||
"clatter": "Tropot",
|
||||
"sizzle": "Šištanje",
|
||||
"clicking": "Klikanje",
|
||||
"clickety_clack": "Klik-tak",
|
||||
"rumble": "Rumbljanje",
|
||||
"plop": "Pljus",
|
||||
"hum": "Pjevušenje",
|
||||
"zing": "Zing",
|
||||
"boing": "Boing",
|
||||
"crunch": "Crunch",
|
||||
"sine_wave": "Sinusna valna",
|
||||
"harmonic": "Harmonični",
|
||||
"chirp_tone": "Tanjirasti ton",
|
||||
"pulse": "Impuls",
|
||||
"inside": "Unutra",
|
||||
"outside": "Van",
|
||||
"reverberation": "Reverberacija",
|
||||
"echo": "Odjek",
|
||||
"noise": "Šum",
|
||||
"mains_hum": "Glavni šum",
|
||||
"distortion": "Distorzija",
|
||||
"sidetone": "Sidetone",
|
||||
"cacophony": "Kacofonija",
|
||||
"throbbing": "Tremor",
|
||||
"vibration": "Vibracija"
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
{
|
||||
"time": {
|
||||
"untilForTime": "Do {{time}}",
|
||||
"untilForRestart": "Do ponovnog pokretanja Frigate.",
|
||||
"untilRestart": "Do ponovnog pokretanja",
|
||||
"never": "Nikad",
|
||||
"ago": "{{timeAgo}} prije",
|
||||
"justNow": "Sada",
|
||||
"today": "Danas",
|
||||
"yesterday": "Jučer",
|
||||
"last7": "Prošlih 7 dana",
|
||||
"last14": "Prošlih 14 dana",
|
||||
"last30": "Prošlih 30 dana",
|
||||
"thisWeek": "Ova sedmica",
|
||||
"lastWeek": "Prošla sedmica",
|
||||
"thisMonth": "Ovaj mjesec",
|
||||
"lastMonth": "Prošli mjesec",
|
||||
"5minutes": "5 minuta",
|
||||
"10minutes": "10 minuta",
|
||||
"30minutes": "30 minuta",
|
||||
"1hour": "1 sat",
|
||||
"12hours": "12 sati",
|
||||
"24hours": "24 sata",
|
||||
"pm": "posle podne",
|
||||
"am": "pre podne",
|
||||
"yr": "{{time}} god",
|
||||
"year_one": "{{time}} godina",
|
||||
"year_few": "{{time}} godine",
|
||||
"year_other": "{{time}} godina",
|
||||
"mo": "{{time}} mjes",
|
||||
"month_one": "{{time}} mjesec",
|
||||
"month_few": "{{time}} mjeseca",
|
||||
"month_other": "{{time}} mjeseci",
|
||||
"d": "{{time}}d",
|
||||
"day_one": "{{time}} dan",
|
||||
"day_few": "{{time}} dana",
|
||||
"day_other": "{{time}} dana",
|
||||
"h": "{{time}}h",
|
||||
"hour_one": "{{time}} sat",
|
||||
"hour_few": "{{time}} sata",
|
||||
"hour_other": "{{time}} sati",
|
||||
"m": "{{time}}m",
|
||||
"minute_one": "{{time}} minuta",
|
||||
"minute_few": "{{time}} minute",
|
||||
"minute_other": "{{time}} minuta",
|
||||
"s": "{{time}}s",
|
||||
"second_one": "{{time}} sekunda",
|
||||
"second_few": "{{time}} sekunde",
|
||||
"second_other": "{{time}} sekundi",
|
||||
"formattedTimestamp": {
|
||||
"12hour": "MMM d, h:mm:ss aaa",
|
||||
"24hour": "MMM d, HH:mm:ss"
|
||||
},
|
||||
"formattedTimestamp2": {
|
||||
"12hour": "MM/dd h:mm:ssa",
|
||||
"24hour": "d MMM HH:mm:ss"
|
||||
},
|
||||
"formattedTimestampHourMinute": {
|
||||
"12hour": "h:mm aaa",
|
||||
"24hour": "HH:mm"
|
||||
},
|
||||
"formattedTimestampHourMinuteSecond": {
|
||||
"12hour": "h:mm:ss aaa",
|
||||
"24hour": "HH:mm:ss"
|
||||
},
|
||||
"formattedTimestampMonthDayHourMinute": {
|
||||
"12hour": "MMM d, h:mm aaa",
|
||||
"24hour": "MMM d, HH:mm"
|
||||
},
|
||||
"formattedTimestampMonthDayYear": {
|
||||
"12hour": "MMM d, yyyy",
|
||||
"24hour": "MMM d, yyyy"
|
||||
},
|
||||
"formattedTimestampMonthDayYearHourMinute": {
|
||||
"12hour": "MMM d yyyy, h:mm aaa",
|
||||
"24hour": "MMM d yyyy, HH:mm"
|
||||
},
|
||||
"formattedTimestampMonthDay": "MMM d",
|
||||
"formattedTimestampFilename": {
|
||||
"12hour": "MM-dd-yy-h-mm-ss-a",
|
||||
"24hour": "MM-dd-yy-HH-mm-ss"
|
||||
},
|
||||
"inProgress": "U toku",
|
||||
"invalidStartTime": "Neispravno početno vrijeme",
|
||||
"invalidEndTime": "Neispravno krajnje vrijeme"
|
||||
},
|
||||
"unit": {
|
||||
"speed": {
|
||||
"mph": "mph",
|
||||
"kph": "kph"
|
||||
},
|
||||
"length": {
|
||||
"feet": "fut",
|
||||
"meters": "metar"
|
||||
},
|
||||
"data": {
|
||||
"kbps": "kB/s",
|
||||
"mbps": "MB/s",
|
||||
"gbps": "GB/s",
|
||||
"kbph": "kB/hour",
|
||||
"mbph": "MB/hour",
|
||||
"gbph": "GB/hour"
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"back": "Povratak",
|
||||
"hide": "Sakrij {{item}}",
|
||||
"show": "Prikaži {{item}}",
|
||||
"ID": "ID",
|
||||
"none": "Nijedan",
|
||||
"all": "Sve",
|
||||
"other": "Ostalo"
|
||||
},
|
||||
"list": {
|
||||
"two": "{{0}} i {{1}}",
|
||||
"many": "{{items}}, i {{last}}",
|
||||
"separatorWithSpace": ", "
|
||||
},
|
||||
"field": {
|
||||
"optional": "Opcionalno",
|
||||
"internalID": "Unutarnji ID koji Frigate koristi u konfiguraciji i bazi podataka"
|
||||
},
|
||||
"button": {
|
||||
"add": "Dodaj",
|
||||
"apply": "Primijeni",
|
||||
"applying": "Primjenjuje se…",
|
||||
"reset": "Resetuj",
|
||||
"undo": "Poništi",
|
||||
"done": "Gotovo",
|
||||
"enabled": "Omogućeno",
|
||||
"enable": "Omogući",
|
||||
"disabled": "Onemogućeno",
|
||||
"disable": "Onemogući",
|
||||
"save": "Sačuvaj",
|
||||
"saving": "Sačuvanje…",
|
||||
"cancel": "Otkaži",
|
||||
"close": "Zatvori",
|
||||
"copy": "Kopiraj",
|
||||
"copiedToClipboard": "Kopirano u međuspremnik",
|
||||
"back": "Nazad",
|
||||
"history": "Historija",
|
||||
"fullscreen": "Pun ekran",
|
||||
"exitFullscreen": "Napusti pun ekran",
|
||||
"pictureInPicture": "Slika u slici",
|
||||
"twoWayTalk": "Dvostrani razgovor",
|
||||
"cameraAudio": "Zvuk kamere",
|
||||
"on": "Uključeno",
|
||||
"off": "Isključeno",
|
||||
"edit": "Uredi",
|
||||
"copyCoordinates": "Kopiraj koordinate",
|
||||
"delete": "Obriši",
|
||||
"yes": "Da",
|
||||
"no": "Ne",
|
||||
"download": "Preuzmi",
|
||||
"info": "Informacija",
|
||||
"suspended": "Otkazano",
|
||||
"unsuspended": "Ponovi",
|
||||
"play": "Reproduciraj",
|
||||
"unselect": "Odznači",
|
||||
"export": "Izvoz",
|
||||
"deleteNow": "Obriši sada",
|
||||
"next": "Sljedeće",
|
||||
"continue": "Nastavi",
|
||||
"modified": "Izmijenjeno",
|
||||
"overridden": "Preklopljeno",
|
||||
"resetToGlobal": "Vrati na globalno",
|
||||
"resetToDefault": "Vrati na podrazumijevano",
|
||||
"saveAll": "Sačuvaj sve",
|
||||
"savingAll": "Sačuvanje svih…",
|
||||
"undoAll": "Poništi sve",
|
||||
"retry": "Pokušaj ponovno"
|
||||
},
|
||||
"menu": {
|
||||
"system": "Sistem",
|
||||
"systemMetrics": "Sistem metrike",
|
||||
"configuration": "Konfiguracija",
|
||||
"systemLogs": "Sistemski zapisi",
|
||||
"profiles": "Profili",
|
||||
"settings": "Postavke",
|
||||
"configurationEditor": "Uređivač konfiguracije",
|
||||
"languages": "Jezici",
|
||||
"language": {
|
||||
"en": "Engleski (English)",
|
||||
"es": "Španjolski (Spanish)",
|
||||
"zhCN": "Jednostavni kineski (Simplified Chinese)",
|
||||
"hi": "Hindi (Hindi)",
|
||||
"fr": "Francuski (French)",
|
||||
"ar": "Arapski (Arabic)",
|
||||
"pt": "Portugalski (Portuguese)",
|
||||
"ptBR": "Portugalski brazilski (Brazilian Portuguese)",
|
||||
"ru": "Ruski (Russian)",
|
||||
"de": "Nemački (German)",
|
||||
"ja": "Japanski (Japanese)",
|
||||
"tr": "Turski (Turkish)",
|
||||
"it": "Talijanski (Italian)",
|
||||
"nl": "Nizozemski (Dutch)",
|
||||
"sv": "Švedski (Swedish)",
|
||||
"cs": "Češki (Czech)",
|
||||
"nb": "Norveški bokmål (Norwegian Bokmål)",
|
||||
"ko": "Koreanski (Korean)",
|
||||
"vi": "Vietnamski (Vietnamese)",
|
||||
"fa": "Perzijski (Persian)",
|
||||
"pl": "Polski (Poljski)",
|
||||
"uk": "Українська (Ukrajinski)",
|
||||
"he": "עברית (Hebrejski)",
|
||||
"el": "Ελληνικά (Grčki)",
|
||||
"ro": "Română (Romunski)",
|
||||
"hu": "Magyar (Mađarski)",
|
||||
"fi": "Suomi (Finski)",
|
||||
"da": "Dansk (Danski)",
|
||||
"sk": "Slovenčina (Slovački)",
|
||||
"yue": "粵語 (Kantonski)",
|
||||
"th": "ไทย (Tajski)",
|
||||
"ca": "Català (Katalonski)",
|
||||
"hr": "Hrvatski (Hrvatski)",
|
||||
"sr": "Српски (Srpski)",
|
||||
"sl": "Slovenščina (Slovenski)",
|
||||
"lt": "Lietuvių (Lietuvių)",
|
||||
"bg": "Български (Bugarinski)",
|
||||
"gl": "Galego (Galicijski)",
|
||||
"id": "Bahasa Indonesia (Indoneziski)",
|
||||
"ur": "اردو (Urdu)",
|
||||
"withSystem": {
|
||||
"label": "Koristite postavke sistema za jezik"
|
||||
}
|
||||
},
|
||||
"appearance": "Izgled",
|
||||
"darkMode": {
|
||||
"label": "Tamni režim",
|
||||
"light": "Svijetla",
|
||||
"dark": "Tamna",
|
||||
"withSystem": {
|
||||
"label": "Koristite postavke sistema za svjetlosni ili tamni režim"
|
||||
}
|
||||
},
|
||||
"withSystem": "Sistem",
|
||||
"theme": {
|
||||
"label": "Tema",
|
||||
"blue": "Plava",
|
||||
"green": "Zelena",
|
||||
"nord": "Nord",
|
||||
"red": "Crvena",
|
||||
"highcontrast": "Visok kontrast",
|
||||
"default": "Zadano"
|
||||
},
|
||||
"help": "Pomoć",
|
||||
"documentation": {
|
||||
"title": "Dokumentacija",
|
||||
"label": "Dokumentacija za Frigate"
|
||||
},
|
||||
"restart": "Ponovno pokreni Frigate",
|
||||
"live": {
|
||||
"title": "Uživo",
|
||||
"allCameras": "Sve Kamere",
|
||||
"cameras": {
|
||||
"title": "Kamere",
|
||||
"count_one": "{{count}} Kamera",
|
||||
"count_few": "{{count}} Kamere",
|
||||
"count_other": "{{count}} Kamere"
|
||||
}
|
||||
},
|
||||
"review": "Pregled",
|
||||
"explore": "Istraži",
|
||||
"export": "Izvoz",
|
||||
"actions": "Akcije",
|
||||
"uiPlayground": "UI Playground",
|
||||
"features": "Funkcije",
|
||||
"faceLibrary": "Biblioteka lica",
|
||||
"classification": "Klasifikacija",
|
||||
"chat": "Razgovor",
|
||||
"user": {
|
||||
"title": "Korisnik",
|
||||
"account": "Račun",
|
||||
"current": "Trenutni korisnik: {{user}}",
|
||||
"anonymous": "anons",
|
||||
"logout": "Odjava",
|
||||
"setPassword": "Postavi lozinku"
|
||||
}
|
||||
},
|
||||
"toast": {
|
||||
"copyUrlToClipboard": "URL kopiran u međuspremnik.",
|
||||
"save": {
|
||||
"title": "Sačuvaj",
|
||||
"error": {
|
||||
"title": "Nije uspješno sačuvana promjena konfiguracije: {{errorMessage}}",
|
||||
"noMessage": "Nije uspješno sačuvana promjena konfiguracije"
|
||||
},
|
||||
"success": "Uspješno sačuvana promjena konfiguracije."
|
||||
}
|
||||
},
|
||||
"role": {
|
||||
"title": "Uloga",
|
||||
"admin": "Administrator",
|
||||
"viewer": "Pregledač",
|
||||
"desc": "Admini imaju pun pristup svim funkcijama u korisničkom sučelju Frigate. Pregledači su ograničeni na pregled kamere, pregled stavki i povijesne snimke u korisničkom sučelju."
|
||||
},
|
||||
"pagination": {
|
||||
"label": "paginacija",
|
||||
"previous": {
|
||||
"title": "Prethodno",
|
||||
"label": "Idi na prethodnu stranicu"
|
||||
},
|
||||
"next": {
|
||||
"title": "Sljedeće",
|
||||
"label": "Idi na sljedeću stranicu"
|
||||
},
|
||||
"more": "Više stranica"
|
||||
},
|
||||
"accessDenied": {
|
||||
"documentTitle": "Pristup odbijen - Frigate",
|
||||
"title": "Pristup odbijen",
|
||||
"desc": "Nemate dozvolu za pregled ove stranice."
|
||||
},
|
||||
"notFound": {
|
||||
"documentTitle": "Nije pronađeno - Frigate",
|
||||
"title": "404",
|
||||
"desc": "Stranica nije pronađena"
|
||||
},
|
||||
"selectItem": "Odaberite {{item}}",
|
||||
"readTheDocumentation": "Pročitajte dokumentaciju",
|
||||
"information": {
|
||||
"pixels": "{{area}}px"
|
||||
},
|
||||
"no_items": "Nema stavki",
|
||||
"validation_errors": "Greške validacije"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"form": {
|
||||
"user": "Korisničko ime",
|
||||
"password": "Lozinka",
|
||||
"login": "Prijava",
|
||||
"firstTimeLogin": "Pokušavate se prijaviti prvi put? Vjerodajnice su ispisane u logovima Frigate.",
|
||||
"errors": {
|
||||
"usernameRequired": "Korisničko ime je obavezno",
|
||||
"passwordRequired": "Lozinka je obavezna",
|
||||
"rateLimit": "Premašen je limit brzine. Pokušajte kasnije.",
|
||||
"loginFailed": "Prijava nije uspješna",
|
||||
"unknownError": "Nepoznata greška. Provjerite zapise.",
|
||||
"webUnknownError": "Nepoznata greška. Provjerite konzolne zapise."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"group": {
|
||||
"label": "Grupe kamere",
|
||||
"add": "Dodaj grupu kamere",
|
||||
"edit": "Uredi grupu kamera",
|
||||
"delete": {
|
||||
"label": "Obriši grupu kamere",
|
||||
"confirm": {
|
||||
"title": "Potvrdi brisanje",
|
||||
"desc": "Sigurno li želite da obrišete grupu kamere <em>{{name}}</em>?"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"label": "Ime",
|
||||
"placeholder": "Unesite ime…",
|
||||
"errorMessage": {
|
||||
"mustLeastCharacters": "Ime grupe kamere mora imati najmanje 2 karaktera.",
|
||||
"exists": "Ime grupe kamere već postoji.",
|
||||
"nameMustNotPeriod": "Ime grupe kamere ne smije sadržavati tačku.",
|
||||
"invalid": "Neispravno ime grupe kamere."
|
||||
}
|
||||
},
|
||||
"cameras": {
|
||||
"label": "Kamere",
|
||||
"desc": "Odaberite kamere za ovu grupu."
|
||||
},
|
||||
"icon": "Ikona",
|
||||
"success": "Grupa kamere ({{name}}) je sačuvana.",
|
||||
"camera": {
|
||||
"birdseye": "Birdseye",
|
||||
"setting": {
|
||||
"label": "Postavke prenošenja kamere",
|
||||
"title": "Postavke prenošenja {{cameraName}}",
|
||||
"desc": "Promijenite opcije uživo prenošenja za tablicu upravljanja ove grupe kamere. <em>Ove postavke su specifične za uređaj/pretvarač.</em>",
|
||||
"audioIsAvailable": "Audio je dostupan za ovaj stream",
|
||||
"audioIsUnavailable": "Zvuk nije dostupan za ovaj tok",
|
||||
"audio": {
|
||||
"tips": {
|
||||
"title": "Audio mora biti izlaz iz vaše kamere i konfiguriran u go2rtc za ovaj stream."
|
||||
}
|
||||
},
|
||||
"stream": "Tok",
|
||||
"placeholder": "Odaberite tok",
|
||||
"streamMethod": {
|
||||
"label": "Način prenošenja",
|
||||
"placeholder": "Odaberite način prenošenja",
|
||||
"method": {
|
||||
"noStreaming": {
|
||||
"label": "Bez prenošenja",
|
||||
"desc": "Slike kamere će se ažurirati samo jednom na minut i neće se dogoditi uživo prenošenje."
|
||||
},
|
||||
"smartStreaming": {
|
||||
"label": "Pametno prenošenje (preporučeno)",
|
||||
"desc": "Pametno prenošenje će ažurirati sliku kamere jednom na minut kada se ne događa detektovana aktivnost kako bi se uštedjelo na širovini i resursima. Kada se detektuje aktivnost, slika se glatko prebacuje u uživo prenošenje."
|
||||
},
|
||||
"continuousStreaming": {
|
||||
"label": "Neprekidno prenošenje",
|
||||
"desc": {
|
||||
"title": "Slika kamere uvijek će biti živo prenošenje kada je vidljiva na ploči, čak i ako se ne detektira aktivnost.",
|
||||
"warning": "Neprekidno prenošenje može uzrokovati visoku upotrebu širine pojasa i probleme s performansama. Koristite s oprezom."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"compatibilityMode": {
|
||||
"label": "Režim kompatibilnosti",
|
||||
"desc": "Omogućite ovu opciju samo ako se živo prenošenje vaše kamere prikazuje s bojnim artefaktima i dijagonalnom linijom na desnoj strani slike."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"options": {
|
||||
"label": "Postavke",
|
||||
"title": "Opcije",
|
||||
"showOptions": "Prikaži opcije",
|
||||
"hideOptions": "Sakrij opcije"
|
||||
},
|
||||
"boundingBox": "Okvir",
|
||||
"timestamp": "Vremenski pečat",
|
||||
"zones": "Zone",
|
||||
"mask": "Maska",
|
||||
"motion": "Kretanje",
|
||||
"regions": "Regije",
|
||||
"paths": "Putanje"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
{
|
||||
"restart": {
|
||||
"title": "Sigurni li ste da želite ponovno pokrenuti Frigate?",
|
||||
"description": "Ovo privremeno zaustavi Frigate dok se ponovno pokreće.",
|
||||
"button": "Ponovno pokretanje",
|
||||
"restarting": {
|
||||
"title": "Frigate se ponovo pokreće",
|
||||
"content": "Ova stranica će se ponovno učitati za {{countdown}} sekundi.",
|
||||
"button": "Silovito ponovno učitavanje sada"
|
||||
}
|
||||
},
|
||||
"explore": {
|
||||
"plus": {
|
||||
"submitToPlus": {
|
||||
"label": "Pošalji na Frigate+",
|
||||
"desc": "Predmeti u lokacijama koje želite izbjeći nisu lažni pozitivi. Pošiljanje ih kao lažne pozitive zbunjuje model."
|
||||
},
|
||||
"review": {
|
||||
"question": {
|
||||
"label": "Potvrdite ovu oznaku za Frigate Plus",
|
||||
"ask_a": "Je li ovaj objekt <code>{{label}}</code>?",
|
||||
"ask_an": "Je li ovaj objekt <code>{{label}}</code>?",
|
||||
"ask_full": "Je li ovaj objekt <code>{{untranslatedLabel}}</code> ({{translatedLabel}})?"
|
||||
},
|
||||
"state": {
|
||||
"submitted": "Pošlato"
|
||||
}
|
||||
}
|
||||
},
|
||||
"video": {
|
||||
"viewInHistory": "Pregledajte u povijesti"
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"time": {
|
||||
"fromTimeline": "Odaberite iz vremenske linije",
|
||||
"lastHour_one": "Prošli sat",
|
||||
"lastHour_few": "Prošla {{count}} sata",
|
||||
"lastHour_other": "Prošlih {{count}} sati",
|
||||
"custom": "Prilagođeno",
|
||||
"start": {
|
||||
"title": "Vrijeme početka",
|
||||
"label": "Odaberite vrijeme početka"
|
||||
},
|
||||
"end": {
|
||||
"title": "Vrijeme kraja",
|
||||
"label": "Odaberite vrijeme kraja"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"placeholder": "Nazovite izvoz"
|
||||
},
|
||||
"case": {
|
||||
"newCaseOption": "Napravite novi slučaj",
|
||||
"newCaseNamePlaceholder": "Novo ime slučaja",
|
||||
"newCaseDescriptionPlaceholder": "Opis slučaja",
|
||||
"label": "Slučaj",
|
||||
"nonAdminHelp": "Za ove izvoze će se stvoriti novi slučaj.",
|
||||
"placeholder": "Odaberite slučaj"
|
||||
},
|
||||
"select": "Odaberite",
|
||||
"export": "Izvoz",
|
||||
"queueing": "Stavljanje izvoza u red...",
|
||||
"selectOrExport": "Odaberite ili izvozite",
|
||||
"tabs": {
|
||||
"export": "Jedna kamera",
|
||||
"multiCamera": "Više kamera"
|
||||
},
|
||||
"multiCamera": {
|
||||
"timeRange": "Vremenski opseg",
|
||||
"selectFromTimeline": "Odaberite iz vremenske linije",
|
||||
"cameraSelection": "Kamere",
|
||||
"cameraSelectionHelp": "Kamere s praćenim objektima u ovom vremenskom opsegu su preselektirane",
|
||||
"checkingActivity": "Provjeravamo aktivnost kamere...",
|
||||
"noCameras": "Nema dostupnih kamera",
|
||||
"detectionCount_one": "1 praćen objekt",
|
||||
"detectionCount_few": "{{count}} praćena objekta",
|
||||
"detectionCount_other": "{{count}} praćenih objekata",
|
||||
"nameLabel": "Ime izvoza",
|
||||
"namePlaceholder": "Nepovlačenje baznog imena za ove izvoze",
|
||||
"queueingButton": "Stavljanje izvoza u red...",
|
||||
"exportButton_one": "Izvoz 1 kamere",
|
||||
"exportButton_few": "Izvoz {{count}} kamere",
|
||||
"exportButton_other": "Izvoz {{count}} kamera"
|
||||
},
|
||||
"multi": {
|
||||
"title_one": "Izvoz 1 pregleda",
|
||||
"title_few": "Izvoz {{count}} pregleda",
|
||||
"title_other": "Izvoz {{count}} pregleda",
|
||||
"description": "Izvoz svakog odabranih pregleda. Svi izvozi bit će grupirani pod jedan slučaj.",
|
||||
"descriptionNoCase": "Izvoz svakog odabranih pregleda.",
|
||||
"caseNamePlaceholder": "Pregled izvoza - {{date}}",
|
||||
"exportButton_one": "Izvoz 1 pregleda",
|
||||
"exportButton_few": "Izvoz {{count}} pregleda",
|
||||
"exportButton_other": "Izvoz {{count}} pregleda",
|
||||
"exportingButton": "Izvoz...",
|
||||
"toast": {
|
||||
"started_one": "Pokrenut 1 izvoz. Otvaranje slučaja sada.",
|
||||
"started_few": "Pokrenuta {{count}} izvoza. Otvaranje slučaja sada.",
|
||||
"started_other": "Pokrenuto {{count}} izvoza. Otvaranje slučaja sada.",
|
||||
"startedNoCase_one": "Pokrenut 1 izvoz.",
|
||||
"startedNoCase_few": "Pokrenuta {{count}} izvoza.",
|
||||
"startedNoCase_other": "Pokrenuto {{count}} izvoza.",
|
||||
"partial": "Pokrenuto {{successful}} od {{total}} izvoza. Neuspješno: {{failedItems}}",
|
||||
"failed": "Neuspješno pokretanje {{total}} izvoza. Neuspješno: {{failedItems}}"
|
||||
}
|
||||
},
|
||||
"toast": {
|
||||
"success": "Uspješno pokrenut izvoz. Pregledajte datoteku na stranici izvoza.",
|
||||
"queued": "Izvoz u redu. Pregledajte napredak na stranici izvoza.",
|
||||
"view": "Pregled",
|
||||
"batchSuccess_one": "Pokrenut 1 izvoz. Otvaranje slučaja sada.",
|
||||
"batchSuccess_few": "Pokrenuta {{count}} izvoza. Otvaranje slučaja sada.",
|
||||
"batchSuccess_other": "Pokrenuto {{count}} izvoza. Otvaranje slučaja sada.",
|
||||
"batchPartial": "Pokrenuto {{successful}} od {{total}} izvoza. Neuspješne kamere: {{failedCameras}}",
|
||||
"batchFailed": "Neuspješno pokretanje {{total}} izvoza. Neuspješne kamere: {{failedCameras}}",
|
||||
"batchQueuedSuccess_one": "U red stavljen 1 izvoz. Otvaranje slučaja sada.",
|
||||
"batchQueuedSuccess_few": "U red stavljena {{count}} izvoza. Otvaranje slučaja sada.",
|
||||
"batchQueuedSuccess_other": "U red stavljeno {{count}} izvoza. Otvaranje slučaja sada.",
|
||||
"batchQueuedPartial": "U redu {{successful}} od {{total}} izvoza. Neuspješne kamere: {{failedCameras}}",
|
||||
"batchQueueFailed": "Neuspješno dodavanje {{total}} izvoza. Neuspješne kamere: {{failedCameras}}",
|
||||
"error": {
|
||||
"failed": "Neuspješno dodavanje izvoza: {{error}}",
|
||||
"endTimeMustAfterStartTime": "Krajnje vrijeme mora biti nakon početnog vremena",
|
||||
"noVaildTimeSelected": "Nije odabran valjan vremenski opseg"
|
||||
}
|
||||
},
|
||||
"fromTimeline": {
|
||||
"saveExport": "Sačuvaj izvoz",
|
||||
"queueingExport": "Kopiranje izvoza...",
|
||||
"previewExport": "Pregled izvoza",
|
||||
"useThisRange": "Koristi ovaj opseg"
|
||||
}
|
||||
},
|
||||
"streaming": {
|
||||
"label": "Tok",
|
||||
"restreaming": {
|
||||
"disabled": "Restreaming nije omogućeno za ovu kameru.",
|
||||
"desc": {
|
||||
"title": "Postavite go2rtc za dodatne opcije uživog pregleda i zvuk za ovu kameru."
|
||||
}
|
||||
},
|
||||
"showStats": {
|
||||
"label": "Prikaži statistiku strima",
|
||||
"desc": "Omogući ovu opciju da prikaže statistiku prijenosa kao preklapanje na toku kamere."
|
||||
},
|
||||
"debugView": "Pregled za otklanjanje grešaka"
|
||||
},
|
||||
"search": {
|
||||
"saveSearch": {
|
||||
"label": "Sačuvaj pretragu",
|
||||
"desc": "Navedite ime za ovu sačuvanu pretragu.",
|
||||
"placeholder": "Unesite ime za svoju pretragu",
|
||||
"overwrite": "{{searchName}} već postoji. Sačuvavanje će prebrisati postojet će vrijednost.",
|
||||
"success": "Pretraga ({{searchName}}) je sačuvana.",
|
||||
"button": {
|
||||
"save": {
|
||||
"label": "Sačuvaj ovu pretragu"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"recording": {
|
||||
"shareTimestamp": {
|
||||
"label": "Dijeli vremensku oznaku",
|
||||
"title": "Dijeli vremensku oznaku",
|
||||
"description": "Dijelite URL označen vremenom trenutne pozicije igrača ili odaberite prilagođenu vremensku oznaku. Napomena: ovo nije javni URL za dijeljenje i dostupan je samo korisnicima koji imaju pristup Frigate i ovoj kameri.",
|
||||
"custom": "Prilagođena vremenska oznaka",
|
||||
"button": "URL za dijeljenje vremenske oznake",
|
||||
"shareTitle": "Vremenska oznaka pregleda Frigate: {{camera}}"
|
||||
},
|
||||
"confirmDelete": {
|
||||
"title": "Potvrdi brisanje",
|
||||
"desc": {
|
||||
"selected": "Sigurni li ste da želite izbrisati sve snimljeno video povezano s ovim preglednim stavkom?<br /><br />Zadržite tipku <em>Shift</em> da biste preskočili ovaj dijalog u budućnosti."
|
||||
},
|
||||
"toast": {
|
||||
"success": "Video snimke povezane s odabranim preglednim stavcima uspješno su izbrisane.",
|
||||
"error": "Neuspješno brisanje: {{error}}"
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"export": "Izvoz",
|
||||
"markAsReviewed": "Označi kao pregledano",
|
||||
"markAsUnreviewed": "Označi kao nepregledano",
|
||||
"deleteNow": "Obriši sada"
|
||||
}
|
||||
},
|
||||
"imagePicker": {
|
||||
"selectImage": "Odaberite minijaturu praćenog objekta",
|
||||
"unknownLabel": "Sačuvana slika izazivača",
|
||||
"search": {
|
||||
"placeholder": "Pretraga po oznaci ili podoznaci..."
|
||||
},
|
||||
"noImages": "Nema mini prikaza za ovu kameru"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"filter": "Filtar",
|
||||
"classes": {
|
||||
"label": "Klase",
|
||||
"all": {
|
||||
"title": "Sve klase"
|
||||
},
|
||||
"count_one": "{{count}} Klasa",
|
||||
"count_other": "{{count}} Klase"
|
||||
},
|
||||
"labels": {
|
||||
"label": "Oznake",
|
||||
"all": {
|
||||
"title": "Sve oznake",
|
||||
"short": "Oznake"
|
||||
},
|
||||
"count_one": "{{count}} Oznaka",
|
||||
"count_other": "{{count}} Oznake"
|
||||
},
|
||||
"zones": {
|
||||
"label": "Zone",
|
||||
"all": {
|
||||
"title": "Sve zone",
|
||||
"short": "Zone"
|
||||
}
|
||||
},
|
||||
"dates": {
|
||||
"selectPreset": "Odaberite predpostavku…",
|
||||
"all": {
|
||||
"title": "Svi datumi",
|
||||
"short": "Datumi"
|
||||
}
|
||||
},
|
||||
"more": "Više filtera",
|
||||
"reset": {
|
||||
"label": "Poništi filtere na zadane vrijednosti"
|
||||
},
|
||||
"timeRange": "Vremenski opseg",
|
||||
"subLabels": {
|
||||
"label": "Podoznake",
|
||||
"all": "Sve podoznake"
|
||||
},
|
||||
"attributes": {
|
||||
"label": "Atributi klasifikacije",
|
||||
"all": "Svi atributi"
|
||||
},
|
||||
"score": "Rezultat",
|
||||
"estimatedSpeed": "Procijenjena brzina ({{unit}})",
|
||||
"features": {
|
||||
"label": "Funkcije",
|
||||
"hasSnapshot": "Ima snimak",
|
||||
"hasVideoClip": "Ima video zapis",
|
||||
"submittedToFrigatePlus": {
|
||||
"label": "Predano Frigate+",
|
||||
"tips": "Prvo morate filtrirati prateće objekte koji imaju snimak.<br /><br />Prateći objekti bez snimka ne mogu se poslati na Frigate+."
|
||||
}
|
||||
},
|
||||
"sort": {
|
||||
"label": "Sortiraj",
|
||||
"dateAsc": "Datum (Uzlazno)",
|
||||
"dateDesc": "Datum (Silazno)",
|
||||
"scoreAsc": "Ocjena objekta (Uzlazno)",
|
||||
"scoreDesc": "Ocjena objekta (Silazno)",
|
||||
"speedAsc": "Procijenjena brzina (Uzlazno)",
|
||||
"speedDesc": "Procijenjena brzina (Silazno)",
|
||||
"relevance": "Relevantnost"
|
||||
},
|
||||
"cameras": {
|
||||
"label": "Filter kamere",
|
||||
"all": {
|
||||
"title": "Sve Kamere",
|
||||
"short": "Kamere"
|
||||
}
|
||||
},
|
||||
"review": {
|
||||
"showReviewed": "Prikaži pregledane"
|
||||
},
|
||||
"motion": {
|
||||
"showMotionOnly": "Prikaži samo pokret"
|
||||
},
|
||||
"explore": {
|
||||
"settings": {
|
||||
"title": "Postavke",
|
||||
"defaultView": {
|
||||
"title": "Zadani prikaz",
|
||||
"desc": "Kada nisu odabrani filteri, prikazuje se sažetak najnovijih pratećih objekata po oznaci, ili prikazuje se mreža bez filtriranja.",
|
||||
"summary": "Sažetak",
|
||||
"unfilteredGrid": "Mreža bez filtriranja"
|
||||
},
|
||||
"gridColumns": {
|
||||
"title": "Kolone mreže",
|
||||
"desc": "Odaberite broj kolona u prikazu mreže."
|
||||
},
|
||||
"searchSource": {
|
||||
"label": "Izvor pretrage",
|
||||
"desc": "Odaberite da li ćete pretraživati miniaturne slike ili opise vaših praćenih objekata.",
|
||||
"options": {
|
||||
"thumbnailImage": "Miniaturna slika",
|
||||
"description": "Opis"
|
||||
}
|
||||
}
|
||||
},
|
||||
"date": {
|
||||
"selectDateBy": {
|
||||
"label": "Odaberite datum za filtriranje"
|
||||
}
|
||||
}
|
||||
},
|
||||
"logSettings": {
|
||||
"label": "Filtrirajte nivo zapisa",
|
||||
"filterBySeverity": "Filtrirajte zapise prema ozbiljnosti",
|
||||
"loading": {
|
||||
"title": "Učitavanje",
|
||||
"desc": "Kada se panel zapisa pomakne do dna, novi zapisi automatski se prikazuju kada se dodaju."
|
||||
},
|
||||
"disableLogStreaming": "Onemogući praćenje zapisa",
|
||||
"allLogs": "Svi zapisi"
|
||||
},
|
||||
"trackedObjectDelete": {
|
||||
"title": "Potvrdi brisanje",
|
||||
"desc": "Brisanje ovih {{objectLength}} praćenih objekata uklanja snimku, bilo koje sačuvane ugradnje, i sve povezane uloge objekata. Snimljeni materijal ovih praćenih objekata u pogledu Historija <em>NEĆE</em> biti obrisan.<br /><br />Sigurni ste da želite nastaviti?<br /><br />Zadržite tipku <em>Shift</em> da biste preskočili ovaj dijalog u budućnosti.",
|
||||
"toast": {
|
||||
"success": "Praćeni objekti uspješno obrisani.",
|
||||
"error": "Neuspješno brisanje praćenih objekata: {{errorMessage}}"
|
||||
}
|
||||
},
|
||||
"zoneMask": {
|
||||
"filterBy": "Filtriraj po maski zone"
|
||||
},
|
||||
"recognizedLicensePlates": {
|
||||
"title": "Prepoznate tablice",
|
||||
"loadFailed": "Neuspješno učitavanje prepoznatih tablica.",
|
||||
"loading": "Učitavanje prepoznatih tablica…",
|
||||
"placeholder": "Unesite za pretragu tablica…",
|
||||
"noLicensePlatesFound": "Nema pronađenih tablica.",
|
||||
"selectPlatesFromList": "Odaberite jednu ili više tablica iz liste.",
|
||||
"selectAll": "Odaberite sve",
|
||||
"clearAll": "Očistite sve"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"iconPicker": {
|
||||
"selectIcon": "Odaberite ikonu",
|
||||
"search": {
|
||||
"placeholder": "Pretražite ikonu…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"button": {
|
||||
"downloadVideo": {
|
||||
"label": "Preuzimanje videa",
|
||||
"toast": {
|
||||
"success": "Vaš video stavke pregleda je započelo preuzimanje."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"noRecordingsFoundForThisTime": "Nisu pronađeni snimci za ovo vrijeme",
|
||||
"noPreviewFound": "Nije pronađen pregled",
|
||||
"noPreviewFoundFor": "Nije pronađen pregled za {{cameraName}}",
|
||||
"submitFrigatePlus": {
|
||||
"title": "Pošalji ovaj okvir Frigate+?",
|
||||
"submit": "Pošalji",
|
||||
"previewError": "Nije moguće učitati prikaz snimke. Snimka možda trenutno nije dostupna."
|
||||
},
|
||||
"livePlayerRequiredIOSVersion": "Za ovaj tip uživo prijenosa potreban je iOS 17.1 ili noviji.",
|
||||
"streamOffline": {
|
||||
"title": "Prijenos je offline",
|
||||
"desc": "Nisu primljeni okviri na {{cameraName}} <code>detect</code> prijenos, provjerite zapise o greškama"
|
||||
},
|
||||
"cameraDisabled": "Kamera je onemogućena",
|
||||
"stats": {
|
||||
"streamType": {
|
||||
"title": "Tip prijenosa:",
|
||||
"short": "Tip"
|
||||
},
|
||||
"bandwidth": {
|
||||
"title": "Širina pojasa:",
|
||||
"short": "Širina pojasa"
|
||||
},
|
||||
"latency": {
|
||||
"title": "Kasnjenje:",
|
||||
"value": "{{seconds}} sekundi",
|
||||
"short": {
|
||||
"title": "Kasnjenje",
|
||||
"value": "{{seconds}} sek"
|
||||
}
|
||||
},
|
||||
"totalFrames": "Ukupno okvira:",
|
||||
"droppedFrames": {
|
||||
"title": "Izgubljeni okviri:",
|
||||
"short": {
|
||||
"title": "Izgubljeni",
|
||||
"value": "{{droppedFrames}} okvira"
|
||||
}
|
||||
},
|
||||
"decodedFrames": "Dekodirani okviri:",
|
||||
"droppedFrameRate": "Stopa izgubljenih okvira:"
|
||||
},
|
||||
"toast": {
|
||||
"success": {
|
||||
"submittedFrigatePlus": "Uspješno je poslano okvir Frigate+"
|
||||
},
|
||||
"error": {
|
||||
"submitFrigatePlusFailed": "Neuspješno slanje okvira Frigate+"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,949 @@
|
||||
{
|
||||
"label": "KameraKonfig",
|
||||
"zones": {
|
||||
"label": "Zone",
|
||||
"description": "Zona omogućava da definirate specifičnu područje okvira da biste odredili je li objekt unutar određenog područja.",
|
||||
"friendly_name": {
|
||||
"label": "Ime zone",
|
||||
"description": "Korisničko ime za zonu, prikazano u UI Frigate. Ako nije postavljeno, koristi se oblikovana verzija imena zone."
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Omogućeno",
|
||||
"description": "Omogući ili onemogući ovu zonu. Onemogućene zone zanemaruju se tijekom izvršavanja."
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Zapamti originalno stanje zone."
|
||||
},
|
||||
"filters": {
|
||||
"label": "Filtri zone",
|
||||
"description": "Filtri za primjenu na objekte unutar ove zone. Koriste se za smanjenje lažnih pozitiva ili ograničavanje kojih objekata se smatraju prisutnim u zoni.",
|
||||
"min_area": {
|
||||
"label": "Minimalna površina objekta",
|
||||
"description": "Minimalna površina okvira (pikseli ili postotak) potrebna za ovaj tip objekta. Može biti pikseli (cijeli broj) ili postotak (float između 0.000001 i 0.99)."
|
||||
},
|
||||
"max_area": {
|
||||
"label": "Maksimalna površina objekta",
|
||||
"description": "Maksimalna površina okvira (pikseli ili postotak) dozvoljena za ovaj tip objekta. Može biti pikseli (cijeli broj) ili postotak (float između 0.000001 i 0.99)."
|
||||
},
|
||||
"min_ratio": {
|
||||
"label": "Minimalni omjer visine/širine",
|
||||
"description": "Minimalni omjer širine/visine potreban da bi okvir bio prihvaćen."
|
||||
},
|
||||
"max_ratio": {
|
||||
"label": "Maksimalni omjer visine/širine",
|
||||
"description": "Maksimalni omjer širine/visine dozvoljen da bi okvir bio prihvaćen."
|
||||
},
|
||||
"threshold": {
|
||||
"label": "Prag pouzdanosti",
|
||||
"description": "Prosjek pragova pouzdanosti detekcije potreban da bi objekt bio smatravan pravim pozitivom."
|
||||
},
|
||||
"min_score": {
|
||||
"label": "Minimalna pouzdanost",
|
||||
"description": "Minimalna pouzdanost detekcije po okviru potrebna da bi objekt bio brojan."
|
||||
},
|
||||
"mask": {
|
||||
"label": "Maska filtriranja",
|
||||
"description": "Koordinate poligona koje definiraju područje na kojem se ovaj filter primjenjuje unutar okvira."
|
||||
},
|
||||
"raw_mask": {
|
||||
"label": "Ručna maska"
|
||||
}
|
||||
},
|
||||
"coordinates": {
|
||||
"label": "Koordinate",
|
||||
"description": "Koordinate poligona koje definiraju područje zone. Može biti niz razdvojen zarezom ili lista nizova koordinata. Koordinate trebaju biti relativne (0-1) ili apsolutne (stariji format)."
|
||||
},
|
||||
"distances": {
|
||||
"label": "Stvarne udaljenosti",
|
||||
"description": "Nepovlačni stvarne udaljenosti za svaku stranu kvadrilateralne zone, koristi se za izračun brzine ili udaljenosti. Moraju imati tačno 4 vrijednosti ako su postavljene."
|
||||
},
|
||||
"inertia": {
|
||||
"label": "Okviri inertnosti",
|
||||
"description": "Broj uzastopnih okvira u kojima mora biti detektovan objekt u zoni da bi bio smatravan prisutnim. Pomaže u filtriranju privremenih detekcija."
|
||||
},
|
||||
"loitering_time": {
|
||||
"label": "Sekunde loiteranja",
|
||||
"description": "Broj sekundi koje objekt mora ostati u zoni da bi bio smatravan loiteranjem. Postaviti na 0 za onemogućavanje detekcije loiteranja."
|
||||
},
|
||||
"speed_threshold": {
|
||||
"label": "Minimalna brzina",
|
||||
"description": "Minimalna brzina (u stvarnim jedinicama ako su udaljenosti postavljene) potrebna da bi objekt bio smatravan prisutnim u zoni. Koristi se za zone koje se aktiviraju na osnovu brzine."
|
||||
},
|
||||
"objects": {
|
||||
"label": "Objekti koji izazivaju",
|
||||
"description": "Lista tipova objekata (iz labelmapa) koji mogu izazvati ovu zonu. Može biti niz ili lista nizova. Ako je prazna, svi objekti se uzimaju u obzir."
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"label": "Ime kamere",
|
||||
"description": "Ime kamere je obavezno"
|
||||
},
|
||||
"friendly_name": {
|
||||
"label": "Prijateljsko ime",
|
||||
"description": "Prijateljsko ime kamere korišteno u korisničkom sučelju Frigate"
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Omogućeno",
|
||||
"description": "Omogućeno"
|
||||
},
|
||||
"audio": {
|
||||
"label": "Audio događaji",
|
||||
"description": "Postavke za detekciju događaja temeljene na audio.",
|
||||
"enabled": {
|
||||
"label": "Omogući detekciju zvuka",
|
||||
"description": "Omogući ili onemogući detekciju događaja temeljenu na audio za ovu kameru."
|
||||
},
|
||||
"max_not_heard": {
|
||||
"label": "Vrijeme trajanja do kraja",
|
||||
"description": "Količina sekundi bez konfiguriranog tipa zvuka prije nego što se audio događaj završi."
|
||||
},
|
||||
"min_volume": {
|
||||
"label": "Minimalna zapremina",
|
||||
"description": "Minimalni prag RMS zapremine potreban za pokretanje detekcije zvuka; niže vrijednosti povećavaju osjetljivost (npr. 200 visoko, 500 srednje, 1000 nisko)."
|
||||
},
|
||||
"listen": {
|
||||
"label": "Tipovi slušanja",
|
||||
"description": "Popis tipova audio događaja za detekciju (npr. zavijanje, požarne zvona, vrisak, govorenje, vikanje)."
|
||||
},
|
||||
"filters": {
|
||||
"label": "Audio filteri",
|
||||
"description": "Postavke filtera po tipu zvuka kao što su pragovi pouzdanosti za smanjenje lažnih pozitiva."
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Originalno stanje zvuka",
|
||||
"description": "Indikuje je li detekcija zvuka izvorno omogućena u statičkoj konfiguracijskoj datoteci."
|
||||
},
|
||||
"num_threads": {
|
||||
"label": "Dretve detekcije",
|
||||
"description": "Broj dretvi za korištenje za obradu detekcije zvuka."
|
||||
}
|
||||
},
|
||||
"audio_transcription": {
|
||||
"label": "Transkripcija zvuka",
|
||||
"description": "Postavke za transkripciju živog i govornog zvuka korištenih za događaje i žive podnaslove.",
|
||||
"enabled": {
|
||||
"label": "Omogući transkripciju",
|
||||
"description": "Omogući ili onemogući transkripciju audio događaja pokrenutu ručno."
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Originalni stanje transkripcije"
|
||||
},
|
||||
"live_enabled": {
|
||||
"label": "Uživo transkripcija",
|
||||
"description": "Omogući streaming uživo transkripcije za audio dok se prima."
|
||||
}
|
||||
},
|
||||
"birdseye": {
|
||||
"label": "Birdseye",
|
||||
"description": "Postavke za sastavni prikaz Birdseye koji kombinuje više snimke kamere u jedinstveni raspored.",
|
||||
"enabled": {
|
||||
"label": "Omogući Birdseye",
|
||||
"description": "Omogući ili onemogući funkciju prikaza Birdseye."
|
||||
},
|
||||
"mode": {
|
||||
"label": "Način praćenja",
|
||||
"description": "Način uključivanja kamera u Birdseye: 'objekti', 'kretanje' ili 'kontinuirano'."
|
||||
},
|
||||
"order": {
|
||||
"label": "Pozicija",
|
||||
"description": "Numerička pozicija koja kontroliše redoslijed kamera u rasporedu Birdseye."
|
||||
}
|
||||
},
|
||||
"detect": {
|
||||
"label": "Detekcija objekata",
|
||||
"description": "Postavke za ulogu detekcije/detekcija koja se koristi za pokretanje detekcije objekata i inicijalizaciju praćenja.",
|
||||
"enabled": {
|
||||
"label": "Omogući detekciju objekata",
|
||||
"description": "Omogući ili onemogući detekciju objekata za ovu kameru."
|
||||
},
|
||||
"height": {
|
||||
"label": "Visina detekcije",
|
||||
"description": "Visina (pikseli) okvira korištenih za detekciju stream-a; ostavite prazno za korištenje originalne rezolucije stream-a."
|
||||
},
|
||||
"width": {
|
||||
"label": "Širina detekcije",
|
||||
"description": "Širina (pikseli) okvira korištenih za detekciju stream-a; ostavite prazno za korištenje originalne rezolucije stream-a."
|
||||
},
|
||||
"fps": {
|
||||
"label": "Detekcija FPS",
|
||||
"description": "Željeni broj okvira po sekundi za pokretanje detekcije; niže vrijednosti smanjuju upotrebu CPU-a (preporučena vrijednost je 5, postavite više - najviše 10 - samo ako praćite vrlo brze objekte)."
|
||||
},
|
||||
"min_initialized": {
|
||||
"label": "Minimalni broj okvira inicijalizacije",
|
||||
"description": "Broj uzastopnih detekcija potreban prije stvaranja praćenog objekta. Povećajte da biste smanjili lažne inicijalizacije. Zadana vrijednost je fps podijeljeno sa 2."
|
||||
},
|
||||
"max_disappeared": {
|
||||
"label": "Maksimalni broj okvira koji su nestali",
|
||||
"description": "Broj okvira bez detekcije prije nego što se praćeni objekt smatra izgubljenim."
|
||||
},
|
||||
"stationary": {
|
||||
"label": "Konfiguracija stacionarnih objekata",
|
||||
"description": "Postavke za detekciju i upravljanje objektima koji ostaju stacionarni tokom određenog vremena.",
|
||||
"interval": {
|
||||
"label": "Stacionarni interval",
|
||||
"description": "Kako često (u snimcima) pokretati provjeru detekcije da biste potvrdili stacionarni objekt."
|
||||
},
|
||||
"threshold": {
|
||||
"label": "Stacionarni prag",
|
||||
"description": "Broj snimaka bez promjene pozicije potreban da bi objekt bio označen kao stacionarni."
|
||||
},
|
||||
"max_frames": {
|
||||
"label": "Maksimalni snimci",
|
||||
"description": "Ograničava koliko dugo se stacionarni objekti praćaju prije nego što se odbacuju.",
|
||||
"default": {
|
||||
"label": "Zadani maksimalni snimci",
|
||||
"description": "Zadani maksimalni broj snimaka za praćenje stacionarnog objekta prije prestanka."
|
||||
},
|
||||
"objects": {
|
||||
"label": "Maksimalni snimci po objektu",
|
||||
"description": "Podešavanja po objektu za maksimalni broj snimaka za praćenje stacionarnih objekata."
|
||||
}
|
||||
},
|
||||
"classifier": {
|
||||
"label": "Omogući vizualni klasifikator",
|
||||
"description": "Koristi vizualni klasifikator za detekciju pravozadanih stacionarnih objekata čak i kada se okviri tresu."
|
||||
}
|
||||
},
|
||||
"annotation_offset": {
|
||||
"label": "Pomak oznake",
|
||||
"description": "Milisekunde za pomak detektiranih oznaka kako bi se bolje poravnali vremenski okviri s snimcima; može biti pozitivan ili negativan."
|
||||
}
|
||||
},
|
||||
"face_recognition": {
|
||||
"label": "Prepoznavanje lica",
|
||||
"description": "Postavke za detekciju i prepoznavanje lica za ovu kameru.",
|
||||
"enabled": {
|
||||
"label": "Omogući prepoznavanje lica",
|
||||
"description": "Omogući ili onemogući prepoznavanje lica."
|
||||
},
|
||||
"min_area": {
|
||||
"label": "Minimalna površina lica",
|
||||
"description": "Minimalna površina (pikseli) detektiranog okvira lica potrebna za pokušaj prepoznavanja."
|
||||
}
|
||||
},
|
||||
"ffmpeg": {
|
||||
"label": "FFmpeg",
|
||||
"description": "Postavke FFmpeg uključuju putanju binarne datoteke, argumente, opcije hwaccel i izlazne argumente po ulozi.",
|
||||
"path": {
|
||||
"label": "Putanja do FFmpeg binarne datoteke",
|
||||
"description": "Putanja do FFmpeg binarne datoteke ili verzija alias (\"5.0\" ili \"7.0\")."
|
||||
},
|
||||
"global_args": {
|
||||
"label": "Globalni argumenti FFmpeg-a",
|
||||
"description": "Globalni argumenti prebačeni na procese FFmpeg."
|
||||
},
|
||||
"hwaccel_args": {
|
||||
"label": "Argumenti za ubrzanje hardvera",
|
||||
"description": "Argumenti za ubrzanje hardvera za FFmpeg. Preporučuju se predložci specifični za dobavljača."
|
||||
},
|
||||
"input_args": {
|
||||
"label": "Unos argumenata",
|
||||
"description": "Ulazni argumenti primjenjeni na ulazne snimke FFmpeg."
|
||||
},
|
||||
"output_args": {
|
||||
"label": "Izlazni argumenti",
|
||||
"description": "Zadani izlazni argumenti korišteni za različite uloge FFmpeg-a poput detekcije i snimanja.",
|
||||
"detect": {
|
||||
"label": "Izlazni argumenti za detekciju",
|
||||
"description": "Zadani izlazni argumenti za snimke uloga detekcije."
|
||||
},
|
||||
"record": {
|
||||
"label": "Izlazni argumenti za snimanje",
|
||||
"description": "Zadani izlazni argumenti za snimke uloga snimanja."
|
||||
}
|
||||
},
|
||||
"retry_interval": {
|
||||
"label": "Vrijeme ponovnog pokušaja FFmpeg-a",
|
||||
"description": "Sekunde koje treba čekati prije nego što se pokuša ponovno uspostaviti veza s tokom kamere nakon neuspjeha. Zadano je 10."
|
||||
},
|
||||
"apple_compatibility": {
|
||||
"label": "Kompatibilnost s Apple-om",
|
||||
"description": "Omogući označavanje HEVC za bolju kompatibilnost s igračima Apple-a prilikom snimanja H.265."
|
||||
},
|
||||
"gpu": {
|
||||
"label": "Indeks GPU-a",
|
||||
"description": "Zadani indeks GPU-a korišten za ubrzanje hardvera ako je dostupan."
|
||||
},
|
||||
"inputs": {
|
||||
"label": "Ulazni podaci kamere",
|
||||
"description": "Popis definicija ulaznih tokova (putanje i uloge) za ovu kameru.",
|
||||
"path": {
|
||||
"label": "Putanja ulaza",
|
||||
"description": "URL ili putanja ulaznog toka kamere."
|
||||
},
|
||||
"roles": {
|
||||
"label": "Uloge ulaza",
|
||||
"description": "Uloge za ovaj ulazni tok."
|
||||
},
|
||||
"global_args": {
|
||||
"label": "Globalni argumenti FFmpeg-a",
|
||||
"description": "Globalni argumenti FFmpeg-a za ovaj ulazni tok."
|
||||
},
|
||||
"hwaccel_args": {
|
||||
"label": "Argumenti za ubrzanje hardvera",
|
||||
"description": "Argumenti za ubrzanje hardvera za ovaj ulazni stream."
|
||||
},
|
||||
"input_args": {
|
||||
"label": "Unos argumenata",
|
||||
"description": "Argumeti unosa specifični za ovaj stream."
|
||||
}
|
||||
}
|
||||
},
|
||||
"live": {
|
||||
"label": "Uživo prikaz",
|
||||
"description": "Postavke korištenje Web UI za kontrolu izbora živog streama, rezolucije i kvalitete.",
|
||||
"streams": {
|
||||
"label": "Imena živih streamova",
|
||||
"description": "Mapiranje konfiguriranih imena streamova na imena restream/go2rtc korишtena za uživo prikaz."
|
||||
},
|
||||
"height": {
|
||||
"label": "Visina uživo",
|
||||
"description": "Visina (piksela) za prikaz jsmpeg živog streama u Web UI; mora biti <= visina detektiranog streama."
|
||||
},
|
||||
"quality": {
|
||||
"label": "Kvalitet uživo",
|
||||
"description": "Kvalitet kodiranja za jsmpeg stream (1 najviši, 31 najniži)."
|
||||
}
|
||||
},
|
||||
"lpr": {
|
||||
"label": "Prepoznavanje tablice vozila",
|
||||
"description": "Postavke prepoznavanja tablice vozila uključujući pragovi detekcije, formatiranje i poznate tablice.",
|
||||
"enabled": {
|
||||
"label": "Omogući LPR",
|
||||
"description": "Omogući ili onemogući LPR na ovoj kameri."
|
||||
},
|
||||
"expire_time": {
|
||||
"label": "Sekunde isteka",
|
||||
"description": "Vrijeme u sekundama nakon kojeg nevidljiva tablica istječe iz praćenja (samo za dedikovane LPR kamere)."
|
||||
},
|
||||
"min_area": {
|
||||
"label": "Minimalna površina tablice",
|
||||
"description": "Minimalna površina tablice (piksela) potrebna za pokušaj prepoznavanja."
|
||||
},
|
||||
"enhancement": {
|
||||
"label": "Nivo poboljšanja",
|
||||
"description": "Nivo poboljšanja (0-10) za primjenu na isječke tablice prije OCR-a; veće vrijednosti ne moraju uvijek poboljšati rezultate, nivoi iznad 5 mogu raditi samo s tablicama u noćnom vremenu i trebaju se koristiti s oprezom."
|
||||
}
|
||||
},
|
||||
"motion": {
|
||||
"label": "Detekcija pokreta",
|
||||
"description": "Zadane postavke detekcije pokreta za ovu kameru.",
|
||||
"enabled": {
|
||||
"label": "Omogući detekciju pokreta",
|
||||
"description": "Omogući ili onemogući detekciju pokreta za ovu kameru."
|
||||
},
|
||||
"threshold": {
|
||||
"label": "Prag pokreta",
|
||||
"description": "Prag razlike piksela korišten za detektor pokreta; veće vrijednosti smanjuju osjetljivost (opseg 1-255)."
|
||||
},
|
||||
"lightning_threshold": {
|
||||
"label": "Prag munje",
|
||||
"description": "Prag za detekciju i zanemarivanje kratkih iskri svjetlosti (niže vrijednosti povećavaju osjetljivost, vrijednosti između 0.3 i 1.0). Ovo ne spriječava detekciju pokreta u potpunosti; jednostavno zaustavlja detektor da analizira dodatne okvire nakon što se prag premaši. Snimci temeljeni na pokretima i dalje se stvaraju tijekom ovih događaja."
|
||||
},
|
||||
"skip_motion_threshold": {
|
||||
"label": "Preskoči prag pokreta",
|
||||
"description": "Ako se postavi na vrijednost između 0.0 i 1.0, i ako se više od ovog udjela slike promijeni u jednom okviru, detektor neće vratiti kutije pokreta i odmah će se ponovno kalibrirati. Ovo može uštedjeti CPU i smanjiti lažne pozitive tijekom munje, oluje itd., ali može propustiti stvarne događaje kao što je automatsko praćenje objekta PTZ kamerom. Tržište je između izgube nekoliko megabajta snimaka i pregleda nekoliko kratkih zapisnika. Ostavite nepostavljeno (Nijedno) za onemogućavanje ove funkcije."
|
||||
},
|
||||
"improve_contrast": {
|
||||
"label": "Poboljšaj kontrast",
|
||||
"description": "Primijeni poboljšanje kontrasta na okvire prije analize pokreta kako bi pomoću detekcije."
|
||||
},
|
||||
"contour_area": {
|
||||
"label": "Površina kontura",
|
||||
"description": "Minimalna površina kontura u pikselima potrebna za brojanje kontura pokreta."
|
||||
},
|
||||
"delta_alpha": {
|
||||
"label": "Delta alfa",
|
||||
"description": "Faktor alfa spajanja korišten za razliku okvira za izračun pokreta."
|
||||
},
|
||||
"frame_alpha": {
|
||||
"label": "Alfa okvira",
|
||||
"description": "Vrijednost alfa korištena prilikom spajanja okvira za predobradbu pokreta."
|
||||
},
|
||||
"frame_height": {
|
||||
"label": "Visina okvira",
|
||||
"description": "Visina u pikselima na koju se skaliraju okviri prilikom izračuna pokreta."
|
||||
},
|
||||
"mask": {
|
||||
"label": "Koordinate maska",
|
||||
"description": "Uredno x,y koordinate koje definiraju poligon maska pokreta za uključivanje/isključivanje područja."
|
||||
},
|
||||
"mqtt_off_delay": {
|
||||
"label": "MQTT zakasnjenje isključivanja",
|
||||
"description": "Sekunde koje se čekaju nakon posljednjeg pokreta prije objave MQTT 'isključeno' stanje."
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Originalno stanje pokreta",
|
||||
"description": "Indikira je li detekcija pokreta bila omogućena u originalnoj statičkoj konfiguraciji."
|
||||
},
|
||||
"raw_mask": {
|
||||
"label": "Ručna maska"
|
||||
}
|
||||
},
|
||||
"objects": {
|
||||
"label": "Objekti",
|
||||
"description": "Zadani parametri praćenja objekata uključujući koje oznake praćenja i filtre po objektu.",
|
||||
"track": {
|
||||
"label": "Objekti za praćenje",
|
||||
"description": "Popis oznaka objekata za praćenje za ovu kameru."
|
||||
},
|
||||
"filters": {
|
||||
"label": "Filtar objekata",
|
||||
"description": "Filtar primijenjen na detektirane objekte kako bi se smanjila broj lažnih pozitiva (površina, omjer, pouzdanost).",
|
||||
"min_area": {
|
||||
"label": "Minimalna površina objekta",
|
||||
"description": "Minimalna površina okvira (pikseli ili postotak) potrebna za ovaj tip objekta. Može biti pikseli (cijeli broj) ili postotak (float između 0.000001 i 0.99)."
|
||||
},
|
||||
"max_area": {
|
||||
"label": "Maksimalna površina objekta",
|
||||
"description": "Maksimalna površina okvira (pikseli ili postotak) dozvoljena za ovaj tip objekta. Može biti pikseli (cijeli broj) ili postotak (float između 0.000001 i 0.99)."
|
||||
},
|
||||
"min_ratio": {
|
||||
"label": "Minimalni omjer visine/širine",
|
||||
"description": "Minimalni omjer širine/visine potreban da bi okvir bio prihvaćen."
|
||||
},
|
||||
"max_ratio": {
|
||||
"label": "Maksimalni omjer visine/širine",
|
||||
"description": "Maksimalni omjer širine/visine dozvoljen da bi okvir bio prihvaćen."
|
||||
},
|
||||
"threshold": {
|
||||
"label": "Prag pouzdanosti",
|
||||
"description": "Prosjek pragova pouzdanosti detekcije potreban da bi objekt bio smatravan pravim pozitivom."
|
||||
},
|
||||
"min_score": {
|
||||
"label": "Minimalna pouzdanost",
|
||||
"description": "Minimalna pouzdanost detekcije po okviru potrebna da bi objekt bio brojan."
|
||||
},
|
||||
"mask": {
|
||||
"label": "Maska filtriranja",
|
||||
"description": "Koordinate poligona koje definiraju područje na kojem se ovaj filter primjenjuje unutar okvira."
|
||||
},
|
||||
"raw_mask": {
|
||||
"label": "Ručna maska"
|
||||
}
|
||||
},
|
||||
"mask": {
|
||||
"label": "Maska objekta",
|
||||
"description": "Poligonalna maska korištena za spriječavanje detekcije objekta u određenim područjima."
|
||||
},
|
||||
"raw_mask": {
|
||||
"label": "Ručna maska"
|
||||
},
|
||||
"genai": {
|
||||
"label": "Konfiguracija GenAI objekta",
|
||||
"description": "Opcije GenAI za opisivanje praćenih objekata i slanje okvira za generisanje.",
|
||||
"enabled": {
|
||||
"label": "Omogući GenAI",
|
||||
"description": "Omogući generisanje opisa za praćene objekte po zadanim postavkama."
|
||||
},
|
||||
"use_snapshot": {
|
||||
"label": "Koristi snimke",
|
||||
"description": "Koristi snimke objekata umjesto miniaturnih slika za generisanje opisa GenAI."
|
||||
},
|
||||
"prompt": {
|
||||
"label": "Naslovni prompt",
|
||||
"description": "Zadani šablon upita korišten za generisanje opisa pomoću GenAI."
|
||||
},
|
||||
"object_prompts": {
|
||||
"label": "Prompti za objekte",
|
||||
"description": "Prompti po objektu za prilagođavanje izlaza GenAI za specifične oznake."
|
||||
},
|
||||
"objects": {
|
||||
"label": "GenAI objekti",
|
||||
"description": "Popis oznaka objekata koje se po defaultu šalju GenAI."
|
||||
},
|
||||
"required_zones": {
|
||||
"label": "Potrebne zone",
|
||||
"description": "Zone koje moraju biti unesene za objekte da bi se kvalifikovali za generisanje opisa GenAI."
|
||||
},
|
||||
"debug_save_thumbnails": {
|
||||
"label": "Sačuvajte miniaturne slike",
|
||||
"description": "Sačuvaj miniaturne slike koje se šalju GenAI za ispravljanje i pregled."
|
||||
},
|
||||
"send_triggers": {
|
||||
"label": "GenAI izazivači",
|
||||
"description": "Definiše kada bi se trebale slati okvir za GenAI (na kraju, nakon ažuriranja, itd.).",
|
||||
"tracked_object_end": {
|
||||
"label": "Pošalji na kraju",
|
||||
"description": "Pošalji zahtjev GenAI kada praćeni objekt završi."
|
||||
},
|
||||
"after_significant_updates": {
|
||||
"label": "Raniji GenAI izazivač",
|
||||
"description": "Pošalji zahtjev GenAI nakon određenog broja značajnih ažuriranja za praćeni objekt."
|
||||
}
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Originalno stanje GenAI",
|
||||
"description": "Pokazuje je li GenAI bio omogućen u originalnoj statičkoj konfiguraciji."
|
||||
}
|
||||
}
|
||||
},
|
||||
"record": {
|
||||
"label": "Snimanje",
|
||||
"description": "Postavke snimanja i zadržavanja za ovu kameru.",
|
||||
"enabled": {
|
||||
"label": "Omogući snimanje",
|
||||
"description": "Omogući ili onemogući snimanje za ovu kameru."
|
||||
},
|
||||
"expire_interval": {
|
||||
"label": "Interval čišćenja snimanja",
|
||||
"description": "Minute između čišćenja koja uklanjaju istekle segmente snimaka."
|
||||
},
|
||||
"continuous": {
|
||||
"label": "Neprekidna retencija",
|
||||
"description": "Broj dana za čuvanje snimaka bez obzira na praćene objekte ili pokret. Postavite na 0 ako želite da čuvate samo snimke upozorenja i detekcije.",
|
||||
"days": {
|
||||
"label": "Dane zadržavanja",
|
||||
"description": "Dana za čuvanje snimaka."
|
||||
}
|
||||
},
|
||||
"motion": {
|
||||
"label": "Retencija pokreta",
|
||||
"description": "Broj dana za čuvanje snimaka izazvanih pokretom bez obzira na praćene objekte. Postavite na 0 ako želite da čuvate samo snimke upozorenja i detekcije.",
|
||||
"days": {
|
||||
"label": "Dane zadržavanja",
|
||||
"description": "Dana za čuvanje snimaka."
|
||||
}
|
||||
},
|
||||
"detections": {
|
||||
"label": "Retencija detekcije",
|
||||
"description": "Postavke retencije snimaka za događaje detekcije uključujući trajanje pre/post snimanja.",
|
||||
"pre_capture": {
|
||||
"label": "Sekundi pre snimanja",
|
||||
"description": "Broj sekundi prije događaja detekcije koje treba uključiti u snimak."
|
||||
},
|
||||
"post_capture": {
|
||||
"label": "Sekunde nakon snimanja",
|
||||
"description": "Broj sekundi nakon događaja detekcije koje se uključuju u snimanje."
|
||||
},
|
||||
"retain": {
|
||||
"label": "Zadržavanje događaja",
|
||||
"description": "Postavke zadržavanja za snimke događaja detekcije.",
|
||||
"days": {
|
||||
"label": "Dane zadržavanja",
|
||||
"description": "Broj dana za koje se zadržavaju snimke događaja detekcije."
|
||||
},
|
||||
"mode": {
|
||||
"label": "Način zadržavanja",
|
||||
"description": "Način zadržavanja: sve (sačuvati sve segmente), pokret (sačuvati segmente s pokretom), ili aktivni_objekti (sačuvati segmente s aktivnim objektima)."
|
||||
}
|
||||
}
|
||||
},
|
||||
"alerts": {
|
||||
"label": "Retencija upozorenja",
|
||||
"description": "Postavke retencije snimaka za događaje upozorenja uključujući trajanje pre/post snimanja.",
|
||||
"pre_capture": {
|
||||
"label": "Sekundi pre snimanja",
|
||||
"description": "Broj sekundi prije događaja detekcije koje treba uključiti u snimak."
|
||||
},
|
||||
"post_capture": {
|
||||
"label": "Sekunde nakon snimanja",
|
||||
"description": "Broj sekundi nakon događaja detekcije koje se uključuju u snimanje."
|
||||
},
|
||||
"retain": {
|
||||
"label": "Zadržavanje događaja",
|
||||
"description": "Postavke zadržavanja za snimke događaja detekcije.",
|
||||
"days": {
|
||||
"label": "Dane zadržavanja",
|
||||
"description": "Broj dana za koje se zadržavaju snimke događaja detekcije."
|
||||
},
|
||||
"mode": {
|
||||
"label": "Način zadržavanja",
|
||||
"description": "Način zadržavanja: sve (sačuvati sve segmente), pokret (sačuvati segmente s pokretom), ili aktivni_objekti (sačuvati segmente s aktivnim objektima)."
|
||||
}
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"label": "Konfiguracija izvoza",
|
||||
"description": "Postavke koje se koriste prilikom izvoza snimaka kao što su timelapse i ubrzavanje dretve.",
|
||||
"hwaccel_args": {
|
||||
"label": "Argumeti ubrzavanja dretve za izvoz",
|
||||
"description": "Argumeti ubrzavanja dretve za operacije izvoza/prenosa."
|
||||
},
|
||||
"max_concurrent": {
|
||||
"label": "Maksimalan broj istovremenih izvoza",
|
||||
"description": "Maksimalan broj poslova izvoza koji se obrađuju istovremeno."
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
"label": "Konfiguracija pregleda",
|
||||
"description": "Postavke koje kontrolišu kvalitet pregleda snimanja prikazanih u UI.",
|
||||
"quality": {
|
||||
"label": "Kvaliteta pregleda",
|
||||
"description": "Nivo kvalitete pregleda (vrlo_nizak, nizak, srednji, visok, vrlo_visok)."
|
||||
}
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Originalno stanje snimanja",
|
||||
"description": "Pokazuje je li snimanje bilo omogućeno u originalnoj statičkoj konfiguraciji."
|
||||
}
|
||||
},
|
||||
"review": {
|
||||
"label": "Pregled",
|
||||
"description": "Postavke koje kontrolišu upozorenja, detekcije i sažetke pregleda GenAI korišteni od strane UI i skladišta za ovu kameru.",
|
||||
"alerts": {
|
||||
"label": "Konfiguracija upozorenja",
|
||||
"description": "Postavke za koje objekti praćeni generišu upozorenja i kako se upozorenja zadržavaju.",
|
||||
"enabled": {
|
||||
"label": "Omogući upozorenja",
|
||||
"description": "Omogući ili onemogući generisanje upozorenja za ovu kameru."
|
||||
},
|
||||
"labels": {
|
||||
"label": "Oznake upozorenja",
|
||||
"description": "Lista oznaka objekata koje se smatraju upozorenjima (npr. automobil, osoba)."
|
||||
},
|
||||
"required_zones": {
|
||||
"label": "Potrebne zone",
|
||||
"description": "Zone koje objekt mora ući da bi se smatrao upozorenjem; ostavite prazno da omogućite bilo koju zonu."
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Originalno stanje upozorenja",
|
||||
"description": "Pratiti je li upozorenja izvorno omogućena u statičkoj konfiguraciji."
|
||||
},
|
||||
"cutoff_time": {
|
||||
"label": "Vrijeme prekida upozorenja",
|
||||
"description": "Sekunde koje treba čekati nakon što nema aktivnosti koja uzrokuje upozorenje prije nego se prekine upozorenje."
|
||||
}
|
||||
},
|
||||
"detections": {
|
||||
"label": "Konfiguracija detekcija",
|
||||
"description": "Postavke koje objekti koje se praćenje generišu detekcije (nepozornja) i kako se detekcije čuvaju.",
|
||||
"enabled": {
|
||||
"label": "Omogući detekcije",
|
||||
"description": "Omogući ili onemogući događaje detekcije za ovu kameru."
|
||||
},
|
||||
"labels": {
|
||||
"label": "Oznake detekcije",
|
||||
"description": "Popis oznaka objekata koje kvalifikuju kao događaji detekcije."
|
||||
},
|
||||
"required_zones": {
|
||||
"label": "Potrebne zone",
|
||||
"description": "Zone koje objekt mora ući da bi se smatrao detekcijom; ostavite prazno da omogućite bilo koju zonu."
|
||||
},
|
||||
"cutoff_time": {
|
||||
"label": "Vrijeme prekida detekcija",
|
||||
"description": "Sekunde koje treba čekati nakon što nema aktivnosti koja uzrokuje detekciju prije nego se prekine detekcija."
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Originalno stanje detekcija",
|
||||
"description": "Pratiti je li detekcije izvorno omogućene u statičkoj konfiguraciji."
|
||||
}
|
||||
},
|
||||
"genai": {
|
||||
"label": "Konfiguracija GenAI",
|
||||
"description": "Kontrolira korištenje generativne AI za proizvodnju opisa i sažetaka stavki za pregled.",
|
||||
"enabled": {
|
||||
"label": "Omogući opise GenAI",
|
||||
"description": "Omogući ili onemogući opise i sažetke generirane GenAI za stavke za pregled."
|
||||
},
|
||||
"alerts": {
|
||||
"label": "Omogući GenAI za upozorenja",
|
||||
"description": "Koristi GenAI za generiranje opisa stavki upozorenja."
|
||||
},
|
||||
"detections": {
|
||||
"label": "Omogući GenAI za detekcije",
|
||||
"description": "Koristite GenAI za generiranje opisa predmeta detekcije."
|
||||
},
|
||||
"image_source": {
|
||||
"label": "Pregledajte izvor slike",
|
||||
"description": "Izvor slika poslatih GenAIJ-u ('preview' ili 'recordings'); 'recordings' koristi kvalitetnije okvire, ali više tokena."
|
||||
},
|
||||
"additional_concerns": {
|
||||
"label": "Dodatne brige",
|
||||
"description": "Popis dodatnih briga ili napomena koje GenAI treba uzeti u obzir prilikom procjene aktivnosti na ovoj kameri."
|
||||
},
|
||||
"debug_save_thumbnails": {
|
||||
"label": "Sačuvajte miniaturne slike",
|
||||
"description": "Sačuvajte miniaturne slike koje se šalju GenAI provajderu za ispravljanje grešaka i pregled."
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Originalno stanje GenAI",
|
||||
"description": "Pratiti je li pregled GenAI izvorno omogućen u statičkoj konfiguraciji."
|
||||
},
|
||||
"preferred_language": {
|
||||
"label": "Preferirani jezik",
|
||||
"description": "Preferirani jezik za zahtijevanje od GenAI provajdera za generirane odgovore."
|
||||
},
|
||||
"activity_context_prompt": {
|
||||
"label": "Prompt konteksta aktivnosti",
|
||||
"description": "Prilagođeni prompt koji opisuje što je i što nije sumnjivo ponašanje kako bi pružio kontekst za sažetke GenAI."
|
||||
}
|
||||
}
|
||||
},
|
||||
"semantic_search": {
|
||||
"label": "Semantička pretraga",
|
||||
"description": "Postavke za semantičku pretragu koja konstruira i upita uključivanje objekata kako bi pronašla slične stavke.",
|
||||
"triggers": {
|
||||
"label": "Pokretači",
|
||||
"description": "Akcije i kriteriji za usklađivanje za pokretače semantičke pretrage specifične za kameru.",
|
||||
"friendly_name": {
|
||||
"label": "Prijateljsko ime",
|
||||
"description": "Nepovlačno prijateljsko ime prikazano u korisničkom sučelju za ovaj pokretač."
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Omogući ovaj pokretač",
|
||||
"description": "Omogući ili onemogući ovaj pokretač semantičke pretrage."
|
||||
},
|
||||
"type": {
|
||||
"label": "Tip pokretača",
|
||||
"description": "Tip pokretača: 'thumbnail' (uspoređivanje slikom) ili 'description' (uspoređivanje teksta)."
|
||||
},
|
||||
"data": {
|
||||
"label": "Sadržaj pokretača",
|
||||
"description": "Tekstualni izraz ili ID miniaturne slike za uspoređivanje s praćenim objektima."
|
||||
},
|
||||
"threshold": {
|
||||
"label": "Prag aktivacije",
|
||||
"description": "Minimalna ocjena sličnosti (0-1) potrebna za aktivaciju ovog izazivača."
|
||||
},
|
||||
"actions": {
|
||||
"label": "Akcije izazivača",
|
||||
"description": "Popis akcija koje se izvršavaju kada izazivač odgovara (obavijest, pod_naziv, atribute)."
|
||||
}
|
||||
}
|
||||
},
|
||||
"snapshots": {
|
||||
"label": "Snimci",
|
||||
"description": "Postavke za snimke generirane preko API-ja za praćene objekte za ovu kameru.",
|
||||
"enabled": {
|
||||
"label": "Omogući snimke",
|
||||
"description": "Omogući ili onemogući snimanje snimaka za ovu kameru."
|
||||
},
|
||||
"timestamp": {
|
||||
"label": "Preklapanje vremenske oznake",
|
||||
"description": "Preklopiti vremensku oznaku na snimke iz API-ja."
|
||||
},
|
||||
"bounding_box": {
|
||||
"label": "Preklapanje okvira",
|
||||
"description": "Crtanje okvira za praćene objekte na snimke iz API-ja."
|
||||
},
|
||||
"crop": {
|
||||
"label": "Izrezivanje snimke",
|
||||
"description": "Izrezivanje snimki iz API-ja do okvira detektiranog objekta."
|
||||
},
|
||||
"required_zones": {
|
||||
"label": "Potrebne zone",
|
||||
"description": "Zone koje objekt mora ući da bi snimka bila sačuvana."
|
||||
},
|
||||
"height": {
|
||||
"label": "Visina snimke",
|
||||
"description": "Visina (pikseli) za promjenu veličine snimki iz API-ja; ostavite prazno da biste sačuvali originalnu veličinu."
|
||||
},
|
||||
"retain": {
|
||||
"label": "Zadržavanje snimki",
|
||||
"description": "Postavke zadržavanja snimki uključujući zadane dane i prekriženja po objektu.",
|
||||
"default": {
|
||||
"label": "Zadano zadržavanje",
|
||||
"description": "Zadani broj dana za zadržavanje snimki."
|
||||
},
|
||||
"mode": {
|
||||
"label": "Način zadržavanja",
|
||||
"description": "Način zadržavanja: sve (sačuvati sve segmente), pokret (sačuvati segmente s pokretom), ili aktivni_objekti (sačuvati segmente s aktivnim objektima)."
|
||||
},
|
||||
"objects": {
|
||||
"label": "Zadržavanje objekata",
|
||||
"description": "Prekriženja po objektu za dane zadržavanja snimki."
|
||||
}
|
||||
},
|
||||
"quality": {
|
||||
"label": "Kvaliteta snimka",
|
||||
"description": "Kvaliteta kodiranja za sačuvane snimke (0-100)."
|
||||
}
|
||||
},
|
||||
"timestamp_style": {
|
||||
"label": "Stil vremenske oznake",
|
||||
"description": "Opcije stilizacije za vremenske oznake u snimcima i snimcima.",
|
||||
"position": {
|
||||
"label": "Pozicija vremenske oznake",
|
||||
"description": "Pozicija vremenske oznake na slici (tl/tr/bl/br)."
|
||||
},
|
||||
"format": {
|
||||
"label": "Format vremenske oznake",
|
||||
"description": "String formata datuma i vremena korišten za vremenske oznake (Python format koda za datum i vrijeme)."
|
||||
},
|
||||
"color": {
|
||||
"label": "Boja vremenske oznake",
|
||||
"description": "RGB vrijednosti boja za tekst vremenske oznake (sve vrijednosti 0-255).",
|
||||
"red": {
|
||||
"label": "Crvena",
|
||||
"description": "Crveni komponent (0-255) za boju vremenske oznake."
|
||||
},
|
||||
"green": {
|
||||
"label": "Zelena",
|
||||
"description": "Zeleni komponent (0-255) za boju vremenske oznake."
|
||||
},
|
||||
"blue": {
|
||||
"label": "Plava",
|
||||
"description": "Plavi komponent (0-255) za boju vremenske oznake."
|
||||
}
|
||||
},
|
||||
"thickness": {
|
||||
"label": "Debljina vremenske oznake",
|
||||
"description": "Debljina linije teksta vremenske oznake."
|
||||
},
|
||||
"effect": {
|
||||
"label": "Efekt vremenske oznake",
|
||||
"description": "Vizualni efekt za tekst vremenske oznake (none, solid, shadow)."
|
||||
}
|
||||
},
|
||||
"best_image_timeout": {
|
||||
"label": "Vrijeme čekanja za najbolju sliku",
|
||||
"description": "Koliko dugo čekati na sliku s najvišim stupnjem pouzdanosti."
|
||||
},
|
||||
"mqtt": {
|
||||
"label": "MQTT",
|
||||
"description": "Postavke objave slika preko MQTT.",
|
||||
"enabled": {
|
||||
"label": "Pošalji sliku",
|
||||
"description": "Omogući objavljivanje snimaka slika za objekte na MQTT teme za ovu kameru."
|
||||
},
|
||||
"timestamp": {
|
||||
"label": "Dodaj vremensku oznaku",
|
||||
"description": "Preklopiti vremensku oznaku na slike objavljene preko MQTT."
|
||||
},
|
||||
"bounding_box": {
|
||||
"label": "Dodaj okvir",
|
||||
"description": "Crtaj okvire na slikama objavljenim preko MQTT."
|
||||
},
|
||||
"crop": {
|
||||
"label": "Iscijepi sliku",
|
||||
"description": "Iscijepi slike objavljene preko MQTT na okvir detektiranog objekta."
|
||||
},
|
||||
"height": {
|
||||
"label": "Visina slike",
|
||||
"description": "Visina (piksela) za promjenu veličine slika objavljenih preko MQTT."
|
||||
},
|
||||
"required_zones": {
|
||||
"label": "Potrebne zone",
|
||||
"description": "Zone koje objekt mora ući da bi se slika preko MQTT objavila."
|
||||
},
|
||||
"quality": {
|
||||
"label": "Kvaliteta JPEG",
|
||||
"description": "Kvaliteta JPEG za slike objavljene preko MQTT (0-100)."
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"label": "Obavještenja",
|
||||
"description": "Postavke za omogućavanje i kontrolu obavijesti za ovu kameru.",
|
||||
"enabled": {
|
||||
"label": "Omogući obavijesti",
|
||||
"description": "Omogući ili onemogući obavijesti za ovu kameru."
|
||||
},
|
||||
"email": {
|
||||
"label": "E-mail za obavijesti",
|
||||
"description": "Adresa e-maila koja se koristi za obavijesti putem push-a ili je potrebna određenim dobavljačima obavijesti."
|
||||
},
|
||||
"cooldown": {
|
||||
"label": "Period hlađenja",
|
||||
"description": "Period hlađenja (sekunde) između obavijesti kako bi se izbjeglo spaming primateljima."
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Originalno stanje obavijesti",
|
||||
"description": "Pokazuje je li obavijesti bile omogućene u originalnoj statičkoj konfiguraciji."
|
||||
}
|
||||
},
|
||||
"onvif": {
|
||||
"label": "ONVIF",
|
||||
"description": "Postavke povezivanja preko ONVIF i automatskog praćenja PTZ za ovu kameru.",
|
||||
"host": {
|
||||
"label": "Gost ONVIF",
|
||||
"description": "Gost (i opcionalni shema) za uslugu ONVIF za ovu kameru."
|
||||
},
|
||||
"port": {
|
||||
"label": "Port ONVIF",
|
||||
"description": "Broj porta za uslugu ONVIF."
|
||||
},
|
||||
"user": {
|
||||
"label": "Korisničko ime za ONVIF",
|
||||
"description": "Korisničko ime za autentifikaciju ONVIF; neki uređaji zahtijevaju korisnika admin za ONVIF."
|
||||
},
|
||||
"password": {
|
||||
"label": "Lozinka za ONVIF",
|
||||
"description": "Lozinka za autentifikaciju ONVIF."
|
||||
},
|
||||
"tls_insecure": {
|
||||
"label": "Onemogući provjeru TLS",
|
||||
"description": "Preskoči provjeru TLS i onemogući digest autentifikaciju za ONVIF (nebezbedno; koristiti samo u sigurnim mrežama)."
|
||||
},
|
||||
"profile": {
|
||||
"label": "ONVIF profil",
|
||||
"description": "Specifičan ONVIF medij profil za korištenje za kontrolu PTZ, prilagođen tokenom ili imenom. Ako nije postavljen, prvi profil s važećom konfiguracijom PTZ automatski se odabire."
|
||||
},
|
||||
"autotracking": {
|
||||
"label": "Autotračenje",
|
||||
"description": "Automatski praćenje pokretanja objekata i držanje ih u sredini okvira korištenjem pokreta kamere PTZ.",
|
||||
"enabled": {
|
||||
"label": "Omogući automatsko praćenje",
|
||||
"description": "Omogući ili onemogući automatsko praćenje kamere PTZ detektiranih objekata."
|
||||
},
|
||||
"calibrate_on_startup": {
|
||||
"label": "Kalibriraj na početku",
|
||||
"description": "Mjeri brzine motora PTZ pri pokretanju kako bi poboljšao preciznost praćenja. Frigate će ažurirati konfiguraciju s težinama pokreta nakon kalibracije."
|
||||
},
|
||||
"zooming": {
|
||||
"label": "Režim zumiranja",
|
||||
"description": "Kontrola ponašanja zumiranja: onemogućeno (samo pan/tilt), apsolutno (najkompatibilnije) ili relativno (konkurentno pan/tilt/zum)."
|
||||
},
|
||||
"zoom_factor": {
|
||||
"label": "Faktor zumiranja",
|
||||
"description": "Kontrola razine zumiranja na praćenim objektima. Niže vrijednosti drže više scene u pogledu; više vrijednosti zumiraju bliže, ali mogu izgubiti praćenje. Vrijednosti između 0.1 i 0.75."
|
||||
},
|
||||
"track": {
|
||||
"label": "Praćeni objekti",
|
||||
"description": "Popis vrsta objekata koji trebaju pokrenuti automatsko praćenje."
|
||||
},
|
||||
"required_zones": {
|
||||
"label": "Potrebne zone",
|
||||
"description": "Objekti moraju ući u jednu od ovih zona prije nego što započne automatsko praćenje."
|
||||
},
|
||||
"return_preset": {
|
||||
"label": "Povratak na predpostavku",
|
||||
"description": "Ime predpostavke konfigurirano u firmware kamere za povratak nakon završetka praćenja."
|
||||
},
|
||||
"timeout": {
|
||||
"label": "Vrijeme čekanja povratka",
|
||||
"description": "Čekajte ovaj broj sekundi nakon gubitka praćenja prije povratka kamere na predpostavljeno mjesto."
|
||||
},
|
||||
"movement_weights": {
|
||||
"label": "Težine pokreta",
|
||||
"description": "Vrijednosti kalibracije automatski generirane kroz kalibraciju kamere. Ne mijenjajte ručno."
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Originalni stanje autotračenja",
|
||||
"description": "Unutarnje polje za praćenje je li autotračenje bilo omogućeno u konfiguraciji."
|
||||
}
|
||||
},
|
||||
"ignore_time_mismatch": {
|
||||
"label": "Zanemari razliku u vremenu",
|
||||
"description": "Zanemari razlike u sinhronizaciji vremena između kamere i Frigate servera za komunikaciju ONVIF."
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"label": "Tip kamere",
|
||||
"description": "Tip kamere"
|
||||
},
|
||||
"ui": {
|
||||
"label": "Korisnički interfejs kamere",
|
||||
"description": "Prikaz redoslijeda i vidljivosti za ovu kameru u UI. Redoslijed utječe na zadani nadzorno pločo. Za detaljniju kontrolu koristite grupe kamere.",
|
||||
"order": {
|
||||
"label": "Redoslijed UI",
|
||||
"description": "Numerički redoslijed koristi se za sortiranje kamere u UI (zadani nadzorno pločo i popisi); veći brojevi pojavljuju se kasnije."
|
||||
},
|
||||
"dashboard": {
|
||||
"label": "Prikaži u UI",
|
||||
"description": "Prekidač je li ova kamera vidljiva svuda u UI Frigate. Onemogućavanje ovoga zahtijeva ručno uređivanje konfiguracije za ponovno prikazivanje ove kamere u UI."
|
||||
}
|
||||
},
|
||||
"webui_url": {
|
||||
"label": "URL kamere",
|
||||
"description": "URL za pristup kamere izravno iz stranice sustava"
|
||||
},
|
||||
"profiles": {
|
||||
"label": "Profili",
|
||||
"description": "Imenovane konfiguracijske profile s parcijalnim preklopima koji se mogu aktivirati tijekom izvršavanja."
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "Originalno stanje kamere",
|
||||
"description": "Pratite originalno stanje kamere."
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"audio": {
|
||||
"global": {
|
||||
"detection": "Globalna detekcija",
|
||||
"sensitivity": "Globalna osjetljivost"
|
||||
},
|
||||
"cameras": {
|
||||
"detection": "Detekcija",
|
||||
"sensitivity": "Osjetljivost"
|
||||
}
|
||||
},
|
||||
"timestamp_style": {
|
||||
"global": {
|
||||
"appearance": "Globalno izgled"
|
||||
},
|
||||
"cameras": {
|
||||
"appearance": "Izgled"
|
||||
}
|
||||
},
|
||||
"motion": {
|
||||
"global": {
|
||||
"sensitivity": "Globalna osjetljivost",
|
||||
"algorithm": "Globalni algoritam"
|
||||
},
|
||||
"cameras": {
|
||||
"sensitivity": "Osjetljivost",
|
||||
"algorithm": "Algoritam"
|
||||
}
|
||||
},
|
||||
"snapshots": {
|
||||
"global": {
|
||||
"display": "Globalno prikazivanje"
|
||||
},
|
||||
"cameras": {
|
||||
"display": "Prikazivanje"
|
||||
}
|
||||
},
|
||||
"detect": {
|
||||
"global": {
|
||||
"resolution": "Globalna rezolucija",
|
||||
"tracking": "Globalno praćenje"
|
||||
},
|
||||
"cameras": {
|
||||
"resolution": "Rezolucija",
|
||||
"tracking": "Praćenje"
|
||||
}
|
||||
},
|
||||
"objects": {
|
||||
"global": {
|
||||
"tracking": "Globalno praćenje",
|
||||
"filtering": "Globalno filtriranje"
|
||||
},
|
||||
"cameras": {
|
||||
"tracking": "Praćenje",
|
||||
"filtering": "Filtriranje"
|
||||
}
|
||||
},
|
||||
"record": {
|
||||
"global": {
|
||||
"retention": "Globalno zadržavanje",
|
||||
"events": "Globalni događaji"
|
||||
},
|
||||
"cameras": {
|
||||
"retention": "Zadržavanje",
|
||||
"events": "Događaji"
|
||||
}
|
||||
},
|
||||
"ffmpeg": {
|
||||
"cameras": {
|
||||
"cameraFfmpeg": "Argumeni FFmpeg specifični za kameru"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"minimum": "Bar {{limit}}",
|
||||
"maximum": "Mora biti najviše {{limit}}",
|
||||
"exclusiveMinimum": "Mora biti veći od {{limit}}",
|
||||
"exclusiveMaximum": "Mora biti manje od {{limit}}",
|
||||
"minLength": "Bar {{limit}} znak(ovi)",
|
||||
"maxLength": "Mora biti najviše {{limit}} znak(ovi)",
|
||||
"minItems": "Mora imati bar {{limit}} stavke",
|
||||
"maxItems": "Mora imati najviše {{limit}} stavke",
|
||||
"pattern": "Neispravan format",
|
||||
"required": "Ovo polje je obavezno",
|
||||
"type": "Neispravan tip vrijednosti",
|
||||
"enum": "Mora biti jedan od dopuštenih vrijednosti",
|
||||
"const": "Vrijednost se ne podudara s očekivanom konstantom",
|
||||
"uniqueItems": "Sve stavke moraju biti jedinstvene",
|
||||
"format": "Neispravan format",
|
||||
"additionalProperties": "Nepoznato svojstvo nije dozvoljeno",
|
||||
"oneOf": "Mora se podudarati s točno jednim od dopuštenih shema",
|
||||
"anyOf": "Mora se podudarati s bar jednim od dopuštenih shema",
|
||||
"proxy": {
|
||||
"header_map": {
|
||||
"roleHeaderRequired": "Zaglavlje uloge je obavezno kada su konfigurirane mapiranja uloga."
|
||||
}
|
||||
},
|
||||
"ffmpeg": {
|
||||
"inputs": {
|
||||
"rolesUnique": "Svaka uloga može biti dodijeljena samo jednom ulaznom toku.",
|
||||
"detectRequired": "Bar jedan ulazni tok mora biti dodijeljen ulozi 'detektirati'.",
|
||||
"hwaccelDetectOnly": "Samo ulazni tok s ulogom detektiranja može definirati argumente ubrzavanja hardvera."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"person": "Ljudsko bit će",
|
||||
"bicycle": "Kolo",
|
||||
"animal": "Životinja",
|
||||
"dog": "Pas",
|
||||
"bark": "Glavu",
|
||||
"cat": "Mačka",
|
||||
"horse": "Konj",
|
||||
"goat": "Koza",
|
||||
"sheep": "Ovca",
|
||||
"bird": "Ptica",
|
||||
"mouse": "Miš",
|
||||
"keyboard": "Klaviatura",
|
||||
"vehicle": "Vozilo",
|
||||
"boat": "Brod",
|
||||
"car": "Automobil",
|
||||
"bus": "Autobus",
|
||||
"motorcycle": "Motocikl",
|
||||
"train": "Vlak",
|
||||
"skateboard": "Skejtbord",
|
||||
"door": "Vrata",
|
||||
"blender": "Miksere",
|
||||
"sink": "Lavabo",
|
||||
"hair_dryer": "Sušilac za kosu",
|
||||
"toothbrush": "Šetka za zube",
|
||||
"scissors": "Škare",
|
||||
"clock": "Sat",
|
||||
"airplane": "Avion",
|
||||
"traffic_light": "Svetofor",
|
||||
"fire_hydrant": "Vatrostaničar",
|
||||
"street_sign": "Ulični znak",
|
||||
"stop_sign": "Znak zaustavljanja",
|
||||
"parking_meter": "Parkirni metar",
|
||||
"bench": "Banko",
|
||||
"cow": "Korova",
|
||||
"elephant": "Slon",
|
||||
"bear": "Medvjed",
|
||||
"zebra": "Zebra",
|
||||
"giraffe": "Žirafa",
|
||||
"hat": "Kaputa",
|
||||
"backpack": "Torba",
|
||||
"umbrella": "Kreveta",
|
||||
"shoe": "Cizma",
|
||||
"eye_glasses": "Očna stakla",
|
||||
"handbag": "Ručna torba",
|
||||
"tie": "Kremplj",
|
||||
"suitcase": "Kufer",
|
||||
"frisbee": "Frizbi",
|
||||
"skis": "Ski",
|
||||
"snowboard": "Snjegobord",
|
||||
"sports_ball": "Sportska lopta",
|
||||
"kite": "Let",
|
||||
"baseball_bat": "Batsa za baseball",
|
||||
"baseball_glove": "Rukavica za baseball",
|
||||
"surfboard": "Surfbord",
|
||||
"tennis_racket": "Teniski raketa",
|
||||
"bottle": "Bocica",
|
||||
"plate": "Ploča",
|
||||
"wine_glass": "Vinsko čaša",
|
||||
"cup": "Kupa",
|
||||
"fork": "Škarpe",
|
||||
"knife": "Nož",
|
||||
"spoon": "Lajna",
|
||||
"bowl": "Tanjir",
|
||||
"banana": "Banana",
|
||||
"apple": "Jabuka",
|
||||
"sandwich": "Sandučić",
|
||||
"orange": "Portakal",
|
||||
"broccoli": "Brobkoli",
|
||||
"carrot": "Mahunika",
|
||||
"hot_dog": "Hot dog",
|
||||
"pizza": "Pica",
|
||||
"donut": "Krofna",
|
||||
"cake": "Torta",
|
||||
"chair": "Stolica",
|
||||
"couch": "Divan",
|
||||
"potted_plant": "Ukrasna biljka",
|
||||
"bed": "Krevet",
|
||||
"mirror": "Zrcalo",
|
||||
"dining_table": "Stol za ručak",
|
||||
"window": "Prozor",
|
||||
"desk": "Radni stol",
|
||||
"toilet": "Toalet",
|
||||
"tv": "TV",
|
||||
"laptop": "Laptop",
|
||||
"remote": "Udaljeno upravljanje",
|
||||
"cell_phone": "Mobilni telefon",
|
||||
"microwave": "Mikrotalasna pećnica",
|
||||
"oven": "Pećnica",
|
||||
"toaster": "Tostera",
|
||||
"refrigerator": "Hladnjak",
|
||||
"book": "Knjiga",
|
||||
"vase": "Vaza",
|
||||
"teddy_bear": "Biberon",
|
||||
"hair_brush": "Kosmetička četka",
|
||||
"squirrel": "Šumski pas",
|
||||
"deer": "Jelen",
|
||||
"fox": "Lisica",
|
||||
"rabbit": "Zajac",
|
||||
"raccoon": "Rakun",
|
||||
"robot_lawnmower": "Robotska kosilica",
|
||||
"waste_bin": "Kanta za otpad",
|
||||
"on_demand": "Na zahtjev",
|
||||
"face": "Lice",
|
||||
"license_plate": "Tablica",
|
||||
"package": "Paket",
|
||||
"bbq_grill": "Grill za BBQ",
|
||||
"amazon": "Amazon",
|
||||
"usps": "USPS",
|
||||
"ups": "UPS",
|
||||
"fedex": "FedEx",
|
||||
"dhl": "DHL",
|
||||
"an_post": "An Post",
|
||||
"purolator": "Purolator",
|
||||
"postnl": "PostNL",
|
||||
"nzpost": "NZPost",
|
||||
"postnord": "PostNord",
|
||||
"gls": "GLS",
|
||||
"dpd": "DPD",
|
||||
"canada_post": "Canada Post",
|
||||
"royal_mail": "Royal Mail",
|
||||
"school_bus": "Školski autobus",
|
||||
"skunk": "Mrdka",
|
||||
"kangaroo": "Kanguru"
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"documentTitle": "Razgovor - Frigate",
|
||||
"title": "Frigate razgovor",
|
||||
"subtitle": "Vaš AI asistent za upravljanje kamerama i insighti",
|
||||
"placeholder": "Pitajte bilo što...",
|
||||
"error": "Nešto je pošlo po zlu. Molimo pokušajte ponovo.",
|
||||
"processing": "Obrađivanje...",
|
||||
"toolsUsed": "Korišteno: {{tools}}",
|
||||
"showTools": "Prikaži alate ({{count}})",
|
||||
"hideTools": "Sakrij alate",
|
||||
"call": "Poziv",
|
||||
"result": "Rezultat",
|
||||
"arguments": "Argumenti:",
|
||||
"response": "Odgovor:",
|
||||
"attachment_chip_label": "{{label}} na {{camera}}",
|
||||
"attachment_chip_remove": "Ukloni privitak",
|
||||
"open_in_explore": "Otvori u Explore",
|
||||
"attach_event_aria": "Prikači događaj {{eventId}}",
|
||||
"attachment_picker_paste_label": "Ili zalijepite ID događaja",
|
||||
"attachment_picker_attach": "Prikači",
|
||||
"attachment_picker_placeholder": "Prikači događaj",
|
||||
"quick_reply_find_similar": "Pronađi slične susreti",
|
||||
"quick_reply_tell_me_more": "Recite mi više o ovome",
|
||||
"quick_reply_when_else": "Kada je još puta vidjeno?",
|
||||
"quick_reply_find_similar_text": "Pronađi slične susreti za ovaj.",
|
||||
"quick_reply_tell_me_more_text": "Recite mi više o ovom.",
|
||||
"quick_reply_when_else_text": "Kada je to još puta vidjeno?",
|
||||
"anchor": "Referenca",
|
||||
"similarity_score": "Sličnost",
|
||||
"no_similar_objects_found": "Nisu pronađeni slični objekti.",
|
||||
"semantic_search_required": "Semantička pretraga mora biti omogućena da bi se pronašli slični objekti.",
|
||||
"send": "Pošalji",
|
||||
"suggested_requests": "Pokušaj pitati:",
|
||||
"starting_requests": {
|
||||
"show_recent_events": "Prikaži nedavne događaje",
|
||||
"show_camera_status": "Prikaži status kamere",
|
||||
"recap": "Što se desilo dok sam bio odsutan?",
|
||||
"watch_camera": "Pratite kameru za aktivnost"
|
||||
},
|
||||
"starting_requests_prompts": {
|
||||
"show_recent_events": "Prikaži mi nedavne događaje iz posljednjeg sata",
|
||||
"show_camera_status": "Koji je trenutni status mojih kamera?",
|
||||
"recap": "Što se desilo dok sam bio odsutan?",
|
||||
"watch_camera": "Pratite ulazna vrata i obavijestite me ako netko dođe"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"documentTitle": "Modeli klasifikacije - Frigate",
|
||||
"details": {
|
||||
"scoreInfo": "Ocjena predstavlja prosjek pouzdanosti klasifikacije kroz sve detekcije ovog objekta.",
|
||||
"none": "Nijedan",
|
||||
"unknown": "Nepoznato"
|
||||
},
|
||||
"button": {
|
||||
"deleteClassificationAttempts": "Obriši slike klasifikacije",
|
||||
"renameCategory": "Preimenuj klasu",
|
||||
"deleteCategory": "Obriši klasu",
|
||||
"deleteImages": "Obriši slike",
|
||||
"trainModel": "Obuci model",
|
||||
"addClassification": "Dodaj klasifikaciju",
|
||||
"deleteModels": "Obriši modele",
|
||||
"editModel": "Uredi model"
|
||||
},
|
||||
"tooltip": {
|
||||
"trainingInProgress": "Model trenutno obučava",
|
||||
"noNewImages": "Nema novih slika za obuku. Prvo klasificirajte više slika u skupu podataka.",
|
||||
"noChanges": "Nema promjena u skupu podataka od posljednje obuke.",
|
||||
"modelNotReady": "Model nije spreman za obuku"
|
||||
},
|
||||
"toast": {
|
||||
"success": {
|
||||
"deletedModel_one": "Uspješno obrisan {{count}} model",
|
||||
"deletedModel_few": "Uspješno obrisani {{count}} modeli",
|
||||
"deletedModel_other": "Uspješno obrisani {{count}} modeli",
|
||||
"categorizedImage": "Uspješno klasificirana slika",
|
||||
"reclassifiedImage": "Uspješno ponovno klasificirana slika",
|
||||
"trainedModel": "Uspješno obučen model.",
|
||||
"trainingModel": "Uspješno pokrenuta obuka modela.",
|
||||
"updatedModel": "Uspješno ažurirana konfiguracija modela",
|
||||
"renamedCategory": "Uspješno preimenovana klasa u {{name}}",
|
||||
"deletedCategory_one": "Obrisana {{count}} klasa",
|
||||
"deletedCategory_few": "Obrisane {{count}} klase",
|
||||
"deletedCategory_other": "Obrisane {{count}} klase",
|
||||
"deletedImage_one": "Izbrisana {{count}} slika",
|
||||
"deletedImage_few": "Izbrisane {{count}} slike",
|
||||
"deletedImage_other": "Izbrisane {{count}} slike"
|
||||
},
|
||||
"error": {
|
||||
"deleteImageFailed": "Neuspješno brisanje: {{errorMessage}}",
|
||||
"deleteCategoryFailed": "Neuspješno brisanje klase: {{errorMessage}}",
|
||||
"deleteModelFailed": "Neuspješno brisanje modela: {{errorMessage}}",
|
||||
"categorizeFailed": "Neuspješno kategoriziranje slike: {{errorMessage}}",
|
||||
"trainingFailed": "Obuka modela nije uspješna. Provjerite zapise Frigate za detalje.",
|
||||
"trainingFailedToStart": "Neuspješno pokretanje obuke modela: {{errorMessage}}",
|
||||
"updateModelFailed": "Neuspješno ažuriranje modela: {{errorMessage}}",
|
||||
"renameCategoryFailed": "Neuspješno preimenovanje klase: {{errorMessage}}",
|
||||
"reclassifyFailed": "Neuspješno ponovno klasifikovanje slike: {{errorMessage}}"
|
||||
}
|
||||
},
|
||||
"deleteCategory": {
|
||||
"title": "Izbriši klasu",
|
||||
"desc": "Sigurni li ste da želite izbrisati klasu {{name}}? Ovo će trajno izbrisati sve povezane slike i zahtijevati ponovnu obuku modela.",
|
||||
"minClassesTitle": "Nemoguće izbrisati klasu",
|
||||
"minClassesDesc": "Model klasifikacije mora imati najmanje 2 klase. Dodajte još jednu klasu prije brisanja ove."
|
||||
},
|
||||
"deleteModel": {
|
||||
"title": "Izbriši model klasifikacije",
|
||||
"single": "Sigurni li ste da želite izbrisati {{name}}? Ovo će trajno izbrisati sve povezane podatke uključujući slike i podatke o obuci. Ova akcija ne može biti poništena.",
|
||||
"desc_one": "Sigurni li ste da želite izbrisati {{count}} model? Ovo će trajno izbrisati sve povezane podatke uključujući slike i podatke o obuci. Ova akcija ne može biti poništena.",
|
||||
"desc_few": "Sigurni li ste da želite izbrisati {{count}} modele? Ovo će trajno izbrisati sve povezane podatke uključujući slike i podatke o obuci. Ova akcija ne može biti poništena.",
|
||||
"desc_other": "Sigurni li ste da želite izbrisati {{count}} modele? Ovo će trajno izbrisati sve povezane podatke uključujući slike i podatke o obuci. Ova akcija ne može biti poništena."
|
||||
},
|
||||
"edit": {
|
||||
"title": "Uredi model klasifikacije",
|
||||
"descriptionState": "Uredi klase za ovaj model klasifikacije stanja. Promjene će zahtijevati ponovnu obuku modela.",
|
||||
"descriptionObject": "Uredi vrstu objekta i vrstu klasifikacije za ovaj model klasifikacije objekta.",
|
||||
"stateClassesInfo": "Napomena: Promjene klasa stanja zahtijevaju ponovnu obuku modela sa ažuriranim klasama."
|
||||
},
|
||||
"deleteDatasetImages": {
|
||||
"title": "Izbriši slike skupa podataka",
|
||||
"desc_one": "Sigurni li ste da želite izbrisati {{count}} sliku iz {{dataset}}? Ova akcija ne može biti poništena i zahtijevati će ponovnu obuku modela.",
|
||||
"desc_few": "Sigurni li ste da želite obrisati {{count}} slike iz {{dataset}}? Ova akcija ne može se poništiti i zahtijevat će ponovno treniranje modela.",
|
||||
"desc_other": "Sigurni li ste da želite obrisati {{count}} slike iz {{dataset}}? Ova akcija ne može se poništiti i zahtijevat će ponovno treniranje modela."
|
||||
},
|
||||
"deleteTrainImages": {
|
||||
"title": "Obriši slike za treniranje",
|
||||
"desc_one": "Sigurni li ste da želite obrisati {{count}} sliku? Ova akcija ne može se poništiti.",
|
||||
"desc_few": "Sigurni li ste da želite obrisati {{count}} slike? Ova akcija ne može se poništiti.",
|
||||
"desc_other": "Sigurni li ste da želite obrisati {{count}} slike? Ova akcija ne može se poništiti."
|
||||
},
|
||||
"renameCategory": {
|
||||
"title": "Preimenuj klasu",
|
||||
"desc": "Unesite novo ime za {{name}}. Za promjenu imena će vam se zahtijevati ponovno treniranje modela."
|
||||
},
|
||||
"description": {
|
||||
"invalidName": "Neprihvatljivo ime. Imena mogu sadržavati samo slova, brojeve, razmake, aposrofe, donje crte i crte."
|
||||
},
|
||||
"train": {
|
||||
"title": "Nedavne klasifikacije",
|
||||
"titleShort": "Nedavno",
|
||||
"aria": "Odaberite nedavne klasifikacije"
|
||||
},
|
||||
"categories": "Klase",
|
||||
"createCategory": {
|
||||
"new": "Stvori novu klasu"
|
||||
},
|
||||
"categorizeImageAs": "Klasificiraj sliku kao:",
|
||||
"categorizeImage": "Klasificiraj sliku",
|
||||
"reclassifyImageAs": "Ponovno klasificiraj sliku kao:",
|
||||
"reclassifyImage": "Ponovno klasificiraj sliku",
|
||||
"menu": {
|
||||
"objects": "Objekti",
|
||||
"states": "Stanja"
|
||||
},
|
||||
"noModels": {
|
||||
"object": {
|
||||
"title": "Nema modela za klasifikaciju objekata",
|
||||
"description": "Stvorite prilagođeni model za klasifikaciju detektiranih objekata.",
|
||||
"buttonText": "Stvori model objekta"
|
||||
},
|
||||
"state": {
|
||||
"title": "Nema modela za klasifikaciju stanja",
|
||||
"description": "Stvorite prilagođeni model za praćenje i klasifikaciju promjena stanja u određenim područjima kamere.",
|
||||
"buttonText": "Stvori model stanja"
|
||||
}
|
||||
},
|
||||
"wizard": {
|
||||
"title": "Stvori novu klasifikaciju",
|
||||
"steps": {
|
||||
"nameAndDefine": "Ime i definicija",
|
||||
"stateArea": "Područje stanja",
|
||||
"chooseExamples": "Odaberite primjere"
|
||||
},
|
||||
"step1": {
|
||||
"description": "Modeli stanja nadziraju fiksne područja kamere za promjene (npr. vrata otvorena/zatvorena). Modeli objekata dodaju klasifikacije detektiranim objektima (npr. poznati životinje, dostavljači, itd.).",
|
||||
"name": "Ime",
|
||||
"namePlaceholder": "Unesite ime modela...",
|
||||
"type": "Tip",
|
||||
"typeState": "Stanje",
|
||||
"typeObject": "Objekt",
|
||||
"objectLabel": "Oznaka objekta",
|
||||
"objectLabelPlaceholder": "Odaberite vrstu objekta...",
|
||||
"classificationType": "Vrsta klasifikacije",
|
||||
"classificationTypeTip": "Učite više o vrstama klasifikacije",
|
||||
"classificationTypeDesc": "Podoznake dodaju dodatni tekst oznaci objekta (npr. 'Ljudsko bit će: UPS'). Atributi su pretraživi metapodaci pohranjeni zasebno u metapodacima objekta.",
|
||||
"classificationSubLabel": "Podoznaka",
|
||||
"classificationAttribute": "Atribut",
|
||||
"classes": "Klase",
|
||||
"states": "Stanja",
|
||||
"classesTip": "Učite više o klasama",
|
||||
"classesStateDesc": "Definirajte različita stanja koja može imati područje kamere. Na primjer: 'otvoreno' i 'zatvoreno' za vrata garaže.",
|
||||
"classesObjectDesc": "Definirajte različite kategorije u koje ćete klasificirati detektirane objekte. Na primjer: 'dostavljac', 'stanovnik', 'stranac' za klasifikaciju ljudi.",
|
||||
"classPlaceholder": "Unesite ime klase...",
|
||||
"errors": {
|
||||
"nameRequired": "Ime modela je obavezno",
|
||||
"nameLength": "Ime modela mora imati 64 znaka ili manje",
|
||||
"nameOnlyNumbers": "Ime modela ne može sadržavati samo brojeve",
|
||||
"classRequired": "Potrebna je bar jedna klasa",
|
||||
"classesUnique": "Imena klasa moraju biti jedinstvena",
|
||||
"noneNotAllowed": "Klasa 'none' nije dozvoljena",
|
||||
"stateRequiresTwoClasses": "Modeli stanja zahtijevaju bar dvije klase",
|
||||
"objectLabelRequired": "Molimo odaberite oznaku objekta",
|
||||
"objectTypeRequired": "Molimo odaberite vrstu klasifikacije"
|
||||
}
|
||||
},
|
||||
"step2": {
|
||||
"description": "Odaberite kamere i definirajte područje koje ćete nadzirati za svaku kameru. Model će klasificirati stanje ovih područja.",
|
||||
"cameras": "Kamere",
|
||||
"selectCamera": "Odaberite Kameru",
|
||||
"noCameras": "Kliknite + za dodavanje kamera",
|
||||
"selectCameraPrompt": "Odaberite kameru iz popisa da biste definirali njezino područje nadzora"
|
||||
},
|
||||
"step3": {
|
||||
"selectImagesPrompt": "Odaberite sve slike s: {{className}}",
|
||||
"selectImagesDescription": "Kliknite na slike da biste ih odabrali. Kliknite Nadalje kada završite s ovom klasifikacijom.",
|
||||
"allImagesRequired_one": "Molimo klasificirajte sve slike. Preostala je {{count}} slika.",
|
||||
"allImagesRequired_few": "Molimo klasificirajte sve slike. Preostale su {{count}} slike.",
|
||||
"allImagesRequired_other": "Molimo klasificirajte sve slike. Preostale su {{count}} slike.",
|
||||
"generating": {
|
||||
"title": "Generisanje uzoraka slika",
|
||||
"description": "Frigate učitava reprezentativne slike iz vaših snimaka. Ovo može trajati trenutak..."
|
||||
},
|
||||
"training": {
|
||||
"title": "Obučavanje modela",
|
||||
"description": "Vaš model se trenutno obučava u pozadini. Zatvorite ovaj dijalog, a vaš model će započeti raditi odmah kada se obuka završi."
|
||||
},
|
||||
"retryGenerate": "Ponovno generisanje",
|
||||
"noImages": "Nema generisanih uzoraka slika",
|
||||
"classifying": "Klasifikacija i obuka...",
|
||||
"trainingStarted": "Obuka je uspješno pokrenuta",
|
||||
"modelCreated": "Model je uspješno stvoren. Koristite pogled Najnovije klasifikacije da dodate slike za nedostajuće stanja, a zatim obučite model.",
|
||||
"errors": {
|
||||
"noCameras": "Nema konfigurisanih kamera",
|
||||
"noObjectLabel": "Nije odabrana oznaka objekta",
|
||||
"generateFailed": "Neuspješno generisanje primera: {{error}}",
|
||||
"generationFailed": "Generisanje nije uspješno. Molimo pokušajte ponovo.",
|
||||
"classifyFailed": "Neuspješna klasifikacija slika: {{error}}"
|
||||
},
|
||||
"generateSuccess": "Uspješno generisane uzorak slike",
|
||||
"refreshExamples": "Generiši nove primjere",
|
||||
"refreshConfirm": {
|
||||
"title": "Generiši nove primjere?",
|
||||
"description": "Ovo će generisati novi skup slika i obrisati sve odabire, uključujući prethodne klase. Trebat će vam ponovno odabrati primjere za sve klase."
|
||||
},
|
||||
"missingStatesWarning": {
|
||||
"title": "Primjeri nedostajućih klasa",
|
||||
"description": "Nisu sve klase imale primjere. Pokušajte generisanje novih primjera da biste pronašli nedostajuću klasu, ili nastavite i koristite pogled Najnovije klasifikacije da biste kasnije dodali slike."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"documentTitle": "Uređivač konfiguracije - Frigate",
|
||||
"configEditor": "Uređivač konfiguracije",
|
||||
"safeConfigEditor": "Uređivač konfiguracije (Sigurnosni režim)",
|
||||
"safeModeDescription": "Frigate je u sigurnosnom režimu zbog greške u validaciji konfiguracije.",
|
||||
"copyConfig": "Kopiraj konfiguraciju",
|
||||
"saveAndRestart": "Sačuvaj i ponovo pokreni",
|
||||
"saveOnly": "Sačuvaj samo",
|
||||
"confirm": "Napusti bez čuvanja?",
|
||||
"toast": {
|
||||
"success": {
|
||||
"copyToClipboard": "Konfiguracija kopirana u međuspremnik."
|
||||
},
|
||||
"error": {
|
||||
"savingError": "Greška prilikom čuvanja konfiguracije"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"alerts": "Upozorenja",
|
||||
"detections": "Detekcije",
|
||||
"camera": "Kamera",
|
||||
"motion": {
|
||||
"label": "Kretanje",
|
||||
"only": "Samo pokret"
|
||||
},
|
||||
"allCameras": "Sve Kamere",
|
||||
"empty": {
|
||||
"alert": "Nema upozorenja za pregled",
|
||||
"detection": "Nema detekcija za pregled",
|
||||
"motion": "Nema podataka o pokretu",
|
||||
"recordingsDisabled": {
|
||||
"title": "Snimci moraju biti omogućeni",
|
||||
"description": "Pregledni stavci mogu se stvarati samo za kameru kada su snimci omogućeni za tu kameru."
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"label": "vremenska linija",
|
||||
"aria": "Odaberite vremensku liniju"
|
||||
},
|
||||
"zoomIn": "Uvećajte",
|
||||
"zoomOut": "Umanjite",
|
||||
"events": {
|
||||
"label": "Događaji",
|
||||
"aria": "Odaberite događaje",
|
||||
"noFoundForTimePeriod": "Nema događaja za ovaj vremenski period."
|
||||
},
|
||||
"detail": {
|
||||
"label": "Detalj",
|
||||
"noDataFound": "Nema detaljnih podataka za pregled",
|
||||
"aria": "Prekidač pregleda detalja",
|
||||
"trackedObject_one": "{{count}} objekt",
|
||||
"trackedObject_other": "{{count}} objekta",
|
||||
"noObjectDetailData": "Nema dostupnih detaljnih podataka o objektu.",
|
||||
"settings": "Postavke pregleda detalja",
|
||||
"alwaysExpandActive": {
|
||||
"title": "Uvijek proširujte aktivno",
|
||||
"desc": "Uvijek proširite detalje objekta aktivnog stavka pregleda kada su dostupni."
|
||||
}
|
||||
},
|
||||
"objectTrack": {
|
||||
"trackedPoint": "Praćeni točka",
|
||||
"clickToSeek": "Kliknite da biste prešli na ovo vrijeme"
|
||||
},
|
||||
"documentTitle": "Pregled - Frigate",
|
||||
"recordings": {
|
||||
"documentTitle": "Snimci - Frigate",
|
||||
"invalidSharedLink": "Nemoguće otvoriti vezu za snimak sa vremenskom oznakom zbog greške u parsiranju.",
|
||||
"invalidSharedCamera": "Nemoguće otvoriti vezu za snimak sa vremenskom oznakom zbog nepoznate ili neovlašćene kamere."
|
||||
},
|
||||
"calendarFilter": {
|
||||
"last24Hours": "Poslednje 24 sata"
|
||||
},
|
||||
"markAsReviewed": "Označi kao pregledano",
|
||||
"markTheseItemsAsReviewed": "Označi ove stavke kao pregledane",
|
||||
"newReviewItems": {
|
||||
"label": "Pregledaj nove stavke za pregled",
|
||||
"button": "Nove stavke za pregled"
|
||||
},
|
||||
"selected_one": "{{count}} odabrano",
|
||||
"selected_other": "{{count}} odabrano",
|
||||
"select_all": "Sve",
|
||||
"detected": "detektovano",
|
||||
"normalActivity": "Normal",
|
||||
"needsReview": "Treba pregledati",
|
||||
"securityConcern": "Sigurnosna zabrinutost",
|
||||
"motionSearch": {
|
||||
"menuItem": "Pretraga kretanja",
|
||||
"openMenu": "Opcije kamere"
|
||||
},
|
||||
"motionPreviews": {
|
||||
"menuItem": "Pregledaj preglednike kretanja",
|
||||
"title": "Preglednici kretanja: {{camera}}",
|
||||
"mobileSettingsTitle": "Postavke preglednika kretanja",
|
||||
"mobileSettingsDesc": "Prilagodite brzinu reprodukcije i osvetljavanje, i odaberite datum za pregled snimaka samo sa kretanjem.",
|
||||
"dim": "Osvetljavanje",
|
||||
"dimAria": "Prilagodite intenzitet osvetljavanja",
|
||||
"dimDesc": "Povećajte osvetljavanje da biste povećali vidljivost područja kretanja.",
|
||||
"speed": "Brzina",
|
||||
"speedAria": "Odaberite brzinu reprodukcije preglednika",
|
||||
"speedDesc": "Odaberite koliko brzo će se pregledni snimci reproducirati.",
|
||||
"back": "Nazad",
|
||||
"empty": "Nema pregleda dostupnih",
|
||||
"noPreview": "Pregled nije dostupan",
|
||||
"seekAria": "Pretражuj {{camera}} igraču do {{time}}",
|
||||
"filter": "Filtar",
|
||||
"filterDesc": "Odaberite područja da biste prikazali samo klipove sa kretanjem u tim područjima.",
|
||||
"filterClear": "Očisti"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
{
|
||||
"documentTitle": "Istraživanje - Frigate",
|
||||
"generativeAI": "Generativna AI",
|
||||
"exploreMore": "Istražite više {{label}} objekata",
|
||||
"exploreIsUnavailable": {
|
||||
"title": "Istraživanje nije dostupno",
|
||||
"embeddingsReindexing": {
|
||||
"context": "Istraživanje može se koristiti nakon što se reindeksiranje ugrađenih objekata završi.",
|
||||
"startingUp": "Pokretanje…",
|
||||
"estimatedTime": "Procijenjeno preostalo vrijeme:",
|
||||
"finishingShortly": "Završetak uskoro",
|
||||
"step": {
|
||||
"thumbnailsEmbedded": "Ugrađene miniaturne slike: ",
|
||||
"descriptionsEmbedded": "Ugrađene opise: ",
|
||||
"trackedObjectsProcessed": "Obrađeni praćeni objekti: "
|
||||
}
|
||||
},
|
||||
"downloadingModels": {
|
||||
"context": "Frigate preuzima potrebne modele ugrađenih objekata kako bi podržao funkciju Semantičke pretrage. Ovo može trajati nekoliko minuta ovisno o brzini vaše mreže.",
|
||||
"setup": {
|
||||
"visionModel": "Model vida",
|
||||
"visionModelFeatureExtractor": "Izvođač značajki modela vida",
|
||||
"textModel": "Model teksta",
|
||||
"textTokenizer": "Tokenizator teksta"
|
||||
},
|
||||
"tips": {
|
||||
"context": "Moguće je da želite ponovno indeksirati ugrađene objekte koji se prate nakon što se modele preuzmu."
|
||||
},
|
||||
"error": "Dogodila se greška. Provjerite zapise Frigate."
|
||||
}
|
||||
},
|
||||
"trackedObjectDetails": "Detalji praćenih objekata",
|
||||
"type": {
|
||||
"details": "Detalji",
|
||||
"snapshot": "Snimak",
|
||||
"thumbnail": "miniaturna slika",
|
||||
"video": "Video",
|
||||
"tracking_details": "detalji praćenja"
|
||||
},
|
||||
"trackingDetails": {
|
||||
"title": "Detalji praćenja",
|
||||
"noImageFound": "Nije pronađena slika za ovaj vremenski moment.",
|
||||
"createObjectMask": "Kreirajte masku objekta",
|
||||
"adjustAnnotationSettings": "Prilagodite postavke oznaka",
|
||||
"scrollViewTips": "Kliknite da biste vidjeli važne trenutke životnog ciklusa ovog objekta.",
|
||||
"autoTrackingTips": "Pozicije okvirnih kutija neće biti tačne za autotracking kamere.",
|
||||
"count": "{{first}} od {{second}}",
|
||||
"trackedPoint": "Praćena tačka",
|
||||
"lifecycleItemDesc": {
|
||||
"visible": "{{label}} detektovan",
|
||||
"entered_zone": "{{label}} ušao u {{zones}}",
|
||||
"active": "{{label}} postao aktivno",
|
||||
"stationary": "{{label}} postao stacionarno",
|
||||
"attribute": {
|
||||
"faceOrLicense_plate": "{{attribute}} detektovan za {{label}}",
|
||||
"other": "{{label}} prepoznat kao {{attribute}}"
|
||||
},
|
||||
"gone": "{{label}} otišao",
|
||||
"heard": "{{label}} čujeo",
|
||||
"external": "{{label}} detektovan",
|
||||
"header": {
|
||||
"zones": "Zone",
|
||||
"ratio": "Omjer",
|
||||
"area": "Površina",
|
||||
"score": "Rezultat",
|
||||
"computedScore": "Izračunata ocjena",
|
||||
"topScore": "Najbolja ocjena",
|
||||
"toggleAdvancedScores": "Prekidač naprednih ocjena"
|
||||
}
|
||||
},
|
||||
"annotationSettings": {
|
||||
"title": "Postavke oznaka",
|
||||
"showAllZones": {
|
||||
"title": "Prikaži sve zone",
|
||||
"desc": "Uvijek prikazujte zone na okvirima gdje su objekti ušli u zonu."
|
||||
},
|
||||
"offset": {
|
||||
"label": "Pomak oznaka",
|
||||
"desc": "Ova podatka dolaze iz vaše kamere detektovane snimke, ali se preklapaju na slikama iz snimke snimke. Vjerojatno nije moguće da su dva toka savršeno sinhronizirana. Kao rezultat, okvirni kutiji i snimke neće se savršeno poklopiti. Možete koristiti ovu postavku da pomaknete oznake unaprijed ili unazad u vremenu da bi ih bolje uskladili s snimljenim snimkom.",
|
||||
"millisecondsToOffset": "Milisekunde za pomak detektovanih oznaka. <em>Podrazumevano: 0</em>",
|
||||
"tips": "Smanjite vrijednost ako je reprodukcija videa ispred kutija i tačaka putanje, a povećajte vrijednost ako je reprodukcija videa iza njih. Ova vrijednost može biti negativna.",
|
||||
"toast": {
|
||||
"success": "Pomak anotacije za {{camera}} je sačuvan u konfiguracionu datoteku."
|
||||
}
|
||||
}
|
||||
},
|
||||
"carousel": {
|
||||
"previous": "Prethodni slajd",
|
||||
"next": "Sljedeći slajd"
|
||||
}
|
||||
},
|
||||
"details": {
|
||||
"item": {
|
||||
"title": "Pregled detalja stavke",
|
||||
"desc": "Detalji stavke za pregled",
|
||||
"button": {
|
||||
"share": "Dijelite ovu stavku za pregled",
|
||||
"viewInExplore": "Pregledajte u Explore"
|
||||
},
|
||||
"tips": {
|
||||
"mismatch_one": "{{count}} nedostupan objekat je detektovan i uključen u ovu stavku pregleda. Ti objekti se nisu kvalifikovali kao upozorenje ili detekcija, ili su već očišćeni/obrisani.",
|
||||
"mismatch_few": "{{count}} nedostupnih objekata je detektovano i uključeno u ovu stavku pregleda. Ti objekti se nisu kvalifikovali kao upozorenje ili detekciju, ili su već očišćeni/obrisani.",
|
||||
"mismatch_other": "{{count}} nedostupnih objekata je detektovano i uključeno u ovu stavku pregleda. Ti objekti se nisu kvalifikovali kao upozorenje ili detekciju, ili su već očišćeni/obrisani.",
|
||||
"hasMissingObjects": "Prilagodite svoju konfiguraciju ako želite da Frigate sačuva pratiti objekte za sljedeće oznake: <em>{{objects}}</em>"
|
||||
},
|
||||
"toast": {
|
||||
"success": {
|
||||
"regenerate": "Zahtjev za novi opis je poslat {{provider}}. Ovisno o brzini vašeg provajdera, novi opis može potrajati neko vrijeme da se ponovno generira.",
|
||||
"updatedSublabel": "Uspješno ažurirana podjezika.",
|
||||
"updatedLPR": "Uspješno ažurirana tablica.",
|
||||
"updatedAttributes": "Uspješno ažurirana atribute.",
|
||||
"audioTranscription": "Uspješno zahtjev za audio transkripciju. Ovisno o brzini vašeg Frigate servera, transkripcija može potrajati neko vrijeme da se završi."
|
||||
},
|
||||
"error": {
|
||||
"regenerate": "Neuspješno poziv {{provider}} za novi opis: {{errorMessage}}",
|
||||
"updatedSublabelFailed": "Neuspješno ažuriranje podjezika: {{errorMessage}}",
|
||||
"updatedLPRFailed": "Neuspješno ažuriranje tablice: {{errorMessage}}",
|
||||
"updatedAttributesFailed": "Neuspješno ažuriranje atribute: {{errorMessage}}",
|
||||
"audioTranscription": "Neuspješno zahtjev za audio transkripciju: {{errorMessage}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": "Oznaka",
|
||||
"editSubLabel": {
|
||||
"title": "Uredi podjeziku",
|
||||
"desc": "Unesite novu podjeziku za ovaj {{label}}",
|
||||
"descNoLabel": "Unesite novu podjeziku za ovaj pratiti objekt"
|
||||
},
|
||||
"editLPR": {
|
||||
"title": "Uredi tablica",
|
||||
"desc": "Unesite novu vrijednost tablice za ovaj {{label}}",
|
||||
"descNoLabel": "Unesite novu vrijednost tablice za ovaj praćeni objekt"
|
||||
},
|
||||
"editAttributes": {
|
||||
"title": "Uredi atribute",
|
||||
"desc": "Odaberite atribute klasifikacije za ovaj {{label}}"
|
||||
},
|
||||
"snapshotScore": {
|
||||
"label": "Snimak Rezultat"
|
||||
},
|
||||
"topScore": {
|
||||
"label": "Najbolji Rezultat",
|
||||
"info": "Najbolji rezultat je najviši srednji rezultat za praćeni objekt, pa se može razlikovati od rezultata prikazanog na minijaturi rezultata pretrage."
|
||||
},
|
||||
"score": {
|
||||
"label": "Rezultat"
|
||||
},
|
||||
"recognizedLicensePlate": "Prepoznata tablica",
|
||||
"attributes": "Atributi klasifikacije",
|
||||
"estimatedSpeed": "Procijenjena brzina",
|
||||
"objects": "Objekti",
|
||||
"camera": "Kamera",
|
||||
"zones": "Zone",
|
||||
"timestamp": "Vremenski pečat",
|
||||
"button": {
|
||||
"findSimilar": "Pronađi slične",
|
||||
"regenerate": {
|
||||
"title": "Regeneriraj",
|
||||
"label": "Regeneriraj opis praćenog objekta"
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"label": "Opis",
|
||||
"placeholder": "Opis praćenog objekta",
|
||||
"aiTips": "Frigate neće tražiti opis od vašeg generativnog AI provajdera dok se životni vijek praćenog objekta ne završi."
|
||||
},
|
||||
"expandRegenerationMenu": "Proširi izbornik regeneracije",
|
||||
"regenerateFromSnapshot": "Regeneriraj iz snimka",
|
||||
"regenerateFromThumbnails": "Regeneriraj iz minijatura",
|
||||
"tips": {
|
||||
"descriptionSaved": "Uspješno sačuvan opis",
|
||||
"saveDescriptionFailed": "Neuspješno ažuriranje opisa: {{errorMessage}}"
|
||||
},
|
||||
"title": {
|
||||
"label": "Naslov"
|
||||
},
|
||||
"scoreInfo": "Informacije o rezultatu"
|
||||
},
|
||||
"itemMenu": {
|
||||
"downloadVideo": {
|
||||
"label": "Preuzmi video",
|
||||
"aria": "Preuzmi video"
|
||||
},
|
||||
"downloadSnapshot": {
|
||||
"label": "Preuzmi snimak",
|
||||
"aria": "Preuzmi snimak"
|
||||
},
|
||||
"downloadCleanSnapshot": {
|
||||
"label": "Preuzmi čist snimak",
|
||||
"aria": "Preuzmi čist snimak"
|
||||
},
|
||||
"viewTrackingDetails": {
|
||||
"label": "Pregledaj detalje praćenja",
|
||||
"aria": "Prikaži detalje praćenja"
|
||||
},
|
||||
"findSimilar": {
|
||||
"label": "Pronađi slične",
|
||||
"aria": "Pronađi slične praćene objekte"
|
||||
},
|
||||
"addTrigger": {
|
||||
"label": "Dodaj izazov",
|
||||
"aria": "Dodaj izazov za ovaj praćeni objekt"
|
||||
},
|
||||
"audioTranscription": {
|
||||
"label": "Transkriptiraj",
|
||||
"aria": "Zatraži transkripciju zvuka"
|
||||
},
|
||||
"submitToPlus": {
|
||||
"label": "Pošalji na Frigate+",
|
||||
"aria": "Pošalji na Frigate Plus"
|
||||
},
|
||||
"viewInHistory": {
|
||||
"label": "Pregledajte u povijesti",
|
||||
"aria": "Pregledajte u povijesti"
|
||||
},
|
||||
"deleteTrackedObject": {
|
||||
"label": "Obriši ovaj praćeni objekt"
|
||||
},
|
||||
"showObjectDetails": {
|
||||
"label": "Prikaži put objekta"
|
||||
},
|
||||
"hideObjectDetails": {
|
||||
"label": "Sakrij put objekta"
|
||||
},
|
||||
"debugReplay": {
|
||||
"label": "Debug ponovno snimanje",
|
||||
"aria": "Pregledaj ovaj praćeni objekt u pogledu debug ponovnog snimanja"
|
||||
},
|
||||
"more": {
|
||||
"aria": "Više"
|
||||
}
|
||||
},
|
||||
"dialog": {
|
||||
"confirmDelete": {
|
||||
"title": "Potvrdi brisanje",
|
||||
"desc": "Brisanje ovog praćenog objekta uklanja snimak, bilo kakve sačuvane ugradnje, i sve povezane unose detalja praćenja. Snimljeni materijal ovog praćenog objekta u pogledu povijesti <em>NEĆE</em> biti obrisan.<br /><br />Sigurno li želite nastaviti?"
|
||||
},
|
||||
"toast": {
|
||||
"error": "Greška prilikom brisanja ovog praćenog objekta: {{errorMessage}}"
|
||||
}
|
||||
},
|
||||
"noTrackedObjects": "Nijedan praćeni objekt nije pronađen",
|
||||
"fetchingTrackedObjectsFailed": "Greška prilikom dohvaćanja praćenih objekata: {{errorMessage}}",
|
||||
"trackedObjectsCount_one": "{{count}} praćeni objekt ",
|
||||
"trackedObjectsCount_few": "{{count}} praćena objekta ",
|
||||
"trackedObjectsCount_other": "{{count}} praćena objekta ",
|
||||
"searchResult": {
|
||||
"tooltip": "Pronađeno {{type}} na {{confidence}}%",
|
||||
"previousTrackedObject": "Prethodni praćeni objekt",
|
||||
"nextTrackedObject": "Sljedeći praćeni objekt",
|
||||
"deleteTrackedObject": {
|
||||
"toast": {
|
||||
"success": "Praćeni objekt je uspješno obrisan.",
|
||||
"error": "Neuspješno brisanje praćenog objekta: {{errorMessage}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"aiAnalysis": {
|
||||
"title": "Analiza AI"
|
||||
},
|
||||
"concerns": {
|
||||
"label": "Pitanja"
|
||||
},
|
||||
"objectLifecycle": {
|
||||
"noImageFound": "Nije pronađena slika za ovaj praćeni objekt."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"search": "Pretraga",
|
||||
"documentTitle": "Izvoz - Frigate",
|
||||
"selected_one": "{{count}} odabrano",
|
||||
"selected_other": "{{count}} odabrano",
|
||||
"noExports": "Nijedan izvoz nije pronađen",
|
||||
"headings": {
|
||||
"cases": "Slučajevi",
|
||||
"uncategorizedExports": "Nekategorizirani izvozi"
|
||||
},
|
||||
"deleteExport": {
|
||||
"label": "Obriši izvoz",
|
||||
"desc": "Da li ste sigurni da želite da obrišete {{exportName}}?"
|
||||
},
|
||||
"editExport": {
|
||||
"title": "Preimenuj izvoz",
|
||||
"desc": "Unesite novi naziv za ovaj izvoz.",
|
||||
"saveExport": "Sačuvaj izvoz"
|
||||
},
|
||||
"tooltip": {
|
||||
"shareExport": "Dijeli izvoz",
|
||||
"downloadVideo": "Preuzmi video",
|
||||
"editName": "Uredi naziv",
|
||||
"deleteExport": "Obriši izvoz",
|
||||
"assignToCase": "Dodaj u slučaj",
|
||||
"removeFromCase": "Ukloni iz slučaja"
|
||||
},
|
||||
"toolbar": {
|
||||
"newCase": "Novi slučaj",
|
||||
"addExport": "Dodaj izvoz",
|
||||
"editCase": "Uredi slučaj",
|
||||
"deleteCase": "Obriši slučaj"
|
||||
},
|
||||
"toast": {
|
||||
"error": {
|
||||
"renameExportFailed": "Neuspješno preimenovanje izvoza: {{errorMessage}}",
|
||||
"assignCaseFailed": "Neuspješno ažuriranje dodjele slučaja: {{errorMessage}}",
|
||||
"caseSaveFailed": "Neuspješno čuvanje slučaja: {{errorMessage}}",
|
||||
"caseDeleteFailed": "Neuspješno brisanje slučaja: {{errorMessage}}"
|
||||
}
|
||||
},
|
||||
"deleteCase": {
|
||||
"label": "Obriši slučaj",
|
||||
"desc": "Da li ste sigurni da želite da obrišete {{caseName}}?",
|
||||
"descKeepExports": "Izvozi će ostati dostupni kao nekategorizirani izvozi.",
|
||||
"descDeleteExports": "Svi izvozi u ovom slučaju trajno će biti obrisani.",
|
||||
"deleteExports": "Takođe izbriši izvoze"
|
||||
},
|
||||
"caseDialog": {
|
||||
"title": "Dodaj u slučaj",
|
||||
"description": "Odaberite postojeći slučaj ili napravite novi.",
|
||||
"selectLabel": "Slučaj",
|
||||
"newCaseOption": "Napravite novi slučaj",
|
||||
"nameLabel": "Ime slučaja",
|
||||
"descriptionLabel": "Opis"
|
||||
},
|
||||
"caseCard": {
|
||||
"emptyCase": "Nema još izvoza"
|
||||
},
|
||||
"jobCard": {
|
||||
"defaultName": "{{camera}} izvoz",
|
||||
"queued": "U redu",
|
||||
"running": "Pokretanje",
|
||||
"preparing": "Priprema",
|
||||
"copying": "Kopiranje",
|
||||
"encoding": "Kodiranje",
|
||||
"encodingRetry": "Kodiranje (ponovi)",
|
||||
"finalizing": "Završavanje"
|
||||
},
|
||||
"caseView": {
|
||||
"noDescription": "Nema opisa",
|
||||
"createdAt": "Kreirano {{value}}",
|
||||
"exportCount_one": "1 izvoz",
|
||||
"exportCount_other": "{{count}} izvozi",
|
||||
"cameraCount_one": "1 kamera",
|
||||
"cameraCount_other": "{{count}} kamere",
|
||||
"showMore": "Prikaži više",
|
||||
"showLess": "Prikaži manje",
|
||||
"emptyTitle": "Ovaj slučaj je prazan",
|
||||
"emptyDescription": "Dodaj postojet će nekategorizirane izvoze kako bi slučaj ostao organizovan.",
|
||||
"emptyDescriptionNoExports": "Nema dostupnih nekategoriziranih izvoza koje je moguće dodati još."
|
||||
},
|
||||
"caseEditor": {
|
||||
"createTitle": "Kreiraj slučaj",
|
||||
"editTitle": "Uredi slučaj",
|
||||
"namePlaceholder": "Ime slučaja",
|
||||
"descriptionPlaceholder": "Dodaj napomene ili kontekst za ovaj slučaj"
|
||||
},
|
||||
"addExportDialog": {
|
||||
"title": "Dodaj izvoz u {{caseName}}",
|
||||
"searchPlaceholder": "Pretraga nekategoriziranih izvoza",
|
||||
"empty": "Nema nekategoriziranih izvoza koji odgovaraju ovoj pretrazi.",
|
||||
"addButton_one": "Dodaj 1 izvoz",
|
||||
"addButton_other": "Dodaj {{count}} izvoza",
|
||||
"adding": "Dodavanje..."
|
||||
},
|
||||
"bulkActions": {
|
||||
"addToCase": "Dodaj u slučaj",
|
||||
"moveToCase": "Premjesti u slučaj",
|
||||
"removeFromCase": "Ukloni iz slučaja",
|
||||
"delete": "Obriši",
|
||||
"deleteNow": "Obriši sada"
|
||||
},
|
||||
"bulkDelete": {
|
||||
"title": "Obriši izvoze",
|
||||
"desc_one": "Sigurni li ste da želite obrisati {{count}} izvoz?",
|
||||
"desc_other": "Sigurni li ste da želite obrisati {{count}} izvoze?"
|
||||
},
|
||||
"bulkRemoveFromCase": {
|
||||
"title": "Ukloni iz slučaja",
|
||||
"desc_one": "Ukloni {{count}} izvoz iz ovog slučaja?",
|
||||
"desc_other": "Ukloni {{count}} izvoze iz ovog slučaja?",
|
||||
"descKeepExports": "Izvozi će biti premješteni u nekategorizirane.",
|
||||
"descDeleteExports": "Izvozi će biti trajno obrisani.",
|
||||
"deleteExports": "Umjesto toga, obriši izvoze"
|
||||
},
|
||||
"bulkToast": {
|
||||
"success": {
|
||||
"delete": "Uspješno obrisani izvozi",
|
||||
"reassign": "Uspješno ažurirana dodjela slučaja",
|
||||
"remove": "Uspješno uklonjeni izvozi iz slučaja"
|
||||
},
|
||||
"error": {
|
||||
"deleteFailed": "Neuspješno brisanje izvoza: {{errorMessage}}",
|
||||
"reassignFailed": "Neuspješno ažuriranje dodjele slučaja: {{errorMessage}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"description": {
|
||||
"addFace": "Dodajte novu kolekciju u Biblioteku lica prema učitavanju svoje prve slike.",
|
||||
"placeholder": "Unesite ime za ovu kolekciju",
|
||||
"invalidName": "Neprihvatljivo ime. Imena mogu sadržavati samo slova, brojeve, razmake, aposrofe, donje crte i crte.",
|
||||
"nameCannotContainHash": "Ime ne može sadržavati #."
|
||||
},
|
||||
"details": {
|
||||
"unknown": "Nepoznato",
|
||||
"timestamp": "Vremenski pečat",
|
||||
"scoreInfo": "Ocjena je težinski prosjek svih ocjena lica, težinski određen prema veličini lica u svakoj slici."
|
||||
},
|
||||
"train": {
|
||||
"titleShort": "Nedavno",
|
||||
"title": "Najnovije prepoznavanja",
|
||||
"aria": "Odaberite nedavna prepoznavanja",
|
||||
"empty": "Nema nedavnih pokušaja prepoznavanja lica"
|
||||
},
|
||||
"documentTitle": "Biblioteka lica - Frigate",
|
||||
"uploadFaceImage": {
|
||||
"title": "Učitajte sliku lica",
|
||||
"desc": "Učitajte sliku za skeniranje lica i uključite za {{pageToggle}}"
|
||||
},
|
||||
"collections": "Kolekcije",
|
||||
"createFaceLibrary": {
|
||||
"new": "Stvori novo lice",
|
||||
"nextSteps": "Da biste izgradili čvrstu osnovu:<li>Koristite karticu Najnovije prepoznavanja da biste odabrali i trenirali se na slikama za svaku detektiranu osobu.</li><li>Fokusirajte se na slike iz pravog ugla za najbolje rezultate; izbjegavajte slike za treniranje koje prikazuju lica pod uglom.</li></ul>"
|
||||
},
|
||||
"steps": {
|
||||
"faceName": "Unesite ime lica",
|
||||
"uploadFace": "Učitajte sliku lica",
|
||||
"nextSteps": "Sljedeći koraci",
|
||||
"description": {
|
||||
"uploadFace": "Učitajte sliku od {{name}} koja prikazuje njihovo lice iz pravog ugla. Slika ne mora biti izrezana samo na njihovo lice."
|
||||
}
|
||||
},
|
||||
"deleteFaceLibrary": {
|
||||
"title": "Izbrišite ime",
|
||||
"desc": "Da li ste sigurni da želite izbrisati kolekciju {{name}}? Ovo će trajno izbrisati sva povezana lica."
|
||||
},
|
||||
"deleteFaceAttempts": {
|
||||
"title": "Izbrišite lica",
|
||||
"desc_one": "Da li ste sigurni da želite izbrisati {{count}} lice? Ova akcija ne može se poništiti.",
|
||||
"desc_few": "Da li ste sigurni da želite izbrisati {{count}} lica? Ova akcija ne može se poništiti.",
|
||||
"desc_other": "Da li ste sigurni da želite izbrisati {{count}} lica? Ova akcija ne može se poništiti."
|
||||
},
|
||||
"renameFace": {
|
||||
"title": "Preimenujte lice",
|
||||
"desc": "Unesite novo ime za {{name}}"
|
||||
},
|
||||
"button": {
|
||||
"deleteFaceAttempts": "Izbrišite lica",
|
||||
"addFace": "Dodaj lice",
|
||||
"renameFace": "Preimenuj lice",
|
||||
"deleteFace": "Obriši lice",
|
||||
"uploadImage": "Prenesi sliku",
|
||||
"reprocessFace": "Ponovno obradi lice"
|
||||
},
|
||||
"imageEntry": {
|
||||
"validation": {
|
||||
"selectImage": "Molimo izaberite datoteku slike."
|
||||
},
|
||||
"dropActive": "Pustite sliku ovdje…",
|
||||
"dropInstructions": "Povucite i ispišite, zalijepite sliku ovdje ili kliknite za odabir",
|
||||
"maxSize": "Maksimalna veličina: {{size}}MB"
|
||||
},
|
||||
"nofaces": "Nema dostupnih lica",
|
||||
"trainFaceAs": "Obuči lice kao:",
|
||||
"trainFace": "Obuči lice",
|
||||
"reclassifyFaceAs": "Ponovno klasificiraj lice kao:",
|
||||
"reclassifyFace": "Ponovno klasificiraj lice",
|
||||
"toast": {
|
||||
"success": {
|
||||
"uploadedImage": "Uspješno prenesena slika.",
|
||||
"addFaceLibrary": "{{name}} je uspješno dodan u biblioteku lica!",
|
||||
"deletedFace_one": "Uspješno obrisano {{count}} lice.",
|
||||
"deletedFace_few": "Uspješno obrisana {{count}} lica.",
|
||||
"deletedFace_other": "Uspješno obrisana {{count}} lica.",
|
||||
"deletedName_one": "{{count}} lice je uspješno obrisano.",
|
||||
"deletedName_few": "{{count}} lica su uspješno obrisana.",
|
||||
"deletedName_other": "{{count}} lica su uspješno obrisana.",
|
||||
"renamedFace": "Uspješno preimenovan lice na {{name}}",
|
||||
"trainedFace": "Uspješno obučeno lice.",
|
||||
"reclassifiedFace": "Uspješno ponovno klasificirano lice.",
|
||||
"updatedFaceScore": "Uspješno ažurirana ocjena lica na {{name}} ({{score}})."
|
||||
},
|
||||
"error": {
|
||||
"uploadingImageFailed": "Nije uspješno prenijeti sliku: {{errorMessage}}",
|
||||
"addFaceLibraryFailed": "Nije uspješno postaviti ime lica: {{errorMessage}}",
|
||||
"deleteFaceFailed": "Neuspješno brisanje: {{errorMessage}}",
|
||||
"deleteNameFailed": "Nije uspješno obrisati ime: {{errorMessage}}",
|
||||
"renameFaceFailed": "Nije uspješno preimenovati lice: {{errorMessage}}",
|
||||
"trainFailed": "Nije uspješno trenirati: {{errorMessage}}",
|
||||
"reclassifyFailed": "Nije uspješno ponovno klasifikovati lice: {{errorMessage}}",
|
||||
"updateFaceScoreFailed": "Nije uspješno ažurirati bodove lica: {{errorMessage}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
{
|
||||
"documentTitle": {
|
||||
"default": "Uživo - Frigate",
|
||||
"withCamera": "{{camera}} - Uživo - Frigate"
|
||||
},
|
||||
"lowBandwidthMode": "Nizopojasni režim",
|
||||
"twoWayTalk": {
|
||||
"enable": "Omogući dvostrani razgovor",
|
||||
"disable": "Onemogući dvostrani razgovor"
|
||||
},
|
||||
"cameraAudio": {
|
||||
"enable": "Omogući zvuk kamere",
|
||||
"disable": "Onemogući zvuk kamere"
|
||||
},
|
||||
"ptz": {
|
||||
"move": {
|
||||
"clickMove": {
|
||||
"label": "Kliknite unutar okvira da biste centrirali kameru",
|
||||
"enable": "Omogući klik za pomak",
|
||||
"enableWithZoom": "Omogući klik za pomak / povucite za uvećanje",
|
||||
"disable": "Onemogući klik za pomak"
|
||||
},
|
||||
"left": {
|
||||
"label": "Pomaknite PTZ kameru ulevo"
|
||||
},
|
||||
"up": {
|
||||
"label": "Pomaknite PTZ kameru gore"
|
||||
},
|
||||
"down": {
|
||||
"label": "Pomaknite PTZ kameru dolje"
|
||||
},
|
||||
"right": {
|
||||
"label": "Pomaknite PTZ kameru udesno"
|
||||
}
|
||||
},
|
||||
"zoom": {
|
||||
"in": {
|
||||
"label": "Uvećajte PTZ kameru"
|
||||
},
|
||||
"out": {
|
||||
"label": "Umanjite PTZ kameru"
|
||||
}
|
||||
},
|
||||
"focus": {
|
||||
"in": {
|
||||
"label": "Fokusirajte PTZ kameru unapred"
|
||||
},
|
||||
"out": {
|
||||
"label": "Fokusirajte PTZ kameru unazad"
|
||||
}
|
||||
},
|
||||
"frame": {
|
||||
"center": {
|
||||
"label": "Kliknite unutar okvira da biste centrirali PTZ kameru"
|
||||
}
|
||||
},
|
||||
"presets": "Preseti PTZ kamere"
|
||||
},
|
||||
"camera": {
|
||||
"enable": "Omogući kameru",
|
||||
"disable": "Onemogući kameru"
|
||||
},
|
||||
"muteCameras": {
|
||||
"enable": "Utišajte sve kamere",
|
||||
"disable": "Ponovo uključite zvuk za sve kamere"
|
||||
},
|
||||
"detect": {
|
||||
"enable": "Omogući detekciju",
|
||||
"disable": "Onemogući detekciju"
|
||||
},
|
||||
"recording": {
|
||||
"enable": "Omogući snimanje",
|
||||
"disable": "Onemogući snimanje"
|
||||
},
|
||||
"snapshots": {
|
||||
"enable": "Omogući snimke",
|
||||
"disable": "Onemogući snimke"
|
||||
},
|
||||
"snapshot": {
|
||||
"takeSnapshot": "Preuzmi trenutni snimak",
|
||||
"noVideoSource": "Nema dostupnog video izvora za snimak.",
|
||||
"captureFailed": "Neuspješno snimanje trenutnog snimka.",
|
||||
"downloadStarted": "Preuzimanje trenutnog snimka započeto."
|
||||
},
|
||||
"audioDetect": {
|
||||
"enable": "Omogući detekciju zvuka",
|
||||
"disable": "Onemogući detekciju zvuka"
|
||||
},
|
||||
"transcription": {
|
||||
"enable": "Omogući prepoznavanje zvuka uživo",
|
||||
"disable": "Onemogući prepoznavanje zvuka uživo"
|
||||
},
|
||||
"autotracking": {
|
||||
"enable": "Omogući automatsko praćenje",
|
||||
"disable": "Onemogući automatsko praćenje"
|
||||
},
|
||||
"streamStats": {
|
||||
"enable": "Prikaži statistiku prijenosa",
|
||||
"disable": "Sakrij statistiku prijenosa"
|
||||
},
|
||||
"manualRecording": {
|
||||
"title": "Na zahtjev",
|
||||
"tips": "Preuzmi trenutni snimak ili pokreni ručni događaj na temelju postavki trajanja snimanja ove kamere.",
|
||||
"playInBackground": {
|
||||
"label": "Ponovno postavi stream",
|
||||
"desc": "Omogući ovu opciju da nastavi streamanje kada je pokazivač sakriven."
|
||||
},
|
||||
"showStats": {
|
||||
"label": "Prikaži statistiku",
|
||||
"desc": "Omogući ovu opciju da prikaže statistiku prijenosa kao preklapanje na toku kamere."
|
||||
},
|
||||
"debugView": "Pregled za otklanjanje grešaka",
|
||||
"start": "Počni snimanje na zahtjev",
|
||||
"started": "Pokrenuto ručno snimanje na zahtjev.",
|
||||
"failedToStart": "Neuspješno pokretanje ručnog snimanja na zahtjev.",
|
||||
"recordDisabledTips": "Kako je snimanje onemogućeno ili ograničeno u konfiguraciji za ovu kameru, spremat će se samo snimak.",
|
||||
"end": "Završi snimanje na zahtjev",
|
||||
"ended": "Završeno ručno snimanje na zahtjev.",
|
||||
"failedToEnd": "Neuspješno završavanje ručnog snimanja na zahtjev."
|
||||
},
|
||||
"streamingSettings": "Postavke streamanja",
|
||||
"notifications": "Obavještenja",
|
||||
"audio": "Audio",
|
||||
"suspend": {
|
||||
"forTime": "Pauziraj za: "
|
||||
},
|
||||
"stream": {
|
||||
"title": "Tok",
|
||||
"audio": {
|
||||
"tips": {
|
||||
"title": "Audio mora biti izlaz iz vaše kamere i konfiguriran u go2rtc za ovaj stream."
|
||||
},
|
||||
"available": "Audio je dostupan za ovaj stream",
|
||||
"unavailable": "Audio nije dostupan za ovaj stream"
|
||||
},
|
||||
"debug": {
|
||||
"picker": "Izbor streama nije dostupan u režimu debuga. Pregled debuga uvijek koristi stream dodeljen ulozi detekcije."
|
||||
},
|
||||
"twoWayTalk": {
|
||||
"tips": "Vaš uređaj mora podržavati funkciju, a WebRTC mora biti konfiguriran za dvosmernu komunikaciju.",
|
||||
"available": "Dvosmerna komunikacija je dostupna za ovaj stream",
|
||||
"unavailable": "Dvosmerna komunikacija nije dostupna za ovaj stream"
|
||||
},
|
||||
"lowBandwidth": {
|
||||
"tips": "Živo prikazivanje je u režimu niske propusnosti zbog buferiranja ili grešaka u streamu.",
|
||||
"resetStream": "Ponovno postavi stream"
|
||||
},
|
||||
"playInBackground": {
|
||||
"label": "Ponovno postavi stream",
|
||||
"tips": "Omogući ovu opciju da nastavi streamanje kada je pokazivač sakriven."
|
||||
}
|
||||
},
|
||||
"cameraSettings": {
|
||||
"title": "{{camera}} Postavke",
|
||||
"cameraEnabled": "Kamera omogućena",
|
||||
"objectDetection": "Detekcija objekata",
|
||||
"recording": "Snimanje",
|
||||
"snapshots": "Snimci",
|
||||
"audioDetection": "Detekcija zvuka",
|
||||
"transcription": "Transkripcija zvuka",
|
||||
"autotracking": "Autotračenje"
|
||||
},
|
||||
"history": {
|
||||
"label": "Prikaži povijesne snimke"
|
||||
},
|
||||
"effectiveRetainMode": {
|
||||
"modes": {
|
||||
"all": "Sve",
|
||||
"motion": "Kretanje",
|
||||
"active_objects": "Aktivni objekti"
|
||||
}
|
||||
},
|
||||
"editLayout": {
|
||||
"label": "Uredi raspored",
|
||||
"group": {
|
||||
"label": "Uredi grupu kamera"
|
||||
},
|
||||
"exitEdit": "Izađi iz uređivanja"
|
||||
},
|
||||
"noCameras": {
|
||||
"title": "Nema konfiguriranih kamera",
|
||||
"description": "Počnite tako što ćete povezati kameru s Frigate.",
|
||||
"buttonText": "Dodaj kameru",
|
||||
"restricted": {
|
||||
"title": "Nema dostupnih kamera",
|
||||
"description": "Nemate dozvolu za pregled bilo koje kamere u ovoj grupi."
|
||||
},
|
||||
"default": {
|
||||
"title": "Nema konfiguriranih kamera",
|
||||
"description": "Počnite tako što ćete povezati kameru s Frigate.",
|
||||
"buttonText": "Dodaj kameru"
|
||||
},
|
||||
"group": {
|
||||
"title": "Nema kamera u grupi",
|
||||
"description": "Ova grupa kamera nema dodeljene ili omogućene kamere.",
|
||||
"buttonText": "Upravljajte grupama"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"documentTitle": "Pretraga pokreta - Frigate",
|
||||
"title": "Pretraga pokreta",
|
||||
"description": "Nacrtaj poligon da biste definirali regiju interesa, a zatim navedite vremenski raspon za pretragu promjena pokreta unutar te regije.",
|
||||
"selectCamera": "Pretraga pokreta učitava se",
|
||||
"startSearch": "Počni pretragu",
|
||||
"searchStarted": "Pretraga započeta",
|
||||
"searchCancelled": "Pretraga otkazana",
|
||||
"cancelSearch": "Otkaži",
|
||||
"searching": "Pretraga u toku.",
|
||||
"searchComplete": "Pretraga završena",
|
||||
"noResultsYet": "Pokrenite pretragu da biste pronašli promjene pokreta u odabranoj regiji",
|
||||
"noChangesFound": "Nisu otkrivene promjene piksela u odabranoj regiji",
|
||||
"changesFound_one": "Pronađeno {{count}} promjena pokreta",
|
||||
"changesFound_few": "Pronađeno {{count}} nekoliko pokreta",
|
||||
"changesFound_other": "Pronađeno {{count}} promjene pokreta",
|
||||
"framesProcessed": "{{count}} okvir procesiran",
|
||||
"jumpToTime": "Preskoči na ovo vrijeme",
|
||||
"results": "Rezultati",
|
||||
"showSegmentHeatmap": "Top mapa",
|
||||
"newSearch": "Nova pretraga",
|
||||
"clearResults": "Očisti rezultate",
|
||||
"clearROI": "Očisti poligon",
|
||||
"polygonControls": {
|
||||
"points_one": "{{count}} tačka",
|
||||
"points_few": "{{count}} tačke",
|
||||
"points_other": "{{count}} tačke",
|
||||
"undo": "Poništi posljednju tačku",
|
||||
"reset": "Ponovi poligon"
|
||||
},
|
||||
"motionHeatmapLabel": "Top mapa pokreta",
|
||||
"dialog": {
|
||||
"title": "Pretraga pokreta",
|
||||
"cameraLabel": "Kamera",
|
||||
"previewAlt": "Pregled kamere za {{camera}}"
|
||||
},
|
||||
"timeRange": {
|
||||
"title": "Opseg pretrage",
|
||||
"start": "Početno vrijeme",
|
||||
"end": "Krajnje vrijeme"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Postavke pretrage",
|
||||
"parallelMode": "Paralelni način",
|
||||
"parallelModeDesc": "Skeniranje više segmenata snimaka istovremeno (brže, ali značajno intenzivnije za CPU)",
|
||||
"threshold": "Praga osjetljivosti",
|
||||
"thresholdDesc": "Niže vrijednosti detektiraju manje promjene (1-255)",
|
||||
"minArea": "Minimalna površina promjene",
|
||||
"minAreaDesc": "Minimalni postotak područja interesa koji mora promijeniti da bi se smatrao značajnim",
|
||||
"frameSkip": "Preskoči okvir",
|
||||
"frameSkipDesc": "Obrađujte svaki N-ti okvir. Postavite ovo na brzinu okvira vaše kamere da biste obradili jedan okvir po sekundi (npr. 5 za 5 FPS kameru, 30 za 30 FPS kameru). Više vrijednosti će biti brže, ali mogu propustiti kratke događaje pokreta.",
|
||||
"maxResults": "Maksimalni rezultati",
|
||||
"maxResultsDesc": "Zaustavi nakon ovog broja odgovarajućih vremenskih oznaka"
|
||||
},
|
||||
"errors": {
|
||||
"noCamera": "Molimo odaberite kameru",
|
||||
"noROI": "Molimo nacrtajte područje interesa",
|
||||
"noTimeRange": "Molimo odaberite vremenski opseg",
|
||||
"invalidTimeRange": "Krajnje vrijeme mora biti nakon početnog vremena",
|
||||
"searchFailed": "Pretraga neuspješna: {{message}}",
|
||||
"polygonTooSmall": "Poligon mora imati najmanje 3 točke",
|
||||
"unknown": "Nepoznata greška"
|
||||
},
|
||||
"changePercentage": "{{percentage}}% promijenjeno",
|
||||
"metrics": {
|
||||
"title": "Metrike pretrage",
|
||||
"segmentsScanned": "Skenirani segmenti",
|
||||
"segmentsProcessed": "Obrađeno",
|
||||
"segmentsSkippedInactive": "Preskočeno (bez aktivnosti)",
|
||||
"segmentsSkippedHeatmap": "Preskočeno (bez preklapanja ROI)",
|
||||
"fallbackFullRange": "Povratni put skeniranje cijelog opsega",
|
||||
"framesDecoded": "Dekodirani okviri",
|
||||
"wallTime": "Vrijeme pretrage",
|
||||
"segmentErrors": "Greške segmenta",
|
||||
"seconds": "{{seconds}}s"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"filter": "Filtar",
|
||||
"export": "Izvoz",
|
||||
"calendar": "Kalendar",
|
||||
"filters": "Filtari",
|
||||
"toast": {
|
||||
"error": {
|
||||
"noValidTimeSelected": "Nije odabran valjan vremenski opseg",
|
||||
"endTimeMustAfterStartTime": "Krajnje vrijeme mora biti nakon početnog vremena"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"title": "Debug ponavljanje",
|
||||
"description": "Ponovno prikazivanje snimaka kamere za ispitivanje. Lista objekata prikazuje zakasnjelje sažetak detektiranih objekata, a kartica Zapisi prikazuje tok unutrašnjih poruka Frigate iz snimaka ponavljanja.",
|
||||
"websocket_messages": "Poruke",
|
||||
"dialog": {
|
||||
"title": "Počni debug ponavljanje",
|
||||
"description": "Kreiraj privremenu kameru za ponavljanje koja ponavlja povijesne snimke za ispitivanje problema detekcije i praćenja objekata. Kamera za ponavljanje će imati istu konfiguraciju detekcije kao i izvorna kamera. Odaberite vremenski raspon za početak.",
|
||||
"camera": "Izvorna kamera",
|
||||
"timeRange": "Vremenski opseg",
|
||||
"preset": {
|
||||
"1m": "Posljednja 1 minuta",
|
||||
"5m": "Posljednje 5 minuta",
|
||||
"timeline": "Iz vremenske linije",
|
||||
"custom": "Prilagođeno"
|
||||
},
|
||||
"startButton": "Počni ponavljanje",
|
||||
"selectFromTimeline": "Odaberite",
|
||||
"starting": "Pokretanje ponavljanja...",
|
||||
"startLabel": "Početak",
|
||||
"endLabel": "Kraj",
|
||||
"toast": {
|
||||
"error": "Neuspješno pokretanje debug ponavljanja: {{error}}",
|
||||
"alreadyActive": "Već postoji aktivna sesija ponavljanja",
|
||||
"stopError": "Neuspješno zaustavljanje debug ponavljanja: {{error}}",
|
||||
"goToReplay": "Idi na ponavljanje"
|
||||
}
|
||||
},
|
||||
"page": {
|
||||
"noSession": "Nema aktivne sesije ponavljanja",
|
||||
"noSessionDesc": "Pokrenite debug ponavljanje iz pogleda Povijest klikom na dugme Debug Replay u alatnoj traci.",
|
||||
"goToRecordings": "Idi na povijest",
|
||||
"sourceCamera": "Izvorna kamera",
|
||||
"replayCamera": "Kamera za ponavljanje",
|
||||
"initializingReplay": "Inicijalizacija ponavljanja...",
|
||||
"stoppingReplay": "Zaustavljanje ponavljanja...",
|
||||
"stopReplay": "Zaustavi ponavljanje",
|
||||
"confirmStop": {
|
||||
"title": "Zaustavi režim ponavljanja za debagovanje?",
|
||||
"description": "Ovo će zaustaviti sesiju ponavljanja i očistiti sve privremene podatke. Sigurni li?",
|
||||
"confirm": "Zaustavi ponavljanje",
|
||||
"cancel": "Otkaži"
|
||||
},
|
||||
"activity": "Aktivnost",
|
||||
"objects": "Popis objekata",
|
||||
"audioDetections": "Audio detekcije",
|
||||
"noActivity": "Nema detektovane aktivnosti",
|
||||
"activeTracking": "Aktivno praćenje",
|
||||
"noActiveTracking": "Nema aktivnog praćenja",
|
||||
"configuration": "Konfiguracija",
|
||||
"configurationDesc": "Podesiti precizno detekciju pokreta i praćenje objekata za kameru za debagovanje ponavljanja. Promjene se ne čuvaju u datoteci konfiguracije Frigate.",
|
||||
"preparingClip": "Pripremam klip…",
|
||||
"preparingClipDesc": "Frigate spaja snimke za odabrani vremenski raspon. Ovo može potrajati minut za duže raspone.",
|
||||
"startingCamera": "Pokretanje ponovnog pokretanja otklanjanja grešaka…",
|
||||
"startError": {
|
||||
"title": "Neuspjelo pokretanje ponovnog prikaza otklanjanja grešaka",
|
||||
"back": "Povratak na historiju"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"search": "Pretraga",
|
||||
"button": {
|
||||
"save": "Sačuvaj pretragu",
|
||||
"clear": "Očisti pretragu",
|
||||
"delete": "Obriši sačuvanu pretragu",
|
||||
"filterInformation": "Filtrirajte informacije",
|
||||
"filterActive": "Filtari aktivni"
|
||||
},
|
||||
"savedSearches": "Sačuvane pretrage",
|
||||
"searchFor": "Pretraga za {{inputValue}}",
|
||||
"trackedObjectId": "ID praćenog objekta",
|
||||
"filter": {
|
||||
"label": {
|
||||
"cameras": "Kamere",
|
||||
"labels": "Oznake",
|
||||
"zones": "Zone",
|
||||
"sub_labels": "Podoznake",
|
||||
"attributes": "Atributi",
|
||||
"search_type": "Tip pretrage",
|
||||
"time_range": "Vremenski opseg",
|
||||
"before": "Prije",
|
||||
"after": "Nakon",
|
||||
"min_score": "Min. bodovi",
|
||||
"max_score": "Max. bodovi",
|
||||
"min_speed": "Min. brzina",
|
||||
"max_speed": "Max. brzina",
|
||||
"recognized_license_plate": "Prepoznata tablica",
|
||||
"has_clip": "Ima klip",
|
||||
"has_snapshot": "Ima snimak"
|
||||
},
|
||||
"searchType": {
|
||||
"thumbnail": "Minijatura",
|
||||
"description": "Opis"
|
||||
},
|
||||
"toast": {
|
||||
"error": {
|
||||
"beforeDateBeLaterAfter": "Datum 'before' mora biti kasniji od datuma 'after'.",
|
||||
"afterDatebeEarlierBefore": "Datum 'after' mora biti raniji od datuma 'before'.",
|
||||
"minScoreMustBeLessOrEqualMaxScore": "Vrijednost 'min_score' mora biti manja ili jednaka vrijednosti 'max_score'.",
|
||||
"maxScoreMustBeGreaterOrEqualMinScore": "Vrijednost 'max_score' mora biti veća ili jednaka vrijednosti 'min_score'.",
|
||||
"minSpeedMustBeLessOrEqualMaxSpeed": "Vrijednost 'min_speed' mora biti manja ili jednaka vrijednosti 'max_speed'.",
|
||||
"maxSpeedMustBeGreaterOrEqualMinSpeed": "Vrijednost 'max_speed' mora biti veća ili jednaka vrijednosti 'min_speed'."
|
||||
}
|
||||
},
|
||||
"tips": {
|
||||
"title": "Kako koristiti tekstualne filtere",
|
||||
"desc": {
|
||||
"text": "Filteri vam pomažu da sužite rezultate pretrage. Evo kako ih koristiti u polju za unos:",
|
||||
"step1": "Unesite ime ključa filtera, zatim dvojtočku (npr. \"kamere:\").",
|
||||
"step2": "Izaberite vrijednost iz predloga ili unesite vlastitu.",
|
||||
"step3": "Koristite više filtera dodavanjem jednog za drugim s razmakom između.",
|
||||
"step4": "Filteri datuma (pre: i nakon:) koriste {{DateFormat}} format.",
|
||||
"step5": "Filter raspona vremena koristi format {{exampleTime}}.",
|
||||
"step6": "Uklonite filtre klikom na 'x' pored njih.",
|
||||
"exampleLabel": "Primjer:"
|
||||
}
|
||||
},
|
||||
"header": {
|
||||
"currentFilterType": "Vrijednosti filtera",
|
||||
"noFilters": "Filtari",
|
||||
"activeFilters": "Aktivni filteri"
|
||||
}
|
||||
},
|
||||
"similaritySearch": {
|
||||
"title": "Pretraga sličnosti",
|
||||
"active": "Pretraga sličnosti aktivna",
|
||||
"clear": "Očisti pretragu sličnosti"
|
||||
},
|
||||
"placeholder": {
|
||||
"search": "Pretraži…"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,256 @@
|
||||
{
|
||||
"documentTitle": {
|
||||
"cameras": "Statistika kamere - Frigate",
|
||||
"storage": "Statistika skladišta - Frigate",
|
||||
"general": "Opća statistika - Frigate",
|
||||
"enrichments": "Statistika bogatstva - Frigate",
|
||||
"logs": {
|
||||
"frigate": "Zapisi Frigate - Frigate",
|
||||
"go2rtc": "Zapisi Go2RTC - Frigate",
|
||||
"nginx": "Zapisi Nginx - Frigate",
|
||||
"websocket": "Zapisi poruka - Frigate"
|
||||
}
|
||||
},
|
||||
"title": "Sistem",
|
||||
"metrics": "Sistem metrike",
|
||||
"logs": {
|
||||
"websocket": {
|
||||
"label": "Zapisi",
|
||||
"pause": "Pauziraj",
|
||||
"resume": "Nastavi",
|
||||
"clear": "Očisti",
|
||||
"filter": {
|
||||
"all": "Svi temi",
|
||||
"topics": "Teme",
|
||||
"events": "Događaji",
|
||||
"reviews": "Pregledi",
|
||||
"classification": "Klasifikacija",
|
||||
"face_recognition": "Prepoznavanje lica",
|
||||
"lpr": "LPR",
|
||||
"camera_activity": "Aktivnost kamere",
|
||||
"system": "Sistem",
|
||||
"camera": "Kamera",
|
||||
"all_cameras": "Sve kamere",
|
||||
"cameras_count_one": "{{count}} Kamera",
|
||||
"cameras_count_other": "{{count}} Kamere"
|
||||
},
|
||||
"empty": "Nema još prihvaćenih poruka",
|
||||
"count_one": "{{count}} poruka",
|
||||
"count_other": "{{count}} poruke",
|
||||
"expanded": {
|
||||
"payload": "Opterećenje"
|
||||
}
|
||||
},
|
||||
"download": {
|
||||
"label": "Preuzimanje zapisa"
|
||||
},
|
||||
"copy": {
|
||||
"label": "Kopiraj u clipboard",
|
||||
"success": "Zapisi su kopirani u clipboard",
|
||||
"error": "Nije moguće kopirati zapise u clipboard"
|
||||
},
|
||||
"type": {
|
||||
"label": "Tip",
|
||||
"timestamp": "Vremenski pečat",
|
||||
"tag": "Oznaka",
|
||||
"message": "Poruka"
|
||||
},
|
||||
"tips": "Zapisi se prenose sa servera",
|
||||
"toast": {
|
||||
"error": {
|
||||
"fetchingLogsFailed": "Greška prilikom preuzimanja zapisa: {{errorMessage}}",
|
||||
"whileStreamingLogs": "Greška prilikom prijenosa protokola: {{errorMessage}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"general": {
|
||||
"title": "Općenito",
|
||||
"detector": {
|
||||
"title": "Detektori",
|
||||
"inferenceSpeed": "Brzina zaključivanja detektora",
|
||||
"temperature": "Temperatura detektora",
|
||||
"cpuUsage": "Korištenje CPU detektora",
|
||||
"cpuUsageInformation": "CPU korištena za pripremu ulaznih i izlaznih podataka za/iz modela detekcije. Ova vrijednost ne mjeri korištenje zaključivanja, čak i ako se koristi GPU ili ubrzivač.",
|
||||
"memoryUsage": "Korištenje memorije detektora"
|
||||
},
|
||||
"hardwareInfo": {
|
||||
"title": "Hardverske informacije",
|
||||
"gpuUsage": "Korištenje GPU",
|
||||
"gpuMemory": "Memorija GPU",
|
||||
"gpuEncoder": "Kodiralo GPU",
|
||||
"gpuCompute": "GPU Izračunavanje / Kodiranje",
|
||||
"gpuDecoder": "Dekodiranje GPU",
|
||||
"gpuTemperature": "Temperatura GPU",
|
||||
"gpuInfo": {
|
||||
"vainfoOutput": {
|
||||
"title": "Vainfo Izlaz",
|
||||
"returnCode": "Kod povratka: {{code}}",
|
||||
"processOutput": "Izlaz procesa:",
|
||||
"processError": "Greška procesa:"
|
||||
},
|
||||
"nvidiaSMIOutput": {
|
||||
"title": "Nvidia SMI Izlaz",
|
||||
"name": "Ime: {{name}}",
|
||||
"driver": "Vozač: {{driver}}",
|
||||
"cudaComputerCapability": "CUDA sposobnost izračunavanja: {{cuda_compute}}",
|
||||
"vbios": "VBios informacije: {{vbios}}"
|
||||
},
|
||||
"closeInfo": {
|
||||
"label": "Zatvori informacije GPU"
|
||||
},
|
||||
"copyInfo": {
|
||||
"label": "Kopiraj informacije GPU"
|
||||
},
|
||||
"toast": {
|
||||
"success": "Kopirano informacije GPU u međuspremnik"
|
||||
}
|
||||
},
|
||||
"npuUsage": "Korišćenje NPU",
|
||||
"npuMemory": "Memorija NPU",
|
||||
"npuTemperature": "Temperatura NPU",
|
||||
"intelGpuWarning": {
|
||||
"title": "Upozorenje o statistikama Intel GPU",
|
||||
"message": "Statistike GPU nedostupne",
|
||||
"description": "Ovo je poznati bug u alatima za prikaz statistika Intel GPU (intel_gpu_top) gdje će se prekiniti i ponovo vratiti GPU korišćenje od 0% čak i u slučajevima kada se hardverska akceleracija i detekcija objekata ispravno izvršavaju na (i)GPU. Ovo nije bug Frigate. Možete ponovo pokrenuti host kako biste privremeno popravili problem i potvrdili da GPU radi ispravno. Ovo ne utiče na performanse."
|
||||
}
|
||||
},
|
||||
"otherProcesses": {
|
||||
"title": "Drugi procesi",
|
||||
"processCpuUsage": "Korišćenje CPU procesa",
|
||||
"processMemoryUsage": "Korišćenje memorije procesa",
|
||||
"series": {
|
||||
"go2rtc": "go2rtc",
|
||||
"recording": "Snimanje",
|
||||
"review_segment": "pregled segmenta",
|
||||
"embeddings": "Ugrađivanja",
|
||||
"audio_detector": "audio detektor"
|
||||
}
|
||||
}
|
||||
},
|
||||
"storage": {
|
||||
"title": "Skladište",
|
||||
"overview": "Pregled",
|
||||
"recordings": {
|
||||
"title": "Snimci",
|
||||
"tips": "Ova vrijednost predstavlja ukupno skladište koje se koristi za snimke u bazi podataka Frigate. Frigate ne praćenje korišćenje skladišta za sve datoteke na vašem disku.",
|
||||
"earliestRecording": "Najstariji dostupni snimak:"
|
||||
},
|
||||
"shm": {
|
||||
"title": "Alokacija SHM (deljenja memorije)",
|
||||
"warning": "Trenutna veličina SHM od {{total}}MB je prevelika. Povećajte je na najmanje {{min_shm}}MB.",
|
||||
"frameLifetime": {
|
||||
"title": "Vijek trajanja okvira",
|
||||
"description": "Svaka kamera ima {{frames}} slotova za okvire u deljenoj memoriji. Na najbržoj brzini okvira kamere, svaki okvir je dostupan za približno {{lifetime}}s prije nego što se prepiše."
|
||||
}
|
||||
},
|
||||
"cameraStorage": {
|
||||
"title": "Skladište kamere",
|
||||
"camera": "Kamera",
|
||||
"unusedStorageInformation": "Informacije o neiskorišćenom skladištu",
|
||||
"storageUsed": "Skladište",
|
||||
"percentageOfTotalUsed": "Postotak ukupno",
|
||||
"bandwidth": "Širina pojasa",
|
||||
"unused": {
|
||||
"title": "Neiskorišćeno",
|
||||
"tips": "Ova vrijednost može nepravilno predstavljati slobodno prostor dostupan Frigate ako imate druge datoteke pohranjene na vašem disku izvan snimaka Frigate. Frigate ne praćenje korišćenje skladišta izvan svojih snimaka."
|
||||
}
|
||||
}
|
||||
},
|
||||
"cameras": {
|
||||
"title": "Kamere",
|
||||
"overview": "Pregled",
|
||||
"info": {
|
||||
"aspectRatio": "odnos stranica",
|
||||
"cameraProbeInfo": "{{camera}} Informacije o ispitivanju kamere",
|
||||
"streamDataFromFFPROBE": "Podaci o prijenosu se dobijaju pomoću <code>ffprobe</code>.",
|
||||
"fetching": "Prenošenje podataka o kameri",
|
||||
"stream": "Prijenos {{idx}}",
|
||||
"video": "Video:",
|
||||
"codec": "Kodek:",
|
||||
"resolution": "Rješenje:",
|
||||
"fps": "FPS:",
|
||||
"unknown": "Nepoznato",
|
||||
"audio": "Zvuk:",
|
||||
"error": "Greška: {{error}}",
|
||||
"tips": {
|
||||
"title": "Informacije o ispitivanju kamere"
|
||||
}
|
||||
},
|
||||
"framesAndDetections": "Okviri / Detekcije",
|
||||
"label": {
|
||||
"camera": "Kamera",
|
||||
"detect": "detektirati",
|
||||
"skipped": "preskočeno",
|
||||
"ffmpeg": "FFmpeg",
|
||||
"capture": "snimiti",
|
||||
"overallFramesPerSecond": "ukupni okviri po sekundi",
|
||||
"overallDetectionsPerSecond": "ukupne detekcije po sekundi",
|
||||
"overallSkippedDetectionsPerSecond": "ukupno preskočene detekcije po sekundi",
|
||||
"cameraFfmpeg": "{{camName}} FFmpeg",
|
||||
"cameraCapture": "{{camName}} snimiti",
|
||||
"cameraDetect": "{{camName}} detektirati",
|
||||
"cameraGpu": "{{camName}} GPU",
|
||||
"cameraFramesPerSecond": "{{camName}} okviri po sekundi",
|
||||
"cameraDetectionsPerSecond": "{{camName}} detekcije po sekundi",
|
||||
"cameraSkippedDetectionsPerSecond": "{{camName}} preskočenih detekcija u sekundi"
|
||||
},
|
||||
"connectionQuality": {
|
||||
"title": "Kvaliteta veze",
|
||||
"excellent": "Izuzetno dobra",
|
||||
"fair": "Uredna",
|
||||
"poor": "Loša",
|
||||
"unusable": "Nepogodna",
|
||||
"fps": "FPS",
|
||||
"expectedFps": "Očekivani FPS",
|
||||
"reconnectsLastHour": "Ponovne povezivanja (posljednje satu)",
|
||||
"stallsLastHour": "Pauze (posljednje satu)"
|
||||
},
|
||||
"toast": {
|
||||
"success": {
|
||||
"copyToClipboard": "Podaci o testiranju kopirani u clipboard."
|
||||
},
|
||||
"error": {
|
||||
"unableToProbeCamera": "Nemoguće testiranje kamere: {{errorMessage}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lastRefreshed": "Posljednje ažuriranje: ",
|
||||
"stats": {
|
||||
"ffmpegHighCpuUsage": "{{camera}} ima visoku upotrebu CPU za FFmpeg ({{ffmpegAvg}}%)",
|
||||
"detectHighCpuUsage": "{{camera}} ima visoku upotrebu CPU za detekciju ({{detectAvg}}%)",
|
||||
"healthy": "Sistem je zdrav",
|
||||
"reindexingEmbeddings": "Ponovno indeksiranje ugrađenih vjerodajnica ({{processed}}% završeno)",
|
||||
"cameraIsOffline": "{{camera}} je offline",
|
||||
"detectIsSlow": "{{detect}} je spor ({{speed}} ms)",
|
||||
"detectIsVerySlow": "{{detect}} je vrlo spor ({{speed}} ms)",
|
||||
"shmTooLow": "/dev/shm alokacija ({{total}} MB) treba povećati na najmanje {{min}} MB.",
|
||||
"debugReplayActive": "Debug ponavljanje sesije je aktivno"
|
||||
},
|
||||
"enrichments": {
|
||||
"title": "Obogaćivanja",
|
||||
"infPerSecond": "Inferencije po sekundi",
|
||||
"averageInf": "Prosjek vremena inferencije",
|
||||
"embeddings": {
|
||||
"image_embedding": "Slika ugrađenih vjerodajnica",
|
||||
"text_embedding": "Tekst ugrađenih vjerodajnica",
|
||||
"face_recognition": "Prepoznavanje lica",
|
||||
"plate_recognition": "Prepoznavanje ploča",
|
||||
"image_embedding_speed": "Brzina ugradnje slika",
|
||||
"face_embedding_speed": "Brzina ugradnje lica",
|
||||
"face_recognition_speed": "Brzina prepoznavanja lica",
|
||||
"plate_recognition_speed": "Brzina prepoznavanja ploča",
|
||||
"text_embedding_speed": "Brzina ugradnje teksta",
|
||||
"yolov9_plate_detection_speed": "Brzina detekcije ploča YOLOv9",
|
||||
"yolov9_plate_detection": "Detekcija ploča YOLOv9",
|
||||
"review_description": "Pregled opisa",
|
||||
"review_description_speed": "Brzina pregleda opisa",
|
||||
"review_description_events_per_second": "Pregled opisa",
|
||||
"object_description": "Opis objekta",
|
||||
"object_description_speed": "Brzina opisa objekta",
|
||||
"object_description_events_per_second": "Opis objekta",
|
||||
"classification": "{{name}} Klasifikacija",
|
||||
"classification_speed": "{{name}} Brzina klasifikacije",
|
||||
"classification_events_per_second": "{{name}} Događaji klasifikacije po sekundi"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,7 +242,7 @@
|
||||
"done": "Fet",
|
||||
"disabled": "Deshabilitat",
|
||||
"disable": "Deshabilitar",
|
||||
"save": "Guardar",
|
||||
"save": "Desa",
|
||||
"copy": "Copiar",
|
||||
"back": "Enrere",
|
||||
"pictureInPicture": "Imatge en Imatge",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"description": "Habilitat"
|
||||
},
|
||||
"audio": {
|
||||
"label": "Esdeveniments d'àudio",
|
||||
"label": "Detecció d'àudio",
|
||||
"description": "Configuració per a la detecció d'esdeveniments basats en àudio per a aquesta càmera.",
|
||||
"enabled": {
|
||||
"label": "Habilita la detecció d'àudio",
|
||||
@@ -485,6 +485,10 @@
|
||||
"hwaccel_args": {
|
||||
"label": "Exporta els arguments de l'hwaccel",
|
||||
"description": "Args d'acceleració de maquinari a utilitzar per a operacions d'exportació/transcodificació."
|
||||
},
|
||||
"max_concurrent": {
|
||||
"label": "Màxim d'exportacions concurrents",
|
||||
"description": "Nombre màxim de treballs d'exportació a processar al mateix temps."
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
|
||||
@@ -341,6 +341,10 @@
|
||||
"hwaccel_args": {
|
||||
"label": "Exporta els arguments de l'hwaccel",
|
||||
"description": "Args d'acceleració de maquinari a utilitzar per a operacions d'exportació/transcodificació."
|
||||
},
|
||||
"max_concurrent": {
|
||||
"label": "Màxim d'exportacions concurrents",
|
||||
"description": "Nombre màxim de treballs d'exportació a processar al mateix temps."
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
@@ -975,8 +979,8 @@
|
||||
"description": "Habilita el monitoratge d'amplada de banda per procés per als processos i detectors de ffmpeg de càmera (requereix capacitats)."
|
||||
},
|
||||
"intel_gpu_device": {
|
||||
"label": "Dispositiu SR-IOV",
|
||||
"description": "Identificador de dispositiu utilitzat quan es tracten les GPU d'Intel com a SR-IOV per corregir les estadístiques de GPU."
|
||||
"label": "Dispositiu GPU d'Intel",
|
||||
"description": "Adreça de bus PCI o camí del dispositiu DRM (p. ex. /dev/dri/card1) utilitzat per fixar les estadístiques de GPU d'Intel a un dispositiu específic quan hi ha múltiples."
|
||||
}
|
||||
},
|
||||
"version_check": {
|
||||
@@ -1963,7 +1967,7 @@
|
||||
}
|
||||
},
|
||||
"audio": {
|
||||
"label": "Esdeveniments d'àudio",
|
||||
"label": "Detecció d'àudio",
|
||||
"description": "Configuració per a la detecció d'esdeveniments basats en àudio per a totes les càmeres; es pot substituir per càmera.",
|
||||
"enabled": {
|
||||
"label": "Habilita la detecció d'àudio",
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"documentTitle": "Xat - Frigate",
|
||||
"title": "Xat Frigate",
|
||||
"subtitle": "El teu assistent d'AI per a gestionar càmeres i coneixements",
|
||||
"placeholder": "Pregunta qualsevol cosa...",
|
||||
"error": "Alguna cosa ha fallat. Torna-ho a provar.",
|
||||
"processing": "Processant...",
|
||||
"toolsUsed": "Usades: {{tools}}",
|
||||
"showTools": "Mostra eines ({{count}})",
|
||||
"hideTools": "Amaga eines",
|
||||
"call": "Truca",
|
||||
"result": "Resultat",
|
||||
"arguments": "Variables:",
|
||||
"response": "Resposta:",
|
||||
"attachment_chip_label": "{{label}} a {{camera}}",
|
||||
"attachment_chip_remove": "Elimina l'adjunt",
|
||||
"open_in_explore": "Obre en l'explorador",
|
||||
"attach_event_aria": "Adjunta l'esdeveniment {{eventId}}",
|
||||
"attachment_picker_paste_label": "O enganxa l'ID de l'esdeveniment",
|
||||
"attachment_picker_attach": "Adjunta",
|
||||
"attachment_picker_placeholder": "Adjunta un esdeveniment",
|
||||
"quick_reply_find_similar": "Troba albiraments similars",
|
||||
"quick_reply_tell_me_more": "Explica'm més sobre això",
|
||||
"quick_reply_when_else": "Quan més es va veure?",
|
||||
"quick_reply_find_similar_text": "Troba albiraments similars a això.",
|
||||
"quick_reply_tell_me_more_text": "Parla'm més d'aquest.",
|
||||
"quick_reply_when_else_text": "Quan més es va veure això?",
|
||||
"anchor": "Referència",
|
||||
"similarity_score": "Similitud",
|
||||
"no_similar_objects_found": "No s'ha trobat cap objecte similar.",
|
||||
"semantic_search_required": "La cerca semàntica ha d'estar habilitada per trobar objectes similars.",
|
||||
"send": "Envia",
|
||||
"suggested_requests": "Proveu de preguntar:",
|
||||
"starting_requests": {
|
||||
"show_recent_events": "Mostra els esdeveniments recents",
|
||||
"show_camera_status": "Mostra l'estat de la càmera",
|
||||
"recap": "Què va passar mentre jo era fora?",
|
||||
"watch_camera": "Observa una càmera per a l'activitat"
|
||||
},
|
||||
"starting_requests_prompts": {
|
||||
"show_recent_events": "Mostra'm els esdeveniments recents de l'última hora",
|
||||
"show_camera_status": "Quin és l'estat actual de les meves càmeres?",
|
||||
"recap": "Què va passar mentre jo era fora?",
|
||||
"watch_camera": "Vigila la porta d'entrada i fes-me saber si algú apareix"
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,8 @@
|
||||
},
|
||||
"recording": {
|
||||
"enable": "Habilitar gravació",
|
||||
"disable": "Deshabilita l'enregistrament"
|
||||
"disable": "Deshabilita l'enregistrament",
|
||||
"disabledInConfig": "L'enregistrament primer s'ha d'habilitar a la configuració d'aquesta càmera."
|
||||
},
|
||||
"snapshots": {
|
||||
"enable": "Habilita captura d'instantània",
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"documentTitle": "Busca Deteccións - Frigate",
|
||||
"title": "Búsqueda de Deteccions",
|
||||
"selectCamera": "Búsqueda de Deteccions s'esta carregant",
|
||||
"startSearch": "Començar Búsqueda",
|
||||
"searchStarted": "Búsqueda inicada",
|
||||
"searchCancelled": "Búsqueda cancel·lada",
|
||||
"cancelSearch": "Cancel·lar",
|
||||
"searching": "Búsqueda en progrés.",
|
||||
"searchComplete": "Búsqueda completa",
|
||||
"description": "Dibuixa un polígon per definir la regió d'interès, i especifica un interval de temps per cercar canvis de moviment dins d'aquesta regió.",
|
||||
"noResultsYet": "Executa una cerca per a trobar canvis de moviment a la regió seleccionada",
|
||||
"noChangesFound": "No s'ha detectat cap canvi de píxel a la regió seleccionada",
|
||||
"changesFound_one": "S'ha trobat el canvi de moviment {{count}}",
|
||||
"changesFound_many": "S'han trobat {{count}} canvis de moviment",
|
||||
"changesFound_other": "S'han trobat {{count}} canvis de moviment",
|
||||
"framesProcessed": "{{count}} fotogrames processats",
|
||||
"jumpToTime": "Salta a aquesta hora",
|
||||
"results": "Resultats",
|
||||
"showSegmentHeatmap": "Mapa de calor",
|
||||
"newSearch": "Cerca nova",
|
||||
"clearResults": "Neteja els resultats",
|
||||
"clearROI": "Neteja el polígon",
|
||||
"polygonControls": {
|
||||
"points_one": "{{count}} punt",
|
||||
"points_many": "{{count}} punts",
|
||||
"points_other": "{{count}} punts",
|
||||
"undo": "Desfés l'últim punt",
|
||||
"reset": "Restableix el polígon"
|
||||
},
|
||||
"motionHeatmapLabel": "Mapa de calor del moviment",
|
||||
"dialog": {
|
||||
"title": "Cerca de moviment",
|
||||
"cameraLabel": "Càmara",
|
||||
"previewAlt": "Vista prèvia de la càmera per a {{camera}}"
|
||||
},
|
||||
"timeRange": {
|
||||
"title": "Interval de cerca",
|
||||
"start": "Hora d'inici",
|
||||
"end": "Hora final"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Configuració de la cerca",
|
||||
"parallelMode": "Mode paral·lel",
|
||||
"parallelModeDesc": "Escaneja múltiples segments d'enregistrament al mateix temps (més ràpid, però significativament més intensiu en CPU)",
|
||||
"threshold": "Llindar de la sensibilitat",
|
||||
"thresholdDesc": "Els valors més baixos detecten canvis més petits (1-255)",
|
||||
"minArea": "Àrea de canvi mínim",
|
||||
"minAreaDesc": "Percentatge mínim de la regió d'interès que s'ha de canviar per considerar-se significatiu",
|
||||
"frameSkip": "Omet el fotograma",
|
||||
"frameSkipDesc": "Processa cada N fotograma. Establiu això a la velocitat de fotogrames de la càmera per processar un fotograma per segon (p. ex. 5 per a una càmera de 5 FPS, 30 per a una càmera de 30 FPS). Els valors més alts seran més ràpids, però poden perdre els esdeveniments de curt moviment.",
|
||||
"maxResults": "Resultats màxims",
|
||||
"maxResultsDesc": "Atura després d'aquestes quantes marques horàries coincidents"
|
||||
},
|
||||
"errors": {
|
||||
"noCamera": "Seleccioneu una càmera",
|
||||
"noROI": "Dibuixeu una regió d'interès",
|
||||
"noTimeRange": "Seleccioneu un interval de temps",
|
||||
"invalidTimeRange": "L'hora de finalització ha de ser posterior a l'hora d'inici",
|
||||
"searchFailed": "Ha fallat la cerca: {{message}}",
|
||||
"polygonTooSmall": "El polígon ha de tenir almenys 3 punts",
|
||||
"unknown": "Error desconegut"
|
||||
},
|
||||
"changePercentage": "{{percentage}}% canviat",
|
||||
"metrics": {
|
||||
"title": "Cerca les mètriques",
|
||||
"segmentsScanned": "Segments escanejats",
|
||||
"segmentsProcessed": "Processat",
|
||||
"segmentsSkippedInactive": "S'ha omès (sense activitat)",
|
||||
"segmentsSkippedHeatmap": "S'ha omès (sense superposició ROI)",
|
||||
"fallbackFullRange": "Escaneig de rang complet alternatiu",
|
||||
"framesDecoded": "Fotogrames descodificats",
|
||||
"wallTime": "Temps de cerca",
|
||||
"segmentErrors": "Errors del segment",
|
||||
"seconds": "{{seconds}}s"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"page": {
|
||||
"startError": {
|
||||
"back": "Torna a l'Historial",
|
||||
"title": "No s'ha pogut iniciar la repetició de la depuració"
|
||||
},
|
||||
"sourceCamera": "Camera d'origen",
|
||||
"replayCamera": "Reproduïr Càmera",
|
||||
"initializingReplay": "Inicialitzant depurar repetició...",
|
||||
"stoppingReplay": "Parant depurar repetició...",
|
||||
"stopReplay": "Parar Repetició",
|
||||
"confirmStop": {
|
||||
"title": "Parar Depurar Repetició?",
|
||||
"description": "Aixó pararà la sessió i netejarà les dades temporals. Estás segur?",
|
||||
"confirm": "Parar Repetició",
|
||||
"cancel": "Cancel·lar"
|
||||
},
|
||||
"activity": "Activitat",
|
||||
"objects": "Llista d'Objectes",
|
||||
"audioDetections": "Deteccions d'Audio",
|
||||
"noActivity": "Sense activitat detectada",
|
||||
"activeTracking": "Tracking Actiu",
|
||||
"noActiveTracking": "Sense tracking actiu",
|
||||
"configuration": "Configuració",
|
||||
"configurationDesc": "Configuració d'ajust fi de detecció de moviment i tracking d'objectes per a la depuració de reproducció de càmera. Cap canvi es graba en el teu arxiu de configuració de Frigate.",
|
||||
"noSession": "No hi ha una sessió activa de reproducció de depuració",
|
||||
"noSessionDesc": "Inicia una reproducció de depuració des de la vista Historial fent clic al botó Accions a la barra d'eines i escollint Depura Repeteix.",
|
||||
"goToRecordings": "Ves a l'historial",
|
||||
"preparingClip": "S'està preparant el clip…",
|
||||
"preparingClipDesc": "Frigate està cosint enregistraments per a l'interval de temps seleccionat. Això pot trigar un minut en intervals més llargs.",
|
||||
"startingCamera": "S'està iniciant la repetició de la depuració…"
|
||||
},
|
||||
"title": "Repetició de depuració",
|
||||
"websocket_messages": "Missatges",
|
||||
"dialog": {
|
||||
"title": "Iniciar Depuració de Repeticions",
|
||||
"camera": "Càmera Font",
|
||||
"timeRange": "Rang de Temps",
|
||||
"preset": {
|
||||
"1m": "Últim 1 Minut",
|
||||
"5m": "Últims 5 Minuts",
|
||||
"timeline": "Desde la Línia de Temps",
|
||||
"custom": "Personalitzat"
|
||||
},
|
||||
"description": "Crea una càmera de reproducció temporal que fa bucles de metratge històric per depurar la detecció d'objectes i els problemes de seguiment. La càmera de reproducció tindrà la mateixa configuració de detecció que la càmera d'origen. Trieu un interval de temps per començar.",
|
||||
"startButton": "Inicia la repetició",
|
||||
"selectFromTimeline": "Selecciona",
|
||||
"starting": "S'està iniciant la repetició...",
|
||||
"startLabel": "Inici",
|
||||
"endLabel": "Final",
|
||||
"toast": {
|
||||
"error": "No s'ha pogut iniciar la repetició de depuració: {{error}}",
|
||||
"alreadyActive": "Ja hi ha activada una sessió de reproducció",
|
||||
"stopError": "No s'ha pogut aturar la repetició de depuració: {{error}}",
|
||||
"goToReplay": "Ves a la repetició"
|
||||
}
|
||||
},
|
||||
"description": "Reprodueix els enregistraments de la càmera per a la depuració. La llista d'objectes mostra un resum retardat en el temps dels objectes detectats i la pestanya Missatges mostra un flux de missatges interns de la fragata a partir del metratge de reproducció."
|
||||
}
|
||||
@@ -43,7 +43,7 @@
|
||||
"globalMotion": "Detecció de moviment",
|
||||
"globalObjects": "Objectes",
|
||||
"globalReview": "Revisió",
|
||||
"globalAudioEvents": "Esdeveniments d'àudio",
|
||||
"globalAudioEvents": "Detecció d'àudio",
|
||||
"globalLivePlayback": "Reproducció en directe",
|
||||
"globalTimestampStyle": "Estil de la marca horària",
|
||||
"systemDatabase": "Base de dades",
|
||||
@@ -73,7 +73,7 @@
|
||||
"cameraMotion": "Detecció de moviment",
|
||||
"cameraObjects": "Objectes",
|
||||
"cameraConfigReview": "Revisió",
|
||||
"cameraAudioEvents": "Esdeveniments d'àudio",
|
||||
"cameraAudioEvents": "Detecció d'àudio",
|
||||
"cameraAudioTranscription": "Transcripció d'àudio",
|
||||
"cameraNotifications": "Notificacions",
|
||||
"cameraLivePlayback": "Reproducció en directe",
|
||||
@@ -1354,6 +1354,14 @@
|
||||
"inherit": "Hereta",
|
||||
"enabled": "Habilitat",
|
||||
"disabled": "Desactivat"
|
||||
},
|
||||
"cameraType": {
|
||||
"title": "Tipus de càmera",
|
||||
"label": "Tipus de càmera",
|
||||
"description": "Estableix el tipus per a cada càmera. Les càmeres LPR dedicades són càmeres d'un sol ús amb un potent zoom òptic per capturar matrícules en vehicles distants. La majoria de les càmeres haurien d'utilitzar el tipus de càmera normal llevat que la càmera sigui específicament per a LPR i tingui una vista molt centrada en les matrícules.",
|
||||
"dedicatedLpr": "LPR dedicat",
|
||||
"saveSuccess": "Tipus de càmera actualitzat per {{cameraName}}. Reinicia la fragata per aplicar els canvis.",
|
||||
"normal": "Normal"
|
||||
}
|
||||
},
|
||||
"cameraReview": {
|
||||
@@ -1720,7 +1728,22 @@
|
||||
"overriddenGlobal": "Sobreescrit (Global)",
|
||||
"overriddenGlobalTooltip": "Aquesta càmera anul·la la configuració global d'aquesta secció",
|
||||
"overriddenBaseConfig": "Sobreescrit (Configuració base)",
|
||||
"overriddenBaseConfigTooltip": "El perfil {{profile}} substitueix la configuració d'aquesta secció"
|
||||
"overriddenBaseConfigTooltip": "El perfil {{profile}} substitueix la configuració d'aquesta secció",
|
||||
"overriddenInCameras": {
|
||||
"label_one": "Sobreescrit a la càmera {{count}}",
|
||||
"label_many": "Sobreescrit en {{count}} càmeres",
|
||||
"label_other": "Sobreescrit en {{count}} càmeres",
|
||||
"tooltip_one": "{{count}} la càmera anul·la els valors d'aquesta secció. Feu clic per veure els detalls.",
|
||||
"tooltip_many": "{{count}} càmeres substitueixen els valors d'aquesta secció. Feu clic per veure els detalls.",
|
||||
"tooltip_other": "{{count}} càmeres substitueixen els valors d'aquesta secció. Feu clic per veure els detalls.",
|
||||
"heading_one": "Aquesta secció global té camps que estan sobreescrits a la càmera {{count}}.",
|
||||
"heading_many": "Aquesta secció global té camps que estan sobreescrits en {{count}} càmeres.",
|
||||
"heading_other": "Aquesta secció global té camps que estan sobreescrits en {{count}} càmeres.",
|
||||
"othersField_one": "{{count}} altre",
|
||||
"othersField_many": "{{count}} altres",
|
||||
"othersField_other": "{{count}} altres",
|
||||
"profilePrefix": "Perfil {{profile}}: {{fields}}"
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"title": "Perfils",
|
||||
@@ -1821,7 +1844,8 @@
|
||||
"review": {
|
||||
"recordDisabled": "L'enregistrament està desactivat, els elements de revisió no es generaran.",
|
||||
"detectDisabled": "La detecció d'objectes està desactivada. Els elements de revisió requereixen objectes detectats per categoritzar alertes i deteccions.",
|
||||
"allNonAlertDetections": "Totes les activitats no alertes s'inclouran com a deteccions."
|
||||
"allNonAlertDetections": "Totes les activitats no alertes s'inclouran com a deteccions.",
|
||||
"genaiImageSourceRecordingsRecordDisabled": "La font d'imatges està configurada com a 'enregistraments', però l'enregistrament està desactivat. La fragata tornarà a la vista prèvia de les imatges."
|
||||
},
|
||||
"audio": {
|
||||
"noAudioRole": "Cap flux té definit el rol d'àudio. Heu d'habilitar el rol d'àudio per a la detecció d'àudio perquè funcioni."
|
||||
@@ -1830,15 +1854,18 @@
|
||||
"audioDetectionDisabled": "La detecció d'àudio no està activada per a aquesta càmera. La transcripció d'àudio requereix que la detecció d'àudio estigui activa."
|
||||
},
|
||||
"detect": {
|
||||
"fpsGreaterThanFive": "No es recomana establir el detect FPS superior a 5."
|
||||
"fpsGreaterThanFive": "No es recomana establir el detect FPS superior a 5. Els valors més alts poden causar problemes de rendiment i no proporcionaran cap benefici.",
|
||||
"disabled": "La detecció d'objectes està desactivada. Les instantànies, articles de revisió i enriquiments com el reconeixement de rostres, el reconeixement de matrícules i la IA Generativa no funcionaran."
|
||||
},
|
||||
"faceRecognition": {
|
||||
"globalDisabled": "El reconeixement de cares no està habilitat a nivell global. Habilita-ho en la configuració global per al reconeixement facial a nivell de càmera per funcionar.",
|
||||
"personNotTracked": "El reconeixement de cares requereix que l'objecte 'persona' sigui rastrejat. Assegureu-vos que «persona» estigui a la llista de seguiment d'objectes."
|
||||
"globalDisabled": "L'enriquiment del reconeixement facial s'ha d'habilitar perquè les funcions de reconeixement facial funcionin en aquesta càmera.",
|
||||
"personNotTracked": "El reconeixement de cares requereix que l'objecte 'persona' sigui rastrejat. Habilita «persona» en objectes per a aquesta càmera.",
|
||||
"modelSizeLarge": "El model 'gran' requereix una GPU o NPU per a un rendiment raonable. Usa «petit» en sistemes només de CPU."
|
||||
},
|
||||
"lpr": {
|
||||
"globalDisabled": "El reconeixement de la matrícula no està habilitat a nivell global. Habilita-ho en la configuració global per al funcionament de LPR a nivell de càmera.",
|
||||
"vehicleNotTracked": "El reconeixement de la matrícula requereix que es faci un seguiment del 'cotxe' o de la 'motocicleta'."
|
||||
"globalDisabled": "L'enriquiment de reconeixement de matrícules ha d'estar habilitat perquè les funcions LPR funcionin en aquesta càmera.",
|
||||
"vehicleNotTracked": "El reconeixement de la matrícula requereix que es faci un seguiment del 'cotxe' o de la 'motocicleta'.",
|
||||
"modelSizeLarge": "El model 'gran' està optimitzat per a matrícules multilínies. El model 'petit' proporciona un millor rendiment sobre 'gran' i s'ha d'utilitzar tret que la vostra regió utilitzi formats de placa multilínia."
|
||||
},
|
||||
"record": {
|
||||
"noRecordRole": "Cap flux té el rol de registre definit. L'enregistrament no funcionarà."
|
||||
@@ -1852,6 +1879,12 @@
|
||||
"detectors": {
|
||||
"mixedTypes": "Tots els detectors han d'utilitzar el mateix tipus. Elimina els detectors existents per utilitzar un tipus diferent.",
|
||||
"mixedTypesSuggestion": "Tots els detectors han d'utilitzar el mateix tipus. Suprimiu detectors existents o seleccioneu {{type}}."
|
||||
},
|
||||
"objects": {
|
||||
"genaiNoDescriptionsProvider": "Heu de configurar un proveïdor de GenAI amb el rol 'descripcions' per a les descripcions que es generaran."
|
||||
},
|
||||
"semanticSearch": {
|
||||
"jinav2SmallModelSize": "La mida 'petita' amb el model Jina V2 té un alt cost de RAM i d'inferència. Es recomana el model 'gran' amb una GPU discreta."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,6 +213,9 @@
|
||||
"expectedFps": "FPS esperat",
|
||||
"reconnectsLastHour": "Reconnecta (última hora)",
|
||||
"stallsLastHour": "Parades (última hora)"
|
||||
},
|
||||
"noCameras": {
|
||||
"title": "No s'ha trobat cap càmera"
|
||||
}
|
||||
},
|
||||
"lastRefreshed": "Darrera actualització: ",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -250,7 +250,8 @@
|
||||
"classification": "Klassifizierung",
|
||||
"actions": "Aktion",
|
||||
"chat": "Chat",
|
||||
"profiles": "Profile"
|
||||
"profiles": "Profile",
|
||||
"features": "Funktionen"
|
||||
},
|
||||
"unit": {
|
||||
"speed": {
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"label": "Kameras",
|
||||
"desc": "Wähle Kameras für diese Gruppe aus."
|
||||
},
|
||||
"label": "Kameragruppen",
|
||||
"label": "Kamera Gruppen",
|
||||
"edit": "Kameragruppe bearbeiten",
|
||||
"success": "Kameragruppe {{name}} wurde gespeichert."
|
||||
},
|
||||
|
||||
@@ -178,6 +178,14 @@
|
||||
"markAsReviewed": "Als geprüft markieren",
|
||||
"deleteNow": "Jetzt löschen",
|
||||
"markAsUnreviewed": "Als ungeprüft markieren"
|
||||
},
|
||||
"shareTimestamp": {
|
||||
"label": "Zeitstempel teilen",
|
||||
"title": "Zeitstempel teilen",
|
||||
"description": "Teile eine URL mit Zeitstempel, die die aktuelle Position des Players angibt, oder wähle einen benutzerdefinierten Zeitstempel aus. Beachte, dass es sich hierbei nicht um eine öffentliche Freigabe-URL handelt und dass nur Benutzer Zugriff darauf haben, die Zugriff auf Frigate und diese Kamera haben.",
|
||||
"custom": "Benutzerdefinierter Zeitstempel",
|
||||
"button": "URL des Zeitstempels teilen",
|
||||
"shareTitle": "Zeitstempel der Fregattenbewertung: {{camera}}"
|
||||
}
|
||||
},
|
||||
"imagePicker": {
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
"noPreviewFound": "Keine Vorschau gefunden",
|
||||
"submitFrigatePlus": {
|
||||
"title": "Dieses Bild an Frigate+ senden?",
|
||||
"submit": "Senden"
|
||||
"submit": "Absenden",
|
||||
"previewError": "Schnappschuss Vorschau konnte nicht geladen werden. Die Aufnahme ist möglicherweise derzeit nicht verfügbar."
|
||||
},
|
||||
"livePlayerRequiredIOSVersion": "iOS 17.1 oder höher ist für diesen Typ eines Live-Streams erforderlich.",
|
||||
"streamOffline": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"description": "Aktiviert"
|
||||
},
|
||||
"audio": {
|
||||
"label": "Audioereignisse",
|
||||
"label": "Audioerkennung",
|
||||
"description": "Einstellungen für audiobasierte Ereigniserkennung für diese Kamera.",
|
||||
"enabled": {
|
||||
"label": "Aktivieren der Audioerkennung",
|
||||
@@ -537,6 +537,10 @@
|
||||
"hwaccel_args": {
|
||||
"label": "hwaccel-Argumente exportieren",
|
||||
"description": "Argumente für die Hardwarebeschleunigung bei Export- und Transkodierungsvorgängen."
|
||||
},
|
||||
"max_concurrent": {
|
||||
"label": "Maximale Anzahl gleichzeitiger Exporte",
|
||||
"description": "Maximale Anzahl der gleichzeitig zu verarbeitenden Exportaufträge."
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"description": "Wenn aktiviert, startet Frigate im abgesicherten Modus mit reduzierten Features für die Fehlersuche."
|
||||
},
|
||||
"audio": {
|
||||
"label": "Audioereignisse",
|
||||
"label": "Audioerkennung",
|
||||
"enabled": {
|
||||
"label": "Aktivieren der Audioerkennung",
|
||||
"description": "Aktivieren oder deaktivieren Sie die Erkennung von Audioereignissen für alle Kameras; diese Einstellung kann für jede Kamera individuell überschrieben werden."
|
||||
@@ -538,8 +538,8 @@
|
||||
"description": "Aktivieren Sie die prozessbezogene Überwachung der Netzwerkbandbreite für Kamera-FFmpeg-Prozesse und Detektoren (erfordert entsprechende Funktionen)."
|
||||
},
|
||||
"intel_gpu_device": {
|
||||
"label": "SR-IOV-Gerät",
|
||||
"description": "Gerätekennung, die verwendet wird, wenn Intel-GPUs als SR-IOV behandelt werden, um die GPU-Statistiken zu korrigieren."
|
||||
"label": "Intel GPU",
|
||||
"description": "PCI-Bus-Adresse oder DRM-Gerätepfad (z. B. /dev/dri/card1), der verwendet wird, um die Intel-GPU-Statistiken einem bestimmten Gerät zuzuordnen, wenn mehrere vorhanden sind."
|
||||
}
|
||||
},
|
||||
"version_check": {
|
||||
@@ -1357,6 +1357,10 @@
|
||||
"hwaccel_args": {
|
||||
"label": "hwaccel-Argumente exportieren",
|
||||
"description": "Argumente für die Hardwarebeschleunigung bei Export- und Transkodierungsvorgängen."
|
||||
},
|
||||
"max_concurrent": {
|
||||
"label": "Maximale Anzahl gleichzeitiger Exporte",
|
||||
"description": "Maximale Anzahl der gleichzeitig zu verarbeitenden Exportaufträge."
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"documentTitle": "Chat - Frigate",
|
||||
"title": "Frigate Chat",
|
||||
"subtitle": "Ihr KI-Assistent für die Kameraverwaltung und Analysen",
|
||||
"placeholder": "Frag mich alles...",
|
||||
"error": "Es ist ein Fehler aufgetreten. Bitte versuche es erneut.",
|
||||
"processing": "Wird verarbeitet...",
|
||||
"toolsUsed": "Verwendet: {{tools}}",
|
||||
"showTools": "Werkzeuge anzeigen ({{count}})",
|
||||
"hideTools": "Werkzeuge ausblenden",
|
||||
"call": "Anruf",
|
||||
"result": "Ergebnis",
|
||||
"arguments": "Argumente:",
|
||||
"response": "Antwort:",
|
||||
"attachment_chip_label": "{{label}} auf der {{camera}}",
|
||||
"attachment_chip_remove": "Anhang entfernen",
|
||||
"open_in_explore": "In „Explore“ öffnen",
|
||||
"attach_event_aria": "Ereignis {{eventId}} hinzufügen",
|
||||
"attachment_picker_paste_label": "Oder fügen Sie die Ereignis-ID ein",
|
||||
"attachment_picker_attach": "Anhängen",
|
||||
"attachment_picker_placeholder": "Ereignis hinzufügen",
|
||||
"quick_reply_find_similar": "Ähnliche Sichtungen finden",
|
||||
"quick_reply_tell_me_more": "Erzähl mir mehr darüber",
|
||||
"quick_reply_when_else": "Wann wurde es sonst noch gesehen?",
|
||||
"quick_reply_find_similar_text": "Ähnliche Sichtungen finden.",
|
||||
"quick_reply_tell_me_more_text": "Erzähl mir mehr darüber.",
|
||||
"quick_reply_when_else_text": "Wann gab es das sonst noch?",
|
||||
"anchor": "Referenz",
|
||||
"similarity_score": "Ähnlichkeit",
|
||||
"no_similar_objects_found": "Es wurden keine ähnlichen Objekte gefunden.",
|
||||
"semantic_search_required": "Die semantische Suche muss aktiviert sein, um ähnliche Objekte zu finden.",
|
||||
"send": "Senden",
|
||||
"suggested_requests": "Versuchen Sie doch mal zu fragen:",
|
||||
"starting_requests": {
|
||||
"show_recent_events": "Aktuelle Ereignisse anzeigen",
|
||||
"show_camera_status": "Kamerastatus anzeigen",
|
||||
"recap": "Was ist passiert, während ich weg war?",
|
||||
"watch_camera": "Beobachten Sie eine Kamera auf Bewegungen"
|
||||
},
|
||||
"starting_requests_prompts": {
|
||||
"show_recent_events": "Zeige mir die Ereignisse der letzten Stunde",
|
||||
"show_camera_status": "Wie ist der aktuelle Status meiner Kameras?",
|
||||
"recap": "Was ist passiert, während ich weg war?",
|
||||
"watch_camera": "Pass auf die Haustür auf und sag mir Bescheid, wenn jemand kommt"
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,9 @@
|
||||
},
|
||||
"documentTitle": "Überprüfung - Frigate",
|
||||
"recordings": {
|
||||
"documentTitle": "Aufnahmen - Frigate"
|
||||
"documentTitle": "Aufnahmen - Frigate",
|
||||
"invalidSharedLink": "Der Link zur zeitgestempelten Aufzeichnung kann aufgrund eines Parsing-Fehlers nicht geöffnet werden.",
|
||||
"invalidSharedCamera": "Der Link zur zeitgestempelten Aufzeichnung kann nicht geöffnet werden, da es sich um eine unbekannte oder nicht autorisierte Kamera handelt."
|
||||
},
|
||||
"calendarFilter": {
|
||||
"last24Hours": "Letzte 24 Stunden"
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
"label": "Schnappschuss Bewertung"
|
||||
},
|
||||
"score": {
|
||||
"label": "Ergebnis"
|
||||
"label": "Treffer"
|
||||
},
|
||||
"editAttributes": {
|
||||
"title": "Attribute bearbeiten",
|
||||
|
||||
@@ -62,7 +62,8 @@
|
||||
},
|
||||
"recording": {
|
||||
"disable": "Aufzeichnung deaktivieren",
|
||||
"enable": "Aufzeichnung aktivieren"
|
||||
"enable": "Aufzeichnung aktivieren",
|
||||
"disabledInConfig": "Aufnahme muss erst in den Einstellung für diese Kamera aktiviert werden."
|
||||
},
|
||||
"snapshots": {
|
||||
"enable": "Schnappschüsse aktivieren",
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"documentTitle": "Bewegungssuche - Frigate",
|
||||
"title": "Bewegungssuche",
|
||||
"description": "Zeichnen Sie ein Polygon, um den gewünschten Bereich zu definieren, und geben Sie einen Zeitbereich an, um innerhalb dieses Bereichs nach Bewegungsänderungen zu suchen.",
|
||||
"selectCamera": "Die Bewegungssuche wird geladen",
|
||||
"startSearch": "Suche starten",
|
||||
"searchStarted": "Die Suche wurde gestartet",
|
||||
"searchCancelled": "Suche abgebrochen",
|
||||
"cancelSearch": "Abbrechen",
|
||||
"searching": "Suche läuft.",
|
||||
"searchComplete": "Suche abgeschlossen",
|
||||
"noResultsYet": "Führen Sie eine Suche durch, um Bewegungsänderungen im ausgewählten Bereich zu finden",
|
||||
"noChangesFound": "Im ausgewählten Bereich wurden keine Pixeländerungen festgestellt",
|
||||
"changesFound_one": "Es wurde {{count}} Bewegungsänderungen gefunden",
|
||||
"changesFound_other": "Es wurden {{count}} Bewegungsänderungen gefunden",
|
||||
"framesProcessed": "{{count}} Bilder verarbeitet",
|
||||
"jumpToTime": "Zu diesem Zeitpunkt springen",
|
||||
"results": "Ergebnisse",
|
||||
"showSegmentHeatmap": "Heatmap",
|
||||
"newSearch": "Neue Suche",
|
||||
"clearResults": "Eindeutige Ergebnisse",
|
||||
"clearROI": "Polygon löschen",
|
||||
"polygonControls": {
|
||||
"points_one": "{{count}} Punkt",
|
||||
"points_other": "{{count}} Punkte",
|
||||
"undo": "Letzten Schritt rückgängig machen",
|
||||
"reset": "Polygon zurücksetzen"
|
||||
},
|
||||
"motionHeatmapLabel": "Bewegungs-Heatmap",
|
||||
"dialog": {
|
||||
"title": "Bewegungssuche",
|
||||
"cameraLabel": "Kamera",
|
||||
"previewAlt": "Kamera-Vorschau für {{camera}}"
|
||||
},
|
||||
"timeRange": {
|
||||
"title": "Suchbereich",
|
||||
"start": "Startzeit",
|
||||
"end": "Endzeit"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Sucheinstellungen",
|
||||
"parallelMode": "Parallelbetrieb",
|
||||
"parallelModeDesc": "Mehrere Aufzeichnungssegmente gleichzeitig scannen (schneller, aber deutlich rechenintensiver)",
|
||||
"threshold": "Empfindlichkeitsschwelle",
|
||||
"thresholdDesc": "Niedrigere Werte erkennen geringere Veränderungen (1–255)",
|
||||
"minArea": "Mindestwechselbereich",
|
||||
"minAreaDesc": "Mindestanteil der untersuchten Region, der sich ändern muss, damit die Veränderung als signifikant gilt",
|
||||
"frameSkip": "Bild überspringen",
|
||||
"frameSkipDesc": "Verarbeite jeden N-ten Frame. Stelle diesen Wert auf die Bildrate deiner Kamera ein, um einen Frame pro Sekunde zu verarbeiten (z. B. 5 für eine Kamera mit 5 FPS, 30 für eine Kamera mit 30 FPS). Höhere Werte sorgen für eine schnellere Verarbeitung, können jedoch kurze Bewegungsabläufe übersehen.",
|
||||
"maxResults": "Maximale Ergebnisse",
|
||||
"maxResultsDesc": "Nach dieser Anzahl übereinstimmender Zeitstempel anhalten"
|
||||
},
|
||||
"errors": {
|
||||
"noCamera": "Bitte wählen Sie eine Kamera aus",
|
||||
"noROI": "Bitte zeichnen Sie einen Bereich von Interesse ein",
|
||||
"noTimeRange": "Bitte wählen Sie einen Zeitraum aus",
|
||||
"invalidTimeRange": "Die Endzeit muss nach der Startzeit liegen",
|
||||
"searchFailed": "Suche fehlgeschlagen: {{message}}",
|
||||
"polygonTooSmall": "Ein Polygon muss mindestens 3 Punkte haben",
|
||||
"unknown": "Unbekannter Fehler"
|
||||
},
|
||||
"changePercentage": "Um {{percentage}} % verändert",
|
||||
"metrics": {
|
||||
"title": "Suchmetriken",
|
||||
"segmentsScanned": "Durchsuchte Segmente",
|
||||
"segmentsProcessed": "Bearbeitet",
|
||||
"segmentsSkippedInactive": "Übersprungen (keine Aktivität)",
|
||||
"segmentsSkippedHeatmap": "Übersprungen (keine Überschneidung der ROI)",
|
||||
"fallbackFullRange": "Ausweich-Vollbereichsscan",
|
||||
"framesDecoded": "Rahmen decodiert",
|
||||
"wallTime": "Suchzeit",
|
||||
"segmentErrors": "Segmentfehler",
|
||||
"seconds": "{{seconds}}s"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user