import sqlite3 import threading from pathlib import Path from app.shared.config import Settings _local = threading.local() def get_db(settings: Settings) -> sqlite3.Connection: if not hasattr(_local, "conn") or _local.conn is None: conn = sqlite3.connect(settings.db_path, check_same_thread=False) conn.row_factory = sqlite3.Row conn.execute("PRAGMA journal_mode=WAL") conn.execute("PRAGMA foreign_keys=ON") _local.conn = conn return _local.conn def init_schema(settings: Settings) -> None: Path(settings.clips_dir).mkdir(parents=True, exist_ok=True) db = get_db(settings) db.executescript(""" CREATE TABLE IF NOT EXISTS rooms ( id INTEGER PRIMARY KEY, name TEXT NOT NULL UNIQUE, device_label TEXT, is_active BOOLEAN DEFAULT 0, last_seen DATETIME, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS speakers ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS voice_embeddings ( id INTEGER PRIMARY KEY, speaker_id INTEGER NOT NULL REFERENCES speakers(id) ON DELETE CASCADE, embedding BLOB NOT NULL, audio_sample BLOB, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS utterances ( id INTEGER PRIMARY KEY, room_id INTEGER NOT NULL REFERENCES rooms(id), speaker_id INTEGER REFERENCES speakers(id), transcript TEXT NOT NULL, embedding BLOB, match_status TEXT NOT NULL DEFAULT 'unreviewed', match_confidence REAL, start_time DATETIME NOT NULL, end_time DATETIME NOT NULL, audio_clip_path TEXT, livekit_room TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE VIRTUAL TABLE IF NOT EXISTS utterances_fts USING fts5( transcript, content=utterances, content_rowid=id ); CREATE TRIGGER IF NOT EXISTS utterances_ai AFTER INSERT ON utterances BEGIN INSERT INTO utterances_fts(rowid, transcript) VALUES (new.id, new.transcript); END; CREATE TRIGGER IF NOT EXISTS utterances_au AFTER UPDATE OF transcript ON utterances BEGIN INSERT INTO utterances_fts(utterances_fts, rowid, transcript) VALUES ('delete', old.id, old.transcript); INSERT INTO utterances_fts(rowid, transcript) VALUES (new.id, new.transcript); END; CREATE TRIGGER IF NOT EXISTS utterances_ad AFTER DELETE ON utterances BEGIN INSERT INTO utterances_fts(utterances_fts, rowid, transcript) VALUES ('delete', old.id, old.transcript); END; CREATE TABLE IF NOT EXISTS daily_summaries ( id INTEGER PRIMARY KEY, date DATE NOT NULL UNIQUE, summary_text TEXT NOT NULL, generated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); """) db.commit()