TTS API

Endpoints для Text-to-Speech. Для server-to-server интеграции отправляйте X-Api-Key в каждом запросе.

API v1 TTS Sync / Async Realtime

Overview #

  1. 1 Для генерации аудио отправьте transcript на POST /api/v1/tts/post/.
  2. 2 Если передать webhook_notification_url, запрос будет обработан async и вернет 202 Accepted.
  3. 3 Проверяйте результат через GET /api/v1/tts/status/{id}/ или history.
  4. 4 Используйте wss://back.aisha.group/api/v1/tts/realtime для realtime TTS через WebSocket или back.aisha.group:443 через gRPC.
  5. 5 Отправляйте несколько text turn через одно постоянное соединение и не подключайтесь заново для каждого turn.
  6. 6 Тарификация TTS идёт по символам после проверки баланса при начале stream.

Удобнее CLI? npm-пакет aisha-ai оборачивает эти endpoints: npx aisha-ai tts / npx aisha-ai stt. aisha-ai на npm

API Key #

  • API Key

    X-Api-Key: <api_key>

    Рекомендуется для server-to-server интеграций.

  • Streaming auth

    WebSocket: ?token=<api_key> | gRPC: x-api-key: <api_key>

    WebSocket использует query token, а gRPC принимает API key в metadata.

Создать аудио #

POST https://back.aisha.group/api/v1/tts/post/

Преобразует текст в аудио. Для language=uz используется built-in модель Gulnoza. Для en и ru параметры model, mood, speed не отправляются.

Аутентификация: Отправьте X-Api-Key. Public-запросы могут требовать reCAPTCHA.

  • Лимит: 1000 символов с API key, 500 символов для public-запроса.
  • speed: 0 или значение в диапазоне 0.5-2.0.
  • mood работает только для built-in Gulnoza. При voice_id параметр mood не используется.

Поля запроса #

transcript обязательно

string

Текст для озвучивания.

Пример: Assalomu alaykum

language

string

Поддерживается: uz, en, ru. Default: uz.

Пример: uz

model

string

Только для built-in потока uz. Сейчас доступна только одна модель: Gulnoza.

Пример: Gulnoza

mood

string

Только для built-in Gulnoza. Доступно 4 mood: Neutral, Cheerful, Happy, Sad. Для voice_id, en, ru не отправляется.

Пример: Neutral

speed

float

Только для потока uz. 0 означает default speed. Custom: 0.5-2.0.

Пример: 1.0

voice_id

integer

READY custom voice ID, принадлежащий user'у. Если используется voice_id, mood не отправляется.

Пример: 12

webhook_notification_url

string

Если задан, TTS запускается async.

Пример: https://example.com/webhooks/tts

Примеры #

Sync request

curl --request POST \
  --url https://back.aisha.group/api/v1/tts/post/ \
  --header 'X-Api-Key: your_api_key' \
  --header 'Accept-Language: uz' \
  --form 'transcript=Assalomu alaykum, bu AIsha TTS sinovi.' \
  --form 'language=uz' \
  --form 'model=Gulnoza' \
  --form 'mood=Neutral' \
  --form 'speed=1.0'

Async request

curl --request POST \
  --url https://back.aisha.group/api/v1/tts/post/ \
  --header 'X-Api-Key: your_api_key' \
  --form 'transcript=Webhook orqali qaytadigan sinov matni.' \
  --form 'language=uz' \
  --form 'webhook_notification_url=https://example.com/webhooks/tts'

CLI (aisha-ai)

export AISHA_API_KEY=your_api_key
npx aisha-ai tts "Salom dunyo" --model Gulnoza --out salom.wav

Ответы #

201 Created

Sync success

{
  "audio_path": "/media/tts_audios/request-id.wav"
}
202 Accepted

Async queued

{
  "id": 184,
  "task_id": "7d5f8779-9cb0-4230-9318-2f8c3c3f0e31",
  "status": "PENDING"
}

Статус-коды #

201

Аудио готово, вернулся `audio_path`.

202

Async task поставлен в очередь.

400

Ошибка transcript, language, model или speed.

401

Для custom voice нужна авторизация.

402

Недостаточно баланса.

503

TTS сервис временно недоступен.

Проверить статус #

GET https://back.aisha.group/api/v1/tts/status/{id}/

Возвращает состояние async TTS task.

Аутентификация: Отправьте X-Api-Key.

  • Возможные статусы: PENDING, SUCCESS, FAILED.

Примеры #

Status request

curl --request GET \
  --url https://back.aisha.group/api/v1/tts/status/184/ \
  --header 'X-Api-Key: your_api_key'

Ответы #

200 OK

Pending

{
  "id": 184,
  "status": "PENDING",
  "task_id": "7d5f8779-9cb0-4230-9318-2f8c3c3f0e31"
}
200 OK

Completed

{
  "id": 184,
  "status": "SUCCESS",
  "task_id": "7d5f8779-9cb0-4230-9318-2f8c3c3f0e31",
  "audio_path": "/media/tts_audios/request-id.wav",
  "characters": 42
}

Статус-коды #

200

Статус получен.

403

Нет доступа к record другого user'а.

404

TTS record не найден.

История #

GET https://back.aisha.group/api/v1/tts/get/?page=1&limit=10

Возвращает paginated историю TTS audio текущего user'а.

Аутентификация: Требуется X-Api-Key.

  • Response приходит в формате count, next, previous, results.

Примеры #

History request

curl --request GET \
  --url 'https://back.aisha.group/api/v1/tts/get/?page=1&limit=10' \
  --header 'X-Api-Key: your_api_key'

Ответы #

200 OK

Paginated success

{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": 184,
      "transcript": "Assalomu alaykum, bu AIsha TTS sinovi.",
      "audio_url": "/media/tts_audios/request-id.wav",
      "model": "Gulnoza",
      "mood": "Neutral",
      "created_at": "2026-05-04T10:15:30Z"
    }
  ]
}

Статус-коды #

200

History получена.

403

API key неверный или не отправлен.

Realtime WebSocket TTS #

WS wss://back.aisha.group/api/v1/tts/realtime?token=YOUR_API_KEY

Send multiple text turns over one persistent WebSocket connection. Each turn returns metadata followed by binary WAV bytes.

Аутентификация: Send the API key as the token query parameter. Balance and character pricing are checked when the session starts.

  • Requests are JSON text messages with request_id, speaker_id, language, text, and speed.
  • Built-in speakers: happy, cheerful, neutral, sad.
  • Defaults: language=uz and speed=1.0.
  • The response is a mono, 16-bit, 16 kHz WAV. The JSON metadata frame is followed by one binary audio frame.
  • Send {"type":"end"} once to close the session. Keep the connection open for subsequent turns.

Поля запроса #

token обязательно

string

API key in the query string.

Пример: YOUR_API_KEY

speaker_id

string

One of happy, cheerful, neutral, sad.

Пример: happy

language

string

Default: uz.

Пример: uz

text обязательно

string

Text to synthesize.

Пример: Assalomu alaykum

speed

float

Default: 1.0.

Пример: 1.0

Примеры #

Browser WebSocket

const token = 'your_api_key'
const ws = new WebSocket('wss://back.aisha.group/api/v1/tts/realtime?token=' + encodeURIComponent(token))

ws.onmessage = event => {
  if (typeof event.data === 'string') {
    const message = JSON.parse(event.data)
    if (message.type === 'audio') console.log(message.request_id, message.sample_rate, message.duration_sec)
    if (message.type === 'error') console.error(message.code, message.message)
    return
  }
  // Binary frame: complete 16 kHz mono WAV bytes.
  playWav(event.data)
}

ws.onopen = () => ws.send(JSON.stringify({
  request_id: 'turn-1',
  speaker_id: 'happy',
  language: 'uz',
  text: 'Assalomu alaykum, bu Aisha TTS sinovi.'
}))

// Reuse this connection for later turns, then close the session once.
function finishSession() {
  ws.send(JSON.stringify({ type: 'end' }))
}

Request JSON

{
  "request_id": "turn-1",
  "speaker_id": "happy",
  "language": "uz",
  "text": "Assalomu alaykum, bu Aisha TTS sinovi.",
  "speed": 1.0
}

Ответы #

message

Session started

{
  "type": "session_started",
  "session_id": "7ab6d67a-9a29-4ad9-90b7-d2f5b2fc08fb",
  "billing": "characters"
}
message + binary

Audio metadata + WAV bytes

{
  "type": "audio",
  "request_id": "turn-1",
  "speaker_id": "happy",
  "sample_rate": 16000,
  "duration_sec": 1.84,
  "characters": 42
}

// The next WebSocket frame is binary audio_wav bytes.
message

Balance error

{
  "type": "error",
  "code": "insufficient_balance",
  "message": "TTS character balance limit reached"
}

Статус-коды #

1000

Session closed normally.

1008

API key or balance was rejected.

synthesis_failed

Text or speaker synthesis failed.

Persistent gRPC TTS stream #

gRPC back.aisha.group:443/aisha.tts.RealtimeTTS/Synthesize

Send sequential text turns in one client-streaming request and receive one server-streaming audio response per turn.

Аутентификация: Send x-api-key: <api_key> as gRPC metadata.

  • TLS endpoint: back.aisha.group:443.
  • Each SynthesizeRequest is one text turn. Send end=true to finish the stream.
  • Reuse one gRPC channel for the complete voice-agent session; do not create a channel for every turn.
  • Each response contains 16 kHz WAV audio_wav, sample_rate, duration_sec, characters, and request_id.
  • TTS billing is based on characters after balance verification at stream start.

Поля запроса #

text обязательно

string

Text to synthesize.

Пример: Assalomu alaykum

speaker_id

string

Built-in speaker ID.

Пример: neutral

language

string

Default: uz.

Пример: uz

speed

float

Default: 1.0.

Пример: 1.0

end

boolean

Finishes the persistent stream.

Пример: true

Примеры #

Python persistent stream

import grpc
import tts_pb2
import tts_pb2_grpc

channel = grpc.secure_channel('back.aisha.group:443', grpc.ssl_channel_credentials())
client = tts_pb2_grpc.RealtimeTTSStub(channel)

def requests():
    yield tts_pb2.SynthesizeRequest(
        request_id='turn-1', speaker_id='happy', language='uz',
        text='Assalomu alaykum, bu Aisha TTS sinovi.'
    )
    yield tts_pb2.SynthesizeRequest(
        request_id='turn-2', speaker_id='neutral', language='uz',
        text='Keyingi turn shu channel ichida davom etadi.'
    )
    yield tts_pb2.SynthesizeRequest(end=True)

for response in client.Synthesize(requests(), metadata=(('x-api-key', 'your_api_key'),)):
    if response.error_code:
        raise RuntimeError(response.error_message)
    save_wav(response.audio_wav)

# Reuse channel and create another Synthesize stream for the next session.
channel.close()

Ответы #

OK

Synthesis response

{
  "request_id": "turn-1",
  "speaker_id": "happy",
  "sample_rate": 16000,
  "duration_sec": 1.84,
  "characters": 42,
  "audio_wav": "bytes"
}
stream response

Error

{
  "type": "error",
  "code": "insufficient_balance",
  "message": "TTS character balance limit reached"
}

Статус-коды #

OK

Audio response returned.

UNAUTHENTICATED

API key metadata is missing or invalid.

RESOURCE_EXHAUSTED

TTS character balance is insufficient.