Add cancel + progress UI, EngineToggle, and Docker deployment

This commit is contained in:
Lucas Winther
2026-07-14 19:32:10 +02:00
parent be82ecfe57
commit 0084e0435a
16 changed files with 972 additions and 60 deletions
+40 -5
View File
@@ -9,8 +9,17 @@ Legend: `[ ]` todo · `[x]` done · `[~]` in progress
---
## WIP Tasks before usage limit cutoff:
- [~] Allow users to cancel current transcription.
- [~] Better user-feedback while transcription is in progress (better than "Listening for the first few words")
- [x] Allow users to cancel current transcription. — Cancel button on the
file line, wired to worker termination (D-018); covers decode, pending
model download, and the pass itself. Server-engine cancel is tracked in
M6 (needs the M5 EngineToggle first).
- [x] Better user-feedback while transcription is in progress (better than
"Listening for the first few words") — the worker now posts
`transcribe-progress` (seconds processed / total, from the streamer's
chunk timestamps via the pure `TranscribeProgressTracker`); the UI shows
a percent in the heading plus a progress bar with mm:ss, and the file
flow's placeholder reads "Processing audio…" (the live wording stays
live-only).
## M0 — Scaffold cleanup & docs (small)
Current state is the raw `bun init` React template.
@@ -143,7 +152,7 @@ Notes (M4):
(availability probe for the toggle)
- [x] `src/lib/engine.ts` — `Engine` interface; `BrowserEngine` (wraps worker) and
`ServerEngine` (wraps fetch stream) (D-010)
- [ ] `EngineToggle` component — visible only with a session; persists choice
- [x] `EngineToggle` component — visible only with a session; persists choice
(persistence helpers + status probe already in `lib/engine.ts`; remaining:
the component, lifting `useAuth` out of `AuthForms` into `App` so both see
one session state, and routing the file flow through the selected engine —
@@ -154,7 +163,7 @@ Notes (M4):
`Bun.spawn` against `tests/fixtures/fake_sidecar.py`); real inference is
the opt-in `FW_INTEGRATION=1` test + manual run in `tests/server-engine.md`
(no pip/browser in the dev environment; same caveat as M2/M3)
- [ ] Deployment: optional Python/faster-whisper layer for the Docker image +
- [x] Deployment: optional Python/faster-whisper layer for the Docker image +
deployer note (base image stays Bun-only; install
`server-py/requirements.txt` to enable the server engine)
@@ -183,11 +192,37 @@ Notes (M5):
- Smoke-tested live against the dev server: `/` + auth unchanged; status
401 → (register) → 200 `{available:false, reason:"faster-whisper is not
installed…"}`; POST → 503 with the same reason, body untouched.
- EngineToggle: one `useAuth()` lives in `App` (passed into `AuthForms` and
gating the toggle); the status probe runs on sign-in and the server option
renders disabled-with-reason when unavailable. The file flow now goes
through the `Engine` interface for **both** paths (D-010): `BrowserEngine`
shares the worker with the live loop (distinct requestId namespaces) and a
new `stream` flag on the transcribe message keeps token partials +
transcribe-progress flowing for id-carrying engine passes (live passes stay
non-streaming). Server runs skip the browser model load, show segment
partials without a progress bar (faster-whisper's stream carries no window
boundaries), and cancel by aborting the fetch (D-018 amendment) — browser
runs keep worker-termination cancel. The choice persists in localStorage
but only takes effect while signed in with the engine available.
- Deployment: multi-stage `Dockerfile` — `runtime` (Bun-only, 244 MB) is the
default target so plain `docker build .` (existing CI) is unchanged;
`--target with-server-engine` (405 MB) adds python3 + faster-whisper in a
venv at `/opt/faster-whisper` (wired via `SIDECAR_PYTHON`), with
`FASTER_WHISPER_DOWNLOAD_ROOT` under the `/app/data` volume so weights
persist. README.md documents both flavors, all runtime env vars, the DB
volume, and the HTTPS/reverse-proxy requirement. Verified live in Docker:
Bun-only image degrades per D-013 (`available:false`, "python3 is not
available…"); server-engine image ran a real `POST /api/transcribe` of
`en_aiproblem.m4a` end-to-end, streamed segments matching the fixture
transcript — the server half of the M5 integration-test item is now
exercised for real (browser half still needs the manual run).
## M6 — Hardening & polish
- [ ] Error taxonomy: unsupported file, out-of-memory (suggest smaller model),
WebGPU device-lost, network loss mid-download (resume or clear retry)
- [ ] Cancel in-flight transcription (both engines)
- [x] Cancel in-flight transcription (both engines) — browser engine via
worker termination (D-018), server engine via aborting the
`/api/transcribe` fetch (D-018 amendment; landed with M5's EngineToggle)
- [ ] Export transcript: .txt and .srt (timestamps already available)
- [ ] Storage management UI: list cached models, per-model delete
- [ ] Basic a11y pass (keyboard, focus, aria on progress/live transcript)