Files
remotion_service/docs/consults/video-features-roadmap_v1_ru.md
2026-03-22 22:42:35 +03:00

433 lines
31 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Дорожная карта видеофич — Техническая консультация v1
**Дата:** 22 марта 2026
**Консультанты:** ML/AI-инженер, Backend-архитектор, Remotion-инженер, Frontend-архитектор, DevOps-инженер, Инженер по производительности
---
## Общая картина
Четыре фичи. От простого к безумному. Вот что получается, если разложить всё по полочкам:
| # | Фича | Сложность | MVP | Полная версия | Доп. инфраструктура |
|---|-------|-----------|-----|---------------|---------------------|
| 1 | Продвинутые шаблоны Remotion | Легко-средне | 3-4 дня | 3-4 дня | Ничего — можно начинать хоть сейчас |
| 2 | Детекция вирусных моментов | Средне | 5-7 дней | 8-12 дней | Только API-ключ для LLM |
| 3 | Авто-монтаж и трекинг лица | Очень сложно | 12-15 дней | 30-45 дней | Фаза 1: ничего; Фаза 2: GPU-воркер |
| 4 | Конвертация в вертикальные Shorts (9:16) | Средне | 6-8 дней | +3-4 дня после #3 | Ничего |
| **Итого** | | | **26-34 дня** | **44-65 дней** | |
Реалистичный прогноз для одного разработчика: **6-8 недель** (все MVP) или **3-4 месяца** (полные версии).
---
## Фича 1: Продвинутые шаблоны Remotion
**Статус:** Спецификация и план реализации уже написаны. Бери и делай.
- Спецификация: `docs/superpowers/specs/2026-03-21-advanced-remotion-templates-design.md`
- План: `docs/superpowers/plans/2026-03-21-advanced-remotion-templates.md`
**Что делаем:** Расширяем `CaptionStyleSchema` четырьмя новыми стилями подсветки слов (pop_in, karaoke, bounce, glow_pulse), двумя переходами (zoom_in, drop_in), тремя полями (word_entrance, highlight_rotation_deg, text_transform). Добавляем два системных пресета: "Shorts" и "Podcast".
**Где трогаем код:** Расширение схемы в Remotion + бэкенде, логика рендеринга в `Captions.tsx`, Alembic-миграция для пресетов, контролы в StyleEditor на фронте.
**Особый интерес специалистов не требуется** — всё спроектировано, новой инфраструктуры нет. Самая безрисковая фича в этом списке.
---
## Фича 2: Детекция вирусных моментов
Вот тут начинается самое интересное. За $0.005 за видео мы можем автоматически находить самые цепляющие фрагменты в подкастах и интервью. Пять копеек — и AI выкладывает тебе на блюдце моменты, которые зрители пересылают друг другу.
### Архитектура
**LLM API:** Gemini 2.5 Flash — лучшая поддержка русского языка, $0.15/$0.60 за 1М токенов. Альтернатива: GPT-4o-mini (те же деньги, русский чуть хуже). Стоимость анализа одного 30-минутного видео: примерно $0.005.
**Аудио-подкрепление:** `librosa` для кривых RMS-энергии — уточняет границы клипов до естественных пауз, повышает скор для энергичных сегментов. Зависимость ~20МБ, обработка 30-минутного аудио за <10 секунд.
**Пайплайн:**
1. Берём транскрипцию из БД
2. librosa считает огибающую энергии по всему аудио (разрешение 100мс)
3. LLM анализирует текст транскрипции через промпт со structured JSON output
4. Постобработка: привязка границ клипов к точкам низкой энергии, расчёт energy-скоров
5. Сохраняем клипы в новую таблицу `clips`
### Бэкенд
**Новый модуль:** `clips` (models, schemas, repository, service, router) — хранит найденные клипы со связями project/file/job.
**Модель клипа:**
```
Clip {
project_id: UUID (FK projects)
source_file_id: UUID (FK files)
job_id: UUID? (FK jobs)
title: str
start_ms: int
end_ms: int
score: float
source_type: "viral_detected" | "user_created" | "auto_generated"
status: "pending" | "approved" | "rejected" | "exported"
meta: JSON? (рассуждения LLM, теги, хэштеги)
}
```
**Новый тип джоба:** `VIRAL_DETECT` в `JobTypeEnum`. Актор вызывает LLM API напрямую через `httpx` из Dramatiq-воркера — отдельный сервис не нужен.
**Интеграция с LLM:**
- Прямой HTTP-вызов из актора с retry + exponential backoff на 429
- Промпты хранятся в `cpv3/infrastructure/prompts/viral_detection_v1.txt`
- Активная версия контролируется через env-переменную `LLM_VIRAL_PROMPT_VERSION`
- Новые настройки: `LLM_API_URL`, `LLM_API_KEY`, `LLM_MODEL_NAME`
### Фронтенд
- Новый `ViralClipsStep` в визарде проекта (features/project/)
- Список клипов с превьюшками, скорами, заголовками, кнопками принять/отклонить
- Модалка редактирования клипа с видео-превью (воспроизведение ограничено диапазоном start/end)
- Новый тип джоба `VIRAL_DETECT` в обработке нотификаций (через существующую WebSocket-инфраструктуру)
### Ключевые цифры
| Метрика | Значение |
|---|---|
| Точность (precision) | 50-70% |
| Полнота (recall) | 60-80% |
| Время обработки | 10-20 секунд |
| Стоимость за видео | ~$0.005 |
| Стоимость при 1 000 видео/месяц | ~$5 |
| Новые зависимости | `google-generativeai` или `openai` (~10МБ) + `librosa` (~20МБ) |
10-20 секунд и пять долларов за тысячу видео. Вдумайтесь в эти цифры.
### Риски
- **Качество промпт-инжиниринга** определяет ценность фичи — придётся итерировать по фидбеку пользователей
- **Визуальные моменты** (мимика, физическая комедия) из текста не ловятся — ~20-30% вирусных моментов проходят мимо
- **Качество транскрипции критично** — Whisper `tiny` даёт ~25% WER на русском; для входных данных вирусной детекции использовать минимум `small`
- **LLM галлюцинирует таймстемпы** — обязательно валидировать возвращённые метки времени против реальных границ сегментов
### MVP vs Полная версия
- **MVP:** Только текстовый анализ через LLM, без аудио-энергии. Возвращает клипы со скорами. Пользователь ревьюит и принимает/отклоняет.
- **Полная:** Добавляем librosa-анализ энергии, few-shot примеры из принятых пользователем клипов, пакетную обработку, прямой экспорт клипов в 9:16.
---
## Фича 3: Авто-монтаж и трекинг лица
Самая амбициозная фича. Самая сложная. И, возможно, самая впечатляющая для пользователей. Представьте: загружаете подкаст с двумя спикерами, а на выходе получаете динамичное вертикальное видео, где камера сама «следит» за говорящим — как будто это снимал живой оператор.
### Архитектура
**Детекция лиц:** MediaPipe BlazeFace (Apache 2.0, модель ~2МБ, 30-60 FPS на CPU). Сэмплируем на 3 FPS — позиции лиц не меняются значительно за 330мс. Зависимость: `mediapipe` (~30МБ).
**Диаризация спикеров:** pyannote.audio 3.1 (MIT, ~10% DER, self-hosted). На CPU работает со скоростью 0.17-0.33x реального времени (5-10 минут на 30-минутное аудио). GPU ускоряет до 1-2 минут. Зависимости: `pyannote-audio` (~200МБ) + `torchaudio` (~50-80МБ). PyTorch уже установлен через Whisper.
**Маппинг лицо-спикер:**
- **Фаза 1:** Эвристика по временнОй корреляции — сопоставляем треки лиц с сегментами спикеров по максимальному пересечению во времени. 70-85% точности для видео с двумя спикерами. Ноль дополнительных зависимостей. Около 100 строк Python.
- **Фаза 2:** TalkNet-ASD (Active Speaker Detection) — совместный анализ движения губ и аудио для определения, кто говорит. 92.3% точности. Требует `torchvision` + веса модели (~50МБ). Нужен GPU (2-5 FPS на CPU vs 15-25 FPS на GPU).
**Видео-композитинг (подход Remotion):**
Динамический кроп через CSS `transform: scale() translate()` на элементе `<Video>` внутри контейнера с `overflow: hidden`. Это GPU-ускоренная браузерная операция — по сути бесплатная с точки зрения производительности. Для самого кропа пере-кодирование через FFmpeg не нужно.
**Новые Remotion-композиции:**
| Композиция | Назначение | Фаза |
|---|---|---|
| `CaptionedVideo` (существует) | Наложение субтитров на нативное видео | Текущая |
| `ShortsVideo` (новая) | Статический/ключевой кроп + субтитры в 9:16 | Фича 4 |
| `AutoEditVideo` (новая) | Кроп с трекингом лица + монтаж + субтитры | Фича 3 (полная) |
Все композиции разделяют компонент `<Captions>` и хук `useCaptions`.
**Формат данных кропа (ключевые кадры):**
```typescript
type FaceKeyframe = {
time: number; // секунды
x: number; // центр лица, 0.0-1.0 нормализовано
y: number; // центр лица, 0.0-1.0 нормализовано
width: number; // ширина bounding box, 0.0-1.0
height: number; // высота bounding box, 0.0-1.0
speakerId?: string;
};
type CropTrack = {
keyframes: FaceKeyframe[];
interpolation: "linear" | "ease" | "smooth";
zoom: number; // базовый множитель зума
safeMargin: number; // отступ вокруг лица (0.1 = 10%)
};
```
Remotion `interpolate()` между ключевыми кадрами для плавного панорамирования/зума. `spring()` используется только для жёстких переключений между спикерами.
### Бэкенд
**Новые типы джобов:** `FACE_DETECT`, `SPEAKER_DIARIZE` в `JobTypeEnum`. Результаты хранятся в `Job.output_data` (JSON) — новая таблица для данных лица/диаризации не нужна.
**Отделение ML-сервиса:**
- **Фаза 1:** Оставляем в Dramatiq-воркерах (тот же образ). MediaPipe + pyannote добавляют только ~280МБ к образу.
- **Фаза 2:** Отдельный Docker-контейнер `ml-worker` на выделенных очередях Dramatiq (`ml_head_tracking`, `ml_diarization`). Тот же код, другой образ, другие лимиты ресурсов.
**Изменения в Remotion-сервисе:** `POST /api/render` нужен параметр `compositionId` для выбора композиции. Props расширяются полями `crop`, `outputWidth`, `outputHeight`.
### Время обработки (30-минутное 1080p видео)
| Шаг | CPU | GPU |
|---|---|---|
| Извлечение аудио (FFmpeg) | 10-20 сек | 10-20 сек |
| Детекция лиц (MediaPipe, 3 FPS) | 1-2 мин | 10-15 сек |
| Диаризация спикеров (pyannote) | **15-30 мин** | 1-2 мин |
| Маппинг лицо-спикер | < 1 сек | < 1 сек |
| Рендер Remotion (кроп + субтитры) | 10-30 мин | 10-30 мин |
| **Итого (с параллелизацией)** | **35-80 мин** | **16-40 мин** |
Детекция лиц и диаризация могут работать параллельно — у них разные входные данные (видеокадры vs аудиодорожка).
### Требования к памяти
| Конфигурация | Пиковое потребление RAM |
|---|---|
| Whisper base + pyannote (параллельно) | 8-12 ГБ |
| Whisper medium + pyannote (параллельно) | 12-16 ГБ |
| Рекомендуемый лимит ML-воркера | 16 ГБ, `--threads 1` |
### Фронтенд
- Превью трекинга лица: видеоплеер с наложением bounding box через canvas
- Трек спикеров в TimelinePanel (расширяет существующую систему из 4 треков)
- Контролы: слайдер уровня зума, скорость перехода, выбор спикера
- Переключатель сравнения «до/после»
- UX-флоу: загрузка подкаста -> запуск анализа (ProcessingStep) -> ревью назначений спикеров -> корректировка -> экспорт
### Ключевые цифры
| Метрика | Значение |
|---|---|
| Точность детекции лиц | ~90% (MediaPipe на talking-head контенте) |
| DER диаризации | ~10% (pyannote 3.1) |
| Точность маппинга лицо-спикер (Фаза 1) | 70-85% |
| Точность маппинга лицо-спикер (Фаза 2, TalkNet) | ~92% |
| Новые зависимости | ~280МБ (mediapipe + pyannote + torchaudio) |
| GPU обязателен? | Нет для Фазы 1; рекомендуется для Фазы 2 |
### Риски
- **Маппинг лицо-спикер** — главная нерешённая подзадача. Точность 70-85% означает, что каждое пятое назначение может быть неверным. Пользователь должен иметь возможность поправить вручную.
- **Диаризация на CPU** — бутылочное горлышко. 15-30 минут на 30-минутное видео. GPU сокращает до 1-2 минут.
- **Конфликты версий PyTorch** между Whisper и pyannote — обязательно тестировать `uv sync` перед коммитом.
- **Потеря качества видео** при кропе 16:9 -> 9:16 — остаётся только ~31.6% ширины кадра. Исходник должен быть минимум 1080p.
- **Скачивание моделей при первом запуске** — модели pyannote (~100МБ) требуют принятия лицензии на Hugging Face. Обрабатывать в Dockerfile, не в рантайме.
### MVP vs Полная версия
- **MVP (12-15 дней):** Детекция лиц на сэмплированных кадрах. Пользователь вручную выбирает, за каким лицом следить. Статический кроп на выбранное лицо. Без переключения спикеров, без диаризации. Работает для одного спикера.
- **Полная (30-45 дней):** Диаризация + маппинг лицо-спикер. Динамический кроп, следующий за активным спикером. Плавные spring()-переходы при смене спикеров. Сплит-скрин для реакций. Поддержка нескольких спикеров.
---
## Фича 4: Конвертация в вертикальные Shorts (9:16)
### Архитектура
**Пайплайн:** Сначала кроп, потом субтитры — всегда. Один проход рендеринга в Remotion через новую композицию `ShortsVideo`. Композиция рендерит в целевых размерах 9:16, применяет CSS-кроп к `<Video>` и накладывает субтитры поверх.
**Позиционирование субтитров:** Новые поля в схеме не нужны. Бэкенд корректирует `font_size`, `padding_px`, `max_width_pct` в `styleConfig` под соотношение 9:16. Remotion — это «глупый рендерер»: логика о том, что выглядит хорошо в 9:16, живёт в пресетах.
**Спецификация кропа:**
```typescript
type CropConfig = {
mode: "static" | "keyframe";
staticCrop?: { x: number; y: number; zoom: number }; // 0-1 нормализовано
keyframes?: Array<{ time: number; x: number; y: number; zoom: number }>;
interpolation?: "linear" | "ease" | "smooth";
};
```
Статический кроп — вырожденный случай ключевого кропа (один ключевой кадр).
### Бэкенд
**Новый тип джоба:** `ASPECT_CONVERT` в `JobTypeEnum`. Новая функция `crop_to_vertical()` в `media/service.py` через FFmpeg crop+scale фильтр.
**Новый тип артефакта:** `VERTICAL_VIDEO` в `ArtifactTypeEnum`.
**Пайплайн:**
1. Обрезка исходного видео до временного диапазона клипа (если из вирусной детекции)
2. Применение кропа (статический центральный кроп или face-tracking кроп из Фичи 3)
3. Загрузка в S3 по пути `{folder}/vertical/{filename}`
4. Webhook + нотификация
### Фронтенд
- Превью кропа: перетаскиваемый прямоугольник 9:16 поверх видеоплеера (CSS `object-fit: cover` + `object-position`)
- Переключатель side-by-side превью: оригинал 16:9 vs обрезанное 9:16
- Интеграция с Фичей 2: кнопка «Конвертировать в Short» на каждом одобренном вирусном клипе
- Интеграция с Фичей 3: автозаполнение региона кропа из данных детекции лица
### Время обработки
| Подход | Время (30-мин видео) |
|---|---|
| FFmpeg кроп (без субтитров) | 12-36 мин |
| Remotion кроп + субтитры (один проход) | 11-45 мин |
| FFmpeg с NVENC (аппаратное кодирование) | 3-5 мин |
### MVP vs Полная версия
- **MVP (6-8 дней):** Ручной выбор региона кропа с превью. Пользователь перетаскивает прямоугольник 9:16 поверх видео. Новая `ShortsVideo` Remotion-композиция рендерит кроп + субтитры.
- **Полная (+3-4 дня после Фичи 3):** Авто-кроп на основе данных детекции лица. Конвертация в один клик. Пакетная конвертация вирусных клипов.
---
## Рекомендуемый порядок разработки
```
Неделя 1-2: Фича 1 (Шаблоны) ████████
Неделя 2-4: Фича 2 (Вирусная детекция) ████████████████
Неделя 4-6: Фича 4 MVP (9:16 кроп) ████████████████
Неделя 6-14: Фича 3 (Трекинг лица) ████████████████████████████████████████
Неделя 14-15: Фича 4 (апгрейд) ████████
```
**Почему именно так:**
1. **Шаблоны первыми** — готовы к реализации, нулевой риск, моментальная польза для пользователей
2. **Вирусная детекция второй** — лучшее соотношение пользы к трудозатратам ($0.005/видео, 5-7 дней MVP), валидирует гипотезу о том, что пользователи хотят автоматический монтаж
3. **9:16 MVP третьим** — создаёт композицию `ShortsVideo`, которую потом расширит Фича 3; полезна сама по себе с ручным кропом
4. **Трекинг лица последним** — самая сложная, самые большие вложения; к этому моменту Фичи 2 и 4 уже валидируют спрос
5. **Апгрейд 9:16** — тривиален, когда трекинг лица уже даёт позиции
---
## Анализ стоимости
### Стоимость обработки одного видео
| Уровень | Состав | Вычисления | LLM API | Итого | Время ожидания |
|---|---|---|---|---|---|
| Только CPU | Всё на CPU | $0.05 | $0.06 | **$0.11** | 35-80 мин |
| GPU (T4) | ML на GPU, FFmpeg на CPU | $0.11 | $0.06 | **$0.17** | 16-40 мин |
| GPU + NVENC | Всё на GPU | $0.13 | $0.06 | **$0.19** | 10-15 мин |
Одиннадцать центов на CPU. Девятнадцать с GPU. Даже на самом дорогом варианте — меньше двадцати центов за полный пайплайн с AI-анализом, трекингом лица и кодированием видео.
### Месячная стоимость инфраструктуры (100 видео/месяц)
| Сценарий | Стоимость |
|---|---|
| Только CPU (текущая инфра) | ~$11 + сервер |
| Modal serverless GPU | ~$21/месяц |
| Spot GPU (g4dn.xlarge) | ~$115/месяц |
| Постоянный GPU (g4dn.xlarge 24/7) | ~$380/месяц |
**Рекомендация:** Начинаем на CPU. Переходим на Modal serverless GPU, когда время ожидания в очереди превышает 15 минут. При 500+ видео/день — смотрим на spot-инстансы.
### Предлагаемые тарифы SaaS
| Тариф | Цена | Ограничения | Себестоимость | Маржа |
|---|---|---|---|---|
| Free | $0 | Видео до 10 мин, низкий приоритет в очереди | ~$0.04/видео | Маркетинг |
| Pro | $15-30/мес | Видео до 30 мин, GPU ML | ~$0.17/видео при 50 видео | 60-80% |
| Business | $50-100/мес | Видео до 60 мин, приоритетная очередь, NVENC | ~$0.38/видео | 70-85% |
Маржинальность 60-85%. При масштабировании — только растёт.
---
## Инфраструктурные решения
### Отделение ML-сервиса
**Фаза 1:** ML остаётся в существующих Dramatiq-воркерах. MediaPipe + pyannote добавляют лишь ~280МБ к образу. PyTorch уже установлен через Whisper.
**Фаза 2:** Отдельный Docker-контейнер `ml-worker` на выделенных очередях. Тот же код, другой образ (`Dockerfile.ml`), другие лимиты ресурсов. Docker Compose profiles:
```bash
docker-compose up # По умолчанию: без ML-воркера
docker-compose --profile ml up # С ML-воркером
```
**НЕ строить отдельный HTTP-микросервис.** Dramatiq уже обеспечивает очередь джобов, ретраи, прогресс и отмену. Добавление HTTP service discovery, API-контрактов и health check — оверхед с нулевой пользой для асинхронных нагрузок.
### Немедленные оптимизации (до начала работы над новыми фичами)
| Действие | Эффект | Трудозатраты |
|---|---|---|
| Переключить PyTorch на CPU-only индекс | -800МБ размер образа | 1 час |
| Исправить дефолт `REMOTION_SERVICE_URL` в воркере | Баг-фикс | 5 мин |
| Добавить лимиты ресурсов к docker-compose сервисам | Предотвращение каскадных OOM | 30 мин |
| Разбить Dramatiq на пулы очередей (легковесные vs ML vs вычисления) | Предотвращение голодания воркеров | 2-3 часа |
Четыре задачи. Суммарно полдня. Экономия: 800МБ, один баг, и страховка от того, что ML-джоб сожрёт всю память и уронит API.
---
## Сводка по технологическому стеку
### Новые зависимости
| Пакет | Размер | Назначение | Фича |
|---|---|---|---|
| `google-generativeai` или `openai` | ~10 МБ | LLM API клиент | 2 |
| `librosa` | ~20 МБ | Анализ энергии аудио | 2 |
| `mediapipe` | ~30 МБ | Детекция лиц | 3 |
| `pyannote-audio` | ~200 МБ | Диаризация спикеров | 3 |
| `torchaudio` | ~50-80 МБ | Обработка аудио для pyannote | 3 |
| **Всего новых зависимостей** | **~310-340 МБ** | | |
### Новые бэкенд-модули
| Модуль | Назначение | Фича |
|---|---|---|
| `clips` | CRUD клипов, воркфлоу ревью | 2 |
### Новые Remotion-композиции
| Композиция | Назначение | Фича |
|---|---|---|
| `ShortsVideo` | Статический/ключевой кроп + субтитры в 9:16 | 4 |
| `AutoEditVideo` | Динамический кроп с трекингом лица + субтитры | 3 |
### Новые типы джобов
| Тип джоба | Назначение | Фича |
|---|---|---|
| `VIRAL_DETECT` | LLM-анализ транскрипции | 2 |
| `ASPECT_CONVERT` | 9:16 кроп + пере-кодирование | 4 |
| `FACE_DETECT` | Детекция bounding box лиц | 3 |
| `SPEAKER_DIARIZE` | Диаризация спикеров | 3 |
---
## Сквозные проблемы
Шесть специалистов — шесть взглядов на одну кодовую базу. Вот что они нашли:
| Проблема | Кто нашёл | Приоритет | Действие |
|---|---|---|---|
| PyTorch тащит CUDA-библиотеки на CPU-only инфру (+800МБ) | DevOps | Высокий | Переключить на CPU-only PyTorch индекс |
| Воркер с `--processes 1 --threads 2` упадёт по OOM на ML-джобах | Performance | Высокий | Разбить на пулы очередей, `--threads 1` для ML |
| `_get_job_status_sync()` течёт соединениями к БД | Performance | Высокий | Починить до добавления новых акторов |
| Нет очистки временных файлов при OOM-крэше | Performance | Средний | Добавить периодическую очистку `/tmp` или cron |
| `tasks/service.py` — 1 674 строки, скоро перевалит за 2К | Backend | Средний | Вынести бойлерплейт акторов в декоратор/контекст-менеджер |
| Дефолт `REMOTION_SERVICE_URL` в воркере неверный (`localhost:8001`) | DevOps | Средний | Исправить на `http://remotion:3001` в docker-compose |
| Ни на одном Docker-сервисе нет лимитов ресурсов | DevOps | Средний | Добавить memory/CPU лимиты на все сервисы |
| Whisper со временем нужно переместить в ML-сервис | Backend | Низкий | Запланировать при разделении ML-воркера в Фазе 2 |
| Проверка `isCurrent` слова в Captions.tsx хрупкая | Remotion | Низкий | Сравнивать по индексу, а не по тексту + start time |
---
## Отчёты специалистов
Полные выводы специалистов доступны в стенограмме сессии. Ключевые файлы, которые изучал каждый:
- **ML-инженер:** `cpv3/modules/transcription/service.py`, `cpv3/modules/tasks/service.py`, `pyproject.toml`
- **Backend-архитектор:** `cpv3/modules/tasks/service.py`, `cpv3/modules/jobs/schemas.py`, `cpv3/modules/media/service.py`, `cpv3/modules/captions/service.py`, `docker-compose.yml`
- **Remotion-инженер:** `remotion_service/src/components/Composition.tsx`, `Captions.tsx`, `Root.tsx`, `useCaptions.ts`, `useVideoMeta.ts`, все определения типов
- **Frontend-архитектор:** `src/widgets/TimelinePanel/`, `src/features/project/FragmentsStep/`, `src/shared/context/WizardContext.tsx`, `src/shared/store/notifications/`
- **DevOps-инженер:** `docker-compose.yml`, `Dockerfile`, `pyproject.toml`, `uv.lock`
- **Инженер по производительности:** `cpv3/modules/tasks/service.py`, `cpv3/modules/media/service.py`, `cpv3/modules/transcription/service.py`, `docker-compose.yml`