docs(project): добавлены PRD и план реализации
- Зачем: - зафиксированы требования к проекту и план разработки для выравнивания команды. - Что: - добавлен docs/PRD.md с требованиями к продукту. - добавлен docs/plan.md с планом реализации. - Проверка: - открыть docs/PRD.md и docs/plan.md и убедиться в корректности содержимого.
This commit is contained in:
+201
@@ -0,0 +1,201 @@
|
||||
# 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` для принудительной перезаписи
|
||||
|
||||
**Пустая речь**: если модель не распознала ни одного сегмента — файл транскрипта всё равно создаётся (с метаданными в шапке), выводится предупреждение: `⚠ Речь не обнаружена в файле <имя>`
|
||||
|
||||
### 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)
|
||||
По умолчанию: auto (CUDA если доступен, иначе 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: CUDA toolkit (cuBLAS, cuDNN) — ставится автоматически через CTranslate2
|
||||
- Дисковое пространство для моделей: ~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` для дефолтов проекта
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
# plan.md — План реализации local-transcriber
|
||||
|
||||
> Источник требований: docs/PRD.md
|
||||
> Каждый шаг — атомарный коммит. После выполнения шага — отметить `[x]`.
|
||||
> Агент: реализуй шаги последовательно. Читай ТОЛЬКО свой текущий шаг + секции PRD, на которые он ссылается. Не реализуй функциональность из других шагов. Не рефактори код предыдущих шагов без явной необходимости.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 1: Scaffold проекта (без ML-зависимостей)
|
||||
|
||||
- [ ] Создать структуру:
|
||||
```
|
||||
local-transcriber/
|
||||
├── pyproject.toml
|
||||
├── .gitignore
|
||||
├── src/
|
||||
│ └── local_transcriber/
|
||||
│ ├── __init__.py
|
||||
│ ├── cli.py
|
||||
│ ├── transcriber.py
|
||||
│ ├── formatter.py
|
||||
│ └── utils.py
|
||||
└── tests/
|
||||
├── __init__.py
|
||||
└── test_formatter.py # заглушка
|
||||
```
|
||||
- [ ] `pyproject.toml`:
|
||||
- `name = "local-transcriber"`, `python = ">=3.10"`
|
||||
- `[project.scripts]`: `transcribe = "local_transcriber.cli:app"`
|
||||
- dependencies: `typer`, `rich` (НЕ faster-whisper — он добавляется в шаге 3)
|
||||
- dev-dependencies: `pytest`
|
||||
- [ ] `.gitignore`: `__pycache__/`, `.venv/`, `*.egg-info/`, `.mypy_cache/`, `dist/`, `*.pyc`
|
||||
- [ ] В каждом модуле — заглушки с сигнатурами и `raise NotImplementedError`:
|
||||
|
||||
**utils.py**:
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
||||
def check_ffmpeg() -> None: ...
|
||||
def detect_device(requested: str = "auto") -> tuple[str, str]: ...
|
||||
def validate_input_file(path: Path) -> Path: ...
|
||||
def build_output_path(input_path: Path, output: Path | None = None) -> Path: ...
|
||||
```
|
||||
|
||||
**transcriber.py**:
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
@dataclass
|
||||
class Segment:
|
||||
start: float # секунды
|
||||
end: float # секунды
|
||||
text: str
|
||||
|
||||
@dataclass
|
||||
class TranscribeResult:
|
||||
segments: list[Segment]
|
||||
language: str
|
||||
language_probability: float
|
||||
duration: float # секунды
|
||||
|
||||
def transcribe(
|
||||
file_path: Path,
|
||||
model_name: str = "large-v3",
|
||||
device: str = "auto",
|
||||
compute_type: str = "int8",
|
||||
language: str | None = None,
|
||||
) -> TranscribeResult: ...
|
||||
```
|
||||
|
||||
**formatter.py**:
|
||||
```python
|
||||
from pathlib import Path
|
||||
from .transcriber import TranscribeResult
|
||||
|
||||
def format_timestamp(seconds: float, use_hours: bool = False) -> str: ...
|
||||
|
||||
def format_transcript(
|
||||
result: TranscribeResult,
|
||||
source_filename: str,
|
||||
model_name: str,
|
||||
device_info: str,
|
||||
language_mode: str,
|
||||
) -> str: ...
|
||||
|
||||
def write_transcript(content: str, output_path: Path) -> None: ...
|
||||
```
|
||||
|
||||
**cli.py**:
|
||||
```python
|
||||
import typer
|
||||
app = typer.Typer()
|
||||
|
||||
@app.command()
|
||||
def main(file: Path) -> None:
|
||||
typer.echo("TODO: not implemented")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
```
|
||||
|
||||
- [ ] `uv sync` → `uv run transcribe --help` работает
|
||||
|
||||
**Критерий готовности**: `uv run transcribe --help` показывает аргументы. `uv run pytest` проходит (тесты пустые, но pytest находит test_formatter.py). Все модули импортируются без ошибок.
|
||||
|
||||
**Коммит**: `git add -A && git commit -m "step 1: scaffold with stubs and interfaces"`
|
||||
|
||||
---
|
||||
|
||||
## Шаг 2: utils.py — проверки окружения
|
||||
|
||||
> PRD-ссылки: 3.1 (flow), 3.2 (опции --device), 3.4 (форматы), 4.2 (ffmpeg)
|
||||
|
||||
- [ ] `check_ffmpeg()`:
|
||||
- `subprocess.run(["ffmpeg", "-version"], capture_output=True)`
|
||||
- При `FileNotFoundError` → `SystemExit` с сообщением и инструкцией: `apt install ffmpeg` / `winget install ffmpeg` / `brew install ffmpeg`
|
||||
- [ ] `detect_device(requested: str = "auto") -> tuple[str, str]`:
|
||||
- Если `requested != "auto"` → вернуть `(requested, "int8")`
|
||||
- Иначе: проверить CUDA через `shutil.which("nvidia-smi")` как быстрый хинт
|
||||
- Если nvidia-smi найден → `("cuda", "int8")`
|
||||
- Иначе → `("cpu", "int8")`
|
||||
- **Не импортировать** ctranslate2 или torch здесь — faster-whisper ещё не в зависимостях
|
||||
- Точная проверка CUDA будет при загрузке модели (шаг 3), здесь — best effort
|
||||
- [ ] `validate_input_file(path: Path) -> Path`:
|
||||
- Проверить: существует, является файлом (не директорией), размер > 0
|
||||
- Расширение из допустимых (PRD 3.4) → если нет, **warning** (не ошибка), продолжить
|
||||
- Вернуть `path.resolve()`
|
||||
- [ ] `build_output_path(input_path: Path, output: Path | None = None) -> Path`:
|
||||
- Если `output` задан → вернуть его
|
||||
- Иначе → `input_path.with_stem(input_path.stem + "-transcript").with_suffix(".md")`
|
||||
|
||||
**Критерий готовности**: `uv run python -c "from local_transcriber.utils import check_ffmpeg, detect_device; check_ffmpeg(); print(detect_device())"` — работает на машине агента (CPU fallback).
|
||||
|
||||
**Коммит**: `git add -A && git commit -m "step 2: utils — ffmpeg check, device detection, path helpers"`
|
||||
|
||||
---
|
||||
|
||||
## Шаг 3: transcriber.py — обёртка над faster-whisper
|
||||
|
||||
> PRD-ссылки: 5.1 (faster-whisper), 4.1.1 (GPU совместимость), 6 (риски OOM)
|
||||
|
||||
- [ ] `uv add faster-whisper` — добавить в зависимости
|
||||
- [ ] Реализовать `transcribe()`:
|
||||
- Создать `WhisperModel(model_name, device=device, compute_type=compute_type)`
|
||||
- При ошибке загрузки на CUDA (OOM, CUDA error) → **поймать**, вывести warning, **повторить с device="cpu"**
|
||||
- `model.transcribe(str(file_path), language=language if language != "auto" else None)`
|
||||
- faster-whisper возвращает `(segment_generator, info)` — итерировать generator, собрать в `list[Segment]`
|
||||
- Заполнить `TranscribeResult` из info (language, duration и т.д.)
|
||||
- [ ] Обработка ошибок:
|
||||
- `RuntimeError` с "CUDA" / "out of memory" → fallback на CPU + warning
|
||||
- Ошибка ffmpeg (невалидный медиафайл) → пробросить с понятным текстом
|
||||
|
||||
**Критерий готовности**: на машине агента — `transcribe()` работает с `device="cpu"`, `model="tiny"` (быстро скачивается). Полноценная проверка с large-v3 и GPU — на локальной машине разработчика.
|
||||
|
||||
**Коммит**: `git add -A && git commit -m "step 3: transcriber — faster-whisper wrapper with CUDA fallback"`
|
||||
|
||||
---
|
||||
|
||||
## Шаг 4: formatter.py + тесты
|
||||
|
||||
> PRD-ссылки: 3.3 (формат выходного файла)
|
||||
|
||||
- [ ] `format_timestamp(seconds: float, use_hours: bool = False) -> str`:
|
||||
- `False` → `"01:23.45"` (MM:SS.ss)
|
||||
- `True` → `"01:23:45.67"` (HH:MM:SS.ss)
|
||||
- Сотые — всегда 2 знака после точки
|
||||
- [ ] `format_transcript(...)`:
|
||||
- Шапка по шаблону PRD 3.3 (заголовок, метаданные, разделитель)
|
||||
- Автоматически `use_hours=True` если `result.duration > 3600`
|
||||
- Сегменты: `[MM:SS.ss - MM:SS.ss] текст\n\n`
|
||||
- Если `len(result.segments) == 0` → после разделителя: `\n*Речь не обнаружена.*\n`
|
||||
- [ ] `write_transcript(content: str, output_path: Path)`:
|
||||
- `open(output_path, "w", encoding="utf-8")`
|
||||
- [ ] Тесты в `tests/test_formatter.py`:
|
||||
- `test_format_timestamp_minutes` — обычный таймкод
|
||||
- `test_format_timestamp_hours` — формат с часами
|
||||
- `test_format_transcript_basic` — проверить шапку + пару сегментов
|
||||
- `test_format_transcript_empty` — 0 сегментов → содержит "Речь не обнаружена"
|
||||
- `test_format_transcript_long` — duration > 3600 → таймкоды с часами
|
||||
|
||||
**Критерий готовности**: `uv run pytest tests/test_formatter.py -v` — все тесты зелёные.
|
||||
|
||||
**Коммит**: `git add -A && git commit -m "step 4: formatter with markdown output and tests"`
|
||||
|
||||
---
|
||||
|
||||
## Шаг 5: cli.py — связка всех модулей, happy path
|
||||
|
||||
> PRD-ссылки: 3.1 (flow), 3.2 (CLI-интерфейс)
|
||||
|
||||
- [ ] Typer command с аргументами и опциями по PRD 3.2:
|
||||
- `file: Path` — позиционный аргумент
|
||||
- `--model` / `-m` → default `"large-v3"`
|
||||
- `--language` / `-l` → default `"auto"`
|
||||
- `--output` / `-o` → optional Path
|
||||
- `--device` / `-d` → default `"auto"`
|
||||
- `--compute-type` → default `"int8"`
|
||||
- `--verbose` / `-v` → flag, default False
|
||||
- [ ] Happy path flow:
|
||||
1. `check_ffmpeg()`
|
||||
2. `validate_input_file(file)`
|
||||
3. `detect_device()` если `--device auto`, иначе использовать переданные device + compute_type
|
||||
4. rich Console → stderr: информация о запуске (модель, устройство, файл)
|
||||
5. rich Spinner/Status во время транскрипции
|
||||
6. `transcribe(...)`
|
||||
7. Если 0 сегментов → `console.print("⚠ Речь не обнаружена в файле ...", style="yellow")`
|
||||
8. `format_transcript(...)` → `write_transcript(...)`
|
||||
9. `console.print("✓ Транскрипт сохранён: <путь>", style="green")`
|
||||
10. Статистика: кол-во сегментов, время работы (замерить через `time.monotonic()`)
|
||||
- [ ] Exit codes: 0 — успех (включая пустую речь), 1 — ошибка
|
||||
|
||||
**Критерий готовности**: `uv run transcribe test.mp3` — создаёт корректный .md файл (проверить на локальной машине с реальным файлом).
|
||||
|
||||
**Коммит**: `git add -A && git commit -m "step 5: CLI happy path — end-to-end transcription"`
|
||||
|
||||
---
|
||||
|
||||
## Шаг 6: Error handling и UX polish
|
||||
|
||||
> PRD-ссылки: 6 (риски)
|
||||
|
||||
- [ ] Graceful Ctrl+C: перехват `KeyboardInterrupt` в cli.py → `console.print("Прервано пользователем", style="yellow")` + `raise SystemExit(130)`
|
||||
- [ ] Красивые ошибки: обернуть main в try/except, для пользовательских ошибок (файл не найден, ffmpeg, OOM) — вывод через rich без traceback; для неожиданных — traceback только с `--verbose`
|
||||
- [ ] `--verbose` режим: при транскрипции выводить каждый сегмент в stderr по мере получения из generator (до сборки в список)
|
||||
- [ ] Проверка: неподдерживаемое расширение → warning, но попытка продолжить
|
||||
|
||||
**Критерий готовности**: ручной прогон edge cases — несуществующий файл, .txt файл, Ctrl+C во время работы.
|
||||
|
||||
**Коммит**: `git add -A && git commit -m "step 6: error handling, verbose mode, graceful shutdown"`
|
||||
|
||||
---
|
||||
|
||||
## Шаг 7: README.md
|
||||
|
||||
> PRD-ссылки: 4.2 (требования), 4.1.1 (GPU таблица), 4.3 (кроссплатформенность)
|
||||
|
||||
- [ ] Описание: что делает, зачем
|
||||
- [ ] Требования: Python ≥ 3.10, ffmpeg, (опционально) NVIDIA GPU + CUDA
|
||||
- [ ] Установка:
|
||||
```bash
|
||||
git clone <repo>
|
||||
cd local-transcriber
|
||||
uv sync
|
||||
```
|
||||
- [ ] Использование: 3-4 примера команд (простой, с языком, с моделью, CPU)
|
||||
- [ ] Установка ffmpeg: Linux (`apt`), Windows (`winget`/`scoop`), WSL2, macOS (`brew`)
|
||||
- [ ] GPU и CUDA: краткое пояснение, ссылка на NVIDIA docs, что CTranslate2 ставит нужное
|
||||
- [ ] Таблица моделей: имя, размер на диске, VRAM (int8), относительная скорость, качество
|
||||
- [ ] Пример выходного файла (сокращённый)
|
||||
|
||||
**Критерий готовности**: коллега может по README установить и запустить на Windows/WSL2 без вопросов.
|
||||
|
||||
**Коммит**: `git add -A && git commit -m "step 7: README with install, usage, GPU guide"`
|
||||
|
||||
---
|
||||
|
||||
## Инструкция для агента
|
||||
|
||||
Команда на каждый шаг:
|
||||
```
|
||||
Прочитай docs/PRD.md (только секции, указанные в текущем шаге) и plan.md (только текущий шаг).
|
||||
Реализуй шаг N.
|
||||
После реализации — отметь все чекбоксы шага как [x] в plan.md.
|
||||
Не трогай код и чекбоксы из других шагов.
|
||||
```
|
||||
|
||||
После каждого шага — `git add -A && git commit -m "<сообщение из шага>"`.
|
||||
Reference in New Issue
Block a user