> ## 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`를 **요청당 300자**로 제한합니다. 이를 초과하면 `400 Bad Request`가 반환됩니다. 더 긴 스크립트를 합성하려면 다음 두 가지 방법이 있습니다.

1. **SDK 사용하기.** Python과 TypeScript SDK는 긴 입력을 자동으로 분할하여 각 세그먼트를 생성하고 오디오를 병합합니다. 입력이 2,000자라도 최종 클립 하나로 받게 됩니다.
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`를 문장 경계(이후 단어 경계, 단어 하나가 너무 길면 문자 경계)에서 분할하고, 최대 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));
    }
    ```

    TS SDK는 응답 처리를 결정적으로 유지하기 위해 세그먼트를 순차적으로 실행합니다.
  </Tab>
</Tabs>

## 긴 텍스트 스트리밍

SDK는 `stream_speech` / `streamSpeech`에서도 자동 분할을 수행합니다. 오디오는 마치 하나의 연속된 스트림인 것처럼 호출자의 이터레이터로 전달되므로, 몇 개의 세그먼트가 사용되었는지 알 필요가 없습니다.

스트리밍 패턴에 대해서는 [Stream speech](/ko/docs/text-to-speech/stream-speech)를 참고해 주십시오.

## 직접 분할하기 (cURL 또는 원시 HTTP)

REST API를 직접 호출하는 경우, 요청을 보내기 전에 분할해야 합니다. 권장 전략은 다음과 같습니다.

1. **문장 종결 구두점**(`.`, `!`, `?`, `。`, `？`)을 기준으로 분할합니다.
2. 한 문장이 여전히 300자를 초과한다면 쉼표, 그리고 단어 경계에서 분할합니다.
3. 각 세그먼트에 대해 `POST /v1/text-to-speech/{voice_id}`를 호출하고 반환된 오디오를 출력 파일에 이어 붙입니다.
4. WAV 연결의 경우, 첫 세그먼트를 제외한 모든 세그먼트에서 WAV 헤더(첫 44바이트)를 제거하여 최종 파일이 하나의 클립으로 재생되도록 해야 합니다.

```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`은 자동 분할되지 않지만, 직접 텍스트를 분할하고 길이를 합산하여 전체 크레딧을 예측할 수 있습니다.
* **속도 제한에 주의하세요.** 하나의 긴 입력이 여러 TTS 요청으로 분할됩니다. 계정의 [속도 제한](/ko/docs/production/rate-limits)을 확인하고, 호출 측에서도 트래픽 조절을 고려해 주십시오.

## 관련 문서

<CardGroup cols={2}>
  <Card title="롱폼 내레이션" icon="book" href="/ko/docs/examples/long-form-narration">
    여러 단락 분량의 내레이션을 생성하는 엔드투엔드 예제입니다.
  </Card>

  <Card title="속도 제한" icon="gauge" href="/ko/docs/production/rate-limits">
    티어별 분당 요청 제한입니다.
  </Card>
</CardGroup>
