メインコンテンツまでスキップ

WebSocket ストリーミング​(TTS)

WebSocket TTS API では、​完全な​テキストを​送信し、​生成された​音声を​ 1 本の​接続で​ストリーミングして​受け取れます。​合成が​完了する​前に​再生を​開始できます。

wss://api.shisa.ai/ws/tts/realtime
完全なテキストを入力、音声をストリーミングで出力

パス名に​反して、​これはリアルタイム ASR のような​入力ストリーミング API ではありません。​完全な​ tts.speak テキストリクエストを​送信すると、​サービスが​生成された​音声を​バイナリフレームまたは​ base64 JSON チャンクと​して​ストリーミングで​返します。

音声ファイル全体を​一度に​返す 1 回の​リクエスト/レスポンスが​必要な​場合は、​代わりに​ POST /tts エンドポイントを​使用してください。

要​件

  • 選択した​音声を​使用できる​ API キー​(WebSocket TTS の​クォータと​レート制限は​ shisa/tts サービスで​管理されます)。
  • GET /tts/voices から​取得した​音声の​ UUID — 音声カタログを​参照してください。
  • Authorization ヘッダーを​設定できる​サーバーサイドの​ WebSocket クライアント。​API キーは​サーバーサイドに​保管してください。

ハンドシェイク時に、​標準の​ベアラートークンで​認証します:

Authorization: Bearer YOUR_API_KEY

仕組み

  1. Authorization ヘッダーを​付けて​ WebSocket を​開きます。
  2. 必須の​ voice_id と​ format(および​任意の​ sample_ratetemperatureaudio_transport)を​含む session.update を​ 1 回送信します。
  3. session.created を​待ちます。
  4. 完全な​テキストを​含む tts.speak リクエストを​ 1 回送信します。
  5. tts.audio.start、​音声フレーム、tts.audio.donetts.usage を​読み取ります。
  6. さらに​ tts.speak リクエストを​順番に​送信するか、​ソケットを​クローズします。
一度に 1 つの合成のみ

1 セッションあたりアクティブに​できる​合成は​ 1 つだけです。​合成が​進行中に​ 2 つ目の​ tts.speak を​送信すると、synthesis_in_progress エラーが​返されます。​次の​リクエストを​送信する​前に​ tts.usage を​待ってください。

クライアントメッセージ

session.update

合成の​前に​ session.update を​ 1 回送信します:

{
"type": "session.update",
"id": "cfg_0001",
"session": {
"voice_id": "61ba1141-60aa-4bc3-a3b3-be1ec20700b3",
"format": "mp3",
"temperature": 0.7,
"audio_transport": "binary"
}
}
フィールド必須備​考
id任意クライアント相関 ID。​設定エラー時に​エコーされます。
voice_id必須GET /tts/voices から​取得した​公開音声の​ UUID。
format必須出力​音声​形式​ —​ mp3wavoggpcmflac の​いずれか。​使用可能な​値は​選択した​音声に​よって​異なります。
sample_rate任意省略するか​ 0 を​設定すると​バックエンドの​デフォルト​(24000 Hz)に​なります。
temperature任意一部の​音声で​受け付けられる、​音声の​ばらつきを​制御する​プロバイダー固有の​パラメータ。​デフォルトの​場合は​省略します。​明示的な​ 0.0 は​実値として​送信されます。
audio_transport任意binary(デフォルト)または​ base64_json音声トランスポートを​参照してください。

tts.speak

合成する​完全な​テキストを​送信します:

{
"type": "tts.speak",
"id": "utt_0001",
"text": "こんにちは。WebSocket TTS のテストです。"
}
フィールド必須備​考
id任意クライアント相関 ID。​この​リクエストの​ TTS イベントで​エコーされます。
text必須合成する​完全な​テキスト。​デフォルトの​上限は​ 5000 文字です。

サービスイベント

session.created

セッションが​設定され、tts.speak の​準備が​整いました​:

{
"type": "session.created",
"session": {
"id": "router-session-request-id",
"service": "shisa/tts",
"voice_id": "61ba1141-60aa-4bc3-a3b3-be1ec20700b3",
"format": "mp3",
"sample_rate": 24000,
"temperature": 0.7,
"model": "kokoro"
}
}

tts.audio.start

受け入れられた​合成リクエストを​示し、​受け取る​音声を​記述します:

{
"type": "tts.audio.start",
"id": "utt_0001",
"request_id": "synthesis-request-id",
"format": "mp3",
"content_type": "audio/mpeg",
"sample_rate": 24000,
"voice_id": "61ba1141-60aa-4bc3-a3b3-be1ec20700b3",
"model": "kokoro",
"audio_transport": "binary"
}

音声トランスポート

音声バイトの​届き方は、session.update で​設定した​ audio_transport に​よって​異なります:

  • binary(デフォルト)​ — 生成された​音声は​生の​バイナリ WebSocket フレームと​して​届きます。​順番に​連結してください。
  • base64_json — 音声は​ tts.audio.delta JSON メッセージと​して​届き、​base64 エンコードされた​バイトが​ audio に、​増加する​ seq が​含まれます:
{
"type": "tts.audio.delta",
"id": "utt_0001",
"request_id": "synthesis-request-id",
"seq": 1,
"audio": "<base64-audio-bytes>"
}

tts.audio.done

この​リクエストの​合成が​完了しました​:

{
"type": "tts.audio.done",
"id": "utt_0001",
"request_id": "synthesis-request-id",
"audio_bytes": 12345,
"chunks": 4
}

tts.usage

リクエストの​最終的な​利用量です。​受け入れられた​ tts.speak ごとに​利用記録が​ 1 件作成されます:

{
"type": "tts.usage",
"request_id": "synthesis-request-id",
"session_id": "router-session-request-id",
"client_id": "utt_0001",
"model": "kokoro",
"usage": {
"input_chars": 24,
"input_bytes": 72,
"audio_bytes": 12345,
"status": "completed",
"final": true
}
}

拒否された​リクエスト​(例: 不正な​ voice_id や​ format)は​ tts.error を​返し、​利用記録は​作成されません

最小限の​ Python クライアント

依存関係を​インストールします:

python -m pip install websockets

キーを​設定して​実行します:

export SHISA_API_KEY="shsk:..."
export TTS_WS_URL="wss://api.shisa.ai/ws/tts/realtime"
export TTS_VOICE_ID="61ba1141-60aa-4bc3-a3b3-be1ec20700b3"
python websocket_tts.py > output.mp3

websocket_tts.py:

#!/usr/bin/env python3
import asyncio
import json
import os
import sys

import websockets


async def main() -> None:
url = os.environ.get("TTS_WS_URL", "wss://api.shisa.ai/ws/tts/realtime")
api_key = os.environ["SHISA_API_KEY"]
voice_id = os.environ["TTS_VOICE_ID"]
text = os.environ.get("TTS_TEXT", "こんにちは。WebSocket TTS のテストです。")
audio_format = os.environ.get("TTS_FORMAT", "mp3")

headers = [("Authorization", f"Bearer {api_key}")]
audio = bytearray()

async with websockets.connect(url, additional_headers=headers, max_size=None) as ws:
await ws.send(
json.dumps(
{
"type": "session.update",
"id": "cfg_0001",
"session": {
"voice_id": voice_id,
"format": audio_format,
"audio_transport": "binary",
},
}
)
)

# session.created を待ってから発話します。
while True:
event = json.loads(await ws.recv())
if event.get("type") == "session.created":
break
if event.get("type") in {"tts.error", "router.error", "error"}:
raise RuntimeError(event)

await ws.send(json.dumps({"type": "tts.speak", "id": "utt_0001", "text": text}))

# バイナリフレームは音声、JSON フレームはイベント。tts.usage で終了します。
while True:
msg = await ws.recv()
if isinstance(msg, bytes):
audio.extend(msg)
continue
event = json.loads(msg)
event_type = event.get("type")
if event_type == "tts.usage":
print(json.dumps(event, ensure_ascii=False), file=sys.stderr)
break
if event_type in {"tts.error", "router.error", "error"}:
raise RuntimeError(event)

sys.stdout.buffer.write(audio)


if __name__ == "__main__":
asyncio.run(main())

次の​ステップ

  • 音声ファイル全体を​ 1 回の​呼び出しで​返すには​ POST /tts エンドポイントを​使用します。
  • 利用​可能な​音声は音声カタログで​閲覧できます。
  • 利用が​どのように​課金されるかは料​金を​参照してください。