* feat(transcribe): add TinyDiarize file transcription surface
Catalog small.en-tdrz (hosted at akashmjn/tinydiarize-whisper.cpp,
pinned commit) while keeping it out of every dictation-model selection
path: its [SPEAKER_TURN] markup would type noise into the focused
window. The checksum generator resolves side-repo models at their own
pinned revision, parakeet-style.
Add speech_recognition.diarization (strict-WAV fast path with ffmpeg
fallback, tdrz transcription, speaker-turn parsing, timestamped
formatting) and surface it through a tray Transcribe Audio File flow
with on-demand model download plus a headless --transcribe-file CLI.
TranscriptDialog offers copy and save of the diarized transcript.
Closes#756
* docs(user-guide): document --transcribe-file
* fix(transcribe): pass tdrz_enable as a pywhispercpp kwarg
pywhispercpp's Model takes decode params as keyword arguments; a
params= dict crashes on the C-level whisper_full_params object. Also
let --transcribe-file report unexpected failures cleanly instead of
dumping a traceback.
* fix(tray): dismiss the tdrz download dialog on response
* test(diarization): pin real wave/numpy/tempfile around sibling mocks
Several test modules replace sys.modules entries with MagicMocks at
import time and never restore them, so diarization's wave/numpy/
tempfile bindings resolved to mocks when this file ran after them in
CI. An autouse fixture reimports the real stdlib modules per test, the
same remedy test_audio_feedback already applies for wave.
* fix(transcribe): verify tdrz model, preload libs, gate formats on ffmpeg
- Hash the on-disk TinyDiarize model against the pinned digest before
native code maps it, matching the dictation load path
- Extract the bundled-lib preloader to utils/pywhispercpp_loader.py and
preload before the lazy pywhispercpp import so the headless
--transcribe-file path works on source-built installs without RPATH
- Offer only WAV in the file picker when ffmpeg is absent; name the
dependency in the filter label
- Type the new tray/diarization callbacks; document --transcribe-file
and the new modules in AGENTS.md
* style(audio): finish type annotations on capture helpers and download path
_setup_alsa_error_handler now declares Optional[Any] and its ctypes
callback gets concrete parameter types; the remaining capture helpers
take audio: Any (PyAudio has no importable type) and test_audio_input's
device_index becomes Optional[int], which also clears the preexisting
implicit-Optional error. _download_whispercpp_model gains -> None and
its HF url is narrowed to str so the concatenation and download call
stop adding new mypy findings.
* style(tests): wrap long monkeypatch line in preload test
* refactor(main): narrow transcribe-file errors and add file context
* style(ui): annotate TranscriptDialog constructor
* fix(diarize): log worker tracebacks, isort test helpers, document --transcribe-file
---------
Co-authored-by: Jatin K Malik <jatinkrmalik@gmail.com>