Files
remotion_service/docs/consults/video-features-roadmap_v2_ru.html
T
2026-03-22 22:42:35 +03:00

1342 lines
55 KiB
HTML
Raw 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.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Video Features Roadmap v2 — API-First</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap');
:root {
--bg: #0a0a0f;
--bg-card: #12121a;
--bg-card-hover: #1a1a26;
--bg-code: #1e1e2e;
--border: #2a2a3a;
--border-accent: #3a3a5a;
--text: #e4e4ef;
--text-dim: #8888a0;
--text-muted: #5a5a72;
--accent: #7c6aef;
--accent-glow: #7c6aef40;
--green: #34d399;
--green-dim: #34d39930;
--red: #f87171;
--red-dim: #f8717130;
--yellow: #fbbf24;
--yellow-dim: #fbbf2430;
--blue: #60a5fa;
--blue-dim: #60a5fa30;
--cyan: #22d3ee;
--pink: #f472b6;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html {
scroll-behavior: smooth;
font-size: 16px;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.7;
-webkit-font-smoothing: antialiased;
}
/* ── Hero ── */
.hero {
position: relative;
padding: 5rem 2rem 4rem;
text-align: center;
overflow: hidden;
background: linear-gradient(180deg, #12102a 0%, var(--bg) 100%);
}
.hero::before {
content: '';
position: absolute;
top: -50%;
left: 50%;
transform: translateX(-50%);
width: 800px;
height: 800px;
background: radial-gradient(circle, var(--accent-glow) 0%, transparent 70%);
pointer-events: none;
}
.hero-badge {
display: inline-flex;
align-items: center;
gap: .5rem;
padding: .4rem 1rem;
border-radius: 100px;
background: var(--accent-glow);
border: 1px solid #7c6aef50;
font-size: .8rem;
font-weight: 600;
color: var(--accent);
letter-spacing: .04em;
text-transform: uppercase;
margin-bottom: 1.5rem;
}
.hero h1 {
font-size: clamp(2rem, 5vw, 3.2rem);
font-weight: 800;
letter-spacing: -.03em;
line-height: 1.15;
background: linear-gradient(135deg, #fff 0%, #b8b0f0 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
max-width: 700px;
margin: 0 auto 1.2rem;
}
.hero-meta {
color: var(--text-dim);
font-size: .9rem;
line-height: 1.8;
}
.hero-meta strong { color: var(--text); font-weight: 600; }
/* ── Navigation ── */
.toc {
position: sticky;
top: 0;
z-index: 100;
background: #0a0a0fdd;
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border-bottom: 1px solid var(--border);
padding: 0 2rem;
overflow-x: auto;
}
.toc-inner {
max-width: 1100px;
margin: 0 auto;
display: flex;
gap: .25rem;
padding: .5rem 0;
}
.toc a {
flex-shrink: 0;
padding: .45rem .85rem;
border-radius: 8px;
font-size: .78rem;
font-weight: 500;
color: var(--text-dim);
text-decoration: none;
transition: all .2s;
white-space: nowrap;
}
.toc a:hover {
color: var(--text);
background: var(--bg-card);
}
/* ── Container ── */
.container {
max-width: 1100px;
margin: 0 auto;
padding: 0 2rem;
}
/* ── Sections ── */
section {
padding: 4rem 0 2rem;
}
section + section {
border-top: 1px solid var(--border);
}
h2 {
font-size: 1.75rem;
font-weight: 800;
letter-spacing: -.025em;
margin-bottom: .75rem;
color: #fff;
}
h2 .num {
color: var(--accent);
font-weight: 700;
margin-right: .3rem;
}
h3 {
font-size: 1.15rem;
font-weight: 700;
margin: 2.2rem 0 .8rem;
color: #ddd;
letter-spacing: -.01em;
}
h4 {
font-size: .95rem;
font-weight: 600;
margin: 1.5rem 0 .5rem;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: .05em;
}
p {
margin-bottom: 1rem;
color: var(--text);
}
.lead {
font-size: 1.1rem;
color: var(--text-dim);
max-width: 750px;
line-height: 1.75;
margin-bottom: 2rem;
}
.callout {
padding: 1rem 1.25rem;
border-radius: 10px;
margin: 1.5rem 0;
font-size: .95rem;
line-height: 1.65;
}
.callout-accent {
background: var(--accent-glow);
border-left: 3px solid var(--accent);
color: #c8c0f8;
}
.callout-green {
background: var(--green-dim);
border-left: 3px solid var(--green);
color: #a7f3d0;
}
.callout-yellow {
background: var(--yellow-dim);
border-left: 3px solid var(--yellow);
color: #fde68a;
}
.callout strong { color: #fff; }
/* ── Stat cards ── */
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin: 2rem 0;
}
.stat {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 1.25rem 1.25rem 1rem;
transition: border-color .2s;
}
.stat:hover { border-color: var(--border-accent); }
.stat-value {
font-size: 2rem;
font-weight: 800;
letter-spacing: -.03em;
line-height: 1.1;
margin-bottom: .35rem;
}
.stat-value.green { color: var(--green); }
.stat-value.red { color: var(--red); }
.stat-value.blue { color: var(--blue); }
.stat-value.accent { color: var(--accent); }
.stat-value.yellow { color: var(--yellow); }
.stat-value.cyan { color: var(--cyan); }
.stat-label {
font-size: .78rem;
color: var(--text-dim);
font-weight: 500;
line-height: 1.4;
}
.stat-change {
font-size: .72rem;
font-weight: 600;
margin-top: .35rem;
display: inline-block;
padding: .15rem .5rem;
border-radius: 100px;
}
.stat-change.good { background: var(--green-dim); color: var(--green); }
.stat-change.bad { background: var(--red-dim); color: var(--red); }
.stat-change.neutral { background: var(--blue-dim); color: var(--blue); }
/* ── Tables ── */
.table-wrap {
overflow-x: auto;
margin: 1.25rem 0;
border-radius: 12px;
border: 1px solid var(--border);
}
table {
width: 100%;
border-collapse: collapse;
font-size: .85rem;
}
thead {
background: #16162a;
}
th {
text-align: left;
padding: .75rem 1rem;
font-weight: 600;
color: var(--text-dim);
font-size: .75rem;
text-transform: uppercase;
letter-spacing: .06em;
white-space: nowrap;
border-bottom: 1px solid var(--border);
}
td {
padding: .65rem 1rem;
border-bottom: 1px solid #1a1a28;
vertical-align: top;
color: var(--text);
}
tr:last-child td { border-bottom: none; }
tr:hover td { background: #16162220; }
td del {
color: var(--text-muted);
text-decoration: line-through;
text-decoration-color: var(--red);
}
td strong { color: #fff; font-weight: 600; }
.tag {
display: inline-block;
padding: .15rem .55rem;
border-radius: 6px;
font-size: .72rem;
font-weight: 600;
white-space: nowrap;
}
.tag-green { background: var(--green-dim); color: var(--green); }
.tag-red { background: var(--red-dim); color: var(--red); }
.tag-yellow { background: var(--yellow-dim); color: var(--yellow); }
.tag-blue { background: var(--blue-dim); color: var(--blue); }
.tag-accent { background: var(--accent-glow); color: var(--accent); }
/* ── Code ── */
pre {
background: var(--bg-code);
border: 1px solid var(--border);
border-radius: 10px;
padding: 1.25rem 1.5rem;
overflow-x: auto;
margin: 1rem 0;
font-size: .82rem;
line-height: 1.7;
}
code {
font-family: 'JetBrains Mono', monospace;
font-size: .82em;
}
p code, li code, td code {
background: var(--bg-code);
padding: .15rem .45rem;
border-radius: 5px;
color: var(--cyan);
border: 1px solid var(--border);
font-size: .8em;
}
/* ── Lists ── */
ul, ol {
padding-left: 1.5rem;
margin-bottom: 1rem;
}
li {
margin-bottom: .4rem;
color: var(--text);
line-height: 1.65;
}
li strong { color: #fff; }
/* ── Feature cards ── */
.feature-header {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1.5rem;
flex-wrap: wrap;
}
.feature-num {
display: flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
border-radius: 14px;
font-size: 1.3rem;
font-weight: 800;
flex-shrink: 0;
}
.feature-num-1 { background: var(--green-dim); color: var(--green); }
.feature-num-2 { background: var(--accent-glow); color: var(--accent); }
.feature-num-3 { background: var(--red-dim); color: var(--red); }
.feature-num-4 { background: var(--blue-dim); color: var(--blue); }
.feature-title {
font-size: 1.5rem;
font-weight: 800;
color: #fff;
letter-spacing: -.02em;
}
/* ── Pipeline ── */
.pipeline {
display: flex;
gap: .5rem;
align-items: center;
flex-wrap: wrap;
margin: 1.25rem 0;
}
.pipeline-step {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 10px;
padding: .6rem 1rem;
font-size: .82rem;
font-weight: 500;
color: var(--text);
position: relative;
}
.pipeline-step .num {
color: var(--accent);
font-weight: 700;
margin-right: .3rem;
}
.pipeline-arrow {
color: var(--text-muted);
font-size: 1.2rem;
flex-shrink: 0;
}
/* ── Gantt ── */
.gantt {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
overflow-x: auto;
}
.gantt-row {
display: grid;
grid-template-columns: 200px 1fr;
align-items: center;
gap: 1rem;
margin-bottom: .6rem;
font-size: .82rem;
}
.gantt-label {
font-weight: 600;
color: var(--text);
white-space: nowrap;
}
.gantt-bar-wrap {
height: 28px;
position: relative;
}
.gantt-bar {
height: 100%;
border-radius: 6px;
position: absolute;
top: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: .7rem;
font-weight: 600;
color: #fff;
min-width: 60px;
}
/* ── Arch diagram ── */
.arch-diagram {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 2rem;
margin: 1.5rem 0;
text-align: center;
}
.arch-row {
display: flex;
justify-content: center;
align-items: center;
gap: .75rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.arch-box {
padding: .6rem 1.1rem;
border-radius: 10px;
font-size: .8rem;
font-weight: 600;
border: 1px solid;
white-space: nowrap;
}
.arch-box-primary { background: #7c6aef20; border-color: #7c6aef60; color: var(--accent); }
.arch-box-service { background: #34d39920; border-color: #34d39960; color: var(--green); }
.arch-box-api { background: #60a5fa20; border-color: #60a5fa60; color: var(--blue); }
.arch-box-storage { background: #fbbf2420; border-color: #fbbf2460; color: var(--yellow); }
.arch-arrow {
color: var(--text-muted);
font-size: 1.2rem;
}
.arch-arrow-down {
display: block;
color: var(--text-muted);
font-size: 1.2rem;
margin: .3rem 0;
}
/* ── Risk items ── */
.risk {
padding: .85rem 1rem;
border-radius: 10px;
background: var(--bg-card);
border: 1px solid var(--border);
margin-bottom: .6rem;
font-size: .88rem;
line-height: 1.6;
}
.risk strong { color: var(--yellow); }
/* ── Comparison cards ── */
.comparison {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin: 1.5rem 0;
}
@media (max-width: 700px) {
.comparison { grid-template-columns: 1fr; }
.gantt-row { grid-template-columns: 140px 1fr; }
.stats { grid-template-columns: repeat(2, 1fr); }
}
.comparison-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 1.25rem;
}
.comparison-card h4 {
margin-top: 0;
font-size: .82rem;
}
.comparison-card p {
font-size: .88rem;
color: var(--text-dim);
margin: 0;
}
/* ── Footer ── */
footer {
padding: 3rem 2rem;
text-align: center;
color: var(--text-muted);
font-size: .82rem;
border-top: 1px solid var(--border);
}
footer a {
color: var(--accent);
text-decoration: none;
}
/* ── Scrollbar ── */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-accent); border-radius: 3px; }
</style>
</head>
<body>
<!-- ═══════ HERO ═══════ -->
<header class="hero">
<div class="hero-badge">v2 &mdash; API-First Architecture</div>
<h1>Дорожная карта видеофич</h1>
<div class="hero-meta">
<strong>Техническая консультация</strong> &middot; 22 марта 2026<br>
ML/AI-инженер &middot; Backend-архитектор &middot; Remotion-инженер &middot; Frontend-архитектор &middot; DevOps &middot; Performance
</div>
</header>
<!-- ═══════ NAV ═══════ -->
<nav class="toc">
<div class="toc-inner">
<a href="#delta">v1 &rarr; v2</a>
<a href="#overview">Обзор</a>
<a href="#f1">1. Шаблоны</a>
<a href="#f2">2. Вирусные моменты</a>
<a href="#f3">3. Трекинг лица</a>
<a href="#f4">4. Shorts 9:16</a>
<a href="#order">Порядок</a>
<a href="#cost">Стоимость</a>
<a href="#infra">Инфраструктура</a>
<a href="#stack">Стек</a>
<a href="#issues">Проблемы</a>
</div>
</nav>
<div class="container">
<!-- ═══════ DELTA ═══════ -->
<section id="delta">
<h2>Что изменилось по сравнению с v1</h2>
<p class="lead">
Одно принципиальное решение перевернуло всю архитектуру: вместо локальных ML-моделей — управляемые API-сервисы.
PyTorch, GPU-инфраструктура, разделение ML-воркеров, большинство проблем с памятью и временем обработки — всё это просто исчезло.
</p>
<h3>Замены API</h3>
<div class="table-wrap">
<table>
<thead>
<tr><th>v1 (локальный ML)</th><th>v2 (API-First)</th><th>Эффект</th></tr>
</thead>
<tbody>
<tr><td>Локальный Whisper (PyTorch, 20-60 мин CPU)</td><td><strong>Deepgram Nova-3</strong> API (~30 сек)</td><td>PyTorch больше не нужен вообще</td></tr>
<tr><td>Локальный pyannote.audio (15-30 мин CPU)</td><td><strong>Deepgram</strong> <code>diarize=true</code></td><td>pyannote + torchaudio — удалены</td></tr>
<tr><td>Gemini 2.5 Flash / GPT-4o-mini</td><td><strong>GigaChat Pro</strong> (Сбер)</td><td>Нативный русский: юмор, сленг, контекст</td></tr>
<tr><td>librosa (энергия аудио)</td><td><strong>Deepgram</strong> <code>sentiment=true</code></td><td>Сентимент заменяет анализ энергии</td></tr>
<tr><td>&mdash;</td><td><strong>DeepInfra</strong> (Llama, Mistral, Qwen)</td><td>Фоллбэк / A/B-тестирование LLM</td></tr>
</tbody>
</table>
</div>
<h3>Ключевые метрики</h3>
<div class="stats">
<div class="stat">
<div class="stat-value green">-75%</div>
<div class="stat-label">Размер Docker-образа</div>
<div class="stat-change good">1.72 ГБ &rarr; 400-500 МБ</div>
</div>
<div class="stat">
<div class="stat-value green">-95%</div>
<div class="stat-label">Пиковое потребление RAM</div>
<div class="stat-change good">8-16 ГБ &rarr; 400 МБ</div>
</div>
<div class="stat">
<div class="stat-value green">-85%</div>
<div class="stat-label">Время обработки</div>
<div class="stat-change good">35-80 мин &rarr; 5-10 мин</div>
</div>
<div class="stat">
<div class="stat-value yellow">+80%</div>
<div class="stat-label">Стоимость за видео</div>
<div class="stat-change bad">$0.11 &rarr; $0.20 (API)</div>
</div>
<div class="stat">
<div class="stat-value green">-88%</div>
<div class="stat-label">Новые Python-зависимости</div>
<div class="stat-change good">310-340 МБ &rarr; 40 МБ</div>
</div>
<div class="stat">
<div class="stat-value cyan">Никогда</div>
<div class="stat-label">Нужен GPU?</div>
<div class="stat-change good">Полностью исключён</div>
</div>
</div>
<div class="callout callout-accent">
Образ в четыре раза легче. RAM в сорок раз меньше. Обработка в шесть-восемь раз быстрее. Цена за единицу чуть выше, но инфраструктурные расходы сжимаются до нуля. Неплохой обмен.
</div>
<h3>Проблемы, которых больше нет</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Проблема из v1</th><th>Почему исчезла</th></tr></thead>
<tbody>
<tr><td><del>Переключить PyTorch на CPU-only индекс</del></td><td>PyTorch удалён полностью</td></tr>
<tr><td><del>OOM воркера на параллельных ML-джобах</del></td><td>Нет тяжёлого ML — стандартный воркер 4 ГБ</td></tr>
<tr><td><del>Отдельный Docker-образ для ML-воркера</del></td><td>Один лёгкий образ</td></tr>
<tr><td><del>Планирование GPU-инфраструктуры</del></td><td>Весь ML через API</td></tr>
<tr><td><del>Конфликты версий PyTorch</del></td><td>Нет PyTorch</td></tr>
<tr><td><del>Скачивание моделей при первом запуске</del></td><td>Нет локальных моделей (кроме MediaPipe, ~2 МБ)</td></tr>
<tr><td><del>Docker Compose profiles для ML</del></td><td>Не нужно</td></tr>
</tbody>
</table>
</div>
<h3>Новые проблемы</h3>
<p style="color: var(--text-dim); margin-bottom: .75rem;">Ничего бесплатного не бывает. Вот что появилось взамен:</p>
<div class="table-wrap">
<table>
<thead><tr><th>Проблема</th><th>Приоритет</th><th>Митигация</th></tr></thead>
<tbody>
<tr><td>Управление API-ключами (3 сервиса)</td><td><span class="tag tag-red">Высокий</span></td><td>Через env-переменные в settings, никогда в коде</td></tr>
<tr><td>Rate limit'ы API</td><td><span class="tag tag-red">Высокий</span></td><td>Retry с exponential backoff в акторах</td></tr>
<tr><td>Vendor lock-in</td><td><span class="tag tag-yellow">Средний</span></td><td>Абстрагировать за интерфейсами движков</td></tr>
<tr><td>API упал = обработка встала</td><td><span class="tag tag-yellow">Средний</span></td><td>Whisper как опциональный фоллбэк</td></tr>
<tr><td>$0.20 vs $0.11 за видео</td><td><span class="tag tag-blue">Низкий</span></td><td>Нулевые инфраструктурные расходы; прибыльно на любом SaaS-тарифе</td></tr>
</tbody>
</table>
</div>
</section>
<!-- ═══════ OVERVIEW ═══════ -->
<section id="overview">
<h2>Общая картина</h2>
<div class="table-wrap">
<table>
<thead><tr><th>#</th><th>Фича</th><th>Сложность</th><th>MVP</th><th>Полная</th><th>Доп. инфраструктура</th></tr></thead>
<tbody>
<tr><td><strong>1</strong></td><td>Продвинутые шаблоны Remotion</td><td><span class="tag tag-green">Легко-средне</span></td><td>3-4 дня</td><td>3-4 дня</td><td>Ничего</td></tr>
<tr><td><strong>2</strong></td><td>Детекция вирусных моментов</td><td><span class="tag tag-yellow">Средне</span></td><td><strong>3-5 дней</strong></td><td>6-10 дней</td><td>API-ключи</td></tr>
<tr><td><strong>3</strong></td><td>Авто-монтаж и трекинг лица</td><td><span class="tag tag-red">Сложно</span></td><td><strong>8-10 дней</strong></td><td>20-30 дней</td><td>MediaPipe (~30 МБ)</td></tr>
<tr><td><strong>4</strong></td><td>Shorts 9:16</td><td><span class="tag tag-yellow">Средне</span></td><td>6-8 дней</td><td>+3-4 дня после #3</td><td>Ничего</td></tr>
<tr style="background: #16162a;"><td></td><td><strong>Итого</strong></td><td></td><td><strong>20-27 дней</strong></td><td><strong>35-47 дней</strong></td><td></td></tr>
</tbody>
</table>
</div>
<div class="callout callout-green">
Реалистичный прогноз для одного разработчика: <strong>5-7 недель</strong> (все MVP) или <strong>2-3 месяца</strong> (полные версии).
</div>
</section>
<!-- ═══════ FEATURE 1 ═══════ -->
<section id="f1">
<div class="feature-header">
<div class="feature-num feature-num-1">1</div>
<div class="feature-title">Продвинутые шаблоны Remotion</div>
</div>
<div class="callout callout-green">
<strong>Без изменений по сравнению с v1.</strong> Эта фича не зависит от ML. Спецификация и план уже написаны &mdash; бери и делай.
</div>
<p><strong>Что делаем:</strong> Расширяем <code>CaptionStyleSchema</code> четырьмя новыми стилями подсветки (<code>pop_in</code>, <code>karaoke</code>, <code>bounce</code>, <code>glow_pulse</code>), двумя переходами (<code>zoom_in</code>, <code>drop_in</code>), тремя полями. Два системных пресета: "Shorts" и "Podcast".</p>
<p><strong>Где трогаем код:</strong> Расширение схемы в Remotion + бэкенде, логика рендеринга в <code>Captions.tsx</code>, Alembic-миграция для пресетов, контролы в StyleEditor на фронте.</p>
</section>
<!-- ═══════ FEATURE 2 ═══════ -->
<section id="f2">
<div class="feature-header">
<div class="feature-num feature-num-2">2</div>
<div class="feature-title">Детекция вирусных моментов</div>
</div>
<h3>Архитектура (v2 &mdash; API-First)</h3>
<p class="lead">
В v1 мы планировали гонять LLM по тексту и считать энергию аудио через librosa.
В v2 подход элегантнее: один вызов Deepgram даёт транскрипцию, разметку спикеров и сентимент-анализ &mdash; три результата за одну цену.
А текст анализирует GigaChat, которому русский язык родной.
</p>
<p><strong>Транскрипция:</strong> Deepgram Nova-3 API с <code>diarize=true</code> + <code>sentiment=true</code>. Один вызов &mdash; пословные таймстемпы, метки спикеров, оценка сентимента. Стоимость: $0.0053/мин ($0.16 за 30-минутное видео). Обработка: ~30 секунд.</p>
<p><strong>LLM-анализ:</strong> GigaChat Pro (Сбер) &mdash; нативная русскоязычная LLM. Лучше ловит русский юмор, культурные отсылки, сленг и вирусные паттерны. Фоллбэк: DeepInfra (Llama 3.1 70B или Qwen) для A/B-тестирования.</p>
<p><strong>Аудио-подкрепление:</strong> Сентимент от Deepgram заменяет librosa. Высокий сентимент коррелирует с вирусными моментами.</p>
<h4>Пайплайн</h4>
<div class="pipeline">
<div class="pipeline-step"><span class="num">1</span> Deepgram транскрипция</div>
<div class="pipeline-arrow">&rarr;</div>
<div class="pipeline-step"><span class="num">2</span> Конвертация в Document</div>
<div class="pipeline-arrow">&rarr;</div>
<div class="pipeline-step"><span class="num">3</span> GigaChat анализ</div>
<div class="pipeline-arrow">&rarr;</div>
<div class="pipeline-step"><span class="num">4</span> Постобработка</div>
<div class="pipeline-arrow">&rarr;</div>
<div class="pipeline-step"><span class="num">5</span> Сохранение в clips</div>
</div>
<h3>Бэкенд</h3>
<p><strong>Новый модуль:</strong> <code>clips</code> (models, schemas, repository, service, router).</p>
<h4>Модель клипа</h4>
<pre><code>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, теги, хэштеги, данные сентимента)
}</code></pre>
<p><strong>Новый тип джоба:</strong> <code>VIRAL_DETECT</code> в <code>JobTypeEnum</code>. GigaChat через <code>httpx</code> из Dramatiq-воркера.</p>
<p><strong>Расширение движков:</strong> <code>engine: "whisper" | "google" | "deepgram"</code>. Deepgram &mdash; дефолт.</p>
<h4>Интеграция с LLM</h4>
<ul>
<li>GigaChat API через <code>httpx</code> (OAuth2 token auth через Sber ID)</li>
<li>DeepInfra как фоллбэк (OpenAI-совместимый API)</li>
<li>Промпты в <code>cpv3/infrastructure/prompts/viral_detection_v1.txt</code></li>
<li>Настройки: <code>GIGACHAT_CLIENT_ID</code>, <code>GIGACHAT_CLIENT_SECRET</code>, <code>DEEPINFRA_API_KEY</code>, <code>DEEPGRAM_API_KEY</code></li>
</ul>
<h3>Ключевые цифры</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Метрика</th><th>v1</th><th>v2</th></tr></thead>
<tbody>
<tr><td>Время транскрипции</td><td>Зависит от Whisper</td><td><strong>~30 сек</strong> (Deepgram)</td></tr>
<tr><td>Время LLM-анализа</td><td>10-20 сек</td><td>10-20 сек</td></tr>
<tr><td>Общее время</td><td>10-20 сек (после транскрипции)</td><td><strong>40-50 сек</strong></td></tr>
<tr><td>Стоимость за видео</td><td>~$0.005</td><td><strong>~$0.17</strong></td></tr>
<tr><td>Точность (precision)</td><td>50-70%</td><td><strong>60-80%</strong></td></tr>
<tr><td>Новые зависимости</td><td>~30 МБ</td><td><strong>~0 МБ</strong></td></tr>
<tr><td>Срок MVP</td><td>5-7 дней</td><td><strong>3-5 дней</strong></td></tr>
</tbody>
</table>
</div>
<div class="callout callout-accent">
Стоимость выросла с полкопейки до семнадцати центов &mdash; но зато ноль зависимостей, ноль локальных моделей и на два дня быстрее в разработке.
</div>
<h3>Риски</h3>
<div class="risk"><strong>Доступность GigaChat API</strong> &mdash; uptime может быть ниже, чем у Google/OpenAI. Митигация: фоллбэк на DeepInfra.</div>
<div class="risk"><strong>Structured output GigaChat</strong> &mdash; проверить JSON mode / function calling. Тестировать рано.</div>
<div class="risk"><strong>WER Deepgram на русском</strong> &mdash; ~10-12% (Nova-3). Сопоставимо с Whisper <code>medium</code>. Достаточно.</div>
<div class="risk"><strong>Визуальные моменты</strong> по-прежнему не ловятся (~20-30%).</div>
<h3>MVP vs Полная версия</h3>
<div class="comparison">
<div class="comparison-card">
<h4>MVP &mdash; 3-5 дней</h4>
<p>Deepgram + GigaChat. Клипы со скорами. Пользователь ревьюит. Без анализа энергии.</p>
</div>
<div class="comparison-card">
<h4>Полная &mdash; 6-10 дней</h4>
<p>Сентимент-скоринг, few-shot тюнинг, пакетная обработка, экспорт в 9:16, A/B через DeepInfra.</p>
</div>
</div>
</section>
<!-- ═══════ FEATURE 3 ═══════ -->
<section id="f3">
<div class="feature-header">
<div class="feature-num feature-num-3">3</div>
<div class="feature-title">Авто-монтаж и трекинг лица</div>
</div>
<p class="lead">
В v1 эта фича была монстром: pyannote на CPU 30 минут жуёт аудио, PyTorch конфликтует с Whisper, GPU-воркеры, 16 ГБ RAM.
В v2 всё, что касалось диаризации, ушло в один API-вызов Deepgram. Осталась только детекция лиц через MediaPipe &mdash; лёгкая библиотека, работающая на CPU за минуту-две.
</p>
<h3>Архитектура (v2 &mdash; API-First)</h3>
<p><strong>Детекция лиц:</strong> MediaPipe BlazeFace. Apache 2.0, ~2МБ, 30-60 FPS на CPU. Сэмплируем на 3 FPS. <strong>Единственный оставшийся локальный ML-компонент.</strong></p>
<p><strong>Диаризация спикеров:</strong> Deepgram API с <code>diarize=true</code> (~30 сек на 30-мин видео). Полностью заменяет pyannote.</p>
<h4>Маппинг лицо-спикер</h4>
<div class="comparison">
<div class="comparison-card">
<h4>Фаза 1</h4>
<p>Временная корреляция: треки лиц &times; сегменты спикеров. 70-85% точности. ~100 строк Python. Ноль зависимостей.</p>
</div>
<div class="comparison-card">
<h4>Фаза 2</h4>
<p>TalkNet-ASD (анализ губ + аудио). ~92% точности. Нужен GPU. Можно откладывать бесконечно.</p>
</div>
</div>
<p><strong>Видео-композитинг:</strong> CSS <code>transform: scale() translate()</code> в Remotion. GPU-ускоренная браузерная операция &mdash; бесплатная по производительности.</p>
<h4>Remotion-композиции</h4>
<div class="table-wrap">
<table>
<thead><tr><th>Композиция</th><th>Назначение</th><th>Фаза</th></tr></thead>
<tbody>
<tr><td><code>CaptionedVideo</code></td><td>Субтитры на нативном видео</td><td><span class="tag tag-green">Текущая</span></td></tr>
<tr><td><code>ShortsVideo</code></td><td>Кроп + субтитры в 9:16</td><td><span class="tag tag-blue">Фича 4</span></td></tr>
<tr><td><code>AutoEditVideo</code></td><td>Трекинг лица + монтаж + субтитры</td><td><span class="tag tag-accent">Фича 3</span></td></tr>
</tbody>
</table>
</div>
<h3>Время обработки (30-мин 1080p видео)</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Шаг</th><th>v1 (CPU)</th><th>v2 (API-First)</th></tr></thead>
<tbody>
<tr><td>Транскрипция + диаризация Deepgram</td><td>&mdash;</td><td><strong>~30 сек</strong></td></tr>
<tr><td>Детекция лиц (MediaPipe, 3 FPS)</td><td>1-2 мин</td><td>1-2 мин</td></tr>
<tr><td><del>Диаризация (pyannote)</del></td><td><del>15-30 мин</del></td><td><strong>Включено в Deepgram</strong></td></tr>
<tr><td>Маппинг лицо-спикер</td><td>&lt; 1 сек</td><td>&lt; 1 сек</td></tr>
<tr><td>Remotion рендер</td><td>10-30 мин</td><td>10-30 мин</td></tr>
<tr style="background: #16162a;"><td><strong>Итого</strong></td><td><strong>35-80 мин</strong></td><td><strong>12-33 мин</strong></td></tr>
</tbody>
</table>
</div>
<div class="callout callout-green">
<strong>Бутылочное горлышко в 15-30 минут на диаризацию &mdash; полностью ликвидировано.</strong>
</div>
<h3>Требования к памяти</h3>
<div class="stats">
<div class="stat">
<div class="stat-value red">8-16 ГБ</div>
<div class="stat-label">v1 &mdash; пиковое RAM</div>
</div>
<div class="stat">
<div class="stat-value green">~400 МБ</div>
<div class="stat-label">v2 &mdash; пиковое RAM</div>
</div>
</div>
<div class="callout callout-accent">
С 16 гигабайт до 400 мегабайт. В сорок раз. Это не оптимизация &mdash; это другая категория задач.
</div>
<h3>Ключевые цифры</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Метрика</th><th>v1</th><th>v2</th></tr></thead>
<tbody>
<tr><td>Время диаризации</td><td>15-30 мин (CPU) / 1-2 мин (GPU)</td><td><strong>~30 сек</strong> (API)</td></tr>
<tr><td>Время детекции лиц</td><td>1-2 мин</td><td>1-2 мин</td></tr>
<tr><td>Общее время анализа</td><td>17-33 мин (CPU)</td><td><strong>~2 мин</strong></td></tr>
<tr><td>Полный пайплайн</td><td>35-80 мин (CPU)</td><td><strong>12-33 мин</strong></td></tr>
<tr><td>Пиковое RAM</td><td>8-16 ГБ</td><td><strong>~400 МБ</strong></td></tr>
<tr><td>Зависимости</td><td>~280 МБ</td><td><strong>~30 МБ</strong></td></tr>
<tr><td>GPU нужен?</td><td>Фаза 2 рекомендуется</td><td><strong>Никогда</strong></td></tr>
<tr><td>Срок MVP</td><td>12-15 дней</td><td><strong>8-10 дней</strong></td></tr>
</tbody>
</table>
</div>
<h3>Риски</h3>
<div class="risk"><strong>Маппинг лицо-спикер</strong> &mdash; 70-85% точности. Каждое пятое назначение может быть неверным. Пользователь должен поправить вручную.</div>
<div class="risk"><strong>Deepgram DER</strong> &mdash; ~12-15% vs ~10% у pyannote. Приемлемо.</div>
<div class="risk"><strong>Потеря качества при кропе</strong> &mdash; без изменений.</div>
<div class="risk"><strong>TalkNet-ASD отложен</strong> &mdash; если нужен GPU, разберёмся когда дойдём.</div>
<h3>MVP vs Полная версия</h3>
<div class="comparison">
<div class="comparison-card">
<h4>MVP &mdash; 8-10 дней</h4>
<p>Детекция лиц + Deepgram спикеры. Временная корреляция. Ручная коррекция. Статический кроп.</p>
</div>
<div class="comparison-card">
<h4>Полная &mdash; 20-30 дней</h4>
<p>Динамический кроп. Плавные переходы. Сплит-скрин. Мульти-спикер. Опциональный TalkNet-ASD.</p>
</div>
</div>
</section>
<!-- ═══════ FEATURE 4 ═══════ -->
<section id="f4">
<div class="feature-header">
<div class="feature-num feature-num-4">4</div>
<div class="feature-title">Конвертация в Shorts (9:16)</div>
</div>
<div class="callout callout-green"><strong>Без изменений по сравнению с v1.</strong> Не зависит от ML.</div>
<p><strong>Пайплайн:</strong> Сначала кроп, потом субтитры &mdash; всегда. Один проход Remotion через <code>ShortsVideo</code>.</p>
<h4>Спецификация кропа</h4>
<pre><code>type CropConfig = {
mode: "static" | "keyframe";
staticCrop?: { x: number; y: number; zoom: number };
keyframes?: Array&lt;{ time: number; x: number; y: number; zoom: number }&gt;;
interpolation?: "linear" | "ease" | "smooth";
};</code></pre>
<h3>Бэкенд</h3>
<p><strong>Новый джоб:</strong> <code>ASPECT_CONVERT</code>. Функция <code>crop_to_vertical()</code> в <code>media/service.py</code>.</p>
<p><strong>Новый артефакт:</strong> <code>VERTICAL_VIDEO</code> в <code>ArtifactTypeEnum</code>.</p>
<h3>Фронтенд</h3>
<ul>
<li>Перетаскиваемый прямоугольник 9:16 поверх видеоплеера</li>
<li>Side-by-side превью: оригинал vs обрезанное</li>
<li>Кнопка &laquo;Конвертировать в Short&raquo; на одобренных вирусных клипах</li>
<li>Автозаполнение кропа из данных детекции лица</li>
</ul>
<h3>Время обработки</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Подход</th><th>Время (30-мин видео)</th></tr></thead>
<tbody>
<tr><td>FFmpeg кроп (без субтитров)</td><td>12-36 мин</td></tr>
<tr><td>Remotion кроп + субтитры</td><td>11-45 мин</td></tr>
<tr><td>FFmpeg с NVENC</td><td>3-5 мин</td></tr>
</tbody>
</table>
</div>
<h3>MVP vs Полная версия</h3>
<div class="comparison">
<div class="comparison-card">
<h4>MVP &mdash; 6-8 дней</h4>
<p>Ручной выбор кропа с превью. Remotion-композиция <code>ShortsVideo</code>.</p>
</div>
<div class="comparison-card">
<h4>Полная &mdash; +3-4 дня после Фичи 3</h4>
<p>Авто-кроп по лицу. Один клик. Пакетный экспорт.</p>
</div>
</div>
</section>
<!-- ═══════ BUILD ORDER ═══════ -->
<section id="order">
<h2>Рекомендуемый порядок разработки</h2>
<div class="gantt">
<div class="gantt-row">
<div class="gantt-label">Фича 1 &mdash; Шаблоны</div>
<div class="gantt-bar-wrap">
<div class="gantt-bar" style="left: 0%; width: 18%; background: linear-gradient(135deg, #34d399, #059669);">Нед 1-2</div>
</div>
</div>
<div class="gantt-row">
<div class="gantt-label">Фича 2 &mdash; Вирусная детекция</div>
<div class="gantt-bar-wrap">
<div class="gantt-bar" style="left: 14%; width: 14%; background: linear-gradient(135deg, #7c6aef, #5b4acf);">Нед 2-3</div>
</div>
</div>
<div class="gantt-row">
<div class="gantt-label">Фича 4 &mdash; 9:16 кроп</div>
<div class="gantt-bar-wrap">
<div class="gantt-bar" style="left: 23%; width: 22%; background: linear-gradient(135deg, #60a5fa, #3b82f6);">Нед 3-5</div>
</div>
</div>
<div class="gantt-row">
<div class="gantt-label">Фича 3 &mdash; Трекинг лица</div>
<div class="gantt-bar-wrap">
<div class="gantt-bar" style="left: 41%; width: 46%; background: linear-gradient(135deg, #f87171, #dc2626);">Нед 5-10</div>
</div>
</div>
<div class="gantt-row">
<div class="gantt-label">Фича 4 &mdash; апгрейд</div>
<div class="gantt-bar-wrap">
<div class="gantt-bar" style="left: 86%; width: 14%; background: linear-gradient(135deg, #60a5fa, #3b82f6);">Нед 10-11</div>
</div>
</div>
</div>
<h3>Почему именно так</h3>
<ol>
<li><strong>Шаблоны первыми</strong> &mdash; готовы, нулевой риск, моментальная польза</li>
<li><strong>Вирусная детекция второй</strong> &mdash; самый быстрый ROI (3-5 дней MVP), валидирует спрос</li>
<li><strong>9:16 MVP третьим</strong> &mdash; создаёт <code>ShortsVideo</code>, полезна сама по себе</li>
<li><strong>Трекинг лица последним</strong> &mdash; самая сложная, но теперь проще без pyannote/GPU</li>
<li><strong>Апгрейд 9:16</strong> &mdash; тривиален, когда трекинг даёт позиции</li>
</ol>
</section>
<!-- ═══════ COST ═══════ -->
<section id="cost">
<h2>Анализ стоимости</h2>
<h3>Стоимость одного видео (30-мин, все фичи)</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Компонент</th><th>v1 (локальный ML)</th><th>v2 (API-First)</th></tr></thead>
<tbody>
<tr><td>Транскрипция + диаризация</td><td>$0.07 compute</td><td><strong>$0.16</strong> (Deepgram)</td></tr>
<tr><td>LLM вирусная детекция</td><td>$0.005 (Gemini)</td><td><strong>$0.01</strong> (GigaChat)</td></tr>
<tr><td>Детекция лиц</td><td>$0.002</td><td>$0.002</td></tr>
<tr><td>FFmpeg/Remotion рендер</td><td>$0.02</td><td>$0.02</td></tr>
<tr style="background: #16162a;"><td><strong>Итого</strong></td><td><strong>$0.11</strong></td><td><strong>$0.20</strong></td></tr>
</tbody>
</table>
</div>
<div class="callout callout-accent">
Двадцать центов. За полный пайплайн: транскрипция, диаризация, поиск вирусных моментов, детекция лиц, рендер. <strong>Двадцать центов.</strong>
</div>
<h3>Сравнение месячных расходов</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Масштаб</th><th>v1</th><th>v2</th></tr></thead>
<tbody>
<tr><td>100 видео/мес</td><td>$11 + сервер + $0-380 GPU</td><td><strong>$20 API + сервер</strong></td></tr>
<tr><td>500 видео/мес</td><td>$255-435</td><td><strong>$100 + сервер</strong></td></tr>
<tr><td>1 000 видео/мес</td><td>$490</td><td><strong>$200 + сервер</strong></td></tr>
<tr><td>5 000 видео/мес</td><td>$930</td><td><strong>$1 000 + сервер</strong></td></tr>
</tbody>
</table>
</div>
<div class="callout callout-yellow">
<strong>Точка безубыточности:</strong> ~2 000-3 000 видео/месяц. Ниже &mdash; API дешевле. А без GPU, ML-инфры и OOM-крэшей реальный breakeven ещё выше.
</div>
<h3>Предлагаемые тарифы SaaS</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Тариф</th><th>Цена</th><th>Ограничения</th><th>Себестоимость</th><th>Маржа</th></tr></thead>
<tbody>
<tr><td><strong>Free</strong></td><td>$0</td><td>Видео до 10 мин, 5/мес</td><td>~$0.07</td><td><span class="tag tag-blue">Маркетинг</span></td></tr>
<tr><td><strong>Pro</strong></td><td>$15-30/мес</td><td>До 30 мин, 50/мес</td><td>~$0.20</td><td><span class="tag tag-green">50-70%</span></td></tr>
<tr><td><strong>Business</strong></td><td>$50-100/мес</td><td>До 60 мин, 200/мес</td><td>~$0.35</td><td><span class="tag tag-green">65-80%</span></td></tr>
</tbody>
</table>
</div>
</section>
<!-- ═══════ INFRA ═══════ -->
<section id="infra">
<h2>Инфраструктура (v2 &mdash; упрощённая)</h2>
<h3>Архитектура</h3>
<div class="arch-diagram">
<div class="arch-row">
<div class="arch-box arch-box-primary">Frontend</div>
<div class="arch-arrow">&rarr;</div>
<div class="arch-box arch-box-primary">Backend API</div>
<div class="arch-arrow">&rarr;</div>
<div class="arch-box arch-box-service">Dramatiq-воркер (MediaPipe)</div>
</div>
<div class="arch-arrow-down">&darr;</div>
<div class="arch-row">
<div class="arch-box arch-box-storage">PostgreSQL</div>
<div class="arch-box arch-box-storage">Redis</div>
<div class="arch-box arch-box-storage">S3/MinIO</div>
<div class="arch-box arch-box-service">Remotion</div>
</div>
<div class="arch-arrow-down">&darr;</div>
<div class="arch-row">
<div class="arch-box arch-box-api">Deepgram API</div>
<div class="arch-box arch-box-api">GigaChat API</div>
<div class="arch-box arch-box-api">DeepInfra</div>
</div>
<p style="margin-top: 1rem; color: var(--text-muted); font-size: .8rem;">Нет ML-воркера. Нет GPU. Нет Docker Compose profiles. Один воркер обрабатывает всё.</p>
</div>
<h3>Docker-образ</h3>
<div class="stats">
<div class="stat">
<div class="stat-value red">1.72 ГБ</div>
<div class="stat-label">v1: python + PyTorch + Whisper + CUDA</div>
</div>
<div class="stat">
<div class="stat-value green">400-500 МБ</div>
<div class="stat-label">v2: python + mediapipe</div>
</div>
<div class="stat">
<div class="stat-value red">16 ГБ</div>
<div class="stat-label">v1: рекомендованная RAM</div>
</div>
<div class="stat">
<div class="stat-value green">4 ГБ</div>
<div class="stat-label">v2: достаточная RAM</div>
</div>
</div>
<h3>Разделение ML-сервиса не требуется</h3>
<p>MediaPipe (~30МБ, ~400МБ RAM) &mdash; это всё, что работает локально. Не нужны:</p>
<ul>
<li>Отдельный контейнер ML-воркера</li>
<li>Docker Compose profiles для ML</li>
<li>GPU-инфраструктура</li>
<li>Выделенные очереди Dramatiq для ML</li>
</ul>
<p>Стандартный воркер с <code>--processes 1 --threads 2</code> справляется со всем.</p>
<h4>Новые настройки</h4>
<pre><code># Deepgram
deepgram_api_key: str = Field(default="", alias="DEEPGRAM_API_KEY")
# GigaChat (Сбер)
gigachat_client_id: str = Field(default="", alias="GIGACHAT_CLIENT_ID")
gigachat_client_secret: str = Field(default="", alias="GIGACHAT_CLIENT_SECRET")
# DeepInfra (фоллбэк LLM)
deepinfra_api_key: str = Field(default="", alias="DEEPINFRA_API_KEY")
# Конфигурация LLM
llm_provider: str = Field(default="gigachat", alias="LLM_PROVIDER")
llm_viral_prompt_version: str = Field(default="v1", alias="LLM_VIRAL_PROMPT_VERSION")</code></pre>
</section>
<!-- ═══════ STACK ═══════ -->
<section id="stack">
<h2>Сводка по технологическому стеку</h2>
<h3>Новые зависимости (v2)</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Пакет</th><th>Размер</th><th>Назначение</th><th>Фича</th></tr></thead>
<tbody>
<tr><td><code>mediapipe</code></td><td>~30 МБ</td><td>Детекция лиц (CPU)</td><td>3</td></tr>
<tr><td><code>httpx</code></td><td>Уже установлен</td><td>API-вызовы</td><td>2, 3</td></tr>
<tr style="background: #16162a;"><td><strong>Итого</strong></td><td><strong>~30 МБ</strong></td><td></td><td></td></tr>
</tbody>
</table>
</div>
<h3>Удалённые зависимости</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Пакет</th><th>Сэкономлено</th><th>Заменён на</th></tr></thead>
<tbody>
<tr><td><del><code>openai-whisper</code></del></td><td>~50 МБ + PyTorch ~2 ГБ</td><td>Deepgram</td></tr>
<tr><td><del><code>pyannote-audio</code></del></td><td>~200 МБ</td><td>Deepgram</td></tr>
<tr><td><del><code>torchaudio</code></del></td><td>~50-80 МБ</td><td>Deepgram</td></tr>
<tr><td><del><code>librosa</code></del></td><td>~20 МБ</td><td>Deepgram sentiment</td></tr>
<tr style="background: #16162a;"><td><strong>Итого удалено</strong></td><td><strong>~2.3 ГБ</strong></td><td></td></tr>
</tbody>
</table>
</div>
<div class="callout callout-green">
Добавили 30 мегабайт. Удалили 2.3 гигабайта. <strong>Соотношение 1:77.</strong>
</div>
<h3>Новые компоненты</h3>
<div class="stats">
<div class="stat">
<div class="stat-value accent">clips</div>
<div class="stat-label">Бэкенд-модуль: CRUD + ревью клипов</div>
</div>
<div class="stat">
<div class="stat-value blue">ShortsVideo</div>
<div class="stat-label">Remotion: кроп + субтитры 9:16</div>
</div>
<div class="stat">
<div class="stat-value cyan">AutoEditVideo</div>
<div class="stat-label">Remotion: трекинг лица + субтитры</div>
</div>
</div>
<h4>Новые типы джобов</h4>
<div class="table-wrap">
<table>
<thead><tr><th>Тип</th><th>Назначение</th><th>Фича</th></tr></thead>
<tbody>
<tr><td><code>VIRAL_DETECT</code></td><td>GigaChat анализ транскрипции</td><td>2</td></tr>
<tr><td><code>ASPECT_CONVERT</code></td><td>9:16 кроп + пере-кодирование</td><td>4</td></tr>
<tr><td><code>FACE_DETECT</code></td><td>Детекция bounding box (MediaPipe)</td><td>3</td></tr>
</tbody>
</table>
</div>
<div class="callout callout-yellow">
<code>SPEAKER_DIARIZE</code> <strong>больше не является отдельным типом джоба</strong> &mdash; диаризация включена в транскрипцию Deepgram.
</div>
<h4>Расширение движков транскрипции</h4>
<pre><code>engine: Literal["whisper", "google", "deepgram"] = "deepgram"</code></pre>
<p>Deepgram &mdash; дефолт. Whisper &mdash; опциональный фоллбэк (<code>uv sync --group whisper</code>).</p>
</section>
<!-- ═══════ ISSUES ═══════ -->
<section id="issues">
<h2>Сквозные проблемы (v2)</h2>
<h3>Остались из v1</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Проблема</th><th>Приоритет</th><th>Действие</th></tr></thead>
<tbody>
<tr><td><code>_get_job_status_sync()</code> течёт соединениями к БД</td><td><span class="tag tag-red">Высокий</span></td><td>Починить до новых акторов</td></tr>
<tr><td><code>tasks/service.py</code> &mdash; 1 674 строки</td><td><span class="tag tag-yellow">Средний</span></td><td>Вынести бойлерплейт акторов</td></tr>
<tr><td><code>REMOTION_SERVICE_URL</code> default неверный</td><td><span class="tag tag-yellow">Средний</span></td><td>Исправить на <code>http://remotion:3001</code></td></tr>
<tr><td>Нет лимитов ресурсов на Docker-сервисах</td><td><span class="tag tag-yellow">Средний</span></td><td>Добавить memory/CPU лимиты</td></tr>
<tr><td>Нет очистки /tmp при OOM</td><td><span class="tag tag-yellow">Средний</span></td><td>Периодическая очистка / cron</td></tr>
<tr><td><code>isCurrent</code> в Captions.tsx хрупкая</td><td><span class="tag tag-blue">Низкий</span></td><td>Сравнивать по индексу</td></tr>
</tbody>
</table>
</div>
<h3>Новые в v2</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Проблема</th><th>Приоритет</th><th>Действие</th></tr></thead>
<tbody>
<tr><td>Управление API-ключами (3 сервиса)</td><td><span class="tag tag-red">Высокий</span></td><td>Всё через env-переменные, никогда в коде</td></tr>
<tr><td>Rate limit'ы API</td><td><span class="tag tag-red">Высокий</span></td><td>Retry + exponential backoff</td></tr>
<tr><td>Vendor lock-in</td><td><span class="tag tag-yellow">Средний</span></td><td>Интерфейс движков (существующий паттерн)</td></tr>
<tr><td>Зависимость от сети</td><td><span class="tag tag-yellow">Средний</span></td><td>Whisper как фоллбэк</td></tr>
<tr><td>Deepgram &rarr; Document конвертация</td><td><span class="tag tag-yellow">Средний</span></td><td>Конвертер под существующую схему</td></tr>
<tr><td>GigaChat OAuth2 token refresh</td><td><span class="tag tag-yellow">Средний</span></td><td>Кэш + авто-обновление в <code>infrastructure/</code></td></tr>
</tbody>
</table>
</div>
<h3>Ликвидированные из v1</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Проблема</th><th>Почему исчезла</th></tr></thead>
<tbody>
<tr><td><del>PyTorch CPU-only индекс</del></td><td>PyTorch удалён полностью</td></tr>
<tr><td><del>OOM воркера на ML-джобах</del></td><td>Нет тяжёлого ML локально</td></tr>
<tr><td><del>Docker-образ ML-воркера</del></td><td>Один лёгкий образ</td></tr>
<tr><td><del>GPU-инфраструктура</del></td><td>Весь ML через API</td></tr>
<tr><td><del>Конфликты версий PyTorch</del></td><td>Нет PyTorch</td></tr>
<tr><td><del>Скачивание моделей при первом запуске</del></td><td>Нет локальных моделей</td></tr>
</tbody>
</table>
</div>
</section>
</div><!-- /.container -->
<footer>
<p>Coffee Project &middot; Техническая консультация v2 &middot; 22 марта 2026</p>
<p style="margin-top: .5rem;">Отчёты специалистов доступны в стенограмме сессии</p>
</footer>
</body>
</html>