27e03cc56c
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1342 lines
55 KiB
HTML
1342 lines
55 KiB
HTML
<!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 — API-First Architecture</div>
|
||
<h1>Дорожная карта видеофич</h1>
|
||
<div class="hero-meta">
|
||
<strong>Техническая консультация</strong> · 22 марта 2026<br>
|
||
ML/AI-инженер · Backend-архитектор · Remotion-инженер · Frontend-архитектор · DevOps · Performance
|
||
</div>
|
||
</header>
|
||
|
||
<!-- ═══════ NAV ═══════ -->
|
||
<nav class="toc">
|
||
<div class="toc-inner">
|
||
<a href="#delta">v1 → 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>—</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 ГБ → 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 ГБ → 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 мин → 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 → $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 МБ → 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. Спецификация и план уже написаны — бери и делай.
|
||
</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 — API-First)</h3>
|
||
<p class="lead">
|
||
В v1 мы планировали гонять LLM по тексту и считать энергию аудио через librosa.
|
||
В v2 подход элегантнее: один вызов Deepgram даёт транскрипцию, разметку спикеров и сентимент-анализ — три результата за одну цену.
|
||
А текст анализирует GigaChat, которому русский язык родной.
|
||
</p>
|
||
|
||
<p><strong>Транскрипция:</strong> Deepgram Nova-3 API с <code>diarize=true</code> + <code>sentiment=true</code>. Один вызов — пословные таймстемпы, метки спикеров, оценка сентимента. Стоимость: $0.0053/мин ($0.16 за 30-минутное видео). Обработка: ~30 секунд.</p>
|
||
|
||
<p><strong>LLM-анализ:</strong> GigaChat Pro (Сбер) — нативная русскоязычная 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">→</div>
|
||
<div class="pipeline-step"><span class="num">2</span> Конвертация в Document</div>
|
||
<div class="pipeline-arrow">→</div>
|
||
<div class="pipeline-step"><span class="num">3</span> GigaChat анализ</div>
|
||
<div class="pipeline-arrow">→</div>
|
||
<div class="pipeline-step"><span class="num">4</span> Постобработка</div>
|
||
<div class="pipeline-arrow">→</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 — дефолт.</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">
|
||
Стоимость выросла с полкопейки до семнадцати центов — но зато ноль зависимостей, ноль локальных моделей и на два дня быстрее в разработке.
|
||
</div>
|
||
|
||
<h3>Риски</h3>
|
||
<div class="risk"><strong>Доступность GigaChat API</strong> — uptime может быть ниже, чем у Google/OpenAI. Митигация: фоллбэк на DeepInfra.</div>
|
||
<div class="risk"><strong>Structured output GigaChat</strong> — проверить JSON mode / function calling. Тестировать рано.</div>
|
||
<div class="risk"><strong>WER Deepgram на русском</strong> — ~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 — 3-5 дней</h4>
|
||
<p>Deepgram + GigaChat. Клипы со скорами. Пользователь ревьюит. Без анализа энергии.</p>
|
||
</div>
|
||
<div class="comparison-card">
|
||
<h4>Полная — 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 — лёгкая библиотека, работающая на CPU за минуту-две.
|
||
</p>
|
||
|
||
<h3>Архитектура (v2 — 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>Временная корреляция: треки лиц × сегменты спикеров. 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-ускоренная браузерная операция — бесплатная по производительности.</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>—</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>< 1 сек</td><td>< 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 минут на диаризацию — полностью ликвидировано.</strong>
|
||
</div>
|
||
|
||
<h3>Требования к памяти</h3>
|
||
<div class="stats">
|
||
<div class="stat">
|
||
<div class="stat-value red">8-16 ГБ</div>
|
||
<div class="stat-label">v1 — пиковое RAM</div>
|
||
</div>
|
||
<div class="stat">
|
||
<div class="stat-value green">~400 МБ</div>
|
||
<div class="stat-label">v2 — пиковое RAM</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="callout callout-accent">
|
||
С 16 гигабайт до 400 мегабайт. В сорок раз. Это не оптимизация — это другая категория задач.
|
||
</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> — 70-85% точности. Каждое пятое назначение может быть неверным. Пользователь должен поправить вручную.</div>
|
||
<div class="risk"><strong>Deepgram DER</strong> — ~12-15% vs ~10% у pyannote. Приемлемо.</div>
|
||
<div class="risk"><strong>Потеря качества при кропе</strong> — без изменений.</div>
|
||
<div class="risk"><strong>TalkNet-ASD отложен</strong> — если нужен GPU, разберёмся когда дойдём.</div>
|
||
|
||
<h3>MVP vs Полная версия</h3>
|
||
<div class="comparison">
|
||
<div class="comparison-card">
|
||
<h4>MVP — 8-10 дней</h4>
|
||
<p>Детекция лиц + Deepgram спикеры. Временная корреляция. Ручная коррекция. Статический кроп.</p>
|
||
</div>
|
||
<div class="comparison-card">
|
||
<h4>Полная — 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> Сначала кроп, потом субтитры — всегда. Один проход Remotion через <code>ShortsVideo</code>.</p>
|
||
|
||
<h4>Спецификация кропа</h4>
|
||
<pre><code>type CropConfig = {
|
||
mode: "static" | "keyframe";
|
||
staticCrop?: { x: number; y: number; zoom: number };
|
||
keyframes?: Array<{ time: number; x: number; y: number; zoom: number }>;
|
||
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>Кнопка «Конвертировать в Short» на одобренных вирусных клипах</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 — 6-8 дней</h4>
|
||
<p>Ручной выбор кропа с превью. Remotion-композиция <code>ShortsVideo</code>.</p>
|
||
</div>
|
||
<div class="comparison-card">
|
||
<h4>Полная — +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 — Шаблоны</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 — Вирусная детекция</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 — 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 — Трекинг лица</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 — апгрейд</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> — готовы, нулевой риск, моментальная польза</li>
|
||
<li><strong>Вирусная детекция второй</strong> — самый быстрый ROI (3-5 дней MVP), валидирует спрос</li>
|
||
<li><strong>9:16 MVP третьим</strong> — создаёт <code>ShortsVideo</code>, полезна сама по себе</li>
|
||
<li><strong>Трекинг лица последним</strong> — самая сложная, но теперь проще без pyannote/GPU</li>
|
||
<li><strong>Апгрейд 9:16</strong> — тривиален, когда трекинг даёт позиции</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 видео/месяц. Ниже — 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 — упрощённая)</h2>
|
||
|
||
<h3>Архитектура</h3>
|
||
<div class="arch-diagram">
|
||
<div class="arch-row">
|
||
<div class="arch-box arch-box-primary">Frontend</div>
|
||
<div class="arch-arrow">→</div>
|
||
<div class="arch-box arch-box-primary">Backend API</div>
|
||
<div class="arch-arrow">→</div>
|
||
<div class="arch-box arch-box-service">Dramatiq-воркер (MediaPipe)</div>
|
||
</div>
|
||
<div class="arch-arrow-down">↓</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">↓</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) — это всё, что работает локально. Не нужны:</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> — диаризация включена в транскрипцию Deepgram.
|
||
</div>
|
||
|
||
<h4>Расширение движков транскрипции</h4>
|
||
<pre><code>engine: Literal["whisper", "google", "deepgram"] = "deepgram"</code></pre>
|
||
<p>Deepgram — дефолт. Whisper — опциональный фоллбэк (<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> — 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 → 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 · Техническая консультация v2 · 22 марта 2026</p>
|
||
<p style="margin-top: .5rem;">Отчёты специалистов доступны в стенограмме сессии</p>
|
||
</footer>
|
||
|
||
</body>
|
||
</html>
|