# Дорожная карта видеофич — Техническая консультация 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`
