feat(dashboard): browser STT recognition test on the GPU
The status page was view-only, so there was no way to actually verify Korean recognition end-to-end. Add a live test: record from the mic (localhost/https) or upload an audio file (works over LAN http, where browsers block getUserMedia), POST it to a new /api/stt endpoint that ffmpeg-normalises the blob to 16 kHz mono and runs the real GPU faster-whisper, then shows the recognised text + latency + device. Results also land in the live turn feed. The dashboard now optionally holds a WhisperSTT and drives it from a private asyncio loop thread. New `python -m wsai --stt-test` serves the page with STT enabled and pre-warms the GPU worker so the first recognition is instant. WhisperSTT.resolved_device is exposed for the UI. Verified: wav and browser-style webm/opus uploads both return the correct Korean text on device=cuda in ~240-280ms. 12 tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -76,6 +76,7 @@ class WhisperSTT:
|
||||
self._proc: asyncio.subprocess.Process | None = None
|
||||
self._lock = asyncio.Lock()
|
||||
self.load_ms: int | None = None
|
||||
self.resolved_device: str | None = None # "cuda" | "cpu", known after start
|
||||
# Keep the worker's most recent stderr so a crash reports its real cause
|
||||
# instead of a bare JSONDecodeError. Bounded so it can't grow unbounded.
|
||||
self._stderr_tail: collections.deque[str] = collections.deque(maxlen=40)
|
||||
@@ -153,6 +154,7 @@ class WhisperSTT:
|
||||
f"whisper worker failed to start: {info}.{self._stderr_hint()}"
|
||||
)
|
||||
self.load_ms = info.get("ms")
|
||||
self.resolved_device = info.get("device")
|
||||
log.info(
|
||||
"whisper worker ready in %s ms on %s (model %s)",
|
||||
self.load_ms, info.get("device"), info.get("model"),
|
||||
|
||||
Reference in New Issue
Block a user