Skip to content

Spectator 0.2.0 — persistent Web UI

Choose a tag to compare

@myurasov myurasov released this 09 May 23:44
· 29 commits to main since this release

Highlights

A persistent web UI that wraps Spectator's CLI. Drag-drop a meeting recording, watch the rt-factor climb in real time, download the transcripts, and ask follow-up questions — all without touching a terminal.

./spectator ui-server start                                    # localhost-only, port 7777
./spectator ui-server start --target <gpu-machine>             # route all jobs to a remote
./spectator ui-server start --bind 0.0.0.0 --port 8080         # expose on the LAN

Open http://localhost:7777/ and:

  • Drop an audio or video file onto the upload zone (or click to browse).
  • Submit with a quality preset / language / task / device override (audio) or a free-form summarization prompt (video).
  • Watch progress live: a per-job WebSocket pushes a snapshot every 2 s — segments processed, rt-factor, wall-clock, ETA. The progress bar updates in place; no page reloads.
  • Download Spectator's output bundle (.txt / .srt / .vtt / .json / .tsv) with one click per format.
  • Toggle the VSS stack up or down from the dashboard.
  • Ask questions of indexed videos (proxies to VSS's OpenAI-compat chat) or of completed audio jobs (transcript text → NVIDIA NIM).

What's new

ui-server lifecycle (CLI)

spectator ui-server start  [--port N] [--bind ADDR] [--target HOST] [--workdir DIR]
spectator ui-server stop
spectator ui-server status
spectator ui-server logs [--follow] [--lines N]

Detached uvicorn process. PID + log live under $workdir/ui-server/. SIGTERMs the whole process group on stop so subprocesses (whisper, ssh, …) exit too.

REST + WebSocket surface

Method + path Purpose
GET /api/status overall health (VSS reachable, audio-venv installed, jobs in flight)
POST /api/vss/{up,down} + GET status VSS stack lifecycle
POST /api/jobs (multipart) submit an audio or video job
GET /api/jobs[/{id}] list / detail with metrics
DELETE /api/jobs/{id} kill a running job (local PID or remote tmux)
GET /api/jobs/{id}/log tail of the subprocess log
GET /api/jobs/{id}/output/{filename} download an output file
WS /api/jobs/{id}/progress live JSON snapshots every 2 s
POST /api/query/{video,audio} Q&A against indexed videos / completed audio transcripts

Persistent job ledger

$workdir/ui-server/jobs/<uuid>.json survives ui-server stop / start. The schema is the public contract for any agent watching alongside the UI:

{
  "id": "...",
  "kind": "audio",
  "status": "running",
  "created_at": 1715300000.0,
  "started_at": 1715300004.5,
  "input_path": "/.../audio-in/meeting.mp3",
  "output_dir": "/.../audio-out/meeting/",
  "params": {"quality": "meeting", "language": null, "task": "transcribe"},
  "metrics": {"rt_factor": 3.04, "device": "mps", "wall_clock_s": 252.1},
  "pid": 12345,
  "target": null,
  "log_path": "/.../jobs/<uuid>.log"
}

Frontend

Vanilla HTML / JS / CSS — no React, no build step. CSS-vars theme with light + dark mode. NVIDIA-green accent on primary buttons and the progress bar fill. Single page, no routing.

Tests

14 new tests under tests/test_webui.py:

  • JobLedger persistence + status transitions + atomic delete.
  • Progress parser: running snapshots, finished runs (==== END rc=0 ==== marker + exit code), unknown duration, long-form HH:MM:SS.mmm timestamps for multi-hour audio.
  • FastAPI routes via TestClient: status / list / submit / 404 / 400 / path-traversal guard.

Total suite: 30 passing.

New runtime dependencies

Package License Why
fastapi >= 0.110, < 1.0 MIT HTTP + WebSocket framework
uvicorn[standard] >= 0.30, < 1.0 BSD-3-Clause ASGI server
python-multipart >= 0.0.9 Apache-2.0 multipart file upload

THIRD_PARTY_NOTICES.md updated.

Compatibility

No breaking changes vs v0.1.1. The CLI's audio + video pipelines are unchanged — the Web UI is a thin orchestration layer on top. Existing ./spectator audio transcribe, ./spectator process, ./spectator query invocations work the same. Nothing in the existing tests was modified; the smoke suite still asserts what it always did.

Security defaults

  • --bind 127.0.0.1 (localhost-only).
  • No built-in auth. Pass --bind 0.0.0.0 only on networks you trust.
  • Path-traversal blocked on output downloads.

Quick try

git clone https://github.com/myurasov/Spectator.git spectator && cd spectator
./spectator install
./spectator audio install
./spectator ui-server start
open http://localhost:7777/
# drop a meeting.mp3 onto the upload zone