Telemost Recorder — запись Яндекс.Телемост
Telemost Recorder — запись Zoom и Яндекс.Телемост 🎙️
Production status, 2026-09-29: оба боевых контура подтверждены реальными встречами — Zoom работает, Яндекс.Телемост работает. Оба проходят цепочку запись → безопасная остановка → сохранение оригинала → транскрипция → саммари/доставка. Телемост работает в строго receive-only режиме: бот не публикует микрофон, камеру или визуал. источник
GitHub: https://github.com/3dstepansky/stepansky-telemost-recorder-doker Боевой checkout: /opt/telemost-recorder, ветка release/multiplatform-voice-rollout; исправления безопасного Телемоста и остановки — 6605ff7, 38f72e0. Исторический snapshot: ветка v04, коммит 508deeb от 2026-07-03. README и старые ветки частично продолжают описывать n8n-оркестрацию; для текущего production-статуса приоритетны боевой checkout и акт приёмки Zoom/Телемоста.
Суть проекта
Telemost Recorder — zero-cost бот для записи встреч в Яндекс.Телемосте. Он заходит на встречу гостем, перехватывает WebRTC-аудио через Puppeteer/Chromium, сохраняет .webm, транскрибирует встречу через AssemblyAI или Groq Whisper, генерирует саммари через Groq Llama 3.3 70B, а затем отдаёт результаты в Telegram и/или Яндекс.Диск через WebDAV. источник
Проект важен для базы как живой пример агентной автоматизации вокруг встреч: браузерный агент действует в видеоконференции, извлекает аудио, строит пайплайн STT → summary → delivery и закладывает будущий RAG/архив встреч.
Следующий исследованный шаг — прямое голосовое общение через Fish Audio. Доступный buildable MVP использует streaming STT → Hermes → Fish WebSocket TTS и отдельный двунаправленный audio bridge между виртуальными устройствами Chromium и Яндекс.Телемостом. Hosted Fish Agents остаётся перспективным gated-вариантом после получения private-beta доступа.
Production-подтверждение платформ — 2026-09-29
| Платформа | Боевой статус | Подтверждённый результат |
|---|---|---|
| Zoom | Работает | Реальная встреча записана; Telegram-stop выполнил graceful leave; два канала прошли AssemblyAI; оригинал, транскрипция и саммари сохранены в Яндекс.Диск, MongoDB и Baza. |
| Яндекс.Телемост | Работает | Реальная контрольная встреча прошла безопасный вход с выключенными mic/camera, каноническую stop-команду, штатный exit code 0, загрузку оригинала и транскрибацию речевого канала. |
Важно: интерактивный голосовой агент — отдельный будущий режим. Текущий recorder по умолчанию только слушает входящие медиатреки. Он не должен говорить, включать камеру, демонстрировать экран или показывать визуал без отдельной явной команды и отдельного безопасного режима. источник
Исправленный production-инцидент
В реальной встрече Телемоста бот ранее транслировал посторонний звук: headless Chromium запускался с fake media device, mic=on, camera=on, а headless-ветка не выполняла mute. Одновременно кнопка остановки не срабатывала на URL с ?from=..., потому что Telegram и recorder вычисляли разные stop-ID.
Исправлено:
- receive-only private join (
mic=off,camera=off); - удалён fake media device;
- pre/post-join проверки всех UI-фреймов;
- WebRTC-level блокировка и удаление локальных audio/video senders;
- единый канонический meeting ID без query-параметров;
- двойная доставка stop: lock-файл + сигнал процессу;
- идемпотентный shutdown и очистка stale lock;
- ожидание
MediaRecorder.stopи последних chunk writes до закрытия Chromium; - отдельный регрессионный тест порядка инициализации shutdown guard.
Полная проверка после исправлений: 73 теста, 73 pass, 0 fail, затем повторная реальная встреча Телемоста с успешным завершением. источник
Архитектура v04
Telegram bot.js / Telegraf
↓
run.js — жизненный цикл сессии
↓
recorder.js — Puppeteer + WebRTC monkey-patch + MediaRecorder
↓
recordings/<timestamp>/
├── meeting_audio.webm
├── tracks/<trackId>.webm
└── meta/track_events.ndjson, tracks_summary.json
↓
transcribe.js
├── AssemblyAI speaker_labels=true
└── Groq Whisper fallback через FFmpeg chunks
↓
summary.txt / transcript.txt / Telegram / Yandex Disk / S3
Ключевой архитектурный сдвиг: в старой версии n8n был внешним orchestrator-слоем, а в v04 основной пользовательский контур перенесён в bot.js + SQLite. n8n-файлы (n8n_workflow_v0.4.json, n8n_workflow_head.json) остаются в репозитории как исторические/совместимые артефакты. источник
Основные компоненты
| Компонент | Назначение |
|---|---|
bot.js | Telegram-бот на Telegraf: меню, FSM, настройки имени бота и Яндекс.Диска, старт/стоп записи |
run.js | Запускает recorder.js, после закрытия записи делает раннюю выгрузку аудио и запускает транскрибацию |
recorder.js | Headless Chromium/Puppeteer, вход в Телемост, WebRTC monkey-patch, запись mix + per-track файлов |
transcribe.js | AssemblyAI → Groq fallback, speaker mapping по track_events.ndjson, выгрузка transcript/summary, отправка в Telegram |
db.js | SQLite: users, meetings, state FSM, имя бота, WebDAV-учётки |
services/webdav.js | Яндекс.Диск через WebDAV: MKCOL, PUT, MOVE, проверка авторизации |
services/summarize.js | Саммари и метаданные папки через Groq llama-3.3-70b-versatile |
services/transcribe.js | AssemblyAI speaker_labels=true, Groq Whisper verbose_json fallback |
services/ffmpeg.js | Конвертация/сегментация аудио для STT |
.specify/ и .github/prompts/speckit.* | Spec Kit / Specify контур для spec-driven разработки |
UX Telegram-бота
Бот имеет три главных пользовательских раздела:
- 🔴 Запись встреч — ждёт ссылку вида
https://telemost.yandex.ru/j/..., заходит в комнату под пользовательским именем, даёт inline-кнопку «Остановить». - 🧠 Аналитика и ИИ — список встреч, транскрипция, саммари. В текущем
bot.jsкнопки «Сделать саммари» и «Транскрибировать» ещё выглядят как заглушки, но автоматическая обработка после записи реализована вtranscribe.js. - ⚙️ Настройки — имя бота и подключение Яндекс.Диска через 16-значный WebDAV app password. Если Диск не подключен, бот пытается присылать файлы прямо в Telegram до лимита 50 МБ.
База данных
Актуальная SQLite-схема в db.js:
users(chat_id primary key, bot_name, yandex_user, yandex_pass, state)
meetings(id, chat_id, meeting_id, title, file_path, transcribed_at, speaker_count, utterance_count)
Историческая database.sql описывает PostgreSQL/Supabase-таблицы telemost_meeting_transcripts и telemost_user_settings, но для v04 рабочий runtime — SQLite внутри контейнера. источник
Статус требований spec 002
Реализовано:
- запись WebRTC-аудио и вход в комнату;
- anti-zombie завершение Chromium через
try/finally,dumb-init, SIGINT/SIGTERM; - автономный Telegram-бот вместо n8n;
- автовыход при завершении встречи/idle/max duration;
- инфостиль сообщений;
- быстрый старт по ссылке;
- персональное имя бота;
- ИИ-саммари и отправка результата в Telegram;
- dual-output WebRTC: общий mix + отдельные per-track
.webm+ события активности.
Частично/требует проверки:
- AssemblyAI-диаризация и сопоставление с локальной картой треков;
- выгрузка на Яндекс.Диск/S3 в реальном окружении;
- ИИ-переименование папок WebDAV
MOVE; - архив встреч в Telegram пока базовый.
Не начато / roadmap:
- Яндекс.Календарь;
- RAG-чат по встрече;
- живой STT/TTS-агент внутри комнаты.
US-16: нативная диаризация через WebRTC-треки
Самая важная исследовательская линия проекта — гипотеза, что Яндекс.Телемост отдаёт отдельные WebRTC-аудиотреки по участникам. В v04 recorder.js уже реализует dual-output:
1. meeting_audio.webm — общий микс для STT. 2. tracks/<trackId>.webm — отдельная запись каждого входящего аудиотрека. 3. meta/track_events.ndjson — события track-added и speech-segment с trackId, временем и амплитудой. 4. tracks_summary.json — сводка по трекам.
Проверка track-probe на реальной встрече 2026-07-02 подтвердила техническую возможность раздельной записи: получены два отдельных .webm трека и события активности. Ограничение: speakerName пока пишется как unknown, нужно улучшить DOM-маппинг имени участника. источник
Проверка и качество
Production acceptance 2026-09-29
- Zoom: реальная запись, graceful stop, 2/2 речевых канала обработаны, transcript/summary доставлены.
- Телемост: повторная реальная приёмка после исправления shutdown guard; безопасный receive-only вход, stop найден, exit code
0, оригинал загружен, речевой канал транскрибирован. - Автотесты текущего боевого checkout: 73 pass, 0 fail.
Ни один коммит или unit-test больше не считается достаточным подтверждением работоспособности платформы: критерий готовности включает реальную встречу, отсутствие исходящего audio/video, штатную остановку, сохранённый файл и запуск downstream-обработки. источник
Историческая проверка v04
npm install
npm test
# tests 3
# suites 1
# pass 3
# fail 0
Первый запуск npm test падал из-за отсутствующих зависимостей (sqlite3 не установлен). После npm install тесты test/db.test.js прошли: создание дефолтного пользователя, сохранение и обновление пользователя. npm install также показал npm audit: 16 vulnerabilities, включая 1 critical — это отдельный quality-gate перед production. источник
Риски и технический долг
- README drift: корневой README смешивает старую n8n-архитектуру и v0.4; для ориентации читать ветку
v04,specs/002,.specify/memory/constitution.mdи код. - Секреты:
yandex_passхранится в SQLite; для production нужен отдельный security review и шифрование/секрет-хранилище. - Speaker names: WebRTC track-level запись подтверждена, но имена участников пока нестабильны (
unknown). - Telegram file limit: без Яндекс.Диска аудио >50 МБ не отправится, хотя текст/саммари должны приходить.
- Vulnerabilities: после
npm installзафиксированы 16 audit issues. - Puppeteer fragility: вход в Телемост зависит от DOM/селекторов Яндекса.
- RAG privacy: будущий архивный поиск должен быть жёстко изолирован по
chat_id, как прописано в конституции.
Roadmap и стратегическое развитие
1. Эксплуатация подтверждённых платформ: сохранять regression/live acceptance для уже работающих Zoom и Яндекс.Телемоста; Google Meet остаётся следующим неподтверждённым контуром. 2. Интерактивный голосовой ассистент и выход по фразе: концепция голосового Q&A в реальном времени и Graceful Exit Triggers («Светочка, покинь встречу»). 3. Починить speakerName: сопоставление WebRTC trackId с DOM-именем участника. 4. Зафиксировать мастер-формат диаризации: mix + per-track или полноценный diarization_map.json. 5. Проверить WebDAV/S3 upload и MOVE-переименование на реальном Яндекс.Диске. 6. Довести ручные кнопки «Транскрибировать»/«Сделать саммари» в Telegram UI. 7. Закрыть npm audit / обновить уязвимые зависимости. 8. Реализовать архивный RAG-Q&A по встречам с изоляцией по chat_id.