feat(asr-pipeline): merge PR #1 webauth/CSRF/locking hardening and web_password fallback
Build image / build (push) Canceled after 0s
Build ASR Pipeline / image (push) Canceled after 0s

This commit is contained in:
Codex
2026-11-02 06:37:33 -08:00
parent 9debd1c47d
commit 3c70861463
44 changed files with 4354 additions and 333 deletions
@@ -157,7 +157,8 @@ class Entity:
def connect() -> sqlite3.Connection:
CFG.state_dir.mkdir(parents=True, exist_ok=True)
con = sqlite3.connect(CFG.lexicon_db)
con = sqlite3.connect(CFG.lexicon_db, timeout=30)
con.execute("PRAGMA journal_mode=WAL")
con.row_factory = sqlite3.Row
con.executescript(SCHEMA)
# One-time compatibility migration for the 158 corrections learned before the
@@ -527,7 +528,7 @@ def stats() -> dict:
# ------------------------------------------------------------------ Web UI CRUD
def list_aliases(q: str = "", origin_filter: str = "", limit: int = 200) -> list[dict]:
def list_aliases(q: str = "", origin_filter: str = "", limit: int = 200, offset: int = 0) -> list[dict]:
con = connect()
sql = "SELECT * FROM alias WHERE 1=1"
args: list = []
@@ -539,13 +540,30 @@ def list_aliases(q: str = "", origin_filter: str = "", limit: int = 200) -> list
sql += " AND origin <> 'card'"
elif origin_filter == "card":
sql += " AND origin = 'card'"
sql += " ORDER BY confirmed DESC, created_at DESC, alias ASC LIMIT ?"
args.append(limit)
sql += " ORDER BY confirmed DESC, created_at DESC, alias ASC LIMIT ? OFFSET ?"
args.extend((max(1, min(limit, 500)), max(0, offset)))
rows = [dict(r) for r in con.execute(sql, args).fetchall()]
con.close()
return rows
def count_aliases(q: str = "", origin_filter: str = "") -> int:
con = connect()
sql = "SELECT count(*) FROM alias WHERE 1=1"
args: list = []
if q.strip():
pat = f"%{q.strip()}%"
sql += " AND (alias LIKE ? OR canonical LIKE ? OR note LIKE ?)"
args.extend([pat, pat, pat])
if origin_filter == "learned":
sql += " AND origin <> 'card'"
elif origin_filter == "card":
sql += " AND origin = 'card'"
n = int(con.execute(sql, args).fetchone()[0])
con.close()
return n
def update_alias(
old_alias: str,
old_canonical: str,
@@ -590,7 +608,7 @@ def delete_alias(alias: str, canonical: str) -> bool:
return deleted
def list_corrections(q: str = "", limit: int = 200) -> list[dict]:
def list_corrections(q: str = "", limit: int = 200, offset: int = 0) -> list[dict]:
con = connect()
sql = "SELECT * FROM correction WHERE 1=1"
args: list = []
@@ -598,13 +616,26 @@ def list_corrections(q: str = "", limit: int = 200) -> list[dict]:
pat = f"%{q.strip()}%"
sql += " AND (surface LIKE ? OR canonical LIKE ? OR note LIKE ?)"
args.extend([pat, pat, pat])
sql += " ORDER BY confirmed DESC, n DESC, last_seen DESC LIMIT ?"
args.append(limit)
sql += " ORDER BY confirmed DESC, n DESC, last_seen DESC LIMIT ? OFFSET ?"
args.extend((max(1, min(limit, 500)), max(0, offset)))
rows = [dict(r) for r in con.execute(sql, args).fetchall()]
con.close()
return rows
def count_corrections(q: str = "") -> int:
con = connect()
sql = "SELECT count(*) FROM correction WHERE 1=1"
args: list = []
if q.strip():
pat = f"%{q.strip()}%"
sql += " AND (surface LIKE ? OR canonical LIKE ? OR note LIKE ?)"
args.extend([pat, pat, pat])
n = int(con.execute(sql, args).fetchone()[0])
con.close()
return n
def update_correction(
old_surface: str,
old_canonical: str,
@@ -651,7 +682,7 @@ def delete_correction(surface: str, canonical: str) -> bool:
return deleted
def list_entities(q: str = "", kind: str = "", limit: int = 200) -> list[dict]:
def list_entities(q: str = "", kind: str = "", limit: int = 200, offset: int = 0) -> list[dict]:
con = connect()
sql = "SELECT * FROM entity WHERE 1=1"
args: list = []
@@ -662,13 +693,29 @@ def list_entities(q: str = "", kind: str = "", limit: int = 200) -> list[dict]:
if kind.strip():
sql += " AND kind=?"
args.append(kind.strip())
sql += " ORDER BY (CASE WHEN card='' THEN 0 ELSE 1 END), canonical ASC LIMIT ?"
args.append(limit)
sql += " ORDER BY (CASE WHEN card='' THEN 0 ELSE 1 END), canonical ASC LIMIT ? OFFSET ?"
args.extend((max(1, min(limit, 500)), max(0, offset)))
rows = [dict(r) for r in con.execute(sql, args).fetchall()]
con.close()
return rows
def count_entities(q: str = "", kind: str = "") -> int:
con = connect()
sql = "SELECT count(*) FROM entity WHERE 1=1"
args: list = []
if q.strip():
pat = f"%{q.strip()}%"
sql += " AND (canonical LIKE ? OR company LIKE ? OR role LIKE ? OR related LIKE ?)"
args.extend([pat, pat, pat, pat])
if kind.strip():
sql += " AND kind=?"
args.append(kind.strip())
n = int(con.execute(sql, args).fetchone()[0])
con.close()
return n
def upsert_entity(
canonical: str,
kind: str = "人名",
@@ -723,7 +770,7 @@ def delete_entity(canonical: str) -> bool:
return deleted
def list_relations(q: str = "", limit: int = 200) -> list[dict]:
def list_relations(q: str = "", limit: int = 200, offset: int = 0) -> list[dict]:
con = connect()
sql = "SELECT * FROM relation WHERE 1=1"
args: list = []
@@ -731,13 +778,26 @@ def list_relations(q: str = "", limit: int = 200) -> list[dict]:
pat = f"%{q.strip()}%"
sql += " AND (subject LIKE ? OR predicate LIKE ? OR object LIKE ? OR source LIKE ?)"
args.extend([pat, pat, pat, pat])
sql += " ORDER BY active DESC, confidence DESC, last_seen DESC LIMIT ?"
args.append(limit)
sql += " ORDER BY active DESC, confidence DESC, last_seen DESC LIMIT ? OFFSET ?"
args.extend((max(1, min(limit, 500)), max(0, offset)))
rows = [dict(r) for r in con.execute(sql, args).fetchall()]
con.close()
return rows
def count_relations(q: str = "") -> int:
con = connect()
sql = "SELECT count(*) FROM relation WHERE 1=1"
args: list = []
if q.strip():
pat = f"%{q.strip()}%"
sql += " AND (subject LIKE ? OR predicate LIKE ? OR object LIKE ? OR source LIKE ?)"
args.extend([pat, pat, pat, pat])
n = int(con.execute(sql, args).fetchone()[0])
con.close()
return n
def update_relation(
old_subject: str,
old_predicate: str,