- Зачем: - 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>
202 lines
13 KiB
Markdown
202 lines
13 KiB
Markdown
# PRD: local-transcriber — Локальный CLI для транскрипции аудио/видео
|
||
|
||
## 1. Обзор продукта
|
||
|
||
**Название**: `local-transcriber`
|
||
**Тип**: CLI-утилита (Python, управление зависимостями через uv)
|
||
**Назначение**: Принимает аудио- или видеофайл, выполняет распознавание речи локально (без внешних API), и создаёт рядом с исходным файлом markdown-файл с транскриптом и таймкодами.
|
||
|
||
**Пример использования**:
|
||
```bash
|
||
transcribe meeting-2026-03-17.mp4
|
||
# → создаёт meeting-2026-03-17-transcript.md
|
||
```
|
||
|
||
## 2. Целевые пользователи и сценарии
|
||
|
||
- Разработчик/инженер, которому нужен текст из записи встречи, лекции, подкаста
|
||
- Дальнейшая обработка транскрипта ИИ (суммаризация, извлечение action items и т.д.) — вне скоупа, но учитывается в формате вывода
|
||
- Машины с GPU (NVIDIA, CUDA) и без GPU (CPU-only fallback)
|
||
- Windows (native / WSL2) и Linux
|
||
|
||
## 3. Функциональные требования
|
||
|
||
### 3.1. Основной flow
|
||
|
||
1. Пользователь вызывает CLI, передаёт путь к файлу (или glob-маску, post-MVP)
|
||
2. Проверка: ffmpeg доступен в PATH
|
||
3. Файл передаётся в faster-whisper (он сам обрабатывает и аудио, и видео через libav/ffmpeg — отдельное извлечение аудиодорожки не нужно)
|
||
4. Результат форматируется в markdown с таймкодами
|
||
5. Файл `<имя>-transcript.md` сохраняется рядом с исходным (кодировка: UTF-8)
|
||
|
||
**Поведение при перезаписи**:
|
||
- Явный вызов по файлу → транскрипт перезаписывается, даже если уже существует
|
||
- Батч-режим (glob-маска, post-MVP) → пропускать файлы, для которых транскрипт уже существует; `--force` для принудительной перезаписи
|
||
|
||
**Пустая речь**: если модель не распознала ни одного сегмента — файл транскрипта всё равно создаётся (шапка с метаданными + `*Речь не обнаружена.*` в теле), выводится предупреждение в stderr: `⚠ Речь не обнаружена в файле <имя>`
|
||
|
||
### 3.2. CLI-интерфейс
|
||
|
||
```
|
||
transcribe <путь_к_файлу> [опции]
|
||
|
||
Опции:
|
||
--model, -m Модель Whisper (tiny|base|small|medium|large-v3)
|
||
По умолчанию: large-v3
|
||
--language, -l Язык (ru|en|auto)
|
||
По умолчанию: auto (автодетект)
|
||
--output, -o Путь к выходному файлу
|
||
По умолчанию: <input_stem>-transcript.md
|
||
--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 Подробный вывод (прогресс сегментов)
|
||
```
|
||
|
||
### 3.3. Формат выходного файла
|
||
|
||
Файл `*-transcript.md`:
|
||
|
||
```markdown
|
||
# Транскрипт: meeting-2026-03-17.mp4
|
||
|
||
- **Дата транскрипции**: 2026-03-17 14:30:05
|
||
- **Модель**: large-v3
|
||
- **Язык**: ru (detected) / ru (forced)
|
||
- **Длительность**: 01:23:45
|
||
- **Устройство**: CUDA (NVIDIA GeForce RTX 3060)
|
||
|
||
---
|
||
|
||
[00:00.00 - 00:04.82] Добрый день, коллеги. Сегодня мы обсудим результаты квартала.
|
||
|
||
[00:04.82 - 00:09.15] Первый вопрос — по метрикам продукта.
|
||
|
||
[00:09.15 - 00:15.40] Как вы видите на слайде, MAU вырос на двадцать три процента
|
||
по сравнению с предыдущим кварталом.
|
||
|
||
...
|
||
```
|
||
|
||
**Правила форматирования**:
|
||
- Таймкоды в формате `[MM:SS.ss - MM:SS.ss]` (минуты:секунды.сотые)
|
||
- Для записей длиннее 1 часа — `[HH:MM:SS.ss - HH:MM:SS.ss]`
|
||
- Каждый сегмент — отдельный абзац
|
||
- Метаданные в шапке файла
|
||
- Пустая строка между сегментами для читаемости
|
||
|
||
### 3.4. Поддерживаемые форматы
|
||
|
||
**Аудио**: mp3, wav, flac, ogg, m4a, wma, aac
|
||
**Видео**: mp4, mkv, avi, mov, webm, ts
|
||
|
||
Определение типа — по расширению. Фактическое декодирование выполняет ffmpeg внутри faster-whisper; если формат не поддерживается, ошибка будет от ffmpeg.
|
||
|
||
## 4. Нефункциональные требования
|
||
|
||
### 4.1. Производительность
|
||
|
||
| Конфигурация | Ожидаемая скорость (real-time factor) |
|
||
|---------------------------|---------------------------------------|
|
||
| RTX 3060 + large-v3 | ~10-15x (1 час аудио ≈ 4-6 мин) |
|
||
| RTX 4050 + large-v3 | ~12-18x (1 час аудио ≈ 3-5 мин) |
|
||
| Quadro M3000M + large-v3 | ~3-5x (1 час аудио ≈ 12-20 мин) |
|
||
| CPU (modern) + large-v3 | ~0.5-1x (1 час аудио ≈ 60-120 мин) |
|
||
| CPU + small | ~3-5x (1 час аудио ≈ 12-20 мин) |
|
||
|
||
### 4.1.1. Совместимость GPU
|
||
|
||
| GPU | VRAM | large-v3 int8 (~2.5 GB) | large-v3 float16 (~4.5 GB) | Рекомендация |
|
||
|-------------------|-------|--------------------------|----------------------------|-------------------------|
|
||
| RTX 3060 | 6 GB | ✅ | ✅ (впритык) | int8 — безопасный выбор |
|
||
| RTX 4050 | 6 GB | ✅ | ✅ (впритык) | int8 — безопасный выбор |
|
||
| Quadro M3000M | 4 GB | ✅ | ⚠️ может OOM | int8 обязательно |
|
||
| Без GPU | — | CPU int8 | — | int8 на CPU |
|
||
|
||
Дефолт `int8` выбран как универсальный: работает на всех GPU от 4 GB и на CPU, при минимальной потере качества относительно float16.
|
||
|
||
### 4.2. Требования к окружению
|
||
|
||
- Python ≥ 3.10
|
||
- ffmpeg в PATH (используется faster-whisper внутри для декодирования любых медиаформатов)
|
||
- Для GPU: Linux/WSL2 — cuBLAS из nvidia-cublas-cu12 (ставится автоматически через `uv sync`); Windows — системный CUDA toolkit (см. ADR-001)
|
||
- Дисковое пространство для моделей: ~3 GB (large-v3)
|
||
- Выходные файлы: UTF-8 (явная кодировка при записи)
|
||
|
||
### 4.3. Кроссплатформенность
|
||
|
||
- Linux: нативный запуск
|
||
- Windows: нативный Python или WSL2
|
||
- macOS: не приоритет, но faster-whisper поддерживает CPU-режим
|
||
|
||
## 5. Технический стек
|
||
|
||
| Компонент | Технология |
|
||
|---------------------|-------------------------------------------------|
|
||
| Язык | Python 3.10+ |
|
||
| Управление проектом | uv (pyproject.toml) |
|
||
| Распознавание речи | faster-whisper (CTranslate2 backend) |
|
||
| Медиа-декодирование | ffmpeg (системная зависимость, используется faster-whisper внутри) |
|
||
| CLI-фреймворк | typer |
|
||
| Прогресс | rich (progress bar + статус) |
|
||
|
||
### 5.1. Почему faster-whisper
|
||
|
||
- В 4× быстрее оригинального OpenAI Whisper при том же качестве
|
||
- Меньше потребление VRAM (large-v3 влезает в 6 GB с float16/int8)
|
||
- Нативный Python API, без Docker
|
||
- Поддержка CPU fallback из коробки
|
||
- Активное сообщество, регулярные обновления
|
||
- Автоматическая загрузка моделей из Hugging Face Hub
|
||
|
||
### 5.2. Структура проекта
|
||
|
||
```
|
||
local-transcriber/
|
||
├── pyproject.toml
|
||
├── README.md
|
||
├── src/
|
||
│ └── local_transcriber/
|
||
│ ├── __init__.py
|
||
│ ├── cli.py # CLI entry point (typer)
|
||
│ ├── transcriber.py # Обёртка над faster-whisper
|
||
│ ├── formatter.py # Форматирование в markdown
|
||
│ └── utils.py # Проверки (ffmpeg), определение device и т.д.
|
||
└── tests/
|
||
└── ...
|
||
```
|
||
|
||
## 6. Риски и ограничения
|
||
|
||
| Риск | Влияние | Митигация |
|
||
|------|---------|-----------|
|
||
| Качество распознавания русского текста | Среднее | large-v3 хорошо справляется с ru; при проблемах — попробовать `--language ru` вместо auto |
|
||
| Нет разделения по спикерам | Низкое | Осознанно выведено за скоуп MVP; добавление diarization (pyannote.audio) — возможное расширение |
|
||
| ffmpeg отсутствует в системе | Высокое | Проверка при старте + понятное сообщение об ошибке с инструкцией по установке |
|
||
| Первый запуск: долгая загрузка модели | Низкое | Прогресс-бар при скачивании; модели кешируются в `~/.cache/huggingface/` |
|
||
| CUDA несовместимость на Windows | Среднее | Автоматический fallback на CPU + предупреждение; в README — инструкция по CUDA |
|
||
| Большие файлы (>2 часов) | Низкое | faster-whisper работает потоково, не грузит всё в память |
|
||
| OOM на GPU с 4 GB VRAM | Среднее | Дефолт int8 (~2.5 GB); при OOM — fallback на CPU с предупреждением |
|
||
| Файл без речи (тишина, музыка, шум) | Низкое | Создаётся транскрипт с шапкой метаданных и `*Речь не обнаружена.*` в теле + предупреждение в stderr |
|
||
|
||
## 7. Вне скоупа MVP
|
||
|
||
- Разделение по спикерам (speaker diarization)
|
||
- Веб-интерфейс / GUI
|
||
- Пакетная обработка нескольких файлов (батч) — см. post-MVP
|
||
- Стриминг с микрофона (real-time)
|
||
- Интеграция с LLM для пост-обработки транскрипта
|
||
- Перевод (translation mode)
|
||
- Вывод в форматах SRT / VTT / JSON
|
||
- Аудиофильтрация / шумоподавление (faster-whisper сам нормализует; ручной препроцессинг может ухудшить результат)
|
||
|
||
## 8. Возможные расширения (post-MVP)
|
||
|
||
1. **Speaker diarization** — pyannote.audio, требует отдельной модели + GPU
|
||
2. **Батч-режим** — `transcribe ./recordings/*.mp4`; по умолчанию пропускает файлы, для которых транскрипт уже есть; `--force` для перезаписи
|
||
3. **Экспорт в SRT/VTT** — для субтитров
|
||
4. **Watch-режим** — мониторинг директории, автотранскрипция новых файлов
|
||
5. **Интеграция с LLM** — `--summarize` для генерации саммари поверх транскрипта
|
||
6. **Конфигурационный файл** — `.transcriber.toml` для дефолтов проекта
|