Демонстрация TTS API: примеры запросов и ответов в реальном времени
Эта демонстрация показывает реальные запросы, которые можно выполнить за минуту, и формат ответа. API — текстовая модель, поэтому вывод — это текст для озвучки, JSON и вызовы функций, которые отдельный голосовой движок может прочитать вслух.
Обновлено

Перед запуском
Честное предупреждение для тех, кто ожидает нажать кнопку воспроизведения и услышать голос: эта демонстрация TTS API не издает звуков. Сервис возвращает текст от одной модели, uncensored, через POST /v1/chat/completions. Есть второй эндпоинт, GET /v1/models, для списка доступных моделей. Ничто не возвращает аудио, изображения или эмбеддинги.
Зачем тогда демонстрация? Потому что многим речевым проектам нужна именно эта часть: автор сценария, очиститель текста, сплиттер, решающий, кто что говорит. Приведенные ниже примеры показывают выполнение этих задач, а формат вывода — это то, что будет парсить ваш речевой код.
Вам нужен ключ. Зарегистрируйтесь на странице API-ключей через Google или с помощью электронной почты и пароля, затем получите пробный баланс $0.50 в один клик. Он действителен в течение 7 дней и не требует привязки карты. Экспортируйте ключ, чтобы приведенные ниже команды могли его прочитать:
export XTTS_API_KEY="paste-your-key-here"
curl -s https://api.xtts.cc/v1/models -H "Authorization: Bearer $XTTS_API_KEY" | grep uncensored
Если этот вызов возвращает список JSON, включающий uncensored, ключ работает, и вы можете продолжить.
Демонстрация 1: обычный запрос
Самый минимальный полезный вызов запрашивает короткий абзац в разговорном стиле:
curl -s https://api.xtts.cc/v1/chat/completions \
-H "Authorization: Bearer $XTTS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "uncensored",
"messages": [
{"role": "system", "content": "You write short lines for a voice actor. No stage directions."},
{"role": "user", "content": "Welcome listeners to a show about lighthouses. Two sentences."}
],
"temperature": 0.7,
"max_tokens": 120
}'
Ответ выглядит так, как показано ниже. Текст внутри content будет отличаться при каждом запуске, поэтому воспринимайте его как иллюстрацию структуры, а не как записанный вывод.
{
"id": "chatcmpl-example",
"object": "chat.completion",
"model": "uncensored",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Welcome to the show. Tonight we climb the stairs of the world's loneliest lighthouses."
},
"finish_reason": "stop"
}
],
"usage": {"prompt_tokens": 38, "completion_tokens": 21, "total_tokens": 59}
}
Ваш код для синтеза речи читает choices[0].message.content. Поле finish_reason указывает причину завершения генерации: stop для естественного завершения, length, если max_tokens обрезал текст. Если вы не указываете max_tokens, завершение может занять оставшееся место в окне на 100 000 токенов, которое включает промпт и завершение вместе.
Что говорят заголовки
Добавьте -i в команду curl, и вы увидите X-Request-Id, X-Balance-USD, X-RateLimit-Limit-Requests и X-RateLimit-Limit-Concurrency. Заголовок баланса полезен в демо, потому что вы можете наблюдать, как он уменьшается на крошечную сумму после каждого вызова. Для этого запроса использование выше составляет 38 x $0,15 / 1 000 000 плюс 21 x $0,50 / 1 000 000, что равно $0,0000057 плюс $0,0000105, около $0,0000162.
Демонстрация 2: потоковая передача сценария
Для аудио вы редко хотите ждать полный текст. Добавьте "stream": true, и API отправляет Server-Sent Events, по небольшому фрагменту текста за раз. Пример на Node ниже выводит текст по мере поступления, и именно сюда можно подключить очередь предложений.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.xtts.cc/v1",
apiKey: process.env.XTTS_API_KEY,
});
const stream = await client.chat.completions.create({
model: "uncensored",
stream: true,
messages: [
{ role: "user", content: "Read a four-line weather report for a coastal town." },
],
});
for await (const chunk of stream) {
const piece = chunk.choices[0]?.delta?.content ?? "";
process.stdout.write(piece);
}
process.stdout.write("\n");
Запустите его как ES-модуль (сохраните как demo.mjs и запустите node demo.mjs после npm install openai). В сети каждое событие — это строка, начинающаяся с data:, за которой следует JSON, и поток закрывается финальным маркером. Использование токенов сообщается в конце потока. Один важный момент для планирования: потоковый запрос удерживает слот параллелизма до тех пор, пока поток не завершится, поэтому медленный потребитель может заблокировать ваш следующий запрос.
Демонстрация 3: вызов функций как маршрутизатор речи
Вызов функций позволяет модели вернуть структурированную инструкцию вместо текста. В голосовом проекте это чистый способ выбрать стиль подачи для каждой строки. Вы определяете функцию с именем say, и модель заполняет ее аргументы. Ваш код затем решает, что с ними делать. Модель не выполняет ничего самостоятельно.
import json
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.xtts.cc/v1", api_key=os.environ["XTTS_API_KEY"])
tools = [{
"type": "function",
"function": {
"name": "say",
"description": "Queue one line for the voice engine.",
"parameters": {
"type": "object",
"properties": {
"text": {"type": "string"},
"style": {"type": "string", "enum": ["calm", "urgent", "whisper"]},
},
"required": ["text", "style"],
},
},
}]
messages = [
{"role": "system", "content": "Always answer by calling say, once per line."},
{"role": "user", "content": "The alarm sounds. The guard tells everyone to leave."},
]
r = client.chat.completions.create(
model="uncensored", messages=messages, tools=tools, tool_choice="auto"
)
msg = r.choices[0].message
for call in msg.tool_calls or []:
args = json.loads(call.function.arguments)
print(args["style"], "->", args["text"])
Аргументы поступают в виде строки JSON, поэтому распарсите их и проверьте перед использованием. Модели могут выдать стиль вне вашего перечисления или пропустить поле, и непроверенное значение никогда не должно достигать вашего движка. Если вы хотите продолжить разговор, добавьте сообщение ассистента и ответ с role: "tool" и соответствующим tool_call_id, затем снова вызовите API.
При потоковой передаче вызовы функций поступают частями. Имя функции приходит первым, а строка аргументов накапливается по частям, поэтому собирайте фрагменты по индексу и парсите их один раз после завершения потока.
Демонстрация 4: JSON-режим для списка ролей
Если вы предпочитаете пропустить определения функций, JSON-режим дает валидный JSON в содержании сообщения. Это хорошее решение для преобразования черновой сцены в строки по говорящим.
curl -s https://api.xtts.cc/v1/chat/completions \
-H "Authorization: Bearer $XTTS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "uncensored",
"response_format": {"type": "json_object"},
"temperature": 0.2,
"messages": [
{"role": "system", "content": "Return JSON: {\"lines\": [{\"speaker\": string, \"text\": string}]}"},
{"role": "user", "content": "Ana asks Ben to hold the ladder. Ben agrees reluctantly."}
]
}'
JSON-режим гарантирует, что вывод будет распарсен, а не то, что он соответствует вашей структуре. Опишите структуру в промпте, как выше, и проверяйте ключи в коде. Низкое значение температуры сохраняет структуру стабильной.
Демонстрация 5: длинный документ в одном запросе
Контекстное окно составляет 100 000 токенов, общих для промпта и завершения. Этого достаточно, чтобы отправить длинную расшифровку или целый короткий рассказ и попросить версию, написанную для слуха. Тело запроса может быть до 8 МБ, поэтому размер редко является ограничением; ограничением является количество токенов.
Вот стоимость тяжелого вызова. Скажем, вы отправляете 80 000 токенов и получаете 2 000 обратно. Вход: 80 000 x $0,15 / 1 000 000 = $0,012. Выход: 2 000 x $0,50 / 1 000 000 = $0,001. Итого $0,013, поэтому пробных $0,50 хватит примерно на 38 таких вызовов. Длинный вход дешев по сравнению с длинным выходом, поэтому краткие пересказы и переписывание больших текстов доступны по цене, а вот генерация целого романа за один раз — нет.
Практический совет для длинных входов: помещайте инструкции в начало и повторяйте ключевое правило в конце. Модели склонны лучше следовать последней инструкции, и однострочное напоминание после 80 000 токенов исходного текста стоит почти ничего.
Чтение ошибок в демонстрации
Намеренно сломайте что-то один раз, чтобы узнать это позже. Отправьте запрос с неверным ключом, и вы получите ошибку аутентификации вместо завершения. Отправьте десять запросов одновременно с пробного ключа, и некоторые из них вернут HTTP 429.
У 429 есть три причины, и код ошибки различает их:
rate_limitedозначает слишком много запросов за одну минуту: 60 на пробном ключе, 300 на полном ключе.concurrencyозначает слишком много запросов в процессе одновременно: 2 на пробном ключе, 8 на полном ключе.- 429 с заголовком
Retry-After: 5означает, что сервис был временно перегружен. Подождите пять секунд и отправьте его снова.
Неудачные или отклоненные запросы не тарифицируются, поэтому ошибки ничего не стоят. Чтобы увидеть лимиты вашего ключа, прочитайте X-RateLimit-Limit-Requests и X-RateLimit-Limit-Concurrency в любом нормальном ответе. Небольшой цикл повторных запросов, который ждет значение Retry-After или пять секунд, если оно отсутствует, — это все, что нужно для демонстрационного скрипта.
Что попробовать дальше
После того как эти четыре вызова заработают, у вас есть компоненты конвейера для сценариев. Оберните обычный запрос в функцию, запустите цикл потоковой передачи в очередь и подключите очередь к речевому движку по вашему выбору. Движки различаются по цене, лицензии и качеству, поэтому ознакомьтесь с их текущими условиями. Этот сервис такой движок не предоставляет и ничего о них не заявляет.
Затраты остаются небольшими во время экспериментов. При цене $0,15 за миллион входных токенов и $0,50 за миллион выходных токенов, типичный вызов демо обходится в долю цента, а пробные $0,50 покрывают сотни таких вызовов. См. страницу цен для пополнения от $20 до $500 с бонусами от 5% до 15%, оплата криптовалютой. документация охватывает полный список параметров, лимиты запросов (8 одновременных и 300 в минуту для полного ключа) и коды ошибок. Промпты не используются для обучения.
Разумный порядок действий для первого вечера: запустите обычный запрос, пока интонация не станет правильной, переключитесь на потоковую передачу и выводите предложения по мере завершения, затем добавьте либо вызовы инструментов, либо JSON-режим, в зависимости от того, как ваш речевой код хочет получать ввод. Храните каждый промпт в файле под контролем версий. Когда строка звучит неправильно в финальном аудио, вы можете отследить ее до точной инструкции, которая ее сгенерировала, и изменить одну вещь за раз.
Дополнительные руководства
Вопросы и ответы
Могу ли я услышать образец голоса в этой демонстрации?
Нет. API возвращает только текст, JSON и вызовы инструментов. Вы предоставляете отдельный речевой движок для преобразования текста в аудио.
Какой ID модели нужно указывать?
Укажите uncensored как значение модели, используя базовый URL https://api.xtts.cc/v1 и свой ключ в заголовке Authorization: Bearer.
Работают ли демо-примеры с пробным API-ключом?
Да. Пробный ключ позволяет выполнять 2 параллельных запроса и 60 запросов в минуту, чего достаточно для этих примеров. Запускайте их по одному.
Почему я получаю ответ 429?
Вы превысили лимит запросов в минуту (rate_limited), у вас было слишком много активных запросов одновременно (concurrency) или сервис был временно перегружен. Если указан заголовок Retry-After, дождитесь его истечения и повторите запрос.
Ваш ключ — всего в одной форме от вас
Создайте аккаунт, скопируйте ключ, измените базовый URL. Это вся настройка.