feat(openvino): добавлена поддержка Intel GPU через OpenVINO
- Зачем: - OpenVINO backend хардкодил "CPU", хотя Intel Arc GPU доступен и даёт ~2x ускорение. - Что: - новые device modes: --device openvino-gpu, openvino-cpu; openvino — авто-детект GPU/CPU. - detect_device() проверяет Intel GPU через OpenVINO Core API (с fail-safe). - OpenVINOBackend передаёт "GPU"/"CPU" в WhisperPipeline вместо хардкода "CPU". - подсказка "Совет: --model large-v3" при наличии GPU и модели не large-v3. - .gitattributes для нормализации line endings (eol=lf). - 150 тестов, включая GPU detection, routing, fallback, CLI device info. - README, docs/gpu.md, docs/PRD.md обновлены для Intel GPU. - Проверка: - uv run pytest (150 passed). - uv run transcribe --device openvino-gpu file.mp4 на Intel Arc 140T GPU. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
dc59d2a620
commit
617181f2dc
@@ -0,0 +1,3 @@
|
||||
* text=auto eol=lf
|
||||
*.{png,jpg,jpeg,gif,ico,webp} binary
|
||||
*.whl binary
|
||||
@@ -8,7 +8,7 @@ transcribe meeting.mp4
|
||||
```
|
||||
|
||||
- **Полностью локально** — данные не покидают машину
|
||||
- **Авто-ускорение** — NVIDIA CUDA, OpenVINO (Intel/AMD CPU) или CPU fallback
|
||||
- **Авто-ускорение** — NVIDIA CUDA, Intel GPU (OpenVINO), OpenVINO CPU или CPU fallback
|
||||
- **Батч-режим** — обработка нескольких файлов за один вызов
|
||||
- **Markdown с таймкодами** — удобен для суммаризации ИИ
|
||||
- **Аудио и видео** — mp3, wav, mp4, mkv и [другие форматы](#поддерживаемые-форматы)
|
||||
@@ -32,7 +32,8 @@ uv tool install git+https://github.com/dementev-dev/local-transcriber
|
||||
|
||||
**3. Ускорение (ставится автоматически):**
|
||||
|
||||
- **OpenVINO** (Intel/AMD x86 CPU): ставится автоматически на Linux и Windows — ускорение в 2-4 раза
|
||||
- **Intel GPU** (Arc, встроенная графика): работает через OpenVINO — ускорение в ~2x vs CPU
|
||||
- **OpenVINO** (Intel/AMD x86 CPU): ставится автоматически на Linux и Windows — ускорение в 2-4x
|
||||
- **NVIDIA CUDA** (GPU): если есть GPU — транскрипция в 5-10× быстрее
|
||||
- **Windows**: `winget install -e --id Nvidia.CUDA --version 12.9` (от администратора), перезапустить терминал
|
||||
- **Linux / WSL2**: работает из коробки (нужен только драйвер: `nvidia-smi`)
|
||||
@@ -107,9 +108,12 @@ transcribe meeting.mp4
|
||||
# Указать язык
|
||||
transcribe lecture.mp3 --language en
|
||||
|
||||
# Максимальное качество на GPU
|
||||
# Максимальное качество на NVIDIA GPU
|
||||
transcribe podcast.wav --model large-v3 --compute-type float16
|
||||
|
||||
# Максимальное качество на Intel GPU
|
||||
transcribe podcast.wav --model large-v3 --device openvino-gpu
|
||||
|
||||
# Сохранить в конкретный файл
|
||||
transcribe interview.m4a --output result.md
|
||||
```
|
||||
@@ -141,8 +145,8 @@ transcribe *.mp4 --force
|
||||
| `--model` | `-m` | `medium` | Модель Whisper |
|
||||
| `--language` | `-l` | `ru` | Язык (ru, en, auto и др.) |
|
||||
| `--output` | `-o` | `<файл>-transcript.md` | Путь к выходному файлу |
|
||||
| `--device` | `-d` | `auto` | Устройство (auto, cpu, cuda, openvino) |
|
||||
| `--compute-type` | — | float16 (CUDA) / int8 (OpenVINO) / float32 (CPU) | Тип вычислений |
|
||||
| `--device` | `-d` | `auto` | Устройство (auto, cpu, cuda, openvino, openvino-gpu, openvino-cpu) |
|
||||
| `--compute-type` | — | float16 (CUDA) / int8 (OpenVINO GPU/CPU) / float32 (CPU) | Тип вычислений |
|
||||
| `--force` | `-f` | — | Перезаписать существующие транскрипты |
|
||||
| `--verbose` | `-v` | — | Подробный вывод |
|
||||
|
||||
@@ -152,12 +156,14 @@ transcribe *.mp4 --force
|
||||
|---|---|---|---|
|
||||
| CPU | ✅ | ✅ | ✅ |
|
||||
| OpenVINO (x86 CPU) | ✅ авто | — | ✅ авто |
|
||||
| OpenVINO (Intel GPU) | ✅ авто | — | ✅ авто |
|
||||
| GPU (NVIDIA) | ✅ авто | — | ✅ (нужен CUDA 12) |
|
||||
|
||||
<details>
|
||||
<summary>Linux / WSL2</summary>
|
||||
|
||||
- GPU работает из коробки — cuBLAS ставится автоматически как зависимость
|
||||
- **Intel GPU** (Arc, встроенная графика) работает из коробки через OpenVINO
|
||||
- **NVIDIA GPU** работает из коробки — cuBLAS ставится автоматически как зависимость
|
||||
- Нужен только драйвер NVIDIA (проверка: `nvidia-smi`)
|
||||
- На ARM (aarch64) cuBLAS через pip недоступен — нужен системный CUDA toolkit
|
||||
|
||||
@@ -175,7 +181,8 @@ transcribe *.mp4 --force
|
||||
<summary>Windows</summary>
|
||||
|
||||
- CPU работает из коробки
|
||||
- Для GPU нужен **CUDA 12** (ctranslate2 4.7 не совместим с CUDA 11 и 13):
|
||||
- **Intel GPU** (Arc, встроенная графика) работает из коробки через OpenVINO
|
||||
- Для **NVIDIA GPU** нужен **CUDA 12** (ctranslate2 4.7 не совместим с CUDA 11 и 13):
|
||||
```
|
||||
winget install -e --id Nvidia.CUDA --version 12.9
|
||||
```
|
||||
@@ -202,17 +209,18 @@ language = "en"
|
||||
|
||||
Дефолты зависят от устройства:
|
||||
|
||||
| Параметр | CUDA | OpenVINO | CPU |
|
||||
|----------|------|----------|-----|
|
||||
| model | medium | medium | medium |
|
||||
| compute_type | float16 | int8 | float32 |
|
||||
| language | ru | ru | ru |
|
||||
| Параметр | CUDA | OpenVINO (GPU) | OpenVINO (CPU) | CPU |
|
||||
|----------|------|----------------|----------------|-----|
|
||||
| model | medium | medium | medium | medium |
|
||||
| compute_type | float16 | int8 | int8 | float32 |
|
||||
| language | ru | ru | ru | ru |
|
||||
|
||||
## Модели и GPU
|
||||
|
||||
Рекомендации:
|
||||
- **По умолчанию:** `medium` — хороший баланс скорости и качества
|
||||
- **Макс. качество:** `large-v3` + `--compute-type float16` (GPU)
|
||||
- **Макс. качество (NVIDIA):** `large-v3` + `--compute-type float16`
|
||||
- **Макс. качество (Intel GPU):** `large-v3` + `--device openvino-gpu`
|
||||
- **Быстрый тест:** `tiny` — для проверки пайплайна
|
||||
|
||||
<details>
|
||||
|
||||
+2
-2
@@ -47,8 +47,8 @@ transcribe <путь_к_файлу> [опции]
|
||||
По умолчанию: auto (автодетект)
|
||||
--output, -o Путь к выходному файлу
|
||||
По умолчанию: <input_stem>-transcript.md
|
||||
--device, -d Устройство (auto|cpu|cuda)
|
||||
По умолчанию: auto (CUDA если доступен, иначе CPU)
|
||||
--device, -d Устройство (auto|cpu|cuda|openvino|openvino-gpu|openvino-cpu)
|
||||
По умолчанию: auto (CUDA → OpenVINO GPU → OpenVINO CPU → CPU)
|
||||
--compute-type Тип вычислений (float16|int8|int8_float16|float32)
|
||||
По умолчанию: int8 (универсален для GPU 4-8 GB и CPU)
|
||||
--verbose, -v Подробный вывод (прогресс сегментов)
|
||||
|
||||
+6
-3
@@ -2,9 +2,11 @@
|
||||
|
||||
## Режимы `--device`
|
||||
|
||||
- `auto` (по умолчанию) — CUDA → OpenVINO → CPU (первый доступный)
|
||||
- `auto` (по умолчанию) — CUDA → OpenVINO GPU → OpenVINO CPU → CPU (первый доступный)
|
||||
- `cuda` — строго NVIDIA GPU, ошибка если недоступен
|
||||
- `openvino` — OpenVINO на CPU (ускорение 2-4x на x86)
|
||||
- `openvino` — авто-выбор OpenVINO GPU или CPU
|
||||
- `openvino-gpu` — строго Intel GPU через OpenVINO
|
||||
- `openvino-cpu` — строго CPU через OpenVINO (ускорение 2-4x на x86)
|
||||
- `cpu` — строго CPU (faster-whisper/CTranslate2)
|
||||
|
||||
## Какой бэкенд на каком оборудовании
|
||||
@@ -12,7 +14,8 @@
|
||||
| Оборудование | Рекомендуемый `--device` | Бэкенд | Ожидаемая скорость |
|
||||
|---|---|---|---|
|
||||
| NVIDIA GPU (6+ GB VRAM) | `auto` / `cuda` | faster-whisper (CTranslate2) | 7-19x реалтайм |
|
||||
| Intel/AMD x86 CPU | `auto` / `openvino` | OpenVINO GenAI | 3-6x реалтайм* |
|
||||
| Intel Arc iGPU / dGPU | `auto` / `openvino-gpu` | OpenVINO GenAI (GPU) | TBD |
|
||||
| Intel/AMD x86 CPU | `auto` / `openvino-cpu` | OpenVINO GenAI (CPU) | 3-6x реалтайм* |
|
||||
| Любой CPU (fallback) | `cpu` | faster-whisper (CTranslate2) | ~1.5x реалтайм |
|
||||
| Apple Silicon (macOS) | `cpu` | faster-whisper (CTranslate2) | ~2x реалтайм |
|
||||
|
||||
|
||||
@@ -14,14 +14,16 @@ def get_backend(device: str, *, compute_type_explicit: bool = True) -> Backend:
|
||||
Импорты ленивые — бэкенд загружается только при запросе.
|
||||
compute_type_explicit: False если compute_type пришёл из дефолтов (влияет на fallback).
|
||||
"""
|
||||
if device == "openvino":
|
||||
if device in ("openvino", "openvino-gpu", "openvino-cpu"):
|
||||
try:
|
||||
from .openvino import OpenVINOBackend
|
||||
except ImportError:
|
||||
raise ValueError(
|
||||
"OpenVINO бэкенд недоступен. Установите: pip install openvino-genai"
|
||||
) from None
|
||||
return OpenVINOBackend(compute_type_explicit=compute_type_explicit)
|
||||
return OpenVINOBackend(
|
||||
ov_device=device, compute_type_explicit=compute_type_explicit
|
||||
)
|
||||
|
||||
# cuda, cpu и всё остальное → faster-whisper
|
||||
from .faster_whisper import FasterWhisperBackend
|
||||
|
||||
@@ -46,10 +46,18 @@ MODEL_REQUIRED_FILES = [
|
||||
class OpenVINOBackend:
|
||||
"""Бэкенд транскрипции через openvino-genai WhisperPipeline."""
|
||||
|
||||
def __init__(self, compute_type_explicit: bool = True):
|
||||
"""compute_type_explicit=False означает, что compute_type пришёл из дефолтов."""
|
||||
def __init__(
|
||||
self,
|
||||
ov_device: str = "openvino-cpu",
|
||||
compute_type_explicit: bool = True,
|
||||
):
|
||||
"""ov_device: "openvino", "openvino-gpu" или "openvino-cpu".
|
||||
compute_type_explicit=False означает, что compute_type пришёл из дефолтов.
|
||||
"""
|
||||
self._ov_device = ov_device
|
||||
self._compute_type_explicit = compute_type_explicit
|
||||
self.actual_compute_type: str | None = None
|
||||
self.actual_ov_device: str | None = None
|
||||
|
||||
def ensure_model_available(
|
||||
self,
|
||||
@@ -76,6 +84,22 @@ class OpenVINOBackend:
|
||||
_validate_model_dir(downloaded_path)
|
||||
return str(downloaded_path)
|
||||
|
||||
def _resolve_ov_device(self) -> str:
|
||||
"""Резолвит device string в OpenVINO device: ``"GPU"`` или ``"CPU"``."""
|
||||
if self._ov_device == "openvino-gpu":
|
||||
return "GPU"
|
||||
if self._ov_device == "openvino-cpu":
|
||||
return "CPU"
|
||||
# "openvino" → авто-детект
|
||||
try:
|
||||
from openvino import Core
|
||||
|
||||
if "GPU" in Core().available_devices:
|
||||
return "GPU"
|
||||
except Exception:
|
||||
pass
|
||||
return "CPU"
|
||||
|
||||
def create_model(
|
||||
self,
|
||||
model_path: str,
|
||||
@@ -85,7 +109,9 @@ class OpenVINOBackend:
|
||||
"""Создаёт WhisperPipeline."""
|
||||
import openvino_genai as ov_genai
|
||||
|
||||
return ov_genai.WhisperPipeline(model_path, "CPU")
|
||||
ov_dev = self._resolve_ov_device()
|
||||
self.actual_ov_device = ov_dev
|
||||
return ov_genai.WhisperPipeline(model_path, ov_dev)
|
||||
|
||||
def transcribe(
|
||||
self,
|
||||
|
||||
@@ -21,6 +21,7 @@ from .utils import (
|
||||
detect_device,
|
||||
expand_globs,
|
||||
get_gpu_name,
|
||||
get_intel_gpu_name,
|
||||
has_existing_transcript,
|
||||
validate_input_file,
|
||||
)
|
||||
@@ -34,7 +35,10 @@ def _format_device_info(device_used: str) -> str:
|
||||
if device_used == "cuda":
|
||||
gpu_name = get_gpu_name()
|
||||
return f"CUDA ({gpu_name or 'Unknown GPU'})"
|
||||
if device_used == "openvino":
|
||||
if device_used == "openvino-gpu":
|
||||
gpu_name = get_intel_gpu_name()
|
||||
return f"OpenVINO ({gpu_name or 'Intel GPU'})"
|
||||
if device_used in ("openvino", "openvino-cpu"):
|
||||
return "OpenVINO (CPU)"
|
||||
return "CPU"
|
||||
|
||||
@@ -51,11 +55,11 @@ 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|openvino) [по умолч.: auto]"
|
||||
help="Устройство (auto|cpu|cuda|openvino|openvino-gpu|openvino-cpu) [по умолч.: auto]"
|
||||
),
|
||||
compute_type: str | None = typer.Option(
|
||||
None, "--compute-type", show_default=False,
|
||||
help="Тип вычислений [по умолч.: float16 (CUDA) / int8 (OpenVINO) / float32 (CPU)]"
|
||||
help="Тип вычислений [по умолч.: float16 (CUDA) / int8 (OpenVINO GPU/CPU) / float32 (CPU)]"
|
||||
),
|
||||
verbose: bool = typer.Option(False, "--verbose", "-v", help="Подробный вывод"),
|
||||
force: bool = typer.Option(False, "--force", "-f", help="Перезаписать существующие транскрипты"),
|
||||
@@ -151,6 +155,11 @@ def _run_single(
|
||||
f"Устройство: [bold]{actual_device}[/bold] "
|
||||
f"Compute: [bold]{actual_ct}[/bold]"
|
||||
)
|
||||
if actual_device == "openvino-gpu" and defaults["model"] != "large-v3":
|
||||
console.print(
|
||||
"Совет: --model large-v3 даёт лучшее качество на GPU (~2x дольше)",
|
||||
style="dim",
|
||||
)
|
||||
|
||||
with Status("Подготавливаю запуск...", console=console) as status:
|
||||
tfr = _transcribe_file(
|
||||
@@ -249,6 +258,12 @@ def _run_batch(
|
||||
compute_type_explicit=compute_type_explicit,
|
||||
)
|
||||
|
||||
if actual_device == "openvino-gpu" and defaults["model"] != "large-v3":
|
||||
console.print(
|
||||
"Совет: --model large-v3 даёт лучшее качество на GPU (~2x дольше)",
|
||||
style="dim",
|
||||
)
|
||||
|
||||
if actual_device != resolved_device:
|
||||
if requested_device == "auto":
|
||||
console.print(
|
||||
|
||||
@@ -20,11 +20,13 @@ 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"},
|
||||
"openvino-gpu": {"model": "medium", "compute_type": "int8"},
|
||||
"openvino-cpu": {"model": "medium", "compute_type": "int8"},
|
||||
}
|
||||
|
||||
# Одно место правды для допустимых ключей конфига
|
||||
_VALID_KEYS = set(HARDCODED_DEFAULTS)
|
||||
_VALID_DEVICES = {"auto", "cpu", "cuda", "openvino"}
|
||||
_VALID_DEVICES = {"auto", "cpu", "cuda", "openvino", "openvino-gpu", "openvino-cpu"}
|
||||
|
||||
|
||||
def find_config_file() -> Path | None:
|
||||
|
||||
@@ -36,6 +36,12 @@ def load_model(
|
||||
try:
|
||||
_notify_status(on_status, f"Инициализирую модель на {device}...")
|
||||
model = backend.create_model(model_path, device, compute_type)
|
||||
# Резолвим actual_device по реальному OpenVINO device
|
||||
ov_dev = getattr(backend, "actual_ov_device", None)
|
||||
if ov_dev == "GPU" and actual_device != "openvino-gpu":
|
||||
actual_device = "openvino-gpu"
|
||||
elif ov_dev == "CPU" and actual_device.startswith("openvino") and actual_device != "openvino-cpu":
|
||||
actual_device = "openvino-cpu"
|
||||
except (RuntimeError, ValueError) as exc:
|
||||
if device != "cpu" and _is_backend_error(exc, device):
|
||||
if strict_device:
|
||||
@@ -157,7 +163,7 @@ def _is_backend_error(exc: BaseException, device: str) -> bool:
|
||||
"""Определяет, связана ли ошибка с конкретным бэкендом (а не с пользовательскими данными)."""
|
||||
if device in ("cuda", "cpu"):
|
||||
return _is_cuda_error(exc)
|
||||
if device == "openvino":
|
||||
if device.startswith("openvino"):
|
||||
return _is_openvino_error(exc)
|
||||
return False
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ class TranscribeResult:
|
||||
language: str
|
||||
language_probability: float
|
||||
duration: float # seconds
|
||||
device_used: str # "cpu" / "cuda" / "openvino"
|
||||
device_used: str # "cpu" / "cuda" / "openvino-gpu" / "openvino-cpu"
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -16,16 +16,23 @@ SUPPORTED_EXTENSIONS = {
|
||||
def detect_device(requested: str = "auto") -> str:
|
||||
"""Определяет устройство для вычислений.
|
||||
|
||||
При ``requested="auto"`` проверяет: CUDA → OpenVINO → CPU.
|
||||
Явное значение возвращается как есть.
|
||||
При ``requested="auto"`` проверяет: CUDA → OpenVINO GPU → OpenVINO CPU → CPU.
|
||||
``"openvino"`` — алиас для авто-детекта внутри OpenVINO (GPU если доступен, иначе CPU).
|
||||
Возвращает всегда конкретное значение (не абстрактный ``"openvino"``).
|
||||
"""
|
||||
if requested != "auto":
|
||||
return requested
|
||||
if shutil.which("nvidia-smi") is not None:
|
||||
return "cuda"
|
||||
if _is_openvino_available():
|
||||
return "openvino"
|
||||
return "cpu"
|
||||
if requested == "auto":
|
||||
if shutil.which("nvidia-smi") is not None:
|
||||
return "cuda"
|
||||
if _is_openvino_gpu_available():
|
||||
return "openvino-gpu"
|
||||
if _is_openvino_available():
|
||||
return "openvino-cpu"
|
||||
return "cpu"
|
||||
if requested == "openvino":
|
||||
if _is_openvino_gpu_available():
|
||||
return "openvino-gpu"
|
||||
return "openvino-cpu"
|
||||
return requested
|
||||
|
||||
|
||||
def _is_openvino_available() -> bool:
|
||||
@@ -40,6 +47,32 @@ def _is_openvino_available() -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _is_openvino_gpu_available() -> bool:
|
||||
"""Проверяет доступность Intel GPU через OpenVINO.
|
||||
|
||||
Сохраняет x86/AMD64 gate и глотает все ошибки импорта/runtime.
|
||||
"""
|
||||
if not _is_openvino_available():
|
||||
return False
|
||||
try:
|
||||
from openvino import Core
|
||||
|
||||
return "GPU" in Core().available_devices
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def get_intel_gpu_name() -> str | None:
|
||||
"""Возвращает название Intel GPU через OpenVINO (для метаданных транскрипта)."""
|
||||
try:
|
||||
from openvino import Core
|
||||
|
||||
name = Core().get_property("GPU", "FULL_DEVICE_NAME")
|
||||
return name if name else None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def get_gpu_name() -> str | None:
|
||||
"""Возвращает название GPU через ``nvidia-smi`` (для метаданных транскрипта)."""
|
||||
try:
|
||||
|
||||
@@ -104,17 +104,70 @@ def test_ensure_model_available_downloads(mock_download, tmp_path):
|
||||
# === create_model ===
|
||||
|
||||
|
||||
def test_create_model():
|
||||
def test_create_model_cpu():
|
||||
mock_ov = MagicMock()
|
||||
mock_pipeline = MagicMock()
|
||||
mock_ov.WhisperPipeline.return_value = mock_pipeline
|
||||
|
||||
backend = OpenVINOBackend()
|
||||
backend = OpenVINOBackend(ov_device="openvino-cpu")
|
||||
with patch.dict("sys.modules", {"openvino_genai": mock_ov}):
|
||||
model = backend.create_model("/path/to/model", "openvino", "int8")
|
||||
model = backend.create_model("/path/to/model", "openvino-cpu", "int8")
|
||||
|
||||
mock_ov.WhisperPipeline.assert_called_once_with("/path/to/model", "CPU")
|
||||
assert model is mock_pipeline
|
||||
assert backend.actual_ov_device == "CPU"
|
||||
|
||||
|
||||
def test_create_model_gpu():
|
||||
mock_ov = MagicMock()
|
||||
mock_pipeline = MagicMock()
|
||||
mock_ov.WhisperPipeline.return_value = mock_pipeline
|
||||
|
||||
backend = OpenVINOBackend(ov_device="openvino-gpu")
|
||||
with patch.dict("sys.modules", {"openvino_genai": mock_ov}):
|
||||
model = backend.create_model("/path/to/model", "openvino-gpu", "fp16")
|
||||
|
||||
mock_ov.WhisperPipeline.assert_called_once_with("/path/to/model", "GPU")
|
||||
assert model is mock_pipeline
|
||||
assert backend.actual_ov_device == "GPU"
|
||||
|
||||
|
||||
def test_create_model_openvino_auto_detects_gpu():
|
||||
"""ov_device='openvino' + GPU доступен → WhisperPipeline получает 'GPU'."""
|
||||
mock_ov = MagicMock()
|
||||
mock_pipeline = MagicMock()
|
||||
mock_ov.WhisperPipeline.return_value = mock_pipeline
|
||||
|
||||
mock_core = MagicMock()
|
||||
mock_core.return_value.available_devices = ["CPU", "GPU"]
|
||||
|
||||
backend = OpenVINOBackend(ov_device="openvino")
|
||||
with (
|
||||
patch.dict("sys.modules", {"openvino_genai": mock_ov, "openvino": MagicMock(Core=mock_core)}),
|
||||
):
|
||||
model = backend.create_model("/path/to/model", "openvino", "int8")
|
||||
|
||||
mock_ov.WhisperPipeline.assert_called_once_with("/path/to/model", "GPU")
|
||||
assert backend.actual_ov_device == "GPU"
|
||||
|
||||
|
||||
def test_create_model_openvino_auto_falls_back_to_cpu():
|
||||
"""ov_device='openvino' + нет GPU → WhisperPipeline получает 'CPU'."""
|
||||
mock_ov = MagicMock()
|
||||
mock_pipeline = MagicMock()
|
||||
mock_ov.WhisperPipeline.return_value = mock_pipeline
|
||||
|
||||
mock_core = MagicMock()
|
||||
mock_core.return_value.available_devices = ["CPU"]
|
||||
|
||||
backend = OpenVINOBackend(ov_device="openvino")
|
||||
with (
|
||||
patch.dict("sys.modules", {"openvino_genai": mock_ov, "openvino": MagicMock(Core=mock_core)}),
|
||||
):
|
||||
model = backend.create_model("/path/to/model", "openvino", "int8")
|
||||
|
||||
mock_ov.WhisperPipeline.assert_called_once_with("/path/to/model", "CPU")
|
||||
assert backend.actual_ov_device == "CPU"
|
||||
|
||||
|
||||
# === transcribe ===
|
||||
|
||||
+75
-1
@@ -4,7 +4,7 @@ from unittest.mock import MagicMock, patch
|
||||
import pytest
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from local_transcriber.cli import app
|
||||
from local_transcriber.cli import _format_device_info, app
|
||||
from local_transcriber.transcriber import Segment, TranscribeFileResult, TranscribeResult
|
||||
|
||||
runner = CliRunner()
|
||||
@@ -788,3 +788,77 @@ def test_cli_batch_model_loaded_once(tmp_path):
|
||||
|
||||
assert out.exit_code == 0
|
||||
mock_load_model.assert_called_once()
|
||||
|
||||
|
||||
# === _format_device_info tests ===
|
||||
|
||||
|
||||
def test_format_device_info_openvino_gpu():
|
||||
with patch("local_transcriber.cli.get_intel_gpu_name", return_value="Intel(R) Arc(TM) 140T GPU"):
|
||||
assert _format_device_info("openvino-gpu") == "OpenVINO (Intel(R) Arc(TM) 140T GPU)"
|
||||
|
||||
|
||||
def test_format_device_info_openvino_gpu_no_name():
|
||||
"""get_intel_gpu_name вернул None → fallback на 'Intel GPU'."""
|
||||
with patch("local_transcriber.cli.get_intel_gpu_name", return_value=None):
|
||||
assert _format_device_info("openvino-gpu") == "OpenVINO (Intel GPU)"
|
||||
|
||||
|
||||
def test_format_device_info_openvino_cpu():
|
||||
assert _format_device_info("openvino-cpu") == "OpenVINO (CPU)"
|
||||
|
||||
|
||||
def test_format_device_info_openvino_legacy():
|
||||
"""Обратная совместимость: 'openvino' → OpenVINO (CPU)."""
|
||||
assert _format_device_info("openvino") == "OpenVINO (CPU)"
|
||||
|
||||
|
||||
def test_format_device_info_cpu():
|
||||
assert _format_device_info("cpu") == "CPU"
|
||||
|
||||
|
||||
def test_format_device_info_cuda():
|
||||
with patch("local_transcriber.cli.get_gpu_name", return_value="RTX 4090"):
|
||||
assert _format_device_info("cuda") == "CUDA (RTX 4090)"
|
||||
|
||||
|
||||
# === CLI with --device openvino-gpu ===
|
||||
|
||||
|
||||
def test_cli_openvino_gpu_happy_path(tmp_path):
|
||||
audio = tmp_path / "test.mp3"
|
||||
audio.write_bytes(b"fake")
|
||||
result = _make_result(device_used="openvino-gpu")
|
||||
|
||||
patches = _single_patches(result=result, tmp_file=audio, actual_device="openvino-gpu")
|
||||
with patches[0], patches[1], patches[2], patches[3], patches[4], patches[5]:
|
||||
with patch("local_transcriber.cli.get_intel_gpu_name", return_value="Intel Arc 140T"):
|
||||
out = runner.invoke(app, [str(audio), "--device", "openvino-gpu"])
|
||||
|
||||
assert out.exit_code == 0
|
||||
|
||||
|
||||
def test_cli_openvino_alias_resolves_to_gpu(tmp_path):
|
||||
"""--device openvino резолвится через detect_device в openvino-gpu."""
|
||||
audio = tmp_path / "test.mp3"
|
||||
audio.write_bytes(b"fake")
|
||||
result = _make_result(device_used="openvino-gpu")
|
||||
model = _make_model()
|
||||
backend = _make_backend()
|
||||
tfr = _make_tfr(result=result, model=model, actual_device="openvino-gpu", backend=backend)
|
||||
mock_load_model = MagicMock(return_value=(model, "openvino-gpu", backend, "/models/medium"))
|
||||
|
||||
with (
|
||||
patch("local_transcriber.cli.load_config", return_value={}),
|
||||
patch("local_transcriber.cli.validate_input_file", return_value=audio),
|
||||
patch("local_transcriber.cli.detect_device", return_value="openvino-gpu"),
|
||||
patch("local_transcriber.cli.load_model", mock_load_model),
|
||||
patch("local_transcriber.cli._transcribe_file", return_value=tfr),
|
||||
patch("local_transcriber.cli.write_transcript"),
|
||||
patch("local_transcriber.cli.get_intel_gpu_name", return_value="Intel Arc 140T"),
|
||||
):
|
||||
out = runner.invoke(app, [str(audio), "--device", "openvino"])
|
||||
|
||||
assert out.exit_code == 0
|
||||
# detect_device("openvino") resolved to "openvino-gpu", load_model receives it
|
||||
assert mock_load_model.call_args[0][1] == "openvino-gpu"
|
||||
|
||||
@@ -137,9 +137,39 @@ def test_load_config_openvino_device(tmp_path):
|
||||
assert result == {"device": "openvino"}
|
||||
|
||||
|
||||
def test_load_config_openvino_gpu_device(tmp_path):
|
||||
config = tmp_path / "config.toml"
|
||||
config.write_text('device = "openvino-gpu"\n')
|
||||
result = load_config(config)
|
||||
assert result == {"device": "openvino-gpu"}
|
||||
|
||||
|
||||
def test_load_config_openvino_cpu_device(tmp_path):
|
||||
config = tmp_path / "config.toml"
|
||||
config.write_text('device = "openvino-cpu"\n')
|
||||
result = load_config(config)
|
||||
assert result == {"device": "openvino-cpu"}
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
def test_apply_device_defaults_openvino_gpu():
|
||||
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-gpu", cli, {})
|
||||
assert result["model"] == "medium"
|
||||
assert result["compute_type"] == "int8"
|
||||
|
||||
|
||||
def test_apply_device_defaults_openvino_cpu():
|
||||
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-cpu", cli, {})
|
||||
assert result["model"] == "medium"
|
||||
assert result["compute_type"] == "int8"
|
||||
|
||||
+66
-17
@@ -372,7 +372,7 @@ def test_ensure_model_available_downloads_on_cache_miss(mock_snapshot_download,
|
||||
|
||||
result = ensure_model_available("large-v3", on_status=statuses.append)
|
||||
|
||||
assert result == "/downloaded/model"
|
||||
assert Path(result) == Path("/downloaded/model")
|
||||
assert mock_snapshot_download.call_args_list[0].kwargs["local_files_only"] is True
|
||||
assert mock_snapshot_download.call_args_list[1].kwargs["local_files_only"] is False
|
||||
assert "Проверяю кэш модели large-v3..." in statuses
|
||||
@@ -446,8 +446,8 @@ def test_ensure_model_available_rejects_incomplete_local_directory(tmp_path):
|
||||
|
||||
|
||||
@patch("local_transcriber.transcriber.get_backend")
|
||||
def test_load_model_openvino_fallback_to_cpu(mock_get_backend):
|
||||
"""OpenVINO ошибка при init → fallback на CPU (FasterWhisper)."""
|
||||
def test_load_model_openvino_gpu_fallback_to_cpu(mock_get_backend):
|
||||
"""OpenVINO GPU ошибка при init → fallback на CPU (FasterWhisper)."""
|
||||
ov_backend = _make_backend(
|
||||
create_model_error=RuntimeError("OpenVINO model load failed"),
|
||||
)
|
||||
@@ -455,13 +455,13 @@ def test_load_model_openvino_fallback_to_cpu(mock_get_backend):
|
||||
cpu_backend = _make_backend(model=cpu_model, model_path="/mock/cpu/model")
|
||||
|
||||
def backend_for_device(device, **kwargs):
|
||||
return ov_backend if device == "openvino" else cpu_backend
|
||||
return ov_backend if device == "openvino-gpu" else cpu_backend
|
||||
|
||||
mock_get_backend.side_effect = backend_for_device
|
||||
|
||||
with pytest.warns(UserWarning, match="Переключение на CPU"):
|
||||
model, actual_device, backend, model_path = load_model(
|
||||
"medium", "openvino", "int8",
|
||||
"medium", "openvino-gpu", "fp16",
|
||||
)
|
||||
|
||||
assert actual_device == "cpu"
|
||||
@@ -471,8 +471,33 @@ def test_load_model_openvino_fallback_to_cpu(mock_get_backend):
|
||||
|
||||
|
||||
@patch("local_transcriber.transcriber.get_backend")
|
||||
def test_transcribe_file_openvino_midstream_fallback(mock_get_backend):
|
||||
"""OpenVINO ошибка при транскрипции → fallback на CPU."""
|
||||
def test_load_model_openvino_cpu_fallback_to_cpu(mock_get_backend):
|
||||
"""OpenVINO CPU ошибка при init → fallback на CPU (FasterWhisper)."""
|
||||
ov_backend = _make_backend(
|
||||
create_model_error=RuntimeError("OpenVINO model load failed"),
|
||||
)
|
||||
cpu_model = MagicMock()
|
||||
cpu_backend = _make_backend(model=cpu_model, model_path="/mock/cpu/model")
|
||||
|
||||
def backend_for_device(device, **kwargs):
|
||||
return ov_backend if device == "openvino-cpu" else cpu_backend
|
||||
|
||||
mock_get_backend.side_effect = backend_for_device
|
||||
|
||||
with pytest.warns(UserWarning, match="Переключение на CPU"):
|
||||
model, actual_device, backend, model_path = load_model(
|
||||
"medium", "openvino-cpu", "int8",
|
||||
)
|
||||
|
||||
assert actual_device == "cpu"
|
||||
assert model is cpu_model
|
||||
assert backend is cpu_backend
|
||||
assert model_path == "/mock/cpu/model"
|
||||
|
||||
|
||||
@patch("local_transcriber.transcriber.get_backend")
|
||||
def test_transcribe_file_openvino_gpu_midstream_fallback(mock_get_backend):
|
||||
"""OpenVINO GPU ошибка при транскрипции → fallback на CPU."""
|
||||
ov_backend = _make_backend(
|
||||
transcribe_error=RuntimeError("OpenVINO inference error"),
|
||||
)
|
||||
@@ -482,19 +507,19 @@ def test_transcribe_file_openvino_midstream_fallback(mock_get_backend):
|
||||
)
|
||||
|
||||
def backend_for_device(device, **kwargs):
|
||||
return ov_backend if device == "openvino" else cpu_backend
|
||||
return ov_backend if device.startswith("openvino") else cpu_backend
|
||||
|
||||
mock_get_backend.side_effect = backend_for_device
|
||||
|
||||
with pytest.warns(UserWarning, match="Переключение на CPU"):
|
||||
tfr = _transcribe_file(
|
||||
model=MagicMock(),
|
||||
actual_device="openvino",
|
||||
actual_device="openvino-gpu",
|
||||
backend=ov_backend,
|
||||
model_path="/mock/ov/model",
|
||||
file_path=Path("test.mp3"),
|
||||
model_name="medium",
|
||||
compute_type="int8",
|
||||
compute_type="fp16",
|
||||
)
|
||||
|
||||
assert tfr.actual_device == "cpu"
|
||||
@@ -503,15 +528,15 @@ def test_transcribe_file_openvino_midstream_fallback(mock_get_backend):
|
||||
|
||||
|
||||
@patch("local_transcriber.transcriber.get_backend")
|
||||
def test_openvino_strict_device_no_fallback(mock_get_backend):
|
||||
"""strict_device=True + OpenVINO ошибка → raise."""
|
||||
def test_openvino_gpu_strict_device_no_fallback(mock_get_backend):
|
||||
"""strict_device=True + OpenVINO GPU ошибка → raise."""
|
||||
backend = _make_backend(
|
||||
create_model_error=RuntimeError("OpenVINO model load failed"),
|
||||
)
|
||||
mock_get_backend.return_value = backend
|
||||
|
||||
with pytest.raises(RuntimeError, match="OpenVINO"):
|
||||
load_model("medium", "openvino", "int8", strict_device=True)
|
||||
load_model("medium", "openvino-gpu", "fp16", strict_device=True)
|
||||
|
||||
|
||||
@patch("local_transcriber.transcriber.get_backend")
|
||||
@@ -523,21 +548,45 @@ def test_openvino_runtime_error_triggers_fallback(mock_get_backend):
|
||||
cpu_backend = _make_backend(model_path="/mock/cpu/model")
|
||||
|
||||
def backend_for_device(device, **kwargs):
|
||||
return ov_backend if device == "openvino" else cpu_backend
|
||||
return ov_backend if device.startswith("openvino") else cpu_backend
|
||||
|
||||
mock_get_backend.side_effect = backend_for_device
|
||||
|
||||
with pytest.warns(UserWarning, match="Переключение на CPU"):
|
||||
_, actual_device, _, _ = load_model("medium", "openvino", "int8")
|
||||
_, actual_device, _, _ = load_model("medium", "openvino-cpu", "int8")
|
||||
|
||||
assert actual_device == "cpu"
|
||||
|
||||
|
||||
@patch("local_transcriber.transcriber.get_backend")
|
||||
def test_load_model_resolves_openvino_gpu_device(mock_get_backend):
|
||||
"""load_model обновляет actual_device по backend.actual_ov_device."""
|
||||
backend = _make_backend()
|
||||
backend.actual_ov_device = "GPU"
|
||||
mock_get_backend.return_value = backend
|
||||
|
||||
_, actual_device, _, _ = load_model("medium", "openvino-cpu", "int8")
|
||||
|
||||
assert actual_device == "openvino-gpu"
|
||||
|
||||
|
||||
@patch("local_transcriber.transcriber.get_backend")
|
||||
def test_load_model_resolves_openvino_cpu_device(mock_get_backend):
|
||||
"""load_model обновляет actual_device по backend.actual_ov_device."""
|
||||
backend = _make_backend()
|
||||
backend.actual_ov_device = "CPU"
|
||||
mock_get_backend.return_value = backend
|
||||
|
||||
_, actual_device, _, _ = load_model("medium", "openvino-gpu", "fp16")
|
||||
|
||||
assert actual_device == "openvino-cpu"
|
||||
|
||||
|
||||
def test_ensure_model_available_openvino_default_compute_type():
|
||||
"""ensure_model_available(device='openvino') без compute_type не падает."""
|
||||
"""ensure_model_available(device='openvino-cpu') без compute_type не падает."""
|
||||
from local_transcriber.backends.openvino import OpenVINOBackend
|
||||
|
||||
backend = OpenVINOBackend(compute_type_explicit=True)
|
||||
backend = OpenVINOBackend(ov_device="openvino-cpu", compute_type_explicit=True)
|
||||
# Проверяем что _resolve_repo работает с дефолтным compute_type для openvino (int8)
|
||||
repo, ct = backend._resolve_repo("medium", "int8")
|
||||
assert repo == "OpenVINO/whisper-medium-int8-ov"
|
||||
|
||||
+90
-7
@@ -1,14 +1,16 @@
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from local_transcriber.utils import (
|
||||
_is_openvino_gpu_available,
|
||||
build_output_path,
|
||||
detect_device,
|
||||
expand_globs,
|
||||
get_gpu_name,
|
||||
get_intel_gpu_name,
|
||||
has_existing_transcript,
|
||||
validate_input_file,
|
||||
)
|
||||
@@ -55,26 +57,38 @@ def test_build_output_path_custom():
|
||||
assert result == custom
|
||||
|
||||
|
||||
def test_detect_device_explicit():
|
||||
def test_detect_device_explicit_passthrough():
|
||||
"""Явные device strings проходят без изменений."""
|
||||
assert detect_device("cpu") == "cpu"
|
||||
assert detect_device("cuda") == "cuda"
|
||||
assert detect_device("openvino") == "openvino"
|
||||
assert detect_device("openvino-gpu") == "openvino-gpu"
|
||||
assert detect_device("openvino-cpu") == "openvino-cpu"
|
||||
|
||||
|
||||
def test_detect_device_auto_openvino():
|
||||
"""Нет nvidia-smi, есть openvino_genai, x86_64 → openvino."""
|
||||
def test_detect_device_auto_openvino_gpu():
|
||||
"""auto + нет nvidia-smi + есть OpenVINO GPU → openvino-gpu."""
|
||||
with (
|
||||
patch("local_transcriber.utils.shutil.which", return_value=None),
|
||||
patch("local_transcriber.utils._is_openvino_gpu_available", return_value=True),
|
||||
):
|
||||
assert detect_device("auto") == "openvino-gpu"
|
||||
|
||||
|
||||
def test_detect_device_auto_openvino_cpu():
|
||||
"""auto + нет nvidia-smi + есть OpenVINO, нет GPU → openvino-cpu."""
|
||||
with (
|
||||
patch("local_transcriber.utils.shutil.which", return_value=None),
|
||||
patch("local_transcriber.utils._is_openvino_gpu_available", return_value=False),
|
||||
patch("local_transcriber.utils._is_openvino_available", return_value=True),
|
||||
):
|
||||
assert detect_device("auto") == "openvino"
|
||||
assert detect_device("auto") == "openvino-cpu"
|
||||
|
||||
|
||||
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),
|
||||
patch("local_transcriber.utils._is_openvino_gpu_available", return_value=True),
|
||||
):
|
||||
assert detect_device("auto") == "cuda"
|
||||
|
||||
@@ -83,11 +97,80 @@ 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_gpu_available", return_value=False),
|
||||
patch("local_transcriber.utils._is_openvino_available", return_value=False),
|
||||
):
|
||||
assert detect_device("auto") == "cpu"
|
||||
|
||||
|
||||
def test_detect_device_openvino_resolves_to_gpu():
|
||||
"""--device openvino + GPU доступен → openvino-gpu."""
|
||||
with patch("local_transcriber.utils._is_openvino_gpu_available", return_value=True):
|
||||
assert detect_device("openvino") == "openvino-gpu"
|
||||
|
||||
|
||||
def test_detect_device_openvino_resolves_to_cpu():
|
||||
"""--device openvino + GPU недоступен → openvino-cpu."""
|
||||
with patch("local_transcriber.utils._is_openvino_gpu_available", return_value=False):
|
||||
assert detect_device("openvino") == "openvino-cpu"
|
||||
|
||||
|
||||
# === _is_openvino_gpu_available ===
|
||||
|
||||
|
||||
def test_is_openvino_gpu_available_true():
|
||||
mock_core = MagicMock()
|
||||
mock_core.return_value.available_devices = ["CPU", "GPU"]
|
||||
with (
|
||||
patch("local_transcriber.utils._is_openvino_available", return_value=True),
|
||||
patch("local_transcriber.utils.Core", mock_core, create=True),
|
||||
):
|
||||
# Need to patch the import inside the function
|
||||
with patch.dict("sys.modules", {"openvino": MagicMock(Core=mock_core)}):
|
||||
assert _is_openvino_gpu_available() is True
|
||||
|
||||
|
||||
def test_is_openvino_gpu_available_no_gpu():
|
||||
mock_core = MagicMock()
|
||||
mock_core.return_value.available_devices = ["CPU"]
|
||||
with (
|
||||
patch("local_transcriber.utils._is_openvino_available", return_value=True),
|
||||
patch.dict("sys.modules", {"openvino": MagicMock(Core=mock_core)}),
|
||||
):
|
||||
assert _is_openvino_gpu_available() is False
|
||||
|
||||
|
||||
def test_is_openvino_gpu_available_no_openvino():
|
||||
"""OpenVINO не установлен → False."""
|
||||
with patch("local_transcriber.utils._is_openvino_available", return_value=False):
|
||||
assert _is_openvino_gpu_available() is False
|
||||
|
||||
|
||||
def test_is_openvino_gpu_available_runtime_error():
|
||||
"""Runtime error от OpenVINO → False (fail-safe)."""
|
||||
with (
|
||||
patch("local_transcriber.utils._is_openvino_available", return_value=True),
|
||||
patch.dict("sys.modules", {"openvino": MagicMock(Core=MagicMock(side_effect=RuntimeError("broken")))}),
|
||||
):
|
||||
assert _is_openvino_gpu_available() is False
|
||||
|
||||
|
||||
# === get_intel_gpu_name ===
|
||||
|
||||
|
||||
def test_get_intel_gpu_name_success():
|
||||
mock_core = MagicMock()
|
||||
mock_core.return_value.get_property.return_value = "Intel(R) Arc(TM) 140T GPU (16GB) (iGPU)"
|
||||
with patch.dict("sys.modules", {"openvino": MagicMock(Core=mock_core)}):
|
||||
assert get_intel_gpu_name() == "Intel(R) Arc(TM) 140T GPU (16GB) (iGPU)"
|
||||
|
||||
|
||||
def test_get_intel_gpu_name_error():
|
||||
"""Ошибка → None (fail-safe)."""
|
||||
with patch.dict("sys.modules", {"openvino": MagicMock(Core=MagicMock(side_effect=Exception("no gpu")))}):
|
||||
assert get_intel_gpu_name() is None
|
||||
|
||||
|
||||
def test_get_gpu_name_no_nvidia_smi():
|
||||
with patch("shutil.which", return_value=None):
|
||||
with patch("subprocess.run", side_effect=FileNotFoundError):
|
||||
|
||||
@@ -301,6 +301,7 @@ source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "faster-whisper" },
|
||||
{ name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||
{ name = "openvino-genai", marker = "(platform_machine == 'AMD64' and sys_platform != 'darwin') or (platform_machine == 'x86_64' and sys_platform != 'darwin')" },
|
||||
{ name = "rich" },
|
||||
{ name = "socksio" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
@@ -316,6 +317,7 @@ dev = [
|
||||
requires-dist = [
|
||||
{ name = "faster-whisper", specifier = ">=1.2.1" },
|
||||
{ name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'", specifier = ">=12.4" },
|
||||
{ name = "openvino-genai", marker = "(platform_machine == 'AMD64' and sys_platform != 'darwin') or (platform_machine == 'x86_64' and sys_platform != 'darwin')", specifier = ">=2025.0" },
|
||||
{ name = "rich" },
|
||||
{ name = "socksio", specifier = ">=1.0.0" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'", specifier = ">=2.0" },
|
||||
@@ -549,6 +551,73 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/d6/413e98ab666c6fb9e8be7d1c6eb3bd403b0bea1b8d42db066dab98c7df07/onnxruntime-1.24.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02aaf6ddfa784523b6873b4176a79d508e599efe12ab0ea1a3a6e7314408b7aa", size = 17240738, upload-time = "2026-03-05T17:18:15.203Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openvino"
|
||||
version = "2026.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
||||
{ name = "numpy", version = "2.4.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
||||
{ name = "openvino-telemetry" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/7d/d7e428f469021c1ce309d1c000a6f186be414c08655a55250229b6b789c7/openvino-2026.0.0-20965-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:3c6a7d9bf433888b85c916a37b0c7c9b9747158760f6fc8a852299cd231fd20a", size = 53425782, upload-time = "2026-02-23T16:10:07.582Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/b4/95a9c1de9259e83ac420f500278e30ccd52cd9979bb5473b27ec762f8a6e/openvino-2026.0.0-20965-cp310-cp310-win_amd64.whl", hash = "sha256:f7b28ad59dc2017ef7d2622628f8b31d052caa1565ce64d4f39937a2db044dc6", size = 69154088, upload-time = "2026-02-23T16:10:13.676Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/f1/21ebfb8f496fe1732de217c6cf676299c884b2e027217d1dec08a8030d65/openvino-2026.0.0-20965-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ba999f7fea57958a533a715afa976704ea6acf39dfd271a89ce78594e7aaa488", size = 53433492, upload-time = "2026-02-23T16:10:20.075Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/e2/712d8ad00e577fbf1f0081132f199a1a6885bfafd6739cc18c560ec7eee2/openvino-2026.0.0-20965-cp311-cp311-win_amd64.whl", hash = "sha256:eee912bf4370a4f454c9bcf2cfe31eda85ba6f324c85137d225edffcbc50c456", size = 69161445, upload-time = "2026-02-23T16:10:26.165Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/f8/bd25df6ebd42b2425a2d5fe504389e941adbee41356078a97357469d18cb/openvino-2026.0.0-20965-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4ad9cbf77ed954b64b056cb91ebb95e5691da1c86238e610b565e5347e73a5c5", size = 53443036, upload-time = "2026-02-23T16:10:32.025Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/ed/dd3886bdfd822bb1671c0f892a007a9e27a7fa1f97ea1a7c0c8e901a137c/openvino-2026.0.0-20965-cp312-cp312-win_amd64.whl", hash = "sha256:10af8a90373547c5dec2b53c60dac38a7a29df8662fe097a3c6c67750e7c88c6", size = 69160616, upload-time = "2026-02-23T16:10:39.123Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/3f/95b15760d7ae4b7dfefdbadeccae9604985d4335b221350e1bb04701a158/openvino-2026.0.0-20965-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:452902e4b8fba526e8740622cd5638c457d3ae44da7b39e6d4ef7919be0e95d4", size = 53444542, upload-time = "2026-02-23T16:10:46.343Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/26/82d326f3769c9e5c17d34ef10dd0aff4a94a3b550e1d2efe977e5754b84e/openvino-2026.0.0-20965-cp313-cp313-win_amd64.whl", hash = "sha256:14069e5af2ac8a77f6ea55d7020d34cc7d3538d49ebda91a18c00d4da830ab58", size = 69160606, upload-time = "2026-02-23T16:10:52.9Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/8e/52df01e8687f4711259729433226219c6839a0495988ddeb7e27af59aba8/openvino-2026.0.0-20965-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:79ce4b5d7f3a7f84de878752d97620b84e0c4a8ee550fb3bca9fc36fe5669450", size = 53449059, upload-time = "2026-02-23T16:10:59.54Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/a8/bc8e75d3f75ee2529a12be9522f52a8d0e5614f24c00f95a20b69f587d3c/openvino-2026.0.0-20965-cp314-cp314-win_amd64.whl", hash = "sha256:6d33440d290e67836825418134ecf9e17f150d50d3d9c07cf481997f5b1f0e6d", size = 69165824, upload-time = "2026-02-23T16:11:03.127Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/06/1a2caa07bfcb4e057048b8d5515a7aff35a2aa53ab5379762c1685cbeacc/openvino-2026.0.0-20965-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:8cbe36e0dacd8676eb69c9a4b564fa430d784f6e2b0e18e7ebc363599256c184", size = 53502042, upload-time = "2026-02-23T16:11:09.744Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/dd/6a05a399d90ad4e8b15e0d5a4dd7de90c10484cb1585bd65e7e69e779762/openvino-2026.0.0-20965-cp314-cp314t-win_amd64.whl", hash = "sha256:a9e5524322c42f6a1283148fb70085aba8640a7d3067ede896085abbff5e33fe", size = 69325734, upload-time = "2026-02-23T16:11:13.283Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openvino-genai"
|
||||
version = "2026.0.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "openvino-tokenizers" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/50/23/39f4d63f1c301f2250ec903345f2775e0d18df5b637d8324501c7874750f/openvino_genai-2026.0.0.0-2050-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c583262256ec5864bc4fed79932d2774dbf2716acbebce36cc40b6b8c26c9509", size = 4920931, upload-time = "2026-02-23T16:17:15.404Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/d0/4160cee845e09789110a55b0b90d49dd457d5322ea03de11dd69014524ac/openvino_genai-2026.0.0.0-2050-cp310-cp310-win_amd64.whl", hash = "sha256:adb3a22584231463e269927f872797ff4a1176a6b2194516c5ed7ffb31218126", size = 2893230, upload-time = "2026-02-23T16:17:18.6Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/16/a4b6647ee0e77b136cc465f5222d3dc586c2cc8626d6a950509945e2317e/openvino_genai-2026.0.0.0-2050-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:deeb2d2e6d85af7e04e6d975c00b65e414bf9886baca2ac5c7ed2963d529ec4a", size = 4922353, upload-time = "2026-02-23T16:17:21.897Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/9b/4eed9a6543534857127b1ed2923c705025234a5c41286dd4dd5d7de95a27/openvino_genai-2026.0.0.0-2050-cp311-cp311-win_amd64.whl", hash = "sha256:b7e4c895da27b00dc6d87153b451b953f5803554e4409b2f5e8def714c71e06f", size = 2894286, upload-time = "2026-02-23T16:17:24.805Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/2d/963844c91c12c95249cd42056ffb1a94e62d209fab12a3e916e32f1fa9fb/openvino_genai-2026.0.0.0-2050-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d68c6dd226e39f6154d946410929ea1be1608ad769b5d2bf2aebe6ffd5d02ce4", size = 4930395, upload-time = "2026-02-23T16:17:28.079Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/0c/ed7e3d54c0ba171b23e91231adaf5b5c3f5343650959e144b5de8f9fcf2b/openvino_genai-2026.0.0.0-2050-cp312-cp312-win_amd64.whl", hash = "sha256:5cfd7c14a697c36af854743f86797b845fe423d0fab9a17d0c6fa5cd5b0cc606", size = 2900307, upload-time = "2026-02-23T16:17:30.9Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/98/fe5716b9dc2f29286b68b98a4c67bc33003e3b02cf4d92236345a2d7280e/openvino_genai-2026.0.0.0-2050-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:08f73852a455d63453e7f74f22b0aebd0c3579f8cb89133e66e438c09df26b71", size = 4930444, upload-time = "2026-02-23T16:17:33.953Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/80/bc87545dfbbd7f4a3bd1667a4c9b5f1d8e1b476fec34225692bca6a86590/openvino_genai-2026.0.0.0-2050-cp313-cp313-win_amd64.whl", hash = "sha256:ada030b34a9e2fe0c6c406c2af2ce7b6e8cb16654329a469055fdac8a3eba19d", size = 2900293, upload-time = "2026-02-23T16:17:37.673Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/09/18e678f2d0ac4ee993244d3cf0e6a80ec7013add2972153ad355d889d8cc/openvino_genai-2026.0.0.0-2050-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:77b73d1947d7f62a672857ef35d187074c6918de1db1d3f981452c2d67511c13", size = 4931196, upload-time = "2026-02-23T16:17:40.423Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/be/3f02a70a16147b08b933908ef1c8af930ecd5c65ba78e14f988112d3d691/openvino_genai-2026.0.0.0-2050-cp314-cp314-win_amd64.whl", hash = "sha256:c59aeab5993c78194dc552cc9249bab509f7e44b1fb2f0d5a90c5e61869f06b8", size = 2900527, upload-time = "2026-02-23T16:17:43.244Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/e8/7da6a1b86e3178e825560442ea4460ba4c92bb417fb8edda9e2210febec6/openvino_genai-2026.0.0.0-2050-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:d807c5cabdea20bab2199ffa736831f57baaf0571e80d19cf4b65004f6b00747", size = 4943971, upload-time = "2026-02-23T16:17:46.021Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/19/221256ce3b0276bb3ba3ce7e8fc57b2968a662c2acde7427c342d917867f/openvino_genai-2026.0.0.0-2050-cp314-cp314t-win_amd64.whl", hash = "sha256:bb537f5a65203eee12326e6bb9578e834d96d94ab3fa48c806990ef04a455935", size = 2900592, upload-time = "2026-02-23T16:17:47.452Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openvino-telemetry"
|
||||
version = "2025.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/71/8a/89d82f1a9d913fb266c2e6dc2f6030935db24b7152963a8db6c4f039787f/openvino_telemetry-2025.2.0.tar.gz", hash = "sha256:8bf8127218e51e99547bf38b8fb85a8b31c9bf96e6f3a82eb0b3b6a34155977c", size = 18894, upload-time = "2025-07-07T10:29:51.159Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/ac/5ab0ca0aa269ad3c73f7bfc3801b10e5f56f75a31bf68c1ae8bd51cf70a4/openvino_telemetry-2025.2.0-py3-none-any.whl", hash = "sha256:bcb667e83a44f202ecf4cfa49281715c6d7e21499daec04ff853b7f964833599", size = 25227, upload-time = "2025-07-07T10:29:50.189Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openvino-tokenizers"
|
||||
version = "2026.0.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "openvino" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/45/22/2b976c129d43b214034a16a999d54eb659d5b2f15c12b2be52ab44e3235d/openvino_tokenizers-2026.0.0.0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:84ee496d9fe4ff7866ed9a1370cb71bf3af9526601a701c59d269854a2b0dfc7", size = 13693316, upload-time = "2026-02-23T16:12:13.41Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/86/4e7428a2fb350311a7f616c897ee1427d70cd814a2d64b2af9efb81fb881/openvino_tokenizers-2026.0.0.0-py3-none-win_amd64.whl", hash = "sha256:90f77c203c40623733e867754b952e8f0b86d9c86782abdbe9cf4bf2c82ce693", size = 13988492, upload-time = "2026-02-23T16:12:19.586Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "26.0"
|
||||
|
||||
Reference in New Issue
Block a user