feat(cli): добавлен батч-режим и конфигурационный файл (шаги 8–12)

- Зачем:
  - обработка нескольких файлов за один вызов с загрузкой модели один раз.
  - хранение дефолтов (модель, язык, устройство) в .transcriber.toml.
- Что:
  - добавлен config.py: поиск .transcriber.toml (CWD → ~/.config), парсинг, валидация, приоритет CLI > конфиг > хардкод.
  - рефакторинг transcriber.py: выделены load_model() и _transcribe_file() с TranscribeFileResult для переиспользования модели в батче.
  - добавлены expand_globs() с дедупликацией и has_existing_transcript() в utils.py.
  - CLI: files: list[Path], --force/-f, prescan-first батч с итоговой статистикой и временем, Status-спиннер для прогресса.
  - README: секции батч-режим, конфигурационный файл, --force в таблице опций.
  - ADR-002: зафиксированы архитектурные решения (prescan-first, TranscribeFileResult, конфиг без мержа).
- Проверка:
  - uv run pytest -q — 94 passed, 1 skipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-18 20:57:19 +03:00
co-authored by Claude Opus 4.6
parent b46827a283
commit e28232ef50
13 changed files with 1227 additions and 103 deletions
+57
View File
@@ -0,0 +1,57 @@
# ADR-002: Batch mode и config
**Статус**: Принято
**Дата**: 2026-03-18
## Контекст
После завершения MVP (шаги 1–7) пользователям не хватает:
- Обработки нескольких файлов за один вызов (batch mode)
- Конфигурационного файла для хранения дефолтов (модель, язык, устройство)
## Решения
### 1. Prescan-first: валидация до загрузки модели
Модель загружается **только если есть файлы для обработки**. Перед загрузкой модели выполняется полный prescan: валидация всех файлов и проверка существующих транскриптов.
**Почему**: загрузка модели (large-v3) занимает ~10 секунд и ~3 GB RAM/VRAM. Повторный запуск по уже обработанным файлам должен быть дешёвым no-op.
### 2. TranscribeFileResult: возврат обновлённого состояния модели
При mid-stream CUDA fallback `_transcribe_file()` перезагружает модель на CPU внутри себя. Чтобы следующие файлы в батче не грузили модель повторно, результат включает обновлённые `model` и `actual_device`.
```python
@dataclass
class TranscribeFileResult:
result: TranscribeResult
model: WhisperModel # может измениться при fallback
actual_device: str # может измениться при fallback
```
**Альтернатива**: передавать модель по ссылке через mutable контейнер — менее явно и сложнее тестировать.
### 3. Конфиг: CWD → глобальный, без мержа
Порядок поиска:
1. `.transcriber.toml` в текущей директории (проектный конфиг)
2. `~/.config/transcriber/config.toml` (глобальный конфиг)
Первый найденный побеждает, мержа между файлами нет.
**Почему**: CWD-конфиг удобен для per-project дефолтов (`language = "ru"` для русскоязычного проекта), глобальный — для машинных дефолтов (`device = "cpu"` на ноутбуке без GPU). Мерж усложняет предсказуемость.
**Приоритет значений**: CLI > конфиг > хардкод.
### 4. `_transcribe_file()` — внутренний helper
Публичный API (`transcribe()`) сохранён без изменений. Новая функция `_transcribe_file()` — внутренний helper с префиксом `_`, не часть публичного контракта.
`transcribe()` стала тонкой обёрткой: `load_model()` + `_transcribe_file()``TranscribeResult`.
## Последствия
- Обратная совместимость CLI: `transcribe file.mp4` работает как раньше
- Все существующие тесты проходят без изменений сигнатур
- Batch mode: модель загружается один раз для всех файлов
- `--force` флаг для перезаписи существующих транскриптов в батч-режиме
+63
View File
@@ -288,6 +288,69 @@
**Критерий готовности**: коллега может по README установить и запустить на Windows/WSL2 без вопросов.
---
## Шаг 8: Конфиг `.transcriber.toml`
- [x] Зависимость `tomli` в `pyproject.toml` (для Python < 3.11)
- [x] Новый файл `src/local_transcriber/config.py`:
- `HARDCODED_DEFAULTS` — дефолтные значения
- `find_config_file()` — ищет `.transcriber.toml` в CWD, потом `~/.config/transcriber/config.toml`
- `load_config()` — парсит TOML, валидирует ключи/значения
- `resolve_defaults()` — приоритет CLI > конфиг > хардкод
- [x] Тесты `tests/test_config.py` — 11 тестов
**Критерий готовности**: `uv run pytest tests/test_config.py -v` — все тесты зелёные.
---
## Шаг 9: Рефакторинг transcriber.py — выделить загрузку модели
- [x] `load_model()` — загрузка модели с CUDA-фолбеком
- [x] `_transcribe_file()` — транскрипция одного файла, возвращает `TranscribeFileResult`
- [x] `TranscribeFileResult` — dataclass с result, model, actual_device
- [x] `transcribe()` — тонкая обёртка для обратной совместимости
- [x] Новые тесты: `test_load_model_cuda_fallback`, `test_load_model_strict_raises`, `test__transcribe_file_basic`
**Критерий готовности**: все существующие тесты `test_transcriber.py` проходят без изменений.
---
## Шаг 10: Утилиты для батч-режима в utils.py
- [x] `expand_globs()` — раскрытие glob-паттернов
- [x] `has_existing_transcript()` — проверка существования транскрипта
- [x] Тесты в `test_utils.py` — 5 новых тестов
**Критерий готовности**: `uv run pytest tests/test_utils.py -v` — все тесты зелёные.
---
## Шаг 11: Батч-режим + конфиг в CLI
- [x] Изменение сигнатуры CLI: `files: list[Path]`, дефолты `None`, `--force`
- [x] Интеграция `load_config()` / `resolve_defaults()` в `main()`
- [x] `_run_single()` — текущий flow для одного файла
- [x] `_run_batch()` — prescan, загрузка модели, транскрипция с итогами
- [x] Обновлённые тесты `test_cli.py` — 11 новых тестов
**Критерий готовности**: `uv run pytest tests/test_cli.py -v` — все тесты зелёные.
---
## Шаг 12: Документация + ADR
- [x] ADR-002: Batch mode и config (`docs/adr/002-batch-and-config.md`)
- [x] README.md: секции «Батч-режим», «Конфигурационный файл», обновлена таблица опций CLI
- [x] `docs/plan.md`: отмечены шаги 8–12
**Критерий готовности**: README содержит документацию по батч-режиму и конфигу.
---
## Инструкция для агента