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
+104 -7
View File
@@ -4,15 +4,19 @@ import sqlite3
import time
from typing import Any
from .config import DB, DEFAULT_PROVIDER, ensure_dirs
from asrpipe.config import CFG, bootstrap_default_settings, get_setting, load_db_settings, set_settings
from .config import DB, ensure_dirs
STATUSES = {
"uploading", "queued", "transcribing", "refining", "review",
"publishing", "complete", "failed",
}
_BOOTSTRAPPED_DB: str = ""
def connect() -> sqlite3.Connection:
global _BOOTSTRAPPED_DB
ensure_dirs()
con = sqlite3.connect(DB, timeout=30)
con.row_factory = sqlite3.Row
@@ -37,8 +41,14 @@ def connect() -> sqlite3.Connection:
status TEXT NOT NULL, detail TEXT NOT NULL DEFAULT '', created_at REAL NOT NULL
);
CREATE INDEX IF NOT EXISTS ix_job_event_job ON job_event(job_id,id);
CREATE TABLE IF NOT EXISTS app_setting(
key TEXT PRIMARY KEY,
value TEXT NOT NULL DEFAULT '',
updated_at REAL NOT NULL
);
""")
cols = {r[1] for r in con.execute("PRAGMA table_info(intake_job)")}
default_prov = CFG.asr_provider or "qwen3cam"
additions = {
"draft": "TEXT NOT NULL DEFAULT ''",
"result": "TEXT NOT NULL DEFAULT ''",
@@ -46,13 +56,19 @@ def connect() -> sqlite3.Connection:
"sha256": "TEXT NOT NULL DEFAULT ''",
"attempts": "INTEGER NOT NULL DEFAULT 0",
"error_code": "TEXT NOT NULL DEFAULT ''",
"asr_provider": f"TEXT NOT NULL DEFAULT '{DEFAULT_PROVIDER}'",
"asr_provider": f"TEXT NOT NULL DEFAULT '{default_prov}'",
"asr_model": "TEXT NOT NULL DEFAULT ''",
}
for name, ddl in additions.items():
if name not in cols:
con.execute(f"ALTER TABLE intake_job ADD COLUMN {name} {ddl}")
con.commit()
if _BOOTSTRAPPED_DB != str(DB):
_BOOTSTRAPPED_DB = str(DB)
try:
bootstrap_default_settings()
except Exception:
pass
return con
@@ -69,7 +85,7 @@ def create_job(
asr_model: str = "",
) -> dict[str, Any]:
now = time.time()
prov = (asr_provider or DEFAULT_PROVIDER or "qwen3cam").strip().lower()
prov = (asr_provider or CFG.asr_provider or "qwen3cam").strip().lower()
with connect() as con:
con.execute(
"INSERT INTO intake_job(id,original_name,stored_name,title,context,size,"
@@ -88,7 +104,7 @@ def update_job(job_id: str, status: str, detail: str = "", **fields: Any) -> boo
raise ValueError(f"invalid status: {status}")
allowed = {
"transcript", "draft", "result", "sha256", "attempts",
"error_code", "asr_provider", "asr_model",
"error_code", "asr_provider", "asr_model", "title", "context",
}
changes = {k: v for k, v in fields.items() if k in allowed and v is not None}
sets = ["status=?", "updated_at=?", "detail=?"]
@@ -106,6 +122,44 @@ def update_job(job_id: str, status: str, detail: str = "", **fields: Any) -> boo
return bool(cur.rowcount)
def update_job_meta(
job_id: str,
*,
title: str | None = None,
context: str | None = None,
asr_provider: str | None = None,
asr_model: str | None = None,
) -> bool:
sets = ["updated_at=?"]
values: list[Any] = [time.time()]
if title is not None:
sets.append("title=?")
values.append(title[:120])
if context is not None:
sets.append("context=?")
values.append(context[:2000])
if asr_provider is not None:
sets.append("asr_provider=?")
values.append(asr_provider[:40])
if asr_model is not None:
sets.append("asr_model=?")
values.append(asr_model[:80])
values.append(job_id)
with connect() as con:
cur = con.execute(f"UPDATE intake_job SET {','.join(sets)} WHERE id=?", values)
return bool(cur.rowcount)
def delete_job(job_id: str) -> dict[str, Any] | None:
job = get_job(job_id)
if not job:
return None
with connect() as con:
con.execute("DELETE FROM job_event WHERE job_id=?", (job_id,))
con.execute("DELETE FROM intake_job WHERE id=?", (job_id,))
return job
def get_job(job_id: str) -> dict[str, Any] | None:
with connect() as con:
row = con.execute("SELECT * FROM intake_job WHERE id=?", (job_id,)).fetchone()
@@ -120,13 +174,27 @@ def find_by_stored(stored_name: str) -> dict[str, Any] | None:
return dict(row) if row else None
def list_jobs(limit: int = 30, offset: int = 0, status: str = "") -> list[dict[str, Any]]:
def list_jobs(
limit: int = 30,
offset: int = 0,
status: str = "",
q: str = "",
provider: str = "",
) -> list[dict[str, Any]]:
limit = min(max(limit, 1), 200)
offset = max(offset, 0)
sql, args = "SELECT * FROM intake_job", []
sql = "SELECT * FROM intake_job WHERE 1=1"
args: list[Any] = []
if status:
sql += " WHERE status=?"
sql += " AND status=?"
args.append(status)
if provider:
sql += " AND asr_provider=?"
args.append(provider)
if q.strip():
pat = f"%{q.strip()}%"
sql += " AND (title LIKE ? OR original_name LIKE ? OR context LIKE ? OR detail LIKE ?)"
args.extend([pat, pat, pat, pat])
sql += " ORDER BY created_at DESC LIMIT ? OFFSET ?"
args.extend((limit, offset))
with connect() as con:
@@ -145,3 +213,32 @@ def pending_recovery() -> list[dict[str, Any]]:
return [dict(r) for r in con.execute(
"SELECT * FROM intake_job WHERE status IN ('queued','transcribing','refining','publishing') "
"ORDER BY created_at").fetchall()]
def get_all_settings() -> dict[str, str]:
connect().close()
return load_db_settings(force=True)
def save_settings(updates: dict[str, Any]) -> dict[str, str]:
connect().close()
set_settings(updates)
return load_db_settings(force=True)
__all__ = [
"STATUSES",
"connect",
"create_job",
"update_job",
"update_job_meta",
"delete_job",
"get_job",
"find_by_stored",
"list_jobs",
"events",
"pending_recovery",
"get_all_settings",
"save_settings",
"get_setting",
]