mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-11-02 20:00:51 +03:00
Moving watermarks after each accepted send kept the install ID and the notice baseline out of step: pre-consent notices went out, notices raised before the first send were dropped, and a send that finished after an off/on toggle overwrote the new identity's baseline. health.notices now carries cumulative counts since the install ID was created. Creating an ID copies the lifetime counts into the existing reported_* columns before the state file names it, and nothing is written after a send, so the backend diffs consecutive reports per install ID.
64 lines
2.3 KiB
Python
64 lines
2.3 KiB
Python
"""Health section: uptime, CPU, enrichment speed, and notice counts."""
|
|
|
|
from typing import Any
|
|
|
|
from frigate.analytics.collectors.common import rate
|
|
from frigate.analytics.context import ReportContext
|
|
from frigate.analytics.schema import (
|
|
EnrichmentTiming,
|
|
HealthSection,
|
|
NoticeCounts,
|
|
NoticeKindKey,
|
|
)
|
|
|
|
TIMING_STATS = {
|
|
EnrichmentTiming.face: "face_recognition_speed",
|
|
EnrichmentTiming.lpr: "plate_recognition_speed",
|
|
EnrichmentTiming.plate_detection: "yolov9_plate_detection_speed",
|
|
EnrichmentTiming.image_embedding: "image_embedding_speed",
|
|
EnrichmentTiming.text_embedding: "text_embedding_speed",
|
|
EnrichmentTiming.review_description: "review_description_speed",
|
|
EnrichmentTiming.object_description: "object_description_speed",
|
|
}
|
|
REPORTABLE_KINDS = frozenset(key.value for key in NoticeKindKey)
|
|
|
|
|
|
def notice_counts(notice_stats: list[dict[str, Any]]) -> dict[Any, NoticeCounts]:
|
|
"""Counts since the install ID was created, per reportable kind."""
|
|
counts: dict[Any, NoticeCounts] = {}
|
|
|
|
for row in notice_stats:
|
|
if row["kind"] not in REPORTABLE_KINDS:
|
|
continue
|
|
|
|
occurrences = max(row["occurrences"] - row["reported_occurrences"], 0)
|
|
acknowledgements = max(
|
|
row["acknowledgements"] - row["reported_acknowledgements"], 0
|
|
)
|
|
mutes = max(row["mutes"] - row["reported_mutes"], 0)
|
|
|
|
if occurrences or acknowledgements or mutes:
|
|
counts[NoticeKindKey(row["kind"])] = NoticeCounts(
|
|
occurrences=occurrences, acknowledgements=acknowledgements, mutes=mutes
|
|
)
|
|
|
|
return counts
|
|
|
|
|
|
def collect(ctx: ReportContext) -> HealthSection:
|
|
"""Read health figures from the latest stats and notice counts."""
|
|
service = ctx.stats.get("service", {})
|
|
embeddings = ctx.stats.get("embeddings", {})
|
|
cpu = ctx.stats.get("cpu_usages", {}).get("frigate.full_system", {}).get("cpu")
|
|
timings = {
|
|
timing: rate(embeddings.get(key)) for timing, key in TIMING_STATS.items()
|
|
}
|
|
|
|
return HealthSection(
|
|
uptime_hours=int(rate(service.get("uptime")) // 3600),
|
|
cpu_percent=min(round(rate(cpu)), 100),
|
|
enrichment_ms={timing: value for timing, value in timings.items() if value > 0},
|
|
retention_unmet=bool(service.get("retention_unmet", False)),
|
|
notices=notice_counts(ctx.notice_stats),
|
|
)
|