wss://tryaxolotl.ru/v1/tts/live. Протокол JSON: вы шлёте текст по кусочкам,
аудио приходит потоком. Один сокет обслуживает весь диалог: интонация остаётся
плавной внутри реплики (без полей previous_text / next_text), а конец аудио
каждой реплики сервер отмечает явным сообщением.
Для разовой озвучки целого текста достаточно HTTP
POST /v1/speech. WebSocket нужен, когда текст
генерируется по ходу (LLM, диалог) или важна непрерывная интонация.Подключение
- заголовок
Authorization: Bearer $AXOLOTL_API_KEY, или - заголовок
X-API-Key: $AXOLOTL_API_KEY, или - query-параметр
?api_key=$AXOLOTL_API_KEY(удобно в браузере).
audio_encoding: "binary" — бинарными кадрами.
Реплики (turns)
Сессия — это последовательность реплик. Реплика — один непрерывный кусок речи: вы стримитеtext, при желании форсируете синтез через flush, а затем
закрываете реплику через end_turn. Сервер отвечает turn_end после того,
как отдал последний чанк аудио этой реплики — угадывать конец по таймауту
тишины не нужно.
После turn_end сокет остаётся открытым: следующий text начинает следующую
реплику. Авторизация и TCP/TLS-хендшейк не повторяются.
flush и end_turn — разные вещи. flush только просит начать синтез
накопленного текста и не имеет подтверждения: интонация продолжает течь
дальше, поэтому его удобно слать после каждого предложения внутри реплики.
end_turn закрывает реплику целиком, подтверждается turn_end и сбрасывает
интонационный контекст перед следующей репликой.Протокол
Клиент → сервер
string
default:"axolotl"
Идентификатор голоса (
axolotl, daniil, sergey, dmitriy, polina,
tatyana или ваш private id). См. Голоса. Голос и
формат задаются один раз на сессию.string
default:"mp3"
Формат аудио:
mp3, mp3_high, mp3_low или pcm.string
default:"low"
Компромисс задержка/качество:
low, balanced, normal. Для агентов
рекомендуем low + pcm.string
default:"base64"
base64 — аудио приходит в JSON-сообщениях audio. binary — аудио
приходит бинарными кадрами WebSocket, без base64 и JSON-обвязки: на треть
меньше байт и меньше работы на обеих сторонах. Управляющие сообщения в обоих
случаях остаются текстовым JSON, так что различать их можно по типу кадра.Сервер → клиент
Пример сессии
ready, затем отправляйте текст:
Если вы отправите
end, не закрыв последнюю реплику через end_turn, сервер
сначала досинтезирует её и пришлёт turn_end, и только потом done.
Поэтому done — всегда надёжный признак того, что аудио больше не будет.Node.js
Python
Пример с бинарными кадрами — реплики отправляются одна за другой по одному сокету, конец каждой определяется поturn_end:
Как встроить в голосового агента
Типичный пайплайн: STT → LLM → TTS → воспроизведение. Axolotl закрывает блок TTS через одну долгоживущую WebSocket-сессию на реплику агента (или на весь диалог).Рекомендуемый цикл
- Подключиться к
wss://tryaxolotl.ru/v1/tts/liveс API-ключом — один раз на весь диалог. - Отправить
startсformat: "pcm"иlatency: "low". - По мере генерации LLM слать
text(токены или целые фразы). - После каждого предложения —
flush, чтобы аудио не ждало буфера. - Когда реплика закончена —
end_turn, дождатьсяturn_end. - Для следующей реплики — снова с шага 3, по тому же сокету.
- В конце диалога —
end, дождатьсяdone.
Как понять, что аудио закончилось
Только поturn_end (или done для всей сессии). Не используйте таймаут
тишины: паузы между чанками зависят от длины реплики и загрузки синтеза, и
любой порог рано или поздно либо обрежет хвост, либо добавит лишнюю задержку.
Единственный «таймаут» в протоколе — серверная страховка: если синтез завис и
за 30 секунд после end_turn не отдал ни одного чанка, сервер всё равно
закроет реплику сообщением turn_end, чтобы клиент не ждал вечно.
Почему нет previous_text / next_text
Эти поля есть у некоторых провайдеров в HTTP API. У Axolotl контекст интонации
держится внутри реплики: каждый новый text учитывает уже озвученное с
начала реплики. Границей контекста служит end_turn — поэтому длинный ответ
не надо резать на отдельные реплики, достаточно flush после предложений.
Pipecat
Создайте сервис на базеWebsocketTTSService:
_receive_messages декодируйте audio.data из base64 в TTSAudioRawFrame
(sample rate 44 100 Hz для pcm).
Barge-in (прерывание пользователем)
Когда пользователь перебивает агента:- Остановите воспроизведение у себя.
- Отправьте
end_turnи игнорируйте аудио доturn_end— сокет останется живым и готовым к следующей реплике. - Если нужно оборвать мгновенно и сессия больше не нужна — просто закройте сокет: уже отданное аудио будет затарифицировано, остальное отменится.
Настройки для минимальной задержки
См. также: Стриминг HTTP, Длинные тексты.
Эмоциональные теги
[смеётся], [шёпотом] и другие [...] работают и в
WebSocket-сессии — см. Эмоции и интонации.