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

# 長文テキスト

> 300 文字の API 制限と SDK の自動チャンク分割の関係 — そして書籍規模の入力を扱う方法。

<Note>
  このドキュメントは英語の原文から自動翻訳されています。表現に不自然な箇所がある場合があります。正確な内容は[英語の原文](/en/docs/text-to-speech/long-text)もあわせてご確認ください。
</Note>

Supertone TTS API は `text` を **1 リクエストあたり 300 文字** までに制限しています。これを超えると `400 Bad Request` が返ります。より長いスクリプトを合成するには、次の 2 つの方法があります。

1. **SDK を利用する。** Python と TypeScript の SDK はいずれも、長い入力を自動的に分割し、各セグメントを生成して、オーディオを結合してくれます。入力が 2,000 文字であっても、最終的なクリップが 1 つ返ります。
2. **自分でチャンク分割する。** REST API を直接呼び出す場合は、文の区切りでテキストを分割し、得られたオーディオを連結します。

## 300 文字制限の概要

| Layer                                               | Behavior on >300 characters                                    |
| --------------------------------------------------- | -------------------------------------------------------------- |
| **REST API** (`POST /v1/text-to-speech/{voice_id}`) | `400 Bad Request` を返します。                                       |
| **Python SDK** (`create_speech`, `stream_speech`)   | 300 文字で自動分割し、`create_speech` では並列生成（ストリーミングでは順次）してオーディオを結合します。 |
| **TypeScript SDK** (`createSpeech`, `streamSpeech`) | 300 文字で自動分割し、順次生成してオーディオを結合します。                                |
| **`predict_duration`**                              | 自動チャンク分割されません — 同じ 300 文字制限が適用されます。                            |

このしきい値は両方の SDK で設定可能です。

```python theme={"dark"}
# Python — pass maxTextLength via SDK options
# (the default is 300; lower it to chunk earlier)
```

```typescript theme={"dark"}
// TypeScript — pass maxTextLength in the options object
const response = await client.textToSpeech.createSpeech(
  { voiceId, apiConvertTextToSpeechUsingCharacterRequest: { text, language: "en" } },
  { maxTextLength: 250 },
);
```

## SDK の自動チャンク分割の流れ

<Tabs>
  <Tab title="Python">
    ```python theme={"dark"}
    import os
    from supertone import Supertone

    VOICE_ID = "20160a4c5ba38967330c84"  # replace with your voice ID

    LONG_TEXT = (
        "Once upon a time, in a faraway land, there lived a quiet librarian "
        "who collected stories of forgotten kingdoms. Every evening she would "
        "open a leather-bound notebook and continue writing the next chapter "
        "of a tale she had been telling herself for years. ...continue with "
        "many more sentences spanning over 300 characters..."
    )

    with Supertone(api_key=os.environ["SUPERTONE_API_KEY"]) as client:
        response = client.text_to_speech.create_speech(
            voice_id=VOICE_ID,
            text=LONG_TEXT,
            language="en",
        )

        with open("narration.wav", "wb") as f:
            f.write(response.result.read())
    ```

    内部では、SDK は `LONG_TEXT` を文の区切り（次に単語の区切り、さらに 1 単語が長すぎる場合は文字の区切り）で分割し、最大 3 つの `create_speech` リクエストを並列実行し、中間ファイルのヘッダーを除去したうえで WAV / MP3 オーディオを結合します。
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"dark"}
    import { Supertone } from "@supertone/supertone";
    import * as fs from "node:fs";

    const VOICE_ID = "20160a4c5ba38967330c84"; // replace with your voice ID

    const LONG_TEXT = `
      Once upon a time, in a faraway land, there lived a quiet librarian
      who collected stories of forgotten kingdoms. Every evening she would
      open a leather-bound notebook and continue writing the next chapter
      of a tale she had been telling herself for years. ...continue with
      many more sentences spanning over 300 characters...
    `.trim();

    const client = new Supertone({ apiKey: process.env.SUPERTONE_API_KEY });

    const response = await client.textToSpeech.createSpeech({
      voiceId: VOICE_ID,
      apiConvertTextToSpeechUsingCharacterRequest: {
        text: LONG_TEXT,
        language: "en",
      },
    });

    if (response.result instanceof Uint8Array) {
      fs.writeFileSync("narration.wav", response.result);
    } else if (response.result && "getReader" in response.result) {
      const reader = (response.result as ReadableStream<Uint8Array>).getReader();
      const chunks: Uint8Array[] = [];
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        if (value) chunks.push(value);
      }
      fs.writeFileSync("narration.wav", Buffer.concat(chunks));
    }
    ```

    TypeScript SDK は、レスポンス処理を決定的に保つためにセグメントを順次実行します。
  </Tab>
</Tabs>

## 長い入力のストリーミング

SDK は `stream_speech` / `streamSpeech` でも自動的にチャンク分割します。オーディオは単一の連続ストリームのようにイテレータへ渡されるため、呼び出し側は内部でいくつのセグメントが使われたかを知る必要はありません。

ストリーミングのパターンについては [Stream speech](/ja/docs/text-to-speech/stream-speech) を参照してください。

## 自分でチャンク分割する場合（cURL や生の HTTP）

REST API を直接呼び出す場合は、送信前にテキストを分割する必要があります。妥当な方針は次のとおりです。

1. **文末の句読点**（`.`、`!`、`?`、`。`、`？`）で分割する。
2. それでも 300 文字を超える文がある場合は、カンマで、さらに単語境界で分割する。
3. 各セグメントについて `POST /v1/text-to-speech/{voice_id}` を呼び出し、返ってきたオーディオを出力ファイルに追記する。
4. WAV を連結する場合は、2 つ目以降のセグメントから WAV ヘッダー（先頭 44 バイト）を除去すると、最終ファイルが 1 つのクリップとして再生されます。

```bash theme={"dark"}
# Pseudo-shell: split a script and concatenate WAV chunks
VOICE_ID="20160a4c5ba38967330c84"

split_into_sentences "$INPUT_TEXT" > sentences.txt
while read -r line; do
  curl -s -X POST "https://supertoneapi.com/v1/text-to-speech/$VOICE_ID" \
    -H "x-sup-api-key: $SUPERTONE_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"text\": \"$line\", \"language\": \"en\"}" \
    >> raw_chunks.bin
done < sentences.txt
# Then merge with your audio tooling (ffmpeg, etc.) and re-attach a single WAV header.
```

ほとんどのプロジェクトでは SDK の利用を推奨します — セグメント間のタイミング、ヘッダーの除去、部分的な失敗時のリトライといったエッジケースを SDK が処理してくれるためです。

## ヒント

* **句読点は重要です。** 自動チャンク分割は文の区切りを優先します。句読点が適切に打たれた入力ほど、きれいな分割と自然なつなぎになります。
* **まずコストを見積もりましょう。** `predict_duration` は自動チャンク分割しませんが、自前でテキストを分割して長さを合計すれば、合計クレジットを見積もれます。
* **レート制限に注意。** 1 つの長い入力は複数の TTS リクエストになります — アカウントの [レート制限](/ja/docs/production/rate-limits) を確認し、必要に応じて呼び出し側で流量制御を行ってください。

## 関連項目

<CardGroup cols={2}>
  <Card title="長文ナレーション" icon="book" href="/ja/docs/examples/long-form-narration">
    複数段落のナレーションを生成するエンドツーエンドの例。
  </Card>

  <Card title="レート制限" icon="gauge" href="/ja/docs/production/rate-limits">
    プランごとの 1 分あたりのリクエスト上限。
  </Card>
</CardGroup>
