feat(tools-pve/asr-pipeline): SQLite model config, task delete/rerefine, multi-recording review, lexicon CRUD
Build image / build (push) Canceled after 0s
Build ASR Pipeline / image (push) Canceled after 0s

This commit is contained in:
Codex
2026-11-01 23:14:31 -08:00
parent 2367c5eb4e
commit be589ff5e0
7 changed files with 2064 additions and 340 deletions
@@ -298,7 +298,7 @@ def sync_from_vault(force: bool = False) -> dict:
now = time.time()
n_ent = n_alias = 0
con.execute("DELETE FROM alias WHERE origin IN ('card','glossary')")
con.execute("DELETE FROM entity")
con.execute("DELETE FROM entity WHERE card <> ''")
con.execute("DELETE FROM relation WHERE source LIKE 'card:%'")
for sub, kind in (("People", "人名"), ("Companies", "公司"), ("Projects", "项目")):
d = CFG.vault / sub
@@ -524,3 +524,261 @@ def stats() -> dict:
d["synced_at"] = r["v"] if r else ""
con.close()
return d
# ------------------------------------------------------------------ Web UI CRUD
def list_aliases(q: str = "", origin_filter: str = "", limit: int = 200) -> list[dict]:
con = connect()
sql = "SELECT * 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'"
sql += " ORDER BY confirmed DESC, created_at DESC, alias ASC LIMIT ?"
args.append(limit)
rows = [dict(r) for r in con.execute(sql, args).fetchall()]
con.close()
return rows
def update_alias(
old_alias: str,
old_canonical: str,
new_alias: str,
new_canonical: str,
*,
kind: str = "",
confirmed: int = 1,
note: str = "",
) -> bool:
con = connect()
row = con.execute(
"SELECT * FROM alias WHERE alias=? AND canonical=?",
(old_alias, old_canonical),
).fetchone()
origin = row["origin"] if row else "manual"
hits = row["hits"] if row else 0
created_at = row["created_at"] if row else time.time()
if not kind:
er = con.execute("SELECT kind FROM entity WHERE canonical=?", (new_canonical,)).fetchone()
kind = er["kind"] if er else (row["kind"] if row else guess_kind(new_canonical))
con.execute(
"DELETE FROM alias WHERE alias=? AND canonical=?",
(old_alias, old_canonical),
)
con.execute(
"INSERT OR REPLACE INTO alias(alias,canonical,kind,origin,confirmed,hits,created_at,note) "
"VALUES(?,?,?,?,?,?,?,?)",
(new_alias, new_canonical, kind, origin, int(bool(confirmed)), hits, created_at, note),
)
con.commit()
con.close()
return True
def delete_alias(alias: str, canonical: str) -> bool:
con = connect()
cur = con.execute("DELETE FROM alias WHERE alias=? AND canonical=?", (alias, canonical))
con.commit()
deleted = cur.rowcount > 0
con.close()
return deleted
def list_corrections(q: str = "", limit: int = 200) -> list[dict]:
con = connect()
sql = "SELECT * 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])
sql += " ORDER BY confirmed DESC, n DESC, last_seen DESC LIMIT ?"
args.append(limit)
rows = [dict(r) for r in con.execute(sql, args).fetchall()]
con.close()
return rows
def update_correction(
old_surface: str,
old_canonical: str,
new_surface: str,
new_canonical: str,
*,
confirmed: int = 1,
note: str = "",
) -> bool:
con = connect()
row = con.execute(
"SELECT * FROM correction WHERE surface=? AND canonical=?",
(old_surface, old_canonical),
).fetchone()
n = row["n"] if row else 1
now = time.time()
con.execute("DELETE FROM correction WHERE surface=? AND canonical=?", (old_surface, old_canonical))
con.execute(
"DELETE FROM phonetic_confusion WHERE heard=? AND intended=?",
(old_surface, old_canonical),
)
con.execute(
"INSERT OR REPLACE INTO correction(surface,canonical,n,confirmed,last_seen,note) "
"VALUES(?,?,?,?,?,?)",
(new_surface, new_canonical, n, int(bool(confirmed)), now, note),
)
con.execute(
"INSERT OR REPLACE INTO phonetic_confusion(heard,intended,n,confirmed,last_seen,note) "
"VALUES(?,?,?,?,?,?)",
(new_surface, new_canonical, n, int(bool(confirmed)), now, note),
)
con.commit()
con.close()
return True
def delete_correction(surface: str, canonical: str) -> bool:
con = connect()
cur = con.execute("DELETE FROM correction WHERE surface=? AND canonical=?", (surface, canonical))
con.execute("DELETE FROM phonetic_confusion WHERE heard=? AND intended=?", (surface, canonical))
con.commit()
deleted = cur.rowcount > 0
con.close()
return deleted
def list_entities(q: str = "", kind: str = "", limit: int = 200) -> list[dict]:
con = connect()
sql = "SELECT * 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())
sql += " ORDER BY (CASE WHEN card='' THEN 0 ELSE 1 END), canonical ASC LIMIT ?"
args.append(limit)
rows = [dict(r) for r in con.execute(sql, args).fetchall()]
con.close()
return rows
def upsert_entity(
canonical: str,
kind: str = "人名",
*,
company: str = "",
role: str = "",
related: str = "",
card: str = "",
) -> None:
con = connect()
con.execute(
"INSERT OR REPLACE INTO entity(canonical,kind,company,role,related,card,synced_at) "
"VALUES(?,?,?,?,?,?,?)",
(canonical, kind or guess_kind(canonical), company, role, related, card, time.time()),
)
con.commit()
con.close()
def update_entity(
old_canonical: str,
new_canonical: str,
kind: str,
*,
company: str = "",
role: str = "",
related: str = "",
) -> bool:
con = connect()
row = con.execute("SELECT * FROM entity WHERE canonical=?", (old_canonical,)).fetchone()
card = row["card"] if row else ""
con.execute("DELETE FROM entity WHERE canonical=?", (old_canonical,))
con.execute(
"INSERT OR REPLACE INTO entity(canonical,kind,company,role,related,card,synced_at) "
"VALUES(?,?,?,?,?,?,?)",
(new_canonical, kind or guess_kind(new_canonical), company, role, related, card, time.time()),
)
if old_canonical != new_canonical:
con.execute("UPDATE alias SET canonical=? WHERE canonical=?", (new_canonical, old_canonical))
con.execute("UPDATE correction SET canonical=? WHERE canonical=?", (new_canonical, old_canonical))
con.commit()
con.close()
return True
def delete_entity(canonical: str) -> bool:
con = connect()
cur = con.execute("DELETE FROM entity WHERE canonical=?", (canonical,))
con.commit()
deleted = cur.rowcount > 0
con.close()
return deleted
def list_relations(q: str = "", limit: int = 200) -> list[dict]:
con = connect()
sql = "SELECT * 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])
sql += " ORDER BY active DESC, confidence DESC, last_seen DESC LIMIT ?"
args.append(limit)
rows = [dict(r) for r in con.execute(sql, args).fetchall()]
con.close()
return rows
def update_relation(
old_subject: str,
old_predicate: str,
old_object: str,
old_source: str,
subject: str,
predicate: str,
object_: str,
*,
confidence: float = 0.8,
active: int = 1,
) -> bool:
con = connect()
row = con.execute(
"SELECT * FROM relation WHERE subject=? AND predicate=? AND object=? AND source=?",
(old_subject, old_predicate, old_object, old_source),
).fetchone()
first_seen = row["first_seen"] if row else time.time()
source = old_source or "manual"
con.execute(
"DELETE FROM relation WHERE subject=? AND predicate=? AND object=? AND source=?",
(old_subject, old_predicate, old_object, old_source),
)
con.execute(
"INSERT OR REPLACE INTO relation(subject,predicate,object,confidence,source,first_seen,last_seen,active) "
"VALUES(?,?,?,?,?,?,?,?)",
(subject, predicate, object_, float(confidence), source, first_seen, time.time(), int(bool(active))),
)
con.commit()
con.close()
return True
def delete_relation(subject: str, predicate: str, object_: str, source: str) -> bool:
con = connect()
cur = con.execute(
"DELETE FROM relation WHERE subject=? AND predicate=? AND object=? AND source=?",
(subject, predicate, object_, source),
)
con.commit()
deleted = cur.rowcount > 0
con.close()
return deleted