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,109 @@
|
||||
"""SQLite database schema and connection management for frigate-notify v2."""
|
||||
|
||||
import logging
|
||||
import sqlite3
|
||||
import threading
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Thread-local storage for database connections
|
||||
_local = threading.local()
|
||||
|
||||
_db_path: str = "/data/frigate-notify.db"
|
||||
|
||||
|
||||
def set_db_path(path: str) -> None:
|
||||
"""Set the database path. Closes any existing connection first."""
|
||||
global _db_path
|
||||
close_connection()
|
||||
_db_path = path
|
||||
|
||||
|
||||
def get_connection() -> sqlite3.Connection:
|
||||
"""Get a thread-local database connection with WAL mode and foreign keys enabled."""
|
||||
if not hasattr(_local, "connection") or _local.connection is None:
|
||||
conn = sqlite3.connect(_db_path)
|
||||
conn.execute("PRAGMA journal_mode=WAL")
|
||||
conn.execute("PRAGMA foreign_keys=ON")
|
||||
conn.row_factory = sqlite3.Row
|
||||
_local.connection = conn
|
||||
return _local.connection
|
||||
|
||||
|
||||
def close_connection() -> None:
|
||||
"""Close the thread-local database connection if one exists."""
|
||||
if hasattr(_local, "connection") and _local.connection is not None:
|
||||
_local.connection.close()
|
||||
_local.connection = None
|
||||
|
||||
|
||||
def init_db() -> None:
|
||||
"""Create all tables and default settings."""
|
||||
conn = get_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.executescript(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS known_objects (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL CHECK(type IN ('person', 'vehicle', 'pet')),
|
||||
action TEXT NOT NULL DEFAULT 'quiet' CHECK(action IN ('quiet', 'suppress', 'alert')),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS embeddings (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
known_object_id INTEGER NOT NULL,
|
||||
embedding BLOB NOT NULL,
|
||||
snapshot_url TEXT,
|
||||
thumbnail BLOB,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (known_object_id) REFERENCES known_objects(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
frigate_event_id TEXT UNIQUE NOT NULL,
|
||||
camera TEXT NOT NULL,
|
||||
label TEXT NOT NULL,
|
||||
score REAL NOT NULL,
|
||||
snapshot BLOB,
|
||||
embedding BLOB,
|
||||
match_status TEXT NOT NULL DEFAULT 'unreviewed'
|
||||
CHECK(match_status IN ('known', 'unknown', 'ambiguous', 'unreviewed')),
|
||||
matched_object_id INTEGER,
|
||||
match_confidence REAL,
|
||||
ai_description TEXT,
|
||||
notified INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (matched_object_id) REFERENCES known_objects(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_events_created_at ON events(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_events_match_status ON events(match_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_events_camera ON events(camera);
|
||||
CREATE INDEX IF NOT EXISTS idx_embeddings_known_object_id ON embeddings(known_object_id);
|
||||
"""
|
||||
)
|
||||
|
||||
# Insert default settings if they don't exist
|
||||
defaults = {
|
||||
"vision_backend": "haiku",
|
||||
"recognition_enabled": "false",
|
||||
"event_retention_days": "90",
|
||||
}
|
||||
for key, value in defaults.items():
|
||||
cursor.execute(
|
||||
"INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)",
|
||||
(key, value),
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
logger.info("Database initialized at %s", _db_path)
|
||||
Reference in New Issue
Block a user