feat(transcriber): cross-backend fallback openvino → cpu

- Зачем:
  - если OpenVINO не справляется (ошибка init или mid-stream), нужен автоматический переход на CPU через faster-whisper.
- Что:
  - _is_openvino_error() распознаёт ошибки OpenVINO runtime по паттернам в сообщении.
  - _is_backend_error() теперь маршрутизирует на правильную проверку по device.
  - при fallback: скачивается модель для CPU бэкенда, создаётся новая модель, обновляются backend/model_path.
  - 3 интеграционных теста: openvino→cpu init fallback, midstream fallback, strict_device без fallback.
- Проверка:
  - uv run pytest -v — 122 passed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-21 23:30:50 +03:00
co-authored by Claude Opus 4.6
parent 42bfbe5280
commit ee9e017083
2 changed files with 80 additions and 2 deletions
+8 -2
View File
@@ -148,11 +148,17 @@ def _is_backend_error(exc: BaseException, device: str) -> bool:
"""Определяет, связана ли ошибка с конкретным бэкендом (а не с пользовательскими данными)."""
if device in ("cuda", "cpu"):
return _is_cuda_error(exc)
# openvino и другие бэкенды: конкретные паттерны ошибок добавим
# при реализации бэкенда; пока — не маскируем ошибки
if device == "openvino":
return _is_openvino_error(exc)
return False
def _is_openvino_error(exc: BaseException) -> bool:
"""Проверка ошибок OpenVINO runtime."""
msg = str(exc).lower()
return any(k in msg for k in ("openvino", "ov_", "inference_engine"))
def _notify_status(on_status: Callable[[str], None] | None, message: str) -> None:
if on_status is not None:
on_status(message)