Files
local-transcriber/src/local_transcriber/utils.py
T
ddadminandClaude Opus 4.6 dfc5f46bf3 feat(transcriber): реализована обёртка над faster-whisper (шаг 3)
- Зачем:
  - необходим модуль транскрипции с CUDA fallback для основного flow приложения.
- Что:
  - добавлена зависимость faster-whisper>=1.2.1 в pyproject.toml.
  - реализована функция transcribe() с fallback CUDA→CPU на всех этапах (загрузка модели, вызов transcribe, итерация сегментов).
  - исправлен IndexError в get_gpu_name() при пустом stdout nvidia-smi.
  - добавлено 6 тестов в test_transcriber.py и 1 тест в test_utils.py (16 тестов зелёные).
- Проверка:
  - uv run pytest -v (16 passed).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 22:30:40 +03:00

71 lines
2.1 KiB
Python

import shutil
import subprocess
import sys
import warnings
from pathlib import Path
SUPPORTED_EXTENSIONS = {
".mp3", ".wav", ".flac", ".ogg", ".m4a", ".wma", ".aac",
".mp4", ".mkv", ".avi", ".mov", ".webm", ".ts",
}
def check_ffmpeg() -> None:
try:
subprocess.run(["ffmpeg", "-version"], capture_output=True, check=False)
except FileNotFoundError:
sys.exit(
"ffmpeg не найден в PATH. Установите ffmpeg:\n"
" Linux: apt install ffmpeg\n"
" Windows: winget install ffmpeg\n"
" macOS: brew install ffmpeg"
)
def detect_device(requested: str = "auto") -> str:
if requested != "auto":
return requested
if shutil.which("nvidia-smi") is not None:
return "cuda"
return "cpu"
def get_gpu_name() -> str | None:
try:
result = subprocess.run(
["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"],
capture_output=True,
text=True,
check=False,
)
if result.returncode == 0:
lines = result.stdout.strip().splitlines()
if lines:
name = lines[0].strip()
return name if name else None
except FileNotFoundError:
pass
return None
def validate_input_file(path: Path) -> Path:
if not path.exists():
raise FileNotFoundError(f"Файл не найден: {path}")
if not path.is_file():
raise ValueError(f"Путь не является файлом: {path}")
if path.stat().st_size == 0:
raise ValueError(f"Файл пустой: {path}")
if path.suffix.lower() not in SUPPORTED_EXTENSIONS:
warnings.warn(
f"Расширение '{path.suffix}' не входит в список поддерживаемых. "
"Попытка продолжить.",
stacklevel=2,
)
return path.resolve()
def build_output_path(input_path: Path, output: Path | None = None) -> Path:
if output is not None:
return output
return input_path.with_stem(input_path.stem + "-transcript").with_suffix(".md")