История о том, как я пытаюсь создать голосового AI помощника для моего 5-летнего сына.
Создание AI помощника - идея не новая, особенно с учетом массового распространения ИИ в последний год и появления голосового ассистента от OpenAI и их Realtime API - которое позволяет разработчикам создавать мультимодальные интерфейсы с низкой задержкой преобразования речи в речь.
Хотя API OpenAI предлагает потрясающие возможности, высокая стоимость ($100 за 1 млн входных токенов и $200 за 1 млн выходных токенов) подталкивает к поиску более доступных решений. Поэтому я обратил внимание на опенсорсный проект LiveKit, предлагающий масштабируемую связь в реальном времени. Одной из интересных функций - возможность интеграции ИИ агентов. И я решил попробовать использовать их решение, для создания госового помощника.
Типичный pipeline голосового агента в LiveKit выглядит следующим образом:
Если просто: голосовой поток пользователя преобразуется в текст. Полученный текст передается в большую языковую модель (LLM), которая, следуя заданным инструкциям (промпту), генерирует текстовый ответ. Текстовый ответ, сгенерированный LLM, преобразуется в аудиопоток. Сгенерированный аудиопоток воспроизводится.
В моем проекте используются следующие компоненты LiveKit:
VAD: детектор голосовой активности - Silero VAD .
SST (Speech-to-Text): Мультиязычная модель nova-2-general от Deepgram.
LLM (Large Language Model): GPT-4o от OpenAI. Однако, LiveKit поддерживает и другие модели, совместимые с OpenAI API (Groq, Perplexity, TogetherAI и др.).
TTS (Text-to-Speech): Использован сервис OpenAI с голосом "alloy". Возможны и другие варианты (Deepgram, и др.).
Цели проекта
Моя цель — создать интерактивного учителя, способного не только объяснять материал, но и управлять интерактивными инструментами в режиме реального времени, подобно живому учителю, который одновременно рассказывает и показывает. Ключевая задача — реализовать голосового помощника с "потоковым" управлением интерактивными инструментами .
Математика с интерактивной таблицей
Чтобы проверить идею управления интерактивными инструментами с помощью голосового помощника, я выбрал упражнение из учебника Oxford International Primary Maths на тему "десятки". Помощник должен объяснять материал и одновременно используя интерактивную таблицу выделять столбцы, строки или отдельные ячейки, иллюстрируя свои объяснения.
Этапы реализации:
1. Создание интерактивной таблицы
На Vue.js создана интерактивная таблица 10x10, позволяющая выделять столбцы, строки и отдельные ячейки.
2. Постановка задачи для LLM
LLM получила инструкцию: объяснить пятилетнему ребенку понятие "десятки" и как с ними считать, используя интерактивную таблицу.
Описание API для взаимодействия с таблицей:
Я описал взаимодействие с интерактивной таблицей через OpenAPI. Например, для выделения столбца должен быть использован вызов: http POST /highlight-column?column=1
.
###API You may call interactive table use openAPI:
openapi: 3.0.0
info:
title: Interactive Table API
version: 1.0.0
description: API for managing a 10x10 interactive number table
paths:
/highlight-column:
post:
summary: Highlight Column
description: Highlights the specified column in the table
operationId: highlightColumn
parameters:
- name: column
in: query
description: Column number to highlight (1-10)
required: true
schema:
type: integer
minimum: 1
maximum: 10
responses:
'200':
description: Successfully highlighted the column
/highlight-row:
post:
summary: Highlight Row
description: Highlights the specified row in the table
operationId: highlightRow
parameters:
- name: row
in: query
description: Row number to highlight (1-10)
required: true
schema:
type: integer
minimum: 1
maximum: 10
responses:
'200':
description: Successfully highlighted the row
/highlight-number:
post:
summary: Highlight Number
description: Highlights the specified number in the table
operationId: highlightNumber
parameters:
- name: number
in: query
description: Number to highlight (1-100)
required: true
schema:
type: integer
minimum: 1
maximum: 100
responses:
'200':
description: Successfully highlighted the number
###CALL API
If you need to set an example for a child, always use an interactive table, for example:
```http POST /highlight-column?column=1```
Ответ LLM: LLM генерирует вызов функции непосредственно в ответе, а не отдельным процессом.
3. Синхронизация вызова функции и воспроизведения аудио
Основная сложность заключалась в синхронизации вызова функции с воспроизведением аудио. Синхронизация должна происходить именно во время воспроизведения, а не во время генерации ответа LLM или преобразования текста в речь.
Архитектура потока данных
Базовый поток данных в системе выглядит следующим образом:
STT → LLM → TTS → PlayoutAudio
Для реализации синхронизации потребовалось внести изменения в исходный код проекта LiveKit на следующих этапах LLM - TTS - PlayoutAudio. А именно, найти и пробросить на все дальнейшие этапы “вызов функции”.
Анализ ответа от LLM: На этапе получения ответа от LLM (в режиме stream) добавлена посимвольная проверка на наличие маски вызова функции, которая определяет, есть ли в тексте вызов функции. Найденная функция собирается как отдельное предложение.
-
Обработка TTS: Текст, генерируемый LLM (в режиме stream), накапливается в буфере и периодически, когда набирается достаточно данных (достигнута минимальная длина предложения), отправляет на генерацию аудио.
При этом, если при разбивке на предложения мы встречаем “вызов функции”, то следующему предложению мы добавляем отдельный параметр call_tools, а сам “вызов функции” не оптравялется в TTS (озвучивать же его не надо).
Таким образом это эмулируют стриминг, разбивая текст на предложения и отправляя каждое предложение в TTS . Это позволяет обрабатывать длинные тексты, обеспечивая постепенное получение аудиофреймов.
Воспроизведение и вызов функции: На этапе воспроизведения (PlayoutAudio) происходит проверка
call_tools
в каждом аудиофрейме. Еслиcall_tools
содержит данные, то осуществляется вызов соответствующей функции в момент начала воспроизведения текущего аудиофрейма. Это обеспечивает синхронизацию с содержанием, произносимым в данный момент.
Таким образом, данная архитектура позволяет достигнуть синхронизации: разбиение текста на предложения и обработка каждого предложения в отдельном экземпляре - ключевой элемент реализации, позволяющий связать команды с аудио и обеспечить их синхронное выполнение.
P.S. Разбиение на отдельные предложения уже был реализован в LiveKit для работы с нестриминговыми TTS.
Почему стандартный вызов функций не подошёл
Как вы знаете LLM может вызывать функции, чтобы управлять внешними сервисами и на самом деле LiveKit реализовало поддержку call function.
Однако, стандартный вызов функций LLM - не обеспечивал необходимую синхронизацию, проблемы возникали при множественных вызовах, не позволяя четко определить момент их исполнения.
Небольшой тест работы вызовов функций в "потоковом" режиме
Это лишь первые эксперименты, и я планирую дальше развивать данный проект. Любые ваши предложения и критика помогут мне улучшить ассистента быстрее. Спасибо!
Комментарии (4)
ioleynikov
31.10.2024 07:31Математические таблицы в 5 лет? несчастный ребенок :-) Я конечно шучу! Но у меня есть похожие идеи. На самом деле можно превратить в интерактивные мультимедиа приложения обычные учебники *.pdf форматов в автоматическом режиме. OCR -> парсинг текста -> генерация дескриптивного описания учебника в HTML для плеера, добавление TTS, картинок и т.д. Это может быть очень полезно для детей, обучения языкам, программированию. Если немного напрячься и подключить генеративные нейронные сети, то картинки и анимацию можно добавить самому по текстам глав, примерами, тестовым вопросам.
DmitriiFilippov Автор
31.10.2024 07:31Пока я доведу эту реализацию до ума - пройдет еще много времени, а так это уровень первого класса.)
Да, идея в том то и была, взять тот же учебник по математике, переработать все задания в инструкции для LLM. Если в задании присутствует элемент интерактивности - с помощью той-же LLM сгенерировать интерактивную среду. Кстати эта таблица тоже была написана с помощью LLM (за 20 минут). Так что да, вектор понятен.ioleynikov
31.10.2024 07:31Я исключительно желаю Вам Удачи и Успеха в Вашем проекте, а так же хороших выходных! На самом деле даже из BERT можно вытащить кучу концептуальных и прагматических знаний. Мое мыло oleynikov.ig@gmail.com Пишите, не стесняйтесь если будут траблы. Мы делаем одно дело!
ENick
Развитие этого проекта может быть очень интересным и для взрослых