Связано с Testlify

MetaNotes: ИИ-ассистент для встреч

Отвечал за фронтенд ИИ-помощника для встреч, который подключается к звонкам и превращает их в расшифровки, сводки и аналитику: используется публично и внутри компании, заменив платного вендора.

MetaNotes, это ИИ-ассистент для встреч, который подключается к звонкам в Google Meet, Microsoft Teams и Zoom и создаёт расшифровки, action item и сводки разговора. Это публичный продукт, а внутри компании он заменил Fireflies и tl;dv: их функции были закрыты платными тарифами, а расходы на хранение записей росли, так что оба сервиса перестали подходить команде. Я был единственным фронтенд-инженером на проекте и полностью отвечал за фичи, деплой и продуктовые решения на протяжении примерно 5 месяцев разработки.

MetaNotes

Что я сделал

  • Интерфейс расшифровки: построил просмотрщик расшифровки с подсветкой, синхронизированной по таймкоду. Активная строка следует за позицией воспроизведения видео, а клик по любой строке перематывает плеер к этому моменту.
  • Дашборд аналитики встреч: разработал интерактивные представления для сводок от ИИ, отслеживания action item, индикаторов тональности и тегов тем.
  • Фронтенд-архитектура: был единственным фронтенд-инженером от идеи до продакшена. Скоуп фич, архитектура компонентов, управление состоянием и деплой были полностью на мне. Бэкенд-пайплайн асинхронный и построен на вебхуках и cron-задачах: расшифровки и сводки подтягиваются одним запросом после завершения обработки, а не транслируются вживую.

Почему это было важно

MetaNotes вышел как публичный SaaS-продукт, а внутри компании его стали использовать более 200 сотрудников Testlify для записи встреч и звонков с клиентами, заменив Fireflies и tl;dv. Это убрало $24 000 годовых операционных расходов, которые раньше платились этим вендорам.

Возглавил проект, с полной ответственностью от начала до конца

Я возглавил MetaNotes как фронтенд-инженер, и ответственность выходила за рамки UI. Скоуп фич, деплой и повседневные продуктовые решения тоже были на мне. От первого коммита до внутреннего запуска прошло около 5 месяцев.

Почему расшифровка появляется после встречи, а не во время неё

MetaNotes не стримит текст расшифровки, пока бот находится на звонке. Во время записи интерфейс показывает только статус-бейдж (Capturing/Paused) с кнопками паузы, возобновления и остановки. Обработка идёт через вебхук Attendee (API бота для встреч, который подключается к звонку и записывает медиа) и набор запланированных cron-задач: расшифровка и суммаризация через OpenAI выполняются асинхронно после завершения звонка, а фронтенд получает готовую расшифровку, сводку и action item одним вызовом серверного экшена.

При пятимесячном сроке разработки, который включал ещё и скоуп фич, деплой и продуктовые решения, живой стриминг не оправдывал своей цены. Он потребовал бы поддерживать WebSocket-соединение, обрабатывать сверку частичной расшифровки и переподключения, и всё это ради возможности (наблюдать, как расшифровка собирается в реальном времени), которая пользователям на самом деле была не нужна. Асинхронная обработка после звонка даёт ту же расшифровку, сводку и action item с гораздо меньшим числом движущихся частей, поэтому в релиз пошло именно это.

Подсветка расшифровки, синхронизированная по таймкоду

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

Модель данных и масштаб

  • Расшифровка хранится как единый JSON-блоб на каждый разговор, без разбивки на чанки и без пагинации на уровне базы данных.
  • Списки разговоров и календаря пагинируются по 10-20 элементов на страницу.
  • Запросы на суммаризацию к OpenAI ограничены 800 токенами вывода на запрос.

При текущем объёме и длительности встреч это работает нормально. Если что-то из этого вырастет на порядок, в первую очередь я бы пересмотрел столбец расшифровки с единым блобом и линейный поиск для подсветки. Это осознанные компромиссы, а не слепые зоны.

Строить самим или покупать

Testlify платил за Fireflies и tl;dv, но оба сервиса закрывали ключевые функции платными тарифами и дорожали по мере роста объёма записанных встреч. Разработка своими силами сняла оба ограничения; после того как более 200 сотрудников стали использовать сервис для записи встреч и звонков с клиентами, это сэкономило $24 000 в год, которые раньше уходили этим вендорам.

Стек

Next.js 16 / React 19 App Router, TypeScript, Zustand для состояния на клиенте (с сохранением в localStorage), Clerk для аутентификации, Radix + Tailwind для интерфейса, Vidstack для плеера записи, Attendee как API бота для захвата встреч в Zoom/Meet/Teams.