feat(cuda): добавлен прозрачный GPU runtime для Linux/WSL2

- Зачем:
  - ctranslate2 требует libcublas.so.12 для CUDA, но не бандлит её в wheel —
    без системного CUDA toolkit GPU не работает из коробки.
- Что:
  - добавлена зависимость nvidia-cublas-cu12 (Linux x86_64).
  - создан _cuda_bootstrap.py: preload libcublas через ctypes.CDLL(RTLD_GLOBAL)
    до импорта ctranslate2 (LD_LIBRARY_PATH не работает — glibc кеширует пути).
  - добавлен strict_device в transcriber: --device cuda/cpu не делает silent fallback.
  - CLI: диагностика requested vs resolved device, Windows CUDA-подсказка.
- Проверка:
  - uv run pytest -v (52 passed, 1 skipped).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-18 18:37:14 +03:00
co-authored by Claude Opus 4.6
parent 3d14ed7b86
commit bdb9b06855
8 changed files with 399 additions and 14 deletions
+11 -1
View File
@@ -3,7 +3,12 @@ from collections.abc import Callable
from dataclasses import dataclass
from pathlib import Path
from faster_whisper import WhisperModel
# Должен быть ДО импорта faster_whisper / ctranslate2
from local_transcriber._cuda_bootstrap import ensure_cublas_loadable
ensure_cublas_loadable()
from faster_whisper import WhisperModel # noqa: E402
from huggingface_hub import snapshot_download
from huggingface_hub.errors import LocalEntryNotFoundError
@@ -55,6 +60,7 @@ def transcribe(
language: str | None = None,
on_segment: Callable[[Segment], None] | None = None,
on_status: Callable[[str], None] | None = None,
strict_device: bool = False,
) -> TranscribeResult:
actual_device = device
lang_arg = language if language and language != "auto" else None
@@ -64,6 +70,8 @@ def transcribe(
model = _create_model(model_name, device, compute_type)
except (RuntimeError, ValueError) as exc:
if device != "cpu" and _is_cuda_error(exc):
if strict_device:
raise
warnings.warn(
f"Не удалось загрузить модель на {device}: {exc}. "
"Переключение на CPU.",
@@ -80,6 +88,8 @@ def transcribe(
segments, info = _run_transcription(model, file_path, lang_arg, on_segment)
except (RuntimeError, ValueError) as exc:
if actual_device != "cpu" and _is_cuda_error(exc):
if strict_device:
raise
warnings.warn(
f"CUDA ошибка при транскрипции: {exc}. "
"Переключение на CPU и повтор.",