Two robustness fixes that share the failure taxonomy:
- Video downloads (#554 douyin "Unsupported URL", #536 "Broken pipe"): yt-dlp's
raw error surfaced with no next step. classify() now names UNSUPPORTED_VIDEO_URL
(non-downloadable link shape — paste a direct video page or drop a file) and
VIDEO_DOWNLOAD_NETWORK (transient CDN/network drop — just retry; the partial
download is already cleaned up), each with an actionable hint. yt-dlp is on a
current pin, so this is graceful classification, not a dependency bump.
- "No module named 'encodings'" (relocated/copied/restored venv whose interpreter
can't bootstrap its stdlib — exit 1, not 106): slipped BOTH #314 self-heal
matchers, so the user saw the error forever. Widen
backend_exit_indicates_broken_venv to also match the full quoted phrase, routing
it into the existing rebuild-once self-heal. Kept narrow so an app-level import
of an 'encodings'-prefixed package can't trigger a rebuild. Plus a BROKEN_VENV
hint for the case where the rebuild itself can't run.
Tests: classify() maps the 3 new classes with hints (a generic reason still ""),
and the 'encodings'-prefixed-package negative guard holds; the Rust matcher test
gains the encodings positive + negative cases. 5 pytest passed; the matcher is
compiled by CI's Tauri shell check.
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#551: both CTranslate2 ASR backends request compute_type="float16" on CUDA with
NO fallback. On GPUs without efficient fp16 (older Maxwell/Pascal, GTX 16xx) or a
CTranslate2/cuDNN binary mismatch, WhisperModel/whisperx.load_model raise a
ValueError at construction — which escaped the existing OOM-only `except
RuntimeError`, so every chunk failed and the user got "Transcription produced no
segments". Add a per-device compute_type fallback chain (cuda: float16 →
int8_float16 → int8; cpu: int8 → float32) to both backends + the ASR sidecar,
alongside (not replacing) the existing OOM→CPU path, with an ASR_COMPUTE_TYPE
override for exotic hardware (documented in README).
Also in the same ASR-robustness pass:
- #549: PyTorchWhisperBackend._ensure_pipe wraps the transformers pipeline load
and re-raises an actionable error (reinstall transformers / use faster-whisper)
instead of a bare "Could not import module 'AutoFeatureExtractor'".
- #516: the /dub/transcribe SSE generator is wrapped so it can NEVER close
without a terminal event — any unanticipated exception now yields a structured
`error` (with build_failure's hint) + `done`, turning "stream dropped, likely
ASR failed" into the real cause + Retry.
- failure.py: COMPUTE_TYPE_UNSUPPORTED + TRANSFORMERS_IMPORT classes so the
no-segments toast is actionable.
Tests (fail-before/pass-after): float16-unsupported → int8 for both WhisperX +
FasterWhisper; a generic non-OOM RuntimeError still raises; classify() maps the
two new classes; the SSE stream always terminates with error→done. 7 + 1 passed,
17 in the failure suite (no regression).
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>