Мы делаем Reels Boss — сервис, который раньше умел одно: резать длинные записи на короткие вертикальные клипы. Недавно мы выкатили в бету вторую большую штуку, Автомонтаж. На вход — вертикальное видео до трёх минут, где человек говорит в камеру. На выход — смонтированный ролик: без пауз и запинок, с субтитрами, акцентами, картинками к словам, наездами камеры, переходами и музыкой. Пользователь при этом не открывает таймлайн ни разу: выбрал один из 48 стилей, нажал кнопку, всё остальное ложится само.
Снаружи это выглядит как «ИИ сделал красиво». Внутри это довольно приземлённая инженерная задача, в которой нейросетей меньше, чем кажется, а правил и компромиссов больше. Расскажу, как это устроено, где мы ошибались и что до сих пор работает хуже, чем хотелось бы.
Главная идея: монтаж как компиляция
Классический видеоредактор работает со временем: дорожки, клипы, точки склейки. Мы от этого отказались сразу. У нас единица монтажа — слово.
Пайплайн устроен как компилятор. Исходник — видеофайл. Первый проход превращает его в промежуточное представление: транскрипт, где у каждого слова есть время начала, время конца и уверенность распознавания. Все дальнейшие стадии работают только с этим представлением и ничего не знают про пиксели. Каждая стадия принимает решения и дописывает их в план монтажа. В конце план исполняется рендером за один проход.
Упрощённо план выглядит так:
{
“keep”: [
{“from”: 0.42, “to”: 3.18},
{“from”: 4.95, “to”: 9.60}
],
“captions”: [
{“t”: 0.42, “words”: [“Каждая”, “твоя”], “accent”: null},
{“t”: 1.10, “words”: [“история”], “accent”: “история”}
],
“overlays”: [
{“t”: 5.30, “type”: “object_image”, “anchor”: “top”, “query”: “кредитная карта”},
{“t”: 7.80, “type”: “zoom”, “scale”: 1.15, “ease”: “out”}
],
“music”: {“track”: “…”, “duck_on_speech”: true}
}
Это упрощённая иллюстрация, а не реальная схема, но принцип именно такой. У подхода три следствия, ради которых всё затевалось.
Первое: исходник не перекодируется по дороге. Сколько бы стадий ни было, видео декодируется и кодируется один раз, в самом конце.
Второе: любую стадию можно перезапустить отдельно. Пользователь сменил стиль — пересчитывается только слой оформления, расшифровка и чистка остаются.
Третье, самое полезное для разработки: план читается глазами. Когда ролик собрался странно, мы открываем JSON и видим, какая стадия приняла плохое решение. С таймлайном внутри чёрного ящика так не получится.
Стадия 1. Слова с таймкодами
Всё держится на точности границ слов. Ошибка в 100 мс на границе — и склейка либо откусывает окончание, либо оставляет вдох перед следующей фразой.
Распознавание даёт текст и приблизительные границы. Этого мало, поэтому поверх идёт принудительное выравнивание: текст уже известен, и задача сводится к тому, чтобы точно привязать фонемы к аудио. [уточнить у разработки: какая ASR-модель и чем делаем выравнивание, какая получается точность границ в мс]
С русским языком тут две специфические неприятности. Безударные окончания произносятся тихо и коротко, и модель охотно отдаёт их тишине. А предлоги и частицы сливаются с соседним словом в одно фонетическое целое, так что граница между «в» и «кадре» существует только в тексте. Мы перестали с этим бороться и склеиваем такие пары в одну неделимую единицу: резать внутри неё запрещено.
Стадия 2. Паузы: почему порог по громкости не работает
Первая версия была наивной: ищем участки тише порога длиннее N миллисекунд и вырезаем. Она прожила примерно день.
Проблем три. Тишины в записи с телефона нет: есть кондиционер, улица, шум самого микрофона, и порог приходится подбирать под каждый файл. Вдох перед фразой громче порога, но это пауза. А глухие согласные в начале слова тише порога, но это речь: вырезаешь «тишину» и получаешь «…лавное» вместо «главное».
Рабочая версия вообще не смотрит на громкость как на основной сигнал. Пауза — это интервал между концом одного слова и началом следующего в транскрипте. Аудио используется только для уточнения: детектор речевой активности подтверждает, что внутри интервала действительно никто не говорит, и помогает найти точку реза.
Дальше начинается то, что мы поняли не сразу. Первая сборка вырезала все паузы длиннее порога. Ролики получались плотные, динамичные и неприятные. Тестовая группа не могла объяснить, что не так, но досматривала хуже.
Оказалось, так не разговаривают. Пауза после вопроса, перед выводом, между двумя мыслями работает как знак препинания. Убираешь её, и речь превращается в сплошной поток, за которым тяжело следить.
Теперь паузы не удаляются, а сжимаются, и степень сжатия зависит от контекста:
def target_pause(gap, prev_word, next_word):
if is_inside_phrase(prev_word, next_word):
return MIN_GAP # внутри фразы — почти в ноль
if ends_sentence(prev_word):
return min(gap, SENTENCE_GAP) # между предложениями — оставляем «точку»
if ends_question(prev_word):
return min(gap, QUESTION_GAP) # после вопроса — чуть больше
return min(gap, DEFAULT_GAP)
[уточнить у разработки: реальные значения порогов и чем определяются границы предложений — пунктуацией из ASR или отдельной моделью]
В режиме «Бережная чистка» на этом всё заканчивается: порядок слов и вся речь сохраняются, уходят только паузы и запинки.
Склейка: как спрятать шов
Вырезать кусок мало, надо, чтобы стык не было видно и слышно.
Со звуком относительно просто: рез ставится не ровно по границе слова, а с небольшим запасом, и на стыке делается короткий кроссфейд. Без него слышен щелчок, потому что фоновый шум слева и справа от склейки разный.
С картинкой сложнее. Человек между двумя фразами успел чуть повернуть голову, и на стыке она дёргается. Это классический джамп-кат, и у монтажёров есть для него классическое лекарство: сменить крупность. Если до склейки кадр был в масштабе 100%, а после — 112%, глаз читает это как смену плана, а не как дефект.
Мы делаем то же самое автоматически. Отсюда, кстати, и берётся значительная часть «наездов камеры» в готовом ролике: это не украшение, а маскировка швов. Чтобы при увеличении лицо не уезжало из кадра, центр масштабирования привязан к положению лица, которое отслеживается по всему ролику.
Стадия 3. Запинки и фальстарты
Слова-паразиты вроде «эээ» и «ну» ловятся проще всего, хотя и тут есть нюанс: распознавалки любят их молча выбрасывать из текста, потому что обучены выдавать чистую расшифровку. В транскрипте дыра, в аудио мычание. Поэтому необъяснённые интервалы с речевой активностью мы считаем кандидатами в мусор.
Фальстарты интереснее. «Сегодня я расска… сегодня я расскажу» — человек начал, сбился, начал заново. В транскрипте это выглядит как повтор начала фразы, часто с оборванным словом на конце первой попытки. Ищем так: если последовательность слов совпадает с началом следующей за ней последовательности, а между ними пауза или оборванное слово, первая попытка помечается на удаление.
Главная опасность тут — ложные срабатывания. «Очень, очень важно» — это не фальстарт, а усиление. «Мы пробовали раз, пробовали два» — перечисление. Отличает их в основном просодия: в фальстарте есть сбой ритма и пауза, в риторическом повторе их нет. Правило простое и грубое: сомневаешься — не режь. Оставленная запинка выглядит как живая речь, вырезанное нужное слово выглядит как баг.
Стадия 4. «Лучший дубль»
Это режим, ради которого всё задумывалось, и он съел больше времени, чем остальное вместе взятое.
Сценарий такой: человек говорит фразу, ему не нравится, он тут же повторяет её ещё раз, иногда третий. Запись не останавливает. Система должна понять, что это попытки одной и той же фразы, выбрать лучшую и выкинуть остальные.
Найти дубли. Буквальное сравнение текста не работает совсем. Люди не повторяют себя дословно: «это сильно упрощает работу» во второй попытке превращается в «работать становится гораздо проще». Общих слов почти нет, смысл тот же.
Поэтому сегменты сравниваются по смыслу: каждая фраза превращается в вектор, и близкие векторы у соседних фраз — сигнал, что перед нами дубль. [уточнить у разработки: какая модель эмбеддингов, какой порог сходства, какого размера окно поиска]
Ключевое слово здесь — «соседних». Мы ищем дубли только в коротком окне подряд идущих фраз. Если человек вернулся к той же мысли через минуту, это не дубль, а повтор тезиса, и резать его нельзя. Без этого ограничения алгоритм радостно выкидывал выводы в конце ролика, потому что они по смыслу совпадали со вступлением.
Вторая ловушка — параллельные конструкции. «Первое — это скорость. Второе — это цена». По структуре и по векторам фразы очень близки, но это два разных пункта. Тут помогает проверка на различающиеся ключевые слова: если в двух похожих фразах разные существительные или числа, это перечисление, а не пересъёмка.
Выбрать лучший. Человек делает это за секунду и объяснить не может. Нам пришлось объяснить. Оценка дубля складывается из нескольких признаков: дошла ли фраза до конца, сколько внутри запинок и слов-паразитов, насколько ровный темп, насколько уверенно распознаны слова (невнятная речь распознаётся хуже, и это неожиданно полезный сигнал), нет ли посторонних звуков.
Есть сильный априорный признак: при прочих равных выигрывает последний дубль. Логика бытовая: человек перестал повторять, значит, результат его устроил. Но делать это жёстким правилом нельзя: бывает, что третья попытка технически чистая и при этом мёртвая, потому что человек уже просто отчитывает текст.
Честно: это место до сих пор самое слабое. «Живость» дубля мы измеряем косвенно и плохо. Система иногда выбирает аккуратный и скучный вариант там, где человек оставил бы первый, с запинкой, но с энергией.
Стадия 5. Оформление: 48 стилей как данные
Когда чистка закончена, остаётся последовательность слов с новыми таймкодами. Поверх неё строится всё, что зритель видит глазами.
Стилей 48, и ни один из них не является шаблоном в привычном смысле. Шаблон — это готовая композиция, куда подставляется текст. У нас стиль — это набор параметров и правил: шрифт и начертание, анимация появления слова, способ выделения акцента (цвет или маркер-подложка), цвет акцента, плотность вставок, характер движения камеры, тип переходов. Комбинации типа ролика, стиля текста и палитры и дают итоговое число. [уточнить у разработки: как именно считаются 48 — из каких осей складываются]
Декларативное описание даёт то же преимущество, что и план монтажа: новый стиль — это новый конфиг, а не новая ветка кода в рендере.
Теперь о том, что решается автоматически внутри любого стиля.
Разбиение на строки. Субтитры идут по два-три слова. Резать строку по счётчику слов нельзя: «не» отдельно от глагола или предлог в конце строки читаются как ошибка вёрстки. Разбиение идёт по синтаксическим группам, с теми же неделимыми парами, что и на стадии выравнивания.
Акцентное слово. В каждой фразе одно слово выделяется крупнее или цветом. Кандидаты — числа, имена, отрицания, слова с просодическим ударением: если человек сам выделил слово голосом, почти наверняка его и надо выделять на экране. Служебные слова исключаются полностью.
Безопасные зоны. Снизу у вертикального видео интерфейс площадки: подпись, кнопки, аватар. Сверху — строка статуса. Субтитры обязаны жить в середине, и эта рамка зашита в рендер, а не оставлена на совесть стиля.
Лицо. Ничто не должно перекрывать лицо говорящего. Трекинг лица, который нужен для наездов, используется второй раз: каждая вставка проверяется на пересечение с областью лица и, если пересекается, уезжает в свободную часть кадра. Реплики «рядом с лицом» позиционируются от этого же прямоугольника.
Стадия 6. Смысловые вставки
Пользователь видит шесть переключателей: картинки предметов, реплики рядом с лицом, движение камеры, виджеты, переходы, музыка. За каждым стоит ответ на один и тот же вопрос: в какой момент это уместно.
Картинки предметов привязываются к конкретным существительным. Не ко всем: «время», «ситуация» и «вопрос» картинкой не проиллюстрируешь, получится случайный сток. Фильтр отбирает слова, у которых есть однозначный визуальный образ, и следит за плотностью, чтобы вставки не шли чаще заданного стилем интервала.
Виджеты и инфографика появляются на числах и перечислениях. Сказал «выросло на тридцать процентов» — число уходит в плашку. В стиле «Разбор» это основной приём, в «Универсальном» он используется реже.
Музыка подмешивается под речь с автоматическим приглушением: когда человек говорит, дорожка уходит вниз, в сохранённых паузах чуть поднимается.
Общее правило для всех вставок мы вывели после первых тестов, где алгоритм иллюстрировал буквально каждую фразу. Приём, применённый везде, перестаёт быть приёмом. У каждого типа вставок есть бюджет на ролик, и стадия планирования распределяет его по самым сильным кандидатам, а не по первым попавшимся.
Рендер
К этому моменту у нас есть полный план: какие куски исходника оставить, где и как масштабировать кадр, какие слои и когда положить сверху, что сделать со звуком. Рендер исполняет его за один проход: декодирование, обрезка, трансформации кадра, композитинг слоёв, сведение звука, кодирование. [уточнить у разработки: на чём собран рендер, CPU или GPU, сколько занимает каждая стадия для ролика в 3 минуты]
Для пользователя весь цикл укладывается в две-пять минут. Превью стиля показывается ещё до обработки, на первом кадре его собственного видео, чтобы не выбирать вслепую.
Что не работает или работает плохо
Без этого раздела статья была бы рекламой, так что по порядку.
Ограничения входа жёсткие: вертикаль 9:16, до трёх минут, до 1 ГБ, обязательно речь. Без речи монтаж строить не из чего, вся конструкция опирается на слова. Два человека в кадре, диалог, речь за кадром — пока не наш случай.
Выбор дубля ошибается в сторону аккуратности, об этом выше.
Картинки к словам иногда промахиваются на омонимах и переносных значениях. «Ключ к успеху» с изображением дверного ключа — наш любимый баг.
Сильный фоновый шум и музыка в исходнике ломают выравнивание, а за ним всё остальное. Ошибка на первой стадии дорого стоит: неверная граница слова превращается в откушенный слог, и никакая следующая стадия этого не исправит.
Функция в бете, и мы это не прячем.
Что мы из этого вынесли
Самая полезная мысль оказалась не про модели. Монтаж говорящей головы — это не задача обработки видео, а задача обработки текста с побочным эффектом в виде видео. Как только мы перестали думать кадрами и начали думать словами, большинство решений стало очевидным, а отладка — возможной.
Вторая мысль: главный враг автоматического монтажа — усердие. Вырезать все паузы, проиллюстрировать все слова, приблизить камеру на каждой фразе технически проще, чем остановиться вовремя. Почти вся работа после первой версии была про то, чтобы научить систему делать меньше.
Попробовать можно на reels-boss.io: при регистрации даются кредиты, которых хватает на пару роликов. Если загрузите запись и получите странный результат, приходите в комментарии с описанием, что пошло не так. Особенно интересны случаи, где «Лучший дубль» выбрал не тот вариант: на них мы сейчас и учимся.
Автор: ReelsBoss
- Запись добавлена: 10.11.2026 в 08:21
- Оставлено в


