feat: frigate-notify v2 (modular app, CLIP recognition) + clip-service
Splits the single main.py into config/database/models/routes/vision/recognition/ ollama_client/cleanup modules, adds a web UI, and introduces clip-service for CLIP (ViT-L-14) embeddings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""Settings and stats API endpoints for frigate-notify v2."""
|
||||
|
||||
import logging
|
||||
from datetime import date
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from config import config
|
||||
from database import get_connection
|
||||
from models import StatsResponse
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/api", tags=["settings"])
|
||||
|
||||
|
||||
@router.get("/settings")
|
||||
async def get_settings():
|
||||
"""Return all settings from DB plus runtime config values."""
|
||||
conn = get_connection()
|
||||
cursor = conn.execute("SELECT key, value FROM settings")
|
||||
db_settings = {row["key"]: row["value"] for row in cursor.fetchall()}
|
||||
|
||||
# Merge with runtime config values
|
||||
return {
|
||||
**db_settings,
|
||||
"recognition_threshold_high": config.RECOGNITION_THRESHOLD_HIGH,
|
||||
"recognition_threshold_low": config.RECOGNITION_THRESHOLD_LOW,
|
||||
"rate_limit_seconds": config.RATE_LIMIT_SECONDS,
|
||||
"allowed_labels": list(config.ALLOWED_LABELS),
|
||||
"min_score": config.MIN_SCORE,
|
||||
}
|
||||
|
||||
|
||||
@router.put("/settings")
|
||||
async def update_settings(body: dict):
|
||||
"""Accept dict body, upsert each key/value into settings table."""
|
||||
conn = get_connection()
|
||||
for key, value in body.items():
|
||||
conn.execute(
|
||||
"INSERT INTO settings (key, value) VALUES (?, ?) "
|
||||
"ON CONFLICT(key) DO UPDATE SET value = excluded.value",
|
||||
(key, str(value)),
|
||||
)
|
||||
conn.commit()
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@router.get("/stats", response_model=StatsResponse)
|
||||
async def get_stats():
|
||||
"""Return event and object counts."""
|
||||
conn = get_connection()
|
||||
|
||||
total = conn.execute("SELECT COUNT(*) FROM events").fetchone()[0]
|
||||
known = conn.execute(
|
||||
"SELECT COUNT(*) FROM events WHERE match_status = 'known'"
|
||||
).fetchone()[0]
|
||||
unknown = conn.execute(
|
||||
"SELECT COUNT(*) FROM events WHERE match_status = 'unknown'"
|
||||
).fetchone()[0]
|
||||
unreviewed = conn.execute(
|
||||
"SELECT COUNT(*) FROM events WHERE match_status = 'unreviewed'"
|
||||
).fetchone()[0]
|
||||
objects_count = conn.execute("SELECT COUNT(*) FROM known_objects").fetchone()[0]
|
||||
today = date.today().isoformat()
|
||||
events_today = conn.execute(
|
||||
"SELECT COUNT(*) FROM events WHERE DATE(created_at) = ?",
|
||||
(today,),
|
||||
).fetchone()[0]
|
||||
|
||||
return StatsResponse(
|
||||
total_events=total,
|
||||
known_matches=known,
|
||||
unknown_events=unknown,
|
||||
unreviewed=unreviewed,
|
||||
known_objects_count=objects_count,
|
||||
events_today=events_today,
|
||||
)
|
||||
Reference in New Issue
Block a user