> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sambanova.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Text-to-speech (音声合成) の実装

<Warning>
  Qwen3-TTS は、SambaStack ユーザーのみ利用できる**プレビュー**機能です。プレビュー機能は、一般提供の開始前に変更される可能性があります。
</Warning>

SambaStack は、`qwen3-tts` モデルによる Text-to-speech (音声合成; TTS) 機能を提供しており、テキスト入力をストリーミング PCM 音声に変換します。このモデルは 11 言語に対応しています。

<Note>
  SambaStack では、Qwen3-TTS は 2 つのバンドル — 音声コードを生成する **talker** (`qwen3-tts-talker`) と、波形を合成する **vocoder** (`qwen3-tts-vocoder`) — としてデプロイされます。各バンドルについては [対応モデルとバンドル](/docs/ja/sambastack/service-administration/model-deployment/supported-models-and-bundles) を、デプロイ手順については [バンドルのデプロイ](/docs/ja/sambastack/service-administration/model-deployment/deploying-models-and-bundles/deploy-a-bundle) をご参照ください。
</Note>

## Qwen3-TTS

* **モデル ID**: `qwen3-tts`
* **提供元**: Qwen (Alibaba Cloud)
* **エンドポイント**: `POST /v1/audio/speech`
* **ステータス**: プレビュー

### 対応ボイス

<Note>
  `voice` パラメータは API 互換性のために受け付けられますが、現在は無視されます。音声は常に、デプロイ時に設定されたリファレンスボイスを使用して生成されます。
</Note>

| ボイス ID | 説明 |
| :- | :- |
| `serena` | 女性 |
| `vivian` | 女性 |
| `uncle_fu` | 男性 |
| `ryan` | 男性 |
| `aiden` | 男性 |
| `ono_anna` | 女性 |
| `sohee` | 女性 |
| `eric` | 男性 |
| `dylan` | 男性 |

### 対応言語

| 言語 | 指定可能な値 |
| :- | :- |
| 自動 (検出) | `auto` |
| 中国語 | `Chinese`、`zh`、`cn`、`chi` |
| 英語 | `English`、`en`、`eng` |
| フランス語 | `French`、`fr`、`fra`、`fre` |
| ドイツ語 | `German`、`de`、`ger` |
| イタリア語 | `Italian`、`it`、`ita` |
| 日本語 | `Japanese`、`ja`、`jp`、`jpn` |
| 韓国語 | `Korean`、`ko`、`kor` |
| ポルトガル語 | `Portuguese`、`pt`、`por` |
| ロシア語 | `Russian`、`ru`、`rus` |
| スペイン語 | `Spanish`、`es`、`spa` |

言語のマッチングでは、大文字と小文字は区別されません。`language` パラメータを省略した場合、デフォルトは `english` です。

### リクエストパラメータ

| パラメータ | 型 | 必須 | 説明 |
| :- | :- | :- | :- |
| `model` | string | はい | `qwen3-tts` を指定する必要があります。 |
| `input` | string | はい | 音声に合成するテキスト。 |
| `voice` | string | いいえ | 話者のボイス ID。API 互換性のために受け付けられますが、現在はどの値も無視されます。[対応ボイス](#対応ボイス) をご参照ください。 |
| `stream` | boolean | はい | `true` を指定する必要があります。非ストリーミング応答はまだ対応していません。 |
| `language` | string | いいえ | 入力テキストの言語。デフォルト: `english`。[対応言語](#対応言語) をご参照ください。 |
| `instructions` | string | いいえ | 話し方のスタイルに影響を与える指示。最大 512 文字。 |
| `sampling_params` | object | いいえ | サンプリング設定。指定可能なキー: `temperature`、`top_k`、`top_p`、`seed`。例: `{"temperature": 0.8, "seed": 42}`。 |

### 使用例

<CodeGroup>
  ```python Python (SambaNova) theme={}
  import base64
  import json
  import struct
  import wave
  import requests

  url = "https://your-sambanova-base-url/v1/audio/speech"
  headers = {
      "Authorization": "Bearer your-sambanova-api-key",
      "Content-Type": "application/json",
  }
  payload = {
      "model": "qwen3-tts",
      "input": "Hello, welcome to SambaNova.",
      "voice": "serena",
      "language": "english",
      "stream": True,
  }

  pcm_frames = []

  with requests.post(url, headers=headers, json=payload, stream=True) as resp:
      resp.raise_for_status()
      for line in resp.iter_lines():
          if not line or not line.startswith(b"data: "):
              continue
          data = line[len(b"data: "):]
          if data == b"[DONE]":
              break
          event = json.loads(data)
          if event.get("finish_reason") == "error":
              raise RuntimeError(f"Stream error: {event.get('error')}")
          audio_b64 = event.get("audio_b64", "")
          if audio_b64:
              pcm_frames.append(base64.b64decode(audio_b64))
          if event.get("finish_reason") == "stop":
              break

  # Write f32le PCM frames to a WAV file
  pcm_bytes = b"".join(pcm_frames)
  num_samples = len(pcm_bytes) // 4  # 4 bytes per f32 sample
  samples = struct.unpack(f"{num_samples}f", pcm_bytes)
  pcm_int16 = bytes(
      struct.pack("<h", max(-32768, min(32767, int(s * 32767)))) for s in samples
  )

  with wave.open("output.wav", "wb") as wf:
      wf.setnchannels(1)
      wf.setsampwidth(2)  # 16-bit
      wf.setframerate(24000)
      wf.writeframes(pcm_int16)

  print("Saved output.wav")
  ```

  ```bash cURL theme={}
  # This command shows the raw SSE stream. Use the Python example to produce a playable audio file.
  curl -X POST https://your-sambanova-base-url/v1/audio/speech \
    -H "Authorization: Bearer your-sambanova-api-key" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "qwen3-tts",
      "input": "Hello, welcome to SambaNova.",
      "voice": "serena",
      "language": "english",
      "stream": true
    }'
  ```
</CodeGroup>

### 応答形式

このエンドポイントは、[Server-Sent Events (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) 形式で応答をストリーミングします。各イベントは、`data:` 行に含まれる JSON オブジェクトです。

**応答ヘッダー**

| ヘッダー | 値 | 説明 |
| :- | :- | :- |
| `Content-Type` | `text/event-stream` | SSE ストリーム |
| `X-Audio-Format` | `f32le` | 32 ビット浮動小数点、リトルエンディアン PCM |
| `X-Audio-Sample-Rate` | `24000` | 24 kHz サンプリングレート |
| `X-Audio-Channels` | `1` | モノラル |

**イベントフィールド**

| フィールド | 型 | 説明 |
| :- | :- | :- |
| `audio_b64` | string | Base64 エンコードされた PCM 音声チャンク。 |
| `chunk_index` | integer | 音声チャンクの連番インデックス。 |
| `finish_reason` | string \| null | ストリーミング中は `null`。最後のチャンクでは `"stop"`、途中でストリームが失敗した場合は `"error"`。 |
| `id` | string | リクエスト識別子。 |
| `object` | string | 常に `audio.speech.chunk`。 |
| `created` | integer | Unix タイムスタンプ。 |

**イベント例**

```json theme={}
{
  "audio_b64": "<base64-encoded PCM data>",
  "chunk_index": 0,
  "finish_reason": null,
  "id": "abc123",
  "object": "audio.speech.chunk",
  "created": 1750000000
}
```

**最終イベント**

```json theme={}
{
  "audio_b64": "<base64-encoded PCM data>",
  "chunk_index": 12,
  "finish_reason": "stop",
  "id": "abc123",
  "object": "audio.speech.chunk",
  "created": 1750000000
}
```

### 制限事項

* **ストリーミングのみ**: `stream: false` は未対応です。すべての応答は SSE ストリームで返されます。
* **同時実行性**: モデルは一度に 1 つのリクエストを処理します。同時に送信されたリクエストは、処理中のリクエストの後ろでキューに入ります。
* **最大音声長**: 1 リクエストあたり 320 秒。入力テキストが長く、この上限を超える場合、応答は上限で打ち切られます (エラーは返されません)。より長い音声が必要な場合は、テキストを短い文章に分割し、個別のリクエストとして送信してください。
* **ストリーム途中の音声アーティファクト**: 長い音声クリップでは、ストリームの途中で耳につくアーティファクト (ノイズ) が発生することがあります。発生した場合は、入力を短い文章に分割し、個別のリクエストとして送信してください。
* **コンテキストキャッシュなし**: 各リクエストはステートレスです。
