Автоматизация встреч — задача, которая кажется простой только на первый взгляд. Многие компании используют встроенные средства записи и расшифровки, но они не всегда доступны или устраивают по функциональности. В этой статье разберём, как собрать собственного ассистента встреч, который подключается к звонкам в Teams, Яндекс Телемост и МТС Линк, записывает разговор, а затем выдаёт расшифровку и саммари с договорённостями. Опираясь на опыт четырёх месяцев продакшена и две тысячи обработанных встреч, рассмотрим архитектурные решения, подводные камни и практические шаги.

Почему не Copilot и не штатная расшифровка

Встроенные инструменты вроде Microsoft Copilot или расшифровки в Zoom/Teams имеют ограничения: они могут быть недоступны на всех платформах, требовать определённых лицензий или не обеспечивать нужный уровень конфиденциальности. Самодельный бот даёт полный контроль над данными, позволяет гибко настраивать формат саммари и интегрироваться с внутренними системами. Кроме того, вы не зависите от изменений в политиках вендоров.

Архитектура: два потока вместо одного

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

  • Поток записи: анонимный Chrome в контейнере, который заходит в встречу по ссылке из календаря, записывает аудио и сохраняет его в хранилище.
  • Поток обработки: сервис, который забирает аудио, прогоняет через ASR (автоматическое распознавание речи), формирует саммари с помощью LLM и отправляет результат участникам.

Анонимный Chrome в контейнере: как это работает

Для подключения к встречам используется headless-браузер Chrome, запущенный в Docker-контейнере. Важно обеспечить анонимность: бот не должен аутентифицироваться под реальным пользователем, чтобы не нарушать политики безопасности и не создавать лишних учётных записей. Вместо этого он подключается как гость по ссылке. Чтобы обойти ограничения на встраивание, применяются флаги --no-sandbox и --disable-dev-shm-usage, а также эмуляция пользовательского агента.

Запись аудио осуществляется через виртуальное аудиоустройство (например, PulseAudio) внутри контейнера. Видео обычно не требуется, но при необходимости можно захватывать и его. Готовый файл сохраняется в S3-совместимое хранилище.

Интеграция с календарём через EWS

Чтобы бот знал о предстоящих встречах, он должен получать события из календаря. Exchange Web Services (EWS) — проверенный способ интеграции с Microsoft Exchange и Outlook. Альтернативы: Microsoft Graph API (для Office 365) или CalDAV (для других серверов). В нашем случае EWS использовался из-за наличия локального Exchange.

Бот периодически опрашивает календарь на предмет новых встреч, извлекает ссылку на подключение (например, Teams или Яндекс Телемост) и ставит задачу на запись. Важно фильтровать события: исключать повторяющиеся, отменённые и те, где бот уже присутствовал. Для надёжности можно использовать вебхуки, если календарь их поддерживает.

Типичные ошибки и грабли

За четыре месяца продакшена мы столкнулись с рядом проблем. Вот основные:

  • Нестабильность headless-браузера: Chrome может падать при длительных встречах или при нехватке памяти. Решение: ограничить длительность записи и настроить автоматический перезапуск контейнера.
  • Проблемы с аудио: виртуальные аудиоустройства иногда не подхватываются. Требуется тщательная настройка прав и проверка доступных устройств.
  • Ошибки распознавания речи: качество ASR сильно зависит от качества записи. Используйте шумоподавление и выбирайте модели, подходящие для русского языка.
  • Задержки обработки: если встреча длинная, расшифровка может занимать много времени. Разделение потоков помогает, но нужно предусмотреть очередь и масштабирование.
  • Безопасность: хранение записей и расшифровок должно быть защищено. Шифруйте данные и ограничивайте доступ.

Что показал продакшен: две тысячи встреч

За четыре месяца бот обработал около двух тысяч встреч. Средняя длительность записи — 45 минут. Время обработки (расшифровка + саммари) занимает от 5 до 15 минут в зависимости от длины. Успешность подключения к встречам — 98%. Основные сбои связаны с нестабильностью сети и изменениями в интерфейсах платформ. Регулярные обновления Chrome и мониторинг помогают поддерживать работоспособность.

Саммари, генерируемые LLM, участники оценивают положительно: они содержат ключевые договорённости и задачи. Важно настроить промпт так, чтобы избегать галлюцинаций и включать только факты из расшифровки.

С чего начать: конкретные шаги

Если вы хотите повторить этот проект, вот план действий:

  • Шаг 1: Определитесь с платформами для встреч (Teams, Телемост, МТС Линк) и проверьте, можно ли подключаться гостем.
  • Шаг 2: Настройте контейнер с Chrome и виртуальным аудио. Протестируйте запись на тестовой встрече.
  • Шаг 3: Реализуйте интеграцию с календарём через EWS или Graph API. Настройте фильтрацию событий.
  • Шаг 4: Выберите ASR-сервис (например, Whisper, Yandex SpeechKit) и LLM для суммаризации. Настройте пайплайн обработки.
  • Шаг 5: Обеспечьте хранение и доставку результатов. Продумайте уведомления участникам.
  • Шаг 6: Запустите в пилотном режиме на нескольких встречах, соберите обратную связь и доработайте.

Не забывайте о юридических аспектах: запись разговоров требует согласия участников. Предупредите их заранее.

Критерии выбора инструментов

При выборе компонентов ориентируйтесь на:

  • ASR: точность на русском языке, стоимость за минуту, возможность работы on-premise.
  • LLM: качество суммаризации, скорость, стоимость, возможность тонкой настройки.
  • Хранилище: надёжность, шифрование, соответствие политикам безопасности.
  • Оркестрация: простота развёртывания и масштабирования (Docker, Kubernetes).

Самодельный ассистент встреч — это не только экономия на подписках, но и гибкость под ваши процессы. Главное — тщательно тестировать каждый компонент и быть готовым к неожиданностям.