Задача по созданию AI-ассистента очень интересная и востребованная на рынке.
Для чего она?
Структуризация и контроль процессов. Самый большой импакт, конечно же, всё это даёт на повторяющихся встречах (дейлики, двухнедельные срезы и т.д.). Большинство сотрудников бегают на десятки встреч в неделю, и «забыть», что было на предыдущей встрече, очень легко - в этот момент можно просто обратиться к RAG или к протоколам напрямую. Также есть сотрудники, участие которых необходимо, но невозможно, - таким сотрудникам можно прислать протокол на апрув. Некоторые уже даже автоматически ставят задачи в Jira через function call или MCP на основе протоколов! Но это не auto-accept - как правило, человек смотрит в протокол и нажимает кнопку.
Вроде вникли в плюсы от сервиса - давайте разберём, из каких частей состоит задача по написанию такого сервиса.
1. Транскрибатор
Две опции применения:
a) Офлайн-транскрибация
Очевидный кейс: запись заканчивается, и мы хотим извлечь из неё текст.
Требования: качество транскрибации, время играет небольшую роль, поэтому можем позволить себе SOTA-решения.
Опенсорс-решений немало хороших, но мы выбираем WhisperX, т.к. качество хорошее и можно добавлять кастомные слова.
У бизнесов часто есть специфичные термины, которые плохо распознаёт любой транскрибатор. Варианта два:
Добавить в словарь STT-модели, если такое возможно. Лечит, но, как правило, не всегда.
LLM few-shot пост-процессинг - пишем промпт вроде: «Ты работаешь с транскрибацией. Вот список терминов, в которых STT-модель могла допустить ошибку. Вот в таких контекстах эти термины используются, вот что они значат \примеры». Я бы рекомендовал отдельным вызовом, но можно и внутри саммари-вызова эту задачу подкинуть.
Минусы - больше нагрузки.
Плюсы - как правило, качественнее варианта 1.
Также под WhisperX есть хорошая диаризация для русского языка через русскую align-модель - а такое мы уважаем.
Как выбирать транскрибатор (от менее трудозатратного к более):
Фидбек в интернете (WhisperX - наш выбор).
Берём пачку записей и берём дорогое проприетарное API (Deepgram, ElevenLabs, Qwen ASR, Google Speech Kit и т.д.). Транскрибируем топ-моделями, смотрим, устраивает ли нас качество. Если качество этих моделей заказчика устраивает, то измеряем количество ошибок нашей модели на этой транскрибации. Скажу сразу - это смелая гипотеза: в такой оценке мы не столько стремимся к эталонному ответу, сколько утверждаем себе, что ответ топ-модели нас устраивает и мы стремимся к нему. Не самый надёжный способ, но хоть что-то.
Транскрибировать руками пачку встреч, проверить нашу модель и посчитать WER/CER + пробежаться глазами, где модель ошибается, поискать закономерности. Посмотреть, какие ошибки наиболее частые:
- такое слово есть, но модель написала его неправильно
- написала лишнее слово
- не дописала слово и т.д.
Также учитывайте наличие хорошей диаризации! Это очень важно, особенно в дальнейшем под идентификацию.
В результате данному сервису мы присылаем запись и получаем ответ вида:
speaker_1 00:00-00:13 привет ребят, собрал вас на часовую встречу, чтобы вы мне помогли найти кнопку, которая чётко прописана в документации, но я клал и на вас, и на документацию speaker_2 00:13-00:18 как ты задолбал, ей-богу, открывай документацию
b) Real-time режим (Wake Word Detection)
Есть заказчики, которые хотят, чтобы ассистента можно было вызвать в ходе встречи и как-то с ним провзаимодействовать. На помощь приходит задачка wake word detection - тут нам уже необходима быстрая real-time модель или API с целью уловить конкретное слово. Когда мы это слово улавливаем - делаем какой-то action. Такая тула позволяет дать ассистенту навыки, а примеры навыков:
Здесь должна быть ссылка на GitHub
Писать что-то напрямую без риска того, что это будет отсутствовать в протоколе: «Барбос (ассистент триггерится), запиши в список дел: убрать .env из публичного репозитория компании, срок выполнения - пару месяцев».
Задавать вопросы по старым встречам через RAG или tools: «Барбос, что мы на прошлой встрече обсуждали?» Барбос должен знать название текущей встречи, дату и календарь. Он заходит в транскрибацию и отвечает на вопрос - либо сообщением в чат ВКС, либо голосом через TTS. Для этого нам нужно взять ответ Барбоса, озвучить его моделью, включить микрофон в ВКС и отдать на этот микрофон запись. И помните, что всё это должно работать быстро - короче, я бы поделал такое, это весело :)
Итог по транскрибатору: мы должны получить асинхронное API, которое принимает на вход аудио и флаг diarize=True/False, а на выходе отдаёт task_id, по которому мы будем проверять статус транскрибации. Когда статус будет completed, отдельным эндпоинтом вытащим транскрибацию.
2. Коннектор
Тааакс, из аудио текст мы научились получать, а вот как извлечь запись и подключить к ней бота? Сейчас расскажем.
У нас должны быть готовы коннекторы к разным ВКС. В зависимости от ссылки мы должны понять, к какой ВКС она ведёт (Google Meet, Телемост, Zoom, Teams и т.д.).
Далее с помощью Playwright (Python-библиотека) пишем код, который будет поднимать контейнер и подключать к нему бота (следим за нагрузкой, чтобы рассчитать инфру - CPU/RAM). В Playwright есть handle-мод, в котором вы можете для каждой страницы изолированно написать код, а потом объединить это в пайплайн. Логируем информацию на странице + скриншоты, мутим звук и видео, указываем имя, прописываем критерии завершения сессии, записываем звук и видео в минимальном разрешении (800×600, например - видео потом расскажу зачем) - и опаааа!
У нас появился сервис, в который мы передаём ссылку, он подключает к этой ссылке бота, записывает видео, из которого мы потом можем извлечь аудиодорожку и передать в транскрибатор - и вуаля!
Если у вас большой трафик, обратите внимание, что у разных площадок разные анти-флуд лимиты на подключения анонимных пользователей с одного IP. Эти лимиты довольно большие, но тем не менее.
3. Интерфейсы для ссылок
Для ссылок мы будем использовать три интерфейса: Telegram-бот, панель нашего сайта (где пользователь может что-нибудь потыкать и посохранять) и календарь рабочей почты.
Если с первыми двумя всё понятно, то с последним нужно будет потрудиться. Все встречи, которые вы планируете через рабочий воркфлоу (Яндекс Календарь, Google Calendar или чем вы там пользуетесь), приходят на почту - либо с ICS-вложением, либо просто текстом. Там находится абсолютно вся нужная для планирования встречи информация.
Пишем SMTP/IMAP клиенты на отправку и чтение и добавляем бота во все встречи, в которые хотите, чтобы он пришёл. На периодичные встречи он будет приходить по той же ссылке - главное, БД продумать нормально и парсить правильно. Но это всё очень легко дебажится через нормальное логирование.
Далее пишем шедулер, который в конкретное время будет отправлять ссылки в наше API (коннектор). А остальные интерфейсы (Telegram и UI) можем подключить к API напрямую.
Промежуточный итог
На данный момент у нас готов сервис, который по получению ссылки напрямую или по событию в календаре подключает бота, извлекает видео и аудио из встречи. Затем аудио мы передаём в транскрибатор и получаем текст. Далее текст - в PostgreSQL, а аудио и видео временно в S3.
4. Идентификация спикеров
Есть два стула…
Наши пользователи уже подключают бота и получают транскрибацию с диаризацией, но наши скромняжки хотят идентификацию…
На помощь приходит то самое видео. Из видео по таймкодам мы вырезаем кадры с определёнными спикерами - по 20 штук, например, каждого спикера со случайных отрезков его речи - и берём то имя, которое чаще попадается. ВКС выводят на мейн-фрейм говорящего: берём кадр, вырезаем имя, отправляем в наше OCR API (см. далее) - получаем ответ, приравниваем к спикеру.
Проблем нет, работает хорошо, НО: наши любимые коллеги любят сидеть в переговорках, а тут засада - таких не победить. Одно решение - копить voice bank и идентифицировать через голосовые эмбеддинги, но это хранение биометрии, и задумайтесь, насколько вы готовы к этому.
А так - просто идентифицируем этих пользователей как «спикер из переговорки», и тоже пойдёт.
Обратите внимание: при извлечении кадров учитывайте, что при демонстрации экрана фрейм активного спикера меняет размер и расположение.
5. OCR API
Нужно только если хотим идентификацию. Surya OCR - лёгкая и справится замечательно. Пишем API, которое принимает изображение и возвращает буквы.
6. LLM (протоколы)
Поднимаем vLLM-раннер с нашей любимой 7B-70B моделью, пишем промпт на structured output, получаем JSON, парсим его в HTML или что угодно. А можно парсить его в ивенты на нашей платформе и, например (то, о чём я говорил в начале), раздать роли - и руководители смогут сразу в Jira из протокола назначать задачи или изменять их по апруву. Ну, короче, прикольно получается.
7. RAG
Про RAG будет отдельная статья, но если вкратце - это даст вам возможность задавать вопросы по предыдущим встречам без указания конкретной встречи (обязательно дайте пользователям пермишены!). Плюс это можно классно интегрировать с wake word detection, когда LLM даёт ответ в режиме real-time в чат вашей ВКС.
Только осторожнее с доступами тут!
Заключение
Ну вот наша песня подошла к концу. Надеюсь, что этот пост помог вам получить какое-то понимание того, как написать свой сервис AI-ассистента для ВКС.
На гитхабе вас уже ждет простенькая реализация от наших младшеньких, которая позволяет подключать бота к телемосту и зуму, а еще выложим в него whisper api репозиторий с хорошей диаризацией на русском!)
Если вам интересен какой-либо AI-сервис - напишите об этом в комментариях, и мы его разберём!
