dddc6734d0
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>
79 lines
2.4 KiB
Python
79 lines
2.4 KiB
Python
"""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,
|
|
)
|