← Журнал
Jiva Studio

Истории, которые можно смотреть

Спросите про случай из жизни Шрилы Прабхупады — и ответ теперь не только текст: приходят короткие видео, где ученики сами рассказывают, как это было.

Слушай СадхуSakhaProductAI

Чат-ассистент в Слушай Садху — тот, что отвечает на вопросы о лекциях и писаниях, — теперь отвечает не только текстом. Спросите про эпизод из жизни Шрилы Прабхупады — и в ответ могут прийти короткие видео: ученики сами рассказывают, как это было.

Раньше, чтобы найти нужную историю, надо было точно знать, где искать. Теперь — не надо. Опишите её своими словами — «кажется, кто-то рассказывал, как Прабхупада заботился об учениках» — и чат найдёт фрагмент.

Что под капотом

Источник — фильм Following Śrīla Prabhupāda, разрезанный на отдельные истории:

  • ~2600 видеофрагментов
  • ~56 часов воспоминаний учеников
  • на двух языках: ~1390 русских клипов (27 ч) и ~1240 английских (29 ч)
  • 350+ учеников Шрилы Прабхупады рассказывают свои истории: Шьямасундара, Брахмананда, Шрутакирти, Ямуна, Гирираджа Свами и многие другие
  • 11 DVD, события 1966–1977 годов: Маяпур, Лос-Анджелес, Вриндаван, Бомбей, Лондон…

От фильма к ~2600 историям

Ни одного из этих фрагментов не было как файла. Источник — одиннадцать DVD со сплошной съёмкой: одно воспоминание переходит в другое, сцена обрывается, начинает говорить новый ученик. Чтобы превратить это в библиотеку с поиском, нужен конвейер, и каждый его этап здесь не зря.

flowchart TD
  F["11 DVD · 56 ч съёмки"] --> T["1 · Распознать речь, Parakeet на Neural Engine, тайминг по словам"]
  T --> SEG["2 · Найти истории, диаризация, затем LLM-судья на стыках"]
  SEG --> REV["3 · Вычитать распознанный текст, имена, санскрит"]
  REV --> META["4 · Определить говорящего и написать строку контекста"]
  META --> CUT["5 · Нарезать видео, ffmpeg, перекодировка в 720p H.264"]
  CUT --> EMB["6 · Встроить в общий корпус и сохранить на CDN"]
  EMB --> CHAT["~2600 клипов, найденных по смыслу"]

Распознать речь

С каждого DVD мы вытягиваем звук через yt-dlp, сводим в моно 16 кГц и прогоняем через распознавание речи. Модель — NVIDIA Parakeet-TDT-0.6b-v3. Одна многоязычная модель на русский и английский материал сразу, причём язык передаётся подсказкой, а не переключается целиком. Работает она локально, на Apple Neural Engine у Mac с M4: веса CoreML держатся в памяти за небольшой HTTP-очередью задач, поэтому 56 часов распознаются в сотни раз быстрее реального времени и без поминутной платы облаку. Управляем прямо из агента через MCP-инструмент: даём файл, получаем job_id, ждём результата.

Приходит не просто текст, а тайминг и уверенность по каждому слову. Именно это потом позволяет резать по границе предложения, а не на полувздохе:

{ "word": "Prabhupada", "startTime": 4.24, "endTime": 4.83, "confidence": 0.997 }

По умолчанию сервис работает на русском. Участки с низкой уверенностью — киртан, речь на другом языке — падают ниже 0.5 и помечаются для проверки человеком.

Найти, где кончается история

Транскрипт — это сплошная стена слов. А у истории есть начало и конец. Почти всегда это целый рассказ одного ученика: с того момента, как он заговорил, и до того, как начнёт говорить другой. Этап самый трудный, и две редакции фильма требуют двух противоположных подходов.

Английская — границы проводят сами голоса. Каждого преданного снимают и подписывают на экране, а монтаж чисто склеивает их между собой. Поэтому модель диаризации (nova-2 от Deepgram) отмечает каждую точку, где голос меняется, и непрерывный отрезок одного голоса становится отдельной историей. Лекция или интервью Прабхупады — одна история. Чистая музыка и титры без слов отбрасываются.

Дальше несколько правил подчищают края. Всё короче ~18 секунд не живёт отдельным клипом — его присоединяют к соседу. Всё длиннее ~4 минут не остаётся целым — его снова делят по самой длинной внутренней паузе. А финальная проверка отмечает клип, который начинается со строчной буквы или кончается без знака препинания: верный признак среза посреди фразы.

Русская задача: один голос, много рассказчиков

Русская редакция ломает этот подход целиком. Дубляж тут не по ролям: всех преданных озвучивает один переводчик. Голос не меняется, и диаризация слепа — для неё весь пятичасовой DVD один говорящий.

Поэтому метод переворачиваем: сначала дробим с запасом, потом судим. Сперва режем транскрипт слишком мелко — по каждой паузе, что длинна для стыка, и каждый рез притягиваем к ближайшему настоящему промежутку между словами. Фрагментов выходит куда больше, чем историй. Дальше для каждой соседней пары рассуждающая модель (Claude) отвечает на один вопрос. Судит по тому, кто говорит и о чём, а не по голосу — голос-то везде один:

Два идущих подряд фрагмента русской озвучки документального фильма, где многие преданные вспоминают Шрилу Прабхупаду (всех озвучивает один переводчик — голос не подсказывает, кто говорит). Отвечай MERGE, только если B — тот же человек и то же воспоминание, что и в A… Отвечай SPLIT, если B — рассказ другого человека или другая история. Ответь одним словом: MERGE или SPLIT.

Тысячи стыков взвешиваются параллельно, а на выходе — целые истории, по одной на рассказчика, заново собранные из кусочков. Две редакции одного фильма, две противоположные стратегии — и обе продиктованы одним решением: как каждую озвучили.

Вычитать распознанное

Распознавание путает санскрит и имена. Поэтому языковая модель проходит по каждой истории и правит только ошибки распознавания: Трипурари Махараджа, Маяпур, Ратха-ятра, единое написание Прабхупады. Ей строго велено ничего не пересказывать, не сокращать и не добавлять ни строчки. (Если модель разойдётся и вернёт текст вдвое длиннее исходного, мы отбрасываем её ответ и оставляем сырой транскрипт.)

Определить и вписать каждую историю в контекст

Кто говорит. Подписанный клип стоит куда больше. В английской редакции имя есть на экране — подпись в нижней трети кадра, «Śyāmasundara dāsa remembers». Поэтому ffmpeg берёт один кадр из каждой истории, обрезает нижнюю треть, а визуальная модель читает подпись и возвращает только имя. У русских клипов подписей нет, только голос переводчика. Поэтому имя берут у английского двойника: каждую русскую историю сопоставляют с ним по содержанию (редакции отличаются порядком и длиной, так что совпадение ищут по сути рассказа, а не по таймкоду) и берут имя оттуда.

Строка контекста. Отдельный клип легко понять неверно: «и тогда он просто улыбнулся мне» ничего не значит, пока не знаешь, кто этот он, кто говорит и когда. Поэтому в том же проходе модель пишет для каждой истории поясняющую строку в одно-два предложения: кто говорит, о чём, когда и где. В помощь ей идёт написанная вручную заметка об эпохе для каждого DVD (DVD 7, например, — это «американский тур 1975 года и фестиваль в Маяпуре»). Заодно модель вытаскивает структурные метаданные: год, места, темы, людей. Эту строку ставят перед транскриптом ещё до встраивания, чтобы семантическому поиску было за что зацепиться, даже если клип нигде не называет своего героя. Это идея контекстного поиска от Anthropic: немного контекста на каждый фрагмент, чтобы поиск не сбивал с толку клип, который сам по себе почти ничего не говорит. Зритель по-прежнему видит только чистый транскрипт — контекст работает за кадром.

Нарезать видео

Только теперь доходит до самого видео. ffmpeg вырезает каждую историю из скачанного файла полного разрешения — с перекодировкой, а не копированием потока, чтобы клип открывался на настоящем кадре — в 720p H.264 со звуком AAC, веб-fast-start и четвертью секунды запаса с каждой стороны, чтобы никого не обрезало на полуслове:

ffmpeg -ss {start-0.25} -i source.mp4 -t {duration} \
  -map 0:v:0 -map 0:a:0 \
  -c:v libx264 -preset veryfast -crf 23 -vf scale=-2:720 \
  -c:a aac -b:a 128k -movflags +faststart  clip.mp4

На том же шаге для каждого клипа берётся кадр-постер.

Встроить, проиндексировать, отдать

Каждую историю — строку контекста перед вычитанным транскриптом — модель text-embedding-3-small от OpenAI (1536 измерений) превращает в эмбеддинг и пишет в тот же корпус chunks, что и лекции, стихи и письма: клип — это просто kind = 'media', один из шести видов. Повторный запуск индексатора встраивает заново только изменившееся, ведь у каждой строки есть хеш содержимого. Тот же поиск, что уже отдаёт аудиофрагменты — частичный HNSW-поиск в pgvector — дотягивается и до клипов, без отдельного видеоиндекса.

Сами нарезки уходят в объектное хранилище (бакет S3 с зеркалами на Yandex и Bunny CDN). База хранит только относительный путь, а приложение при старте достраивает его до ближайшего узла CDN. Поэтому, когда клип выигрывает в поиске, чат стримит вам именно этот момент, а рядом — его транскрипт.


В итоге видео — не сбоку прикрученная функция. Клип — просто ещё один вид записи в корпусе, который остальная система уже понимает. Потому-то вопрос, написанный вашими словами, и может его найти.

Спросите о местах, годах или событиях — или просто «расскажи историю о…» — и смотрите, как это было.


Часть проекта

Слушай Садху

Открыть проект