> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# リアルタイムでオーディオを生成

WebSocketストリーミングは、単一の長時間維持される接続を介してデータを送受信する方法です。この方法は、利用可能になった音声データをストリーミングする必要があるリアルタイムアプリケーションに役立ちます。

ElevenLabsテキスト読み上げAPIへのWebSocket接続のレイテンシー（最初のバイトが届くまでの時間）をすばやくテストするには、`npm`で`elevenlabs-latency`をインストールし、[こちら](https://www.npmjs.com/package/elevenlabs-latency?activeTab=readme)の手順に従ってください。

> **Note**
>
> WebSocketはテキスト読み上げとAgents Platformで利用できます。このガイドでは、**テキスト
> 読み上げ** WebSocket（`/v1/text-to-speech/{voice_id}/stream-input`）について説明します。このエンドポイントは、**`eleven_v3`** または\*\*`eleven_v4`\*\* モデルをサポートしていません。WebSocket経由で**Eleven v3** または**Eleven v4** の対話を行う場合は、[Realtime Text to Dialogue](/docs/ja/eleven-api/guides/how-to/websockets/realtime-tdd)
> および[Text to Speech vs Text to Dialogue WebSockets](/docs/ja/eleven-api/guides/how-to/websockets/tts-vs-ttd-websockets)を参照してください。

## 要件

* APIキーを持つElevenLabsアカウント（[APIキーの確認方法](/docs/ja/api-reference/authentication)）。
* マシンにPythonまたはNode.js（または別のJavaScriptランタイム）がインストールされていること

## セットアップ

必要な依存関係をインストールします。

**`Python`**

```python Python
pip install python-dotenv
pip install websockets
```

**`TypeScript`**

```typescript TypeScript
npm install dotenv
npm install @types/dotenv --save-dev
npm install ws
```

次に、プロジェクトディレクトリに`.env`ファイルを作成し、APIキーを追加します。

**`.env`**

```bash .env
ELEVENLABS_API_KEY=your_elevenlabs_api_key_here
```

## WebSocket接続を開始する

ボイスライブラリから音声を選択し、使用するテキスト読み上げモデルを決めたら、テキスト読み上げAPIへのWebSocket接続を開始します。

**`text-to-speech-websocket.py`**

```python text-to-speech-websocket.py
import os
from dotenv import load_dotenv
import websockets

# Load the API key from the .env file
load_dotenv()
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")

voice_id = 'Xb7hH8MSUJpSbSDYk0k2'

# For use cases where latency is important, we recommend using the 'eleven_flash_v2_5' model.
model_id = 'eleven_flash_v2_5'

async def text_to_speech_ws_streaming(voice_id, model_id):
    uri = f"wss://api.elevenlabs.io/v1/text-to-speech/{voice_id}/stream-input?model_id={model_id}"

    async with websockets.connect(uri) as websocket:
       ...
```

**`text-to-speech-websocket.ts`**

```typescript text-to-speech-websocket.ts
import * as dotenv from "dotenv";
import * as fs from "node:fs";
import WebSocket from "ws";

// Load the API key from the .env file
dotenv.config();
const ELEVENLABS_API_KEY = process.env.ELEVENLABS_API_KEY;

const voiceId = "Xb7hH8MSUJpSbSDYk0k2";

// For use cases where latency is important, we recommend using the 'eleven_flash_v2_5' model.
const model = "eleven_flash_v2_5";

const uri = `wss://api.elevenlabs.io/v1/text-to-speech/${voiceId}/stream-input?model_id=${model}`;
const websocket = new WebSocket(uri, {
  headers: { "xi-api-key": `${ELEVENLABS_API_KEY}` },
});

// Create a directory for saving the audio
const outputDir = "./output";

try {
  fs.accessSync(outputDir, fs.constants.R_OK | fs.constants.W_OK);
} catch (err) {
  fs.mkdirSync(outputDir);
}

// Create a write stream for saving the audio into mp3
const writeStream = fs.createWriteStream(outputDir + "/test.mp3", {
  flags: "a",
});
```

## 入力テキストを送信する

WebSocket接続が開いたら、最初に音声設定を指定します。次に、テキストメッセージをAPIに送信します。

**`text-to-speech-websocket.py`**

```python text-to-speech-websocket.py
async def text_to_speech_ws_streaming(voice_id, model_id):
    async with websockets.connect(uri) as websocket:
        await websocket.send(json.dumps({
            "text": " ",
            "voice_settings": {"stability": 0.5, "similarity_boost": 0.8, "use_speaker_boost": False},
            "generation_config": {
                "chunk_length_schedule": [120, 160, 250, 290]
            },
            "xi_api_key": ELEVENLABS_API_KEY,
        }))

        text = "The twilight sun cast its warm golden hues upon the vast rolling fields, saturating the landscape with an ethereal glow. Silently, the meandering brook continued its ceaseless journey, whispering secrets only the trees seemed privy to."
        await websocket.send(json.dumps({"text": text}))

        # Send empty string to indicate the end of the text sequence which will close the WebSocket connection
        await websocket.send(json.dumps({"text": ""}))
```

**`text-to-speech-websocket.ts`**

```typescript text-to-speech-websocket.ts
const text =
  "The twilight sun cast its warm golden hues upon the vast rolling fields, saturating the landscape with an ethereal glow. Silently, the meandering brook continued its ceaseless journey, whispering secrets only the trees seemed privy to.";

websocket.on("open", async () => {
  websocket.send(
    JSON.stringify({
      text: " ",
      voice_settings: {
        stability: 0.5,
        similarity_boost: 0.8,
        use_speaker_boost: false,
      },
      generation_config: { chunk_length_schedule: [120, 160, 250, 290] },
    })
  );

  websocket.send(JSON.stringify({ text: text }));

  // Send empty string to indicate the end of the text sequence which will close the websocket connection
  websocket.send(JSON.stringify({ text: "" }));
});
```

## 音声をファイルに保存する

WebSocket接続から受信したメッセージを読み取り、音声チャンクをローカルファイルに書き込みます。

**`text-to-speech-websocket.py`**

```python text-to-speech-websocket.py
import asyncio

async def write_to_local(audio_stream):
    """Write the audio encoded in base64 string to a local mp3 file."""

    with open(f'./output/test.mp3', "wb") as f:
        async for chunk in audio_stream:
            if chunk:
                f.write(chunk)

async def listen(websocket):
    """Listen to the websocket for audio data and stream it."""

    while True:
        try:
            message = await websocket.recv()
            data = json.loads(message)
            if data.get("audio"):
                yield base64.b64decode(data["audio"])
            elif data.get('isFinal'):
                break

        except websockets.exceptions.ConnectionClosed:
            print("Connection closed")
            break

async def text_to_speech_ws_streaming(voice_id, model_id):
    async with websockets.connect(uri) as websocket:
          ...
          # Add listen task to submit the audio chunks to the write_to_local function
          listen_task = asyncio.create_task(write_to_local(listen(websocket)))

          await listen_task

asyncio.run(text_to_speech_ws_streaming(voice_id, model_id))
```

**`text-to-speech-websocket.ts`**

```typescript text-to-speech-websocket.ts
// Helper function to write the audio encoded in base64 string into local file
function writeToLocal(base64str: any, writeStream: fs.WriteStream) {
  const audioBuffer: Buffer = Buffer.from(base64str, "base64");
  writeStream.write(audioBuffer, (err) => {
    if (err) {
      console.error("Error writing to file:", err);
    }
  });
}

// Listen to the incoming message from the websocket connection
websocket.on("message", function incoming(event) {
  const data = JSON.parse(event.toString());
  if (data["audio"]) {
    writeToLocal(data["audio"], writeStream);
  }
});

// Close the writeStream when the websocket connection closes
websocket.on("close", () => {
  writeStream.end();
});
```

## スクリプトを実行する

ターミナルで次のコマンドを実行すると、スクリプトを実行できます。MP3音声ファイルが`output`ディレクトリに保存されます。

**`Python`**

```python Python
python text-to-speech-websocket.py
```

**`TypeScript`**

```typescript TypeScript
npx tsx text-to-speech-websocket.ts
```

## 高度な設定

WebSocketには、リアルタイム音声生成を微調整できる高度な設定があります。

### バッファリング

リアルタイム音声を生成する際には、Time To First Byte（TTFB）とバッファリングという2つの重要な概念を考慮する必要があります。高品質な音声を生成し、コンテキストを推測するために、モデルには一定量の入力テキストが必要です。WebSocket接続で送信するテキストが多いほど、音声品質は向上します。必要な量に達していない場合、モデルはテキストをバッファに追加し、バッファが満たされると音声を生成します。

レイテンシーの観点では、TTFBは最初の音声バイトがクライアントに送信されるまでの時間です。これは音声の体感レイテンシーに影響するため重要です。そのため、品質とレイテンシーのバランスを取るために、バッファサイズを制御することができます。

これを管理するには、WebSocket接続の初期化時またはテキスト送信時に`chunk_length_schedule`パラメータを使用します。このパラメータは、音声を生成する前にモデルへ送信される文字数を表す整数の配列です。たとえば、`chunk_length_schedule`を`[120, 160, 250, 290]`に設定すると、120、160、250、290文字が送信された後に、それぞれモデルが音声を生成します。

以下は、`chunk_length_schedule`のデフォルト設定での動作例です。

![](/docs/_fern-img/077efc232570b0f92355aed2d6766b66bba815e335466e81cd64f8dfcce10ada.webp)

上の図では、2つ目のメッセージがサーバーに送信された後にのみ音声が生成されます。これは、最初のメッセージが120文字のしきい値未満である一方、2つ目のメッセージによって合計文字数がしきい値を超えるためです。3つ目のメッセージは160文字のしきい値を超えているため、音声がすぐに生成され、クライアントに返されます。

WebSocket接続の初期化時またはテキスト送信時に、`chunk_length_schedule`のカスタム値を指定できます。

```python
await websocket.send(json.dumps({
    "text": text,
    "generation_config": {
        # Generate audio after 50, 120, 160, and 290 characters have been sent
        "chunk_length_schedule": [50, 120, 160, 290]
    },
    "xi_api_key": ELEVENLABS_API_KEY,
}))
```

```typescript
websocket.send(
  JSON.stringify({
    text: text,
    // Generate audio after 50, 120, 160, and 290 characters have been sent
    generation_config: { chunk_length_schedule: [50, 120, 160, 290] },
    xi_api_key: ELEVENLABS_API_KEY,
  })
);
```

音声をすぐに返す必要がある場合は、`flush: true`を使用してバッファをクリアし、バッファ内のテキストを強制的に生成できます。たとえば、ドキュメントの末尾に到達し、最後のセクションの音声を生成したい場合に役立ちます。

![](/docs/_fern-img/84011e01024effe1bba1556f0007c7947165a0101bce3a41f8b955d1a9788a9c.webp)

これは、メッセージ内で`flush: true`を設定することで、メッセージごとに指定できます。

```python
await websocket.send(json.dumps({"text": "Generate this audio immediately.", "flush": True}))
```

```typescript
websocket.send(JSON.stringify({ text: "Generate this audio immediately.", flush: true }));
```

また、WebSocketを閉じると、バッファ内のテキストは自動的に強制生成されます。

### 音声設定

WebSocket接続を初期化するとき、以降の生成に使用する音声設定を指定できます。これにより、生成される音声の速度、安定性、その他の音声特性を制御できます。

```python
await websocket.send(json.dumps({
    "text": text,
    "voice_settings": {"stability": 0.5, "similarity_boost": 0.8, "use_speaker_boost": False},
}))
```

```typescript
websocket.send(
  JSON.stringify({
    text: text,
    voice_settings: { stability: 0.5, similarity_boost: 0.8, use_speaker_boost: false },
  })
);
```

メッセージ内で異なる`voice_settings`を指定することで、メッセージごとに上書きできます。

### 発音辞書

発音辞書を使用すると、特定の単語やフレーズの発音を制御できます。特定の単語を正しく発音させたり、特定の単語やフレーズを強調したりする場合に役立ちます。

`voice_settings`や`generation_config`とは異なり、発音辞書は「接続を初期化」メッセージで指定する必要があります。詳しくは、[APIリファレンス](/docs/ja/api-reference/text-to-speech/v-1-text-to-speech-voice-id-stream-input#send.Initialize%20Connection.pronunciation_dictionary_locators)を参照してください。

> **Tip**
>
> WebSocketで音素ベースの発音辞書を使用する場合、WebSocket URIのクエリパラメータとして`enable_ssml_parsing=true`を追加する必要があります。例：
>
> ```
> wss://api.elevenlabs.io/v1/text-to-speech/{voice_id}/stream-input?model_id={model_id}&enable_ssml_parsing=true
> ```

## ベストプラクティス

* `generation_config`では、`chunk_length_schedule`のデフォルト設定を使用することをおすすめします。
* リアルタイム会話エージェントアプリケーションを開発する場合は、タイムリーな音声生成を確保するため、会話ターンの終わりのテキストとともに`flush: true`を使用することをおすすめします。
* デフォルト設定でユースケースに最適なレイテンシーが得られない場合は、`chunk_length_schedule`を変更できます。ただし、この調整によってレイテンシーを短縮すると、品質が低下する可能性がある点に注意してください。

## ヒント

* WebSocket接続は、20秒間操作がないと自動的に閉じます。接続を維持するには、半角スペース1文字の`" "`を送信します。この文字列にはスペースを含める必要があります。完全に空の文字列`""`を送信すると、WebSocketが閉じます。
* 最後のテキストメッセージを送信した後、空の文字列を送信してWebSocket接続を閉じます。
* `alignment`を使用すると、テキスト内の各単語の単語レベルのタイムスタンプを取得できます。これは、ビデオ内で音声とテキストを同期させる場合や、正確なタイミングを必要とするその他のアプリケーションで役立ちます。詳しくは、[APIリファレンス](/docs/ja/api-reference/text-to-speech/v-1-text-to-speech-voice-id-stream-input#receive.Audio%20Output.alignment)を参照してください。

## 次のステップ

#### [TTSストリーミング](/docs/ja/eleven-api/guides/how-to/text-to-speech/streaming)

入力テキストがリアルタイムで生成されるのではなく、あらかじめ利用可能な場合はHTTPストリーミングを使用します。

#### [レイテンシーの最適化](/docs/ja/eleven-api/guides/how-to/best-practices/latency-optimization)

モデルの選択、音声の選択、地理的ルーティングにより、最初の音声が届くまでの時間を短縮します。