Почему ручная нарезка — это путь в никуда
Вы выступили на конференции. Запись лежит на YouTube, 40 минут ценного контента. Чтобы сделать из этого 5-10 вертикальных роликов для Reels или Shorts, нужно вручную пересмотреть часы видео, найти удачные моменты, вырезать, склеить, наложить субтитры. День работы за 3 минуты контента. Знакомо?
В 2026 году это нелепо. У нас есть AI модели, которые понимают речь лучше человека (Whisper large-v4-turbo), большие языковые модели (LLM), способные оценить, что именно делает фрагмент «вирусным», и утилиты типа ffmpeg, которые могут нарезать и перекодировать видео быстрее, чем вы скажете «экспорт». Я собрал пайплайн, который берет на себя всю рутину. Он не идеален, но экономит 90% времени. А главное — код, который я покажу, работает прямо сейчас.
Пайплайн за 15 минут: от транскрипции до готового Reels
Весь процесс состоит из трёх этапов: транскрибация видео в текст, анализ текста LLM для поиска хайлайтов и, наконец, нарезка с кадрированием через ffmpeg. Ниже — каждый шаг с кодом и пояснениями.
1Транскрибация — Whisper решает
Первый шаг — получить чистый текст с таймкодами. Я использую Whisper.cpp (версия 1.7.5) с моделью large-v4-turbo — она даёт почти идеальное распознавание русского и английского, при этом работает в 4 раза быстрее real-time на обычном ноутбуке с CPU. Если у вас есть GPU — скорость возрастает ещё сильнее. Для установки: клонируете репозиторий, компилируете, скачиваете модель.
git clone https://github.com/ggerganov/whisper.cpp.git
cd whisper.cpp
make -j4
bash models/download-ggml-model.sh large-v4-turbo
# Транскрибация видео в JSON с таймкодами
./main -m models/ggml-large-v4-turbo.bin -f input_video.mp4 -oj -of transcriptФлаг -oj выдаёт JSON с массивом сегментов: каждый содержит start, end и текст. Если нужно больше контекста — рекомендую прочитать нашу статью «Whisper.cpp в продакшене: как собрать локальный редактор субтитров» — там подробно про тонкие настройки и выравнивание.
2Поиск хайлайтов — LLM в роли редактора
Теперь у нас есть текст с метками времени. Нужно понять, какие фрагменты (по 15–60 секунд) будут интересны зрителю. Человек-редактор ищет: шутки, вопросы из зала, неожиданные цифры, конфликты. LLM справляется с этим не хуже, если дать правильный промпт.
Я использую GPT-4o (OpenAI API) или Claude 4 (Anthropic) — оба отлично работают с длинными текстами. Можно обойтись и локальной моделью, вроде Llama 4 70B через ollama, но для русского языка качество выше у коммерческих моделей. Скрипт читает JSON от Whisper, формирует куски по 3-5 предложений, и отправляет в LLM с промптом:
Важно: Не отправляйте весь транскрипт сразу — LLM начнет «галлюцинировать» таймкоды. Делите текст на блоки по 30-60 секунд (10-15 сегментов).
import openai
import json
with open('transcript.json', 'r') as f:
data = json.load(f)
# Группируем сегменты в чанки по 30 секунд
chunks = []
current_chunk = []
for seg in data['segments']:
current_chunk.append(seg)
if seg['end'] - current_chunk[0]['start'] >= 30:
chunks.append(current_chunk)
current_chunk = []
if current_chunk:
chunks.append(current_chunk)
prompt_template = """Ты — видеоредактор. Из списка сегментов (с таймкодами) выбери 2-3 лучших для короткого Reels. Критерии: эмоциональность, неожиданность, важные цифры, вопросы из зала. Ответь строго в JSON: [{"start": X, "end": Y, "reason": "..."}]"""
highlights = []
for chunk in chunks:
# Преобразуем chunk в текст с таймкодами
text_block = ''.join([f"[{s['start']:.2f}-{s['end']:.2f}] {s['text']}" for s in chunk])
response = openai.chat.completions.create(
model="gpt-4o-2026-05-01",
messages=[{"role": "user", "content": prompt_template + text_block}],
response_format={"type": "json_object"}
)
highlights.extend(json.loads(response.choices[0].message.content))На выходе — список хайлайтов с точными таймкодами. Часто LLM предлагает фрагменты по 15-40 секунд — идеально для вертикального формата.
3Нарезка и кадрирование — ffmpeg делает грязную работу
Теперь берём ffmpeg (я использую сборку от BtbN, версия 7.1) и для каждого хайлайта вырезаем фрагмент, кадрируем его в вертикальный формат 9:16 и накладываем субтитры. Субтитры можно сгенерировать из тех же сегментов Whisper — я предпочитаю формат SRT, который ffmpeg умеет «вживлять» в видео.
for highlight in highlights; do
start=$(echo $highlight | jq -r '.start')
end=$(echo $highlight | jq -r '.end')
# Кадрирование по центру: обрезаем левую и правую части (1080 -> 608)
# и одновременно накладываем субтитры
ffmpeg -i input.mp4 \
-ss $start -to $end \
-vf "crop=608:1080:(in_w-608)/2:0,subtitles=subs.srt" \
-c:v libx264 -preset fast -crf 22 \
-c:a aac -b:a 128k \
-movflags +faststart \
"output_${start}.mp4"
doneБум — готовый набор вертикальных клипов. Если нужно склеить их в одно видео, используем concat demuxer или донарезаем с одинаковыми параметрами и объединяем через ffmpeg -f concat.
Когда всё идёт не по плану: 5 граблей, которые я собрал
Пайплайн работал не сразу. Вот ошибки, на которые я потратил часы, чтобы вы их не повторили.
- LLM выбирает фрагменты, которые не начинаются с начала фразы. Решение: просите в промпте округлять таймкоды до ближайшей «паузы» (смотрите по сегментам Whisper).
- Субтитры не синхронизируются. Если ffmpeg не может найти шрифт, субтитры могут отображаться с задержкой. Всегда используйте
:force_style='FontName=Arial', а лучше конвертируйте SRT в ASS черезffmpeg -i subs.srt subs.ass. - Кадрирование обрезает спикера, если он не по центру. Видео с конференций часто сняты с двух камер. Если докладчик смещён — используйте детектор лиц (например, Dive с MCP) или автоматический кроп (ffmpeg фильтр
cropdetect). - Whisper ошибается на плохом аудио. Сначала прогоните дорожку через фильтр шумоподавления:
anlmdnили внешний инструмент типаnoisereduce. - LLM выбирает слишком короткие фрагменты (5-10 секунд). В промпте явно укажите минимальную длину — 15 секунд. Иначе зритель не успеет понять суть.
Полноценный пример автоматизации похожего пайплайна — в статье «Как построить „аниме-завод“» — там тоже используется цепочка AI+ffmpeg, но для генерации аниме-шортсов.
Полный код пайплайна
Собрал всё в один Python-скрипт. Он вызывает Whisper.cpp (через subprocess), парсит JSON, общается с OpenAI, генерирует субтитры и запускает ffmpeg. Можно адаптировать под свою инфраструктуру. Код выложен на GitHub (ссылка в конце статьи), но базовую версию покажу здесь:
import subprocess, json, openai, os
VIDEO = "talk.mp4"
WHISPER_CPP = "./whisper.cpp/main"
MODEL = "models/ggml-large-v4-turbo.bin"
LLM_MODEL = "gpt-4o-2026-05-01"
def transcribe():
subprocess.run([WHISPER_CPP, "-m", MODEL, "-f", VIDEO, "-oj", "-of", "transcript"])
with open("transcript.json") as f:
return json.load(f)
def get_highlights(data):
chunks = []
current = []
for seg in data['segments']:
current.append(seg)
if seg['end'] - current[0]['start'] >= 30:
chunks.append(current)
current = []
if current: chunks.append(current)
highlights = []
for chunk in chunks:
text = ''.join([f"[{s['start']:.2f}] {s['text']}" for s in chunk])
prompt = "Из текста с таймкодами выбери 2-3 лучших фрагмента для Reels (15-60 сек). Критерии: инсайты, эмоции, вопросы. Ответ JSON: [{start, end, reason}]\n" + text
r = openai.chat.completions.create(model=LLM_MODEL, messages=[{"role":"user","content":prompt}], response_format={"type":"json_object"})
highlights.extend(json.loads(r.choices[0].message.content))
return highlights
def generate_subtitles(data):
# Создаём SRT из сегментов Whisper
with open("subs.srt", "w") as f:
for i, seg in enumerate(data['segments']):
start = seg['start']
end = seg['end']
f.write(f"{i+1}\n{to_srt_time(start)} --> {to_srt_time(end)}\n{seg['text']}\n\n")
def to_srt_time(sec):
h = int(sec//3600); m = int((sec%3600)//60); s = int(sec%60); ms = int((sec - int(sec))*1000)
return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"
def cut_highlights(highlights):
for hl in highlights:
start = hl['start']; end = hl['end']
out = f"clip_{start}.mp4"
subprocess.run(["ffmpeg", "-i", VIDEO, "-ss", str(start), "-to", str(end),
"-vf", "crop=608:1080:(in_w-608)/2:0,subtitles=subs.srt",
"-c:v", "libx264", "-preset", "fast", "-crf", "22", "-c:a", "aac", out])
data = transcribe()
highlights = get_highlights(data)
generate_subtitles(data)
cut_highlights(highlights)
print("Готово! Клипы в папке.")Код рассчитан на Linux/macOS с установленными ffmpeg и Whisper.cpp. На Windows придется адаптировать пути. Для масштабирования — оберните в Docker и крутите на сервере. Кстати, про развёртывание таких пайплайнов на GPU читайте в «YumCut: как заменить дорогие SaaS подписки на open-source фабрику faceless-видео» — там похожая архитектура.
FAQ: Короткие ответы на частые вопросы
Какие минимальные требования к железу?
Whisper.cpp работает на CPU (16 ГБ ОЗУ для large-v4-turbo). LLM через API — нужен только интернет. ffmpeg — любой. Весь пайплайн можно запустить на MacBook Air M3.
Как часто LLM ошибается при выборе хайлайтов?
Примерно в 30% случаев. Но это легко фильтровать — проверяйте, что длительность фрагмента не менее 15 секунд, и отбрасывайте повторы. Поставьте порог уверенности: просите LLM добавлять score (1-10) и берите только от 7.
Можно ли добавить распознавание лиц для авто-кадрирования?
Да. Используйте детектор из OpenCV или MediaPipe. Пропишите в ffmpeg фильтр crop, который отслеживает координаты лица. Пример есть в статье «Локальный RAG для видео: с нуля до поиска за 15 минут» — там как раз детекция объектов.
Не пытайтесь сделать идеальный пайплайн с первой итерации. Запустите на одном видео, посмотрите, что LLM выбрала «мусор», подправьте промпт. Повторите. Через 5 видео пайплайн начнёт выдавать 80% годного контента. Оставшиеся 20% — ваша работа как креативного редактора (её никто не отменял). А я пошёл допиливать поддержку нескольких языков и динамическую вставку B-roll. Код обновлённого пайплайна лежит в моём репозитории — ссылка в профиле.