diff --git a/src/local_transcriber/cli.py b/src/local_transcriber/cli.py index a62215e..84edf27 100644 --- a/src/local_transcriber/cli.py +++ b/src/local_transcriber/cli.py @@ -51,7 +51,7 @@ def main( output: Path | None = typer.Option(None, "--output", "-o", help="Путь к выходному файлу"), device: str | None = typer.Option( None, "--device", "-d", show_default=False, - help="Устройство (auto|cpu|cuda) [по умолч.: auto]" + help="Устройство (auto|cpu|cuda|openvino) [по умолч.: auto]" ), compute_type: str | None = typer.Option( None, "--compute-type", show_default=False, diff --git a/src/local_transcriber/config.py b/src/local_transcriber/config.py index 9ba8cdf..f58b57b 100644 --- a/src/local_transcriber/config.py +++ b/src/local_transcriber/config.py @@ -19,11 +19,12 @@ HARDCODED_DEFAULTS: dict[str, str] = { DEVICE_DEFAULTS: dict[str, dict[str, str]] = { "cuda": {"model": "medium", "compute_type": "float16"}, "cpu": {"model": "medium", "compute_type": "float32"}, + "openvino": {"model": "medium", "compute_type": "int8"}, } # Одно место правды для допустимых ключей конфига _VALID_KEYS = set(HARDCODED_DEFAULTS) -_VALID_DEVICES = {"auto", "cpu", "cuda"} +_VALID_DEVICES = {"auto", "cpu", "cuda", "openvino"} def find_config_file() -> Path | None: diff --git a/src/local_transcriber/utils.py b/src/local_transcriber/utils.py index bb22fa4..8a7fcfd 100644 --- a/src/local_transcriber/utils.py +++ b/src/local_transcriber/utils.py @@ -1,6 +1,7 @@ """Утилиты для валидации входных файлов, определения устройства и работы с путями.""" import glob +import platform import shutil import subprocess import warnings @@ -15,16 +16,30 @@ SUPPORTED_EXTENSIONS = { def detect_device(requested: str = "auto") -> str: """Определяет устройство для вычислений. - При ``requested="auto"`` проверяет наличие ``nvidia-smi`` в PATH - и возвращает ``"cuda"`` или ``"cpu"``. Явное значение возвращается как есть. + При ``requested="auto"`` проверяет: CUDA → OpenVINO → CPU. + Явное значение возвращается как есть. """ if requested != "auto": return requested if shutil.which("nvidia-smi") is not None: return "cuda" + if _is_openvino_available(): + return "openvino" return "cpu" +def _is_openvino_available() -> bool: + """Проверяет доступность OpenVINO: x86/AMD64 архитектура + пакет установлен.""" + if platform.machine().lower() not in {"x86_64", "amd64"}: + return False + try: + import openvino_genai # noqa: F401 + + return True + except ImportError: + return False + + def get_gpu_name() -> str | None: """Возвращает название GPU через ``nvidia-smi`` (для метаданных транскрипта).""" try: diff --git a/tests/test_config.py b/tests/test_config.py index 0fdd84e..77888e1 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -128,3 +128,18 @@ def test_apply_device_defaults_config_overrides(): result = apply_device_defaults(defaults, "cuda", cli, config) assert result["model"] == "small" assert result["compute_type"] == "int8" + + +def test_load_config_openvino_device(tmp_path): + config = tmp_path / "config.toml" + config.write_text('device = "openvino"\n') + result = load_config(config) + assert result == {"device": "openvino"} + + +def test_apply_device_defaults_openvino(): + defaults = {"model": "medium", "language": "ru", "device": "auto", "compute_type": "float32"} + cli = {"model": None, "language": None, "device": None, "compute_type": None} + result = apply_device_defaults(defaults, "openvino", cli, {}) + assert result["model"] == "medium" + assert result["compute_type"] == "int8" diff --git a/tests/test_utils.py b/tests/test_utils.py index d49cd2b..8ebb49d 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -58,6 +58,34 @@ def test_build_output_path_custom(): def test_detect_device_explicit(): assert detect_device("cpu") == "cpu" assert detect_device("cuda") == "cuda" + assert detect_device("openvino") == "openvino" + + +def test_detect_device_auto_openvino(): + """Нет nvidia-smi, есть openvino_genai, x86_64 → openvino.""" + with ( + patch("local_transcriber.utils.shutil.which", return_value=None), + patch("local_transcriber.utils._is_openvino_available", return_value=True), + ): + assert detect_device("auto") == "openvino" + + +def test_detect_device_cuda_over_openvino(): + """nvidia-smi доступен и openvino тоже → cuda побеждает.""" + with ( + patch("local_transcriber.utils.shutil.which", return_value="/usr/bin/nvidia-smi"), + patch("local_transcriber.utils._is_openvino_available", return_value=True), + ): + assert detect_device("auto") == "cuda" + + +def test_detect_device_auto_cpu_fallback(): + """Ни nvidia-smi, ни openvino → cpu.""" + with ( + patch("local_transcriber.utils.shutil.which", return_value=None), + patch("local_transcriber.utils._is_openvino_available", return_value=False), + ): + assert detect_device("auto") == "cpu" def test_get_gpu_name_no_nvidia_smi():