feat(tools-pve/asr-pipeline): multi-backend ASR web app with LiteLLM routing
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sqlite3
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from .config import DB, ensure_dirs
|
||||
from .config import DB, DEFAULT_PROVIDER, ensure_dirs
|
||||
|
||||
STATUSES = {"uploading", "queued", "transcribing", "refining", "review",
|
||||
"publishing", "complete", "failed"}
|
||||
STATUSES = {
|
||||
"uploading", "queued", "transcribing", "refining", "review",
|
||||
"publishing", "complete", "failed",
|
||||
}
|
||||
|
||||
|
||||
def connect() -> sqlite3.Connection:
|
||||
@@ -26,6 +27,8 @@ def connect() -> sqlite3.Connection:
|
||||
draft TEXT NOT NULL DEFAULT '', result TEXT NOT NULL DEFAULT '',
|
||||
source TEXT NOT NULL DEFAULT 'web', sha256 TEXT NOT NULL DEFAULT '',
|
||||
attempts INTEGER NOT NULL DEFAULT 0, error_code TEXT NOT NULL DEFAULT '',
|
||||
asr_provider TEXT NOT NULL DEFAULT 'qwen3cam',
|
||||
asr_model TEXT NOT NULL DEFAULT '',
|
||||
created_at REAL NOT NULL, updated_at REAL NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS job_event(
|
||||
@@ -37,9 +40,14 @@ def connect() -> sqlite3.Connection:
|
||||
""")
|
||||
cols = {r[1] for r in con.execute("PRAGMA table_info(intake_job)")}
|
||||
additions = {
|
||||
"draft": "TEXT NOT NULL DEFAULT ''", "result": "TEXT NOT NULL DEFAULT ''",
|
||||
"source": "TEXT NOT NULL DEFAULT 'web'", "sha256": "TEXT NOT NULL DEFAULT ''",
|
||||
"attempts": "INTEGER NOT NULL DEFAULT 0", "error_code": "TEXT NOT NULL DEFAULT ''",
|
||||
"draft": "TEXT NOT NULL DEFAULT ''",
|
||||
"result": "TEXT NOT NULL DEFAULT ''",
|
||||
"source": "TEXT NOT NULL DEFAULT 'web'",
|
||||
"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_model": "TEXT NOT NULL DEFAULT ''",
|
||||
}
|
||||
for name, ddl in additions.items():
|
||||
if name not in cols:
|
||||
@@ -48,23 +56,40 @@ def connect() -> sqlite3.Connection:
|
||||
return con
|
||||
|
||||
|
||||
def create_job(job_id: str, original_name: str, stored_name: str, *, title: str = "",
|
||||
context: str = "", size: int = 0, source: str = "web") -> dict[str, Any]:
|
||||
def create_job(
|
||||
job_id: str,
|
||||
original_name: str,
|
||||
stored_name: str,
|
||||
*,
|
||||
title: str = "",
|
||||
context: str = "",
|
||||
size: int = 0,
|
||||
source: str = "web",
|
||||
asr_provider: str = "",
|
||||
asr_model: str = "",
|
||||
) -> dict[str, Any]:
|
||||
now = time.time()
|
||||
prov = (asr_provider or DEFAULT_PROVIDER or "qwen3cam").strip().lower()
|
||||
with connect() as con:
|
||||
con.execute("INSERT INTO intake_job(id,original_name,stored_name,title,context,size,"
|
||||
"status,source,created_at,updated_at) VALUES(?,?,?,?,?,?,?,?,?,?)",
|
||||
(job_id, original_name, stored_name, title, context, size,
|
||||
"queued", source, now, now))
|
||||
con.execute("INSERT INTO job_event(job_id,status,detail,created_at) VALUES(?,?,?,?)",
|
||||
(job_id, "queued", "录音已进入队列", now))
|
||||
con.execute(
|
||||
"INSERT INTO intake_job(id,original_name,stored_name,title,context,size,"
|
||||
"status,source,asr_provider,asr_model,created_at,updated_at) "
|
||||
"VALUES(?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
(job_id, original_name, stored_name, title, context, size,
|
||||
"queued", source, prov, asr_model, now, now))
|
||||
con.execute(
|
||||
"INSERT INTO job_event(job_id,status,detail,created_at) VALUES(?,?,?,?)",
|
||||
(job_id, "queued", f"录音已进入队列 (ASR: {prov})", now))
|
||||
return get_job(job_id) or {}
|
||||
|
||||
|
||||
def update_job(job_id: str, status: str, detail: str = "", **fields: Any) -> bool:
|
||||
if status not in STATUSES:
|
||||
raise ValueError(f"invalid status: {status}")
|
||||
allowed = {"transcript", "draft", "result", "sha256", "attempts", "error_code"}
|
||||
allowed = {
|
||||
"transcript", "draft", "result", "sha256", "attempts",
|
||||
"error_code", "asr_provider", "asr_model",
|
||||
}
|
||||
changes = {k: v for k, v in fields.items() if k in allowed and v is not None}
|
||||
sets = ["status=?", "updated_at=?", "detail=?"]
|
||||
values: list[Any] = [status, time.time(), detail[:1000]]
|
||||
@@ -75,8 +100,9 @@ def update_job(job_id: str, status: str, detail: str = "", **fields: Any) -> boo
|
||||
with connect() as con:
|
||||
cur = con.execute(f"UPDATE intake_job SET {','.join(sets)} WHERE id=?", values)
|
||||
if cur.rowcount:
|
||||
con.execute("INSERT INTO job_event(job_id,status,detail,created_at) VALUES(?,?,?,?)",
|
||||
(job_id, status, detail[:1000], time.time()))
|
||||
con.execute(
|
||||
"INSERT INTO job_event(job_id,status,detail,created_at) VALUES(?,?,?,?)",
|
||||
(job_id, status, detail[:1000], time.time()))
|
||||
return bool(cur.rowcount)
|
||||
|
||||
|
||||
@@ -88,8 +114,9 @@ def get_job(job_id: str) -> dict[str, Any] | None:
|
||||
|
||||
def find_by_stored(stored_name: str) -> dict[str, Any] | None:
|
||||
with connect() as con:
|
||||
row = con.execute("SELECT * FROM intake_job WHERE stored_name=? ORDER BY created_at DESC LIMIT 1",
|
||||
(stored_name,)).fetchone()
|
||||
row = con.execute(
|
||||
"SELECT * FROM intake_job WHERE stored_name=? ORDER BY created_at DESC LIMIT 1",
|
||||
(stored_name,)).fetchone()
|
||||
return dict(row) if row else None
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user