Download feedback/pattern_store.py from sahilfarib/Legal-Document-Intelligence: direct link, hf CLI and curl.
- Browser
- Download file 6.28 kB
-
https://huggingface.co/spaces/sahilfarib/Legal-Document-Intelligence/resolve/main/feedback/pattern_store.py
- Command line
-
hf download hf://spaces/sahilfarib/Legal-Document-Intelligence/feedback/pattern_store.py
-
curl -L -o pattern_store.py https://huggingface.co/spaces/sahilfarib/Legal-Document-Intelligence/resolve/main/feedback/pattern_store.py
6.28 kB
| """ | |
| feedback/pattern_store.py — SQLite CRUD for learned patterns and draft history | |
| Uses context manager for safe connection handling. All schema is | |
| created on first init. Supports draft history and feedback logging. | |
| """ | |
| import sqlite3 | |
| from contextlib import contextmanager | |
| from datetime import datetime | |
| from uuid import uuid4 | |
| from pathlib import Path | |
| from loguru import logger | |
| from config import PATTERNS_DB_PATH | |
| SCHEMA = """\ | |
| CREATE TABLE IF NOT EXISTS learned_patterns ( | |
| id TEXT PRIMARY KEY, | |
| pattern TEXT NOT NULL, | |
| doc_type TEXT, | |
| source_diff TEXT, | |
| created_at TEXT NOT NULL, | |
| use_count INTEGER DEFAULT 0, | |
| active INTEGER DEFAULT 1 | |
| ); | |
| CREATE TABLE IF NOT EXISTS draft_history ( | |
| draft_id TEXT PRIMARY KEY, | |
| draft_type TEXT NOT NULL, | |
| doc_ids TEXT NOT NULL, | |
| draft_text TEXT NOT NULL, | |
| validation_json TEXT, | |
| created_at TEXT NOT NULL, | |
| was_edited INTEGER DEFAULT 0 | |
| ); | |
| CREATE TABLE IF NOT EXISTS feedback_log ( | |
| id TEXT PRIMARY KEY, | |
| draft_id TEXT NOT NULL, | |
| original_text TEXT NOT NULL, | |
| edited_text TEXT NOT NULL, | |
| change_ratio REAL, | |
| pattern_id TEXT, | |
| created_at TEXT NOT NULL | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_patterns_active | |
| ON learned_patterns (active, doc_type); | |
| """ | |
| class PatternStore: | |
| """SQLite-backed store for learned patterns and draft history.""" | |
| def __init__(self, db_path: str | Path = PATTERNS_DB_PATH): | |
| self.db_path = str(db_path) | |
| Path(self.db_path).parent.mkdir(parents=True, exist_ok=True) | |
| self._init_db() | |
| def _conn(self): | |
| conn = sqlite3.connect(self.db_path) | |
| conn.row_factory = sqlite3.Row | |
| try: | |
| yield conn | |
| conn.commit() | |
| except Exception: | |
| conn.rollback() | |
| raise | |
| finally: | |
| conn.close() | |
| def _init_db(self): | |
| with self._conn() as conn: | |
| conn.executescript(SCHEMA) | |
| logger.debug(f"PatternStore initialised: {self.db_path}") | |
| # ----- Pattern CRUD ----- | |
| def save_pattern(self, pattern: str, doc_type: str, source_diff: str = "") -> str: | |
| pid = str(uuid4()) | |
| with self._conn() as conn: | |
| conn.execute( | |
| "INSERT INTO learned_patterns VALUES (?,?,?,?,?,?,?)", | |
| (pid, pattern, doc_type, source_diff, | |
| datetime.utcnow().isoformat(), 0, 1), | |
| ) | |
| logger.info(f"Pattern saved: [{pid[:8]}] {pattern}") | |
| return pid | |
| def update_pattern(self, pattern_id: str, new_text: str): | |
| with self._conn() as conn: | |
| conn.execute( | |
| "UPDATE learned_patterns SET pattern=? WHERE id=?", | |
| (new_text, pattern_id), | |
| ) | |
| logger.info(f"Pattern updated: [{pattern_id[:8]}]") | |
| def deactivate_pattern(self, pattern_id: str): | |
| with self._conn() as conn: | |
| conn.execute( | |
| "UPDATE learned_patterns SET active=0 WHERE id=?", | |
| (pattern_id,), | |
| ) | |
| def delete_pattern(self, pattern_id: str): | |
| with self._conn() as conn: | |
| conn.execute("DELETE FROM learned_patterns WHERE id=?", (pattern_id,)) | |
| def get_active_patterns( | |
| self, doc_type: str | None = None, limit: int = 8 | |
| ) -> list[tuple[str, str]]: | |
| with self._conn() as conn: | |
| if doc_type: | |
| rows = conn.execute( | |
| "SELECT id, pattern FROM learned_patterns " | |
| "WHERE active=1 AND (doc_type=? OR doc_type IS NULL) " | |
| "ORDER BY use_count DESC LIMIT ?", | |
| (doc_type, limit), | |
| ).fetchall() | |
| else: | |
| rows = conn.execute( | |
| "SELECT id, pattern FROM learned_patterns " | |
| "WHERE active=1 ORDER BY use_count DESC LIMIT ?", | |
| (limit,), | |
| ).fetchall() | |
| return [(r["id"], r["pattern"]) for r in rows] | |
| def get_all_patterns(self) -> list[dict]: | |
| with self._conn() as conn: | |
| rows = conn.execute( | |
| "SELECT * FROM learned_patterns ORDER BY created_at DESC" | |
| ).fetchall() | |
| return [dict(r) for r in rows] | |
| def increment_use_count(self, pattern_ids: list[str]): | |
| with self._conn() as conn: | |
| for pid in pattern_ids: | |
| conn.execute( | |
| "UPDATE learned_patterns SET use_count = use_count + 1 WHERE id=?", | |
| (pid,), | |
| ) | |
| def pattern_count(self, active_only: bool = True) -> int: | |
| with self._conn() as conn: | |
| q = "SELECT COUNT(*) FROM learned_patterns" | |
| if active_only: | |
| q += " WHERE active=1" | |
| return conn.execute(q).fetchone()[0] | |
| # ----- Draft History ----- | |
| def save_draft(self, draft_id: str, draft_type: str, doc_ids: str, | |
| draft_text: str, validation_json: str = ""): | |
| with self._conn() as conn: | |
| conn.execute( | |
| "INSERT OR REPLACE INTO draft_history VALUES (?,?,?,?,?,?,?)", | |
| (draft_id, draft_type, doc_ids, draft_text, validation_json, | |
| datetime.utcnow().isoformat(), 0), | |
| ) | |
| def get_draft(self, draft_id: str) -> dict | None: | |
| with self._conn() as conn: | |
| row = conn.execute( | |
| "SELECT * FROM draft_history WHERE draft_id=?", (draft_id,) | |
| ).fetchone() | |
| return dict(row) if row else None | |
| def mark_draft_edited(self, draft_id: str): | |
| with self._conn() as conn: | |
| conn.execute( | |
| "UPDATE draft_history SET was_edited=1 WHERE draft_id=?", | |
| (draft_id,), | |
| ) | |
| # ----- Feedback Log ----- | |
| def log_feedback(self, draft_id: str, original: str, edited: str, | |
| change_ratio: float, pattern_id: str = ""): | |
| fid = str(uuid4()) | |
| with self._conn() as conn: | |
| conn.execute( | |
| "INSERT INTO feedback_log VALUES (?,?,?,?,?,?,?)", | |
| (fid, draft_id, original, edited, change_ratio, | |
| pattern_id, datetime.utcnow().isoformat()), | |
| ) | |