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

# PHP

타입캐스트 [API](https://studio.typecast.ai/developers/api)를 위한 공식 PHP 라이브러리입니다. AI 음성을 사용하여 텍스트를 자연스러운 음성으로 변환합니다.

Guzzle 7 기반의 안정적인 HTTP 통신. PHP 8.1+ 및 Composer 필요.

<CardGroup cols={2}>
<Card title="Packagist" icon="cube" href="https://packagist.org/packages/neosapience/typecast-php">
타입캐스트 PHP SDK
</Card>

<Card title="소스 코드" icon="github" href="https://github.com/neosapience/typecast-sdk/tree/main/typecast-php">
타입캐스트 PHP SDK 소스 코드
</Card>
</CardGroup>

## 설치

Composer로 설치합니다:

```bash
composer require neosapience/typecast-php:0.1.14
```

<Warning>
권장 PHP SDK 릴리스는 Packagist의 **v0.1.14**이며, 위 명령에서 이 버전을 지정합니다. **PHP 8.1 이상** 및 Composer가 필요합니다. `php -v`로 버전을 확인하세요.
</Warning>

## 빠른 시작

```php
<?php
use Neosapience\Typecast\TypecastClient;
use Neosapience\Typecast\Models\TTSRequest;

// 클라이언트 초기화
$client = new TypecastClient(apiKey: 'YOUR_API_KEY');

// 텍스트를 음성으로 변환
$response = $client->textToSpeech(new TTSRequest(
    voiceId: 'tc_672c5f5ce59fac2a48faeaee',
    text: '안녕하세요! 타입캐스트 PHP SDK입니다.',
    model: 'ssfm-v30',
));

// 오디오 파일 저장
file_put_contents('output.wav', $response->audioData);

echo "재생 시간: {$response->duration}초, 포맷: {$response->format}\n";
```

## 기능

- **다중 음성 모델**: `ssfm-v30` (최신) 및 `ssfm-v21` AI 음성 모델 지원
- **다국어 지원**: 영어, 한국어, 스페인어, 일본어, 중국어 등 35+개 언어
- **감정 제어**: 프리셋 감정 (normal, happy, sad, angry, whisper, toneup, tonedown) 또는 스마트 문맥 인식 추론
- **오디오 커스터마이징**: 음량 (LUFS -70 to 0), 피치 (-12 to +12 세미톤), 템포 (0.5x to 2.0x), 포맷 (WAV/MP3) 제어
- **보이스 탐색**: V2 Voices API로 모델, 성별, 나이, 용도별 필터링
- **타임스탬프 TTS**: 자막, 가라오케, 립싱크를 위한 단어·문자 단위 정렬 데이터
- **스트리밍**: 저지연 재생을 위한 실시간 청크 오디오 전송 (콜백 기반)
- **Guzzle 7**: 업계 표준 HTTP 클라이언트
- **타입 안전성**: 타입 프로퍼티와 네임드 아규먼트 (PHP 8.1+)

## 보이스 추천

원하는 스타일은 알지만 정확한 `voice_id`를 모를 때 `recommendVoices`를 사용합니다.

```php
$voices = $client->recommendVoices(
    'warm female voice for a product tutorial',
    count: 3,
);

foreach ($voices as $voice) {
    echo "{$voice->voiceId} {$voice->voiceName} {$voice->score}\n";
}
```

추천 결과에는 `voiceId`, `voiceName`, `score`만 포함됩니다. 지원 모델, 감정, 성별, 연령대, 사용 사례 같은 상세 메타데이터가 필요하면 `getVoiceV2` 또는 `getVoicesV2`로 추가 조회하세요.

## 설정

환경변수 또는 직접 API 키를 전달할 수 있습니다:

<CodeGroup>

```bash 환경변수
export TYPECAST_API_KEY="your-api-key-here"
```

```php 환경변수에서 읽기
use Neosapience\Typecast\TypecastClient;

$client = new TypecastClient(
    apiKey: getenv('TYPECAST_API_KEY'),
);
```

```php 직접 전달
use Neosapience\Typecast\TypecastClient;

$client = new TypecastClient(
    apiKey: 'your-api-key-here',
);
```

</CodeGroup>

<Info>
자체 프록시를 통해 요청하는 경우 `baseUrl`을 프록시 엔드포인트로 설정하고 `apiKey`를 생략할 수 있습니다. API 키가 비어 있거나 없으면 SDK는 `X-API-KEY` 헤더를 보내지 않습니다. 기본 Typecast 호스트로 요청할 때는 API 키가 계속 필요합니다.
</Info>

```php API 키 없는 프록시
$client = new TypecastClient(
    baseUrl: 'https://your-proxy.example.com',
);
```

## 고급 사용법

### 감정 제어 (ssfm-v30)

ssfm-v30은 두 가지 감정 제어 모드를 제공합니다: **프리셋** 및 **스마트**.

<Tabs>
  <Tab title="스마트 모드">
    AI가 문맥에서 감정을 추론합니다:

    ```php
    use Neosapience\Typecast\Models\{TTSRequest, SmartPrompt};

    $response = $client->textToSpeech(new TTSRequest(
        voiceId: 'tc_672c5f5ce59fac2a48faeaee',
        text: '모든 것이 잘 될 거예요.',
        model: 'ssfm-v30',
        prompt: new SmartPrompt(
            previousText: '방금 최고의 소식을 들었어요!',
            nextText: '축하하고 싶어요!',
        ),
    ));
    ```
  </Tab>

  <Tab title="프리셋 모드">
    프리셋 값으로 감정을 명시적으로 설정합니다:

    ```php
    use Neosapience\Typecast\Models\{TTSRequest, PresetPrompt};

    $response = $client->textToSpeech(new TTSRequest(
        voiceId: 'tc_672c5f5ce59fac2a48faeaee',
        text: '이 기능들을 보여드리게 되어 정말 기쁩니다!',
        model: 'ssfm-v30',
        prompt: new PresetPrompt(
            emotionPreset: 'happy',
            emotionIntensity: 1.5,
        ),
    ));
    ```
  </Tab>
</Tabs>

### 오디오 커스터마이징

음량, 피치, 템포, 출력 포맷을 제어합니다:

```php
use Neosapience\Typecast\Models\{TTSRequest, Output};

$response = $client->textToSpeech(new TTSRequest(
    voiceId: 'tc_672c5f5ce59fac2a48faeaee',
    text: '커스터마이징된 오디오 출력!',
    model: 'ssfm-v30',
    output: new Output(
        targetLufs: -14.0,
        audioPitch: 2,
        audioTempo: 1.2,
        audioFormat: 'mp3',
    ),
));

file_put_contents('output.mp3', $response->audioData);
```

### 파일로 바로 생성하기

`generateToFile`은 음성 합성과 파일 저장을 한 번에 처리합니다. `model`은 기본값으로 `ssfm-v30`을 사용하고, `.mp3` 또는 `.wav` 확장자로 출력 형식을 결정합니다.

```php
$client->generateToFile(
    'hello.mp3',
    '안녕하세요, 타입캐스트입니다.',
    'tc_672c5f5ce59fac2a48faeaee' // voice_id는 https://studio.typecast.ai/developers/api/voices 에서 확인하세요.
);
```

### 텍스트만으로 쉼 표현

한 voice로 읽는 문장 안에 쉼만 넣고 싶다면 텍스트에 pause markup을 직접 작성합니다. `<|5s|>`, `<|1s|>`, `<|0.3s|>`, `<|0.34413s|>`처럼 쓰며 값은 초 단위이고 반드시 `s`로 끝납니다. 별도 pause 함수를 호출하지 않아도 텍스트만 보고 쉼 위치를 확인할 수 있습니다.

```php
$audio = $client->composeSpeech()
    ->defaults(new ComposerSettings(voiceId: 'tc_672c5f5ce59fac2a48faeaee', model: 'ssfm-v30'))
    ->say('안녕하세요<|5s|>반갑습니다<|1s|>오늘<|2s|>날씨는 어떤 것 같으세요?')
    ->generate();
```

### 다중 화자 합성

한 파일 안에서 서로 다른 voice나 구간별 pitch, tempo, prompt 같은 옵션을 조합해야 할 때 사용합니다. composer는 세그먼트를 `POST /v1/text-to-speech/compose`로 보내며 WAV 또는 MP3를 직접 반환합니다. 무음 제거는 TTS 세그먼트에 명시적으로 설정하고, 명시적인 쉼은 유지됩니다.

```php
use Neosapience\Typecast\ComposerSettings;
use Neosapience\Typecast\Models\Output;

$audio = $client->composeSpeech()
    ->defaults(new ComposerSettings(voiceId: 'tc_672c5f5ce59fac2a48faeaee', model: 'ssfm-v30'))
    ->say('Hello there')
    ->pause(5.0)
    ->say('Nice to meet you', new ComposerSettings(
        voiceId: 'tc_60e5426de8b95f1d3000d7b5',
        output: new Output(audioPitch: 2)
    ))
    ->say('Today')
    ->pause(2.0)
    ->say('How does the weather feel?')
    ->generate();

file_put_contents('conversation.wav', $audio->audioData);
```

### 보이스 탐색 (V2 API)

향상된 메타데이터와 함께 사용 가능한 보이스를 조회합니다:

```php
use Neosapience\Typecast\Models\VoicesV2Filter;

// 모든 보이스 조회
$voices = $client->getVoicesV2();

// 필터링
$filtered = $client->getVoicesV2(new VoicesV2Filter(
    model: 'ssfm-v30',
    gender: 'female',
    age: 'young_adult',
));

foreach ($voices as $voice) {
    echo "ID: {$voice->voiceId}, 이름: {$voice->voiceName}\n";
}

// 특정 보이스 조회
$voice = $client->getVoiceV2('tc_672c5f5ce59fac2a48faeaee');
```

### 스트리밍

콜백을 통해 실시간으로 오디오 청크를 스트리밍합니다:

```php
use Neosapience\Typecast\Models\TTSRequestStream;

$first = true;
$client->textToSpeechStream(
    new TTSRequestStream(
        voiceId: 'tc_672c5f5ce59fac2a48faeaee',
        text: '이 텍스트를 실시간으로 오디오로 스트리밍합니다.',
        model: 'ssfm-v30',
    ),
    function (string $chunk) use (&$first): void {
        if ($first) {
            $chunk = substr($chunk, 44); // 44바이트 WAV 헤더 건너뛰기
            $first = false;
        }
        // $chunk는 32000 Hz 16비트 모노 원시 PCM
        // 오디오 출력으로 전달 또는 ffplay로 파이핑
    },
);
```

<Note>
**WAV 스트리밍 형식:** 32000 Hz, 16비트, 모노 PCM. 첫 번째 청크에 44바이트 WAV 헤더(size = `0xFFFFFFFF`)가 포함되며, 이후 청크는 원시 PCM 데이터만 포함합니다. MP3 형식: 320 kbps, 44100 Hz, 각 청크는 독립적으로 디코딩 가능합니다.
</Note>

## 타임스탬프 TTS

`textToSpeechWithTimestamps()`는 `POST /v1/text-to-speech/with-timestamps`를 래핑하며, 오디오와 함께 단어·문자 단위 정렬 데이터를 반환합니다. 가라오케 하이라이트, 자막 생성, 립싱크 애플리케이션에 활용할 수 있습니다.

### 기본 사용법

```php
<?php
require 'vendor/autoload.php';

use Typecast\TypecastClient;
use Typecast\Models\TTSRequestWithTimestamps;

$client = new TypecastClient('YOUR_API_KEY');

$result = $client->textToSpeechWithTimestamps(new TTSRequestWithTimestamps([
    'voice_id' => 'tc_60e5426de8b95f1d3000d7b5',
    'text'     => 'Hello. How are you?',
    'model'    => 'ssfm-v30',
]));

file_put_contents('output.wav', $result->audioBytes());
printf("재생 시간: %.3f초\n", $result->audioDuration);

foreach ($result->words as $word) {
    printf("  [%.3fs – %.3fs] %s\n", $word->startTime, $word->endTime, $word->text);
}
```

### 정밀도(Granularity) 설정

`'granularity' => 'word'`(기본값) 또는 `'granularity' => 'char'`를 설정해 정렬 단위를 제어합니다.

```php
// 문자 단위 정렬 - 일본어·중국어에 필수
$result = $client->textToSpeechWithTimestamps(new TTSRequestWithTimestamps([
    'voice_id'    => 'tc_60e5426de8b95f1d3000d7b5',
    'text'        => 'Hello. How are you?',
    'model'       => 'ssfm-v30',
    'granularity' => 'char',
]));
```

### 자막 내보내기

```php
$srt = $result->toSrt();
file_put_contents('output.srt', $srt);

$vtt = $result->toVtt();
file_put_contents('output.vtt', $vtt);
```

<Note>
**일본어·중국어:** 공백 구분자가 없는 언어(jpn, zho)는 단어 단위 세그먼트가 의미를 갖지 않습니다. 해당 언어에는 `'granularity' => 'char'`를 사용해 문자 단위 정렬 데이터를 얻으세요.
</Note>

## 지원 언어

35+개 언어를 지원하며 자동 언어 감지 기능을 제공합니다:

| 코드 | 언어 | 코드 | 언어 | 코드 | 언어 |
|------|------|------|------|------|------|
| `eng` | 영어 | `jpn` | 일본어 | `ukr` | 우크라이나어 |
| `kor` | 한국어 | `ell` | 그리스어 | `ind` | 인도네시아어 |
| `spa` | 스페인어 | `tam` | 타밀어 | `dan` | 덴마크어 |
| `deu` | 독일어 | `tgl` | 타갈로그어 | `swe` | 스웨덴어 |
| `fra` | 프랑스어 | `fin` | 핀란드어 | `msa` | 말레이어 |
| `ita` | 이탈리아어 | `zho` | 중국어 | `ces` | 체코어 |
| `pol` | 폴란드어 | `slk` | 슬로바키아어 | `por` | 포르투갈어 |
| `nld` | 네덜란드어 | `ara` | 아랍어 | `bul` | 불가리아어 |
| `rus` | 러시아어 | `hrv` | 크로아티아어 | `ron` | 루마니아어 |
| `ben` | 벵골어 | `hin` | 힌디어 | `hun` | 헝가리어 |
| `nan` | 민난어 | `nor` | 노르웨이어 | `pan` | 펀자브어 |
| `tha` | 태국어 | `tur` | 터키어 | `vie` | 베트남어 |
| `yue` | 광둥어 | | | | |

<Info>
언어를 지정하지 않으면 입력 텍스트에서 자동으로 감지됩니다.
</Info>

## 에러 처리

SDK는 HTTP 에러별 구체적인 예외를 발생시킵니다:

```php
use Neosapience\Typecast\Exceptions\{
    TypecastException,
    UnauthorizedException,
    PaymentRequiredException,
    RateLimitException,
};

try {
    $response = $client->textToSpeech($request);
} catch (UnauthorizedException $e) {
    echo "유효하지 않은 API 키: {$e->getMessage()}\n";
} catch (PaymentRequiredException $e) {
    echo "크레딧 부족\n";
} catch (RateLimitException $e) {
    echo "요청 한도 초과 - 잠시 후 재시도\n";
} catch (TypecastException $e) {
    echo "에러: {$e->getMessage()}\n";
}
```

| 예외 | 상태 코드 | 설명 |
|------|-----------|------|
| `BadRequestException` | 400 | 잘못된 요청 파라미터 |
| `UnauthorizedException` | 401 | 유효하지 않거나 누락된 API 키 |
| `PaymentRequiredException` | 402 | 크레딧 부족 |
| `NotFoundException` | 404 | 리소스를 찾을 수 없음 |
| `UnprocessableEntityException` | 422 | 유효성 검사 오류 |
| `RateLimitException` | 429 | 요청 한도 초과 |
| `InternalServerException` | 500 | 서버 오류 |

## API 레퍼런스

### TypecastClient 메서드

| 메서드 | 설명 |
|--------|------|
| `textToSpeech(TTSRequest)` | 텍스트를 음성 오디오로 변환 |
| `generateToFile(path, text, voiceId)` | 음성을 생성하고 로컬 파일로 바로 저장 |
| `textToSpeechStream(TTSRequestStream, callable)` | 콜백을 통한 오디오 청크 스트리밍 |
| `getMySubscription()` | 구독 정보 조회 |
| `getVoices(?string $model)` | 사용 가능한 보이스 조회 (V1) |
| `getVoicesV2(?VoicesV2Filter)` | 메타데이터와 함께 보이스 조회 (V2) |
| `getVoiceV2(string $voiceId)` | 특정 보이스 조회 |

## 무음 길이 조절

이 기능은 **0.1.14 이상**에서 지원합니다.

`remove_silence_ms`는 제거할 시간이 아니라 **남길 무음 길이**를 지정합니다. `0`부터 `1000`ms까지의 정수를 사용하세요. `0`은 검출된 무음을 제거하며, 생략하거나 `null`을 지정하면 지정 길이에 따른 무음 제거를 적용하지 않습니다.

일반·스트리밍·타임스탬프 TTS는 `output.remove_silence_ms`, Compose는 각 `tts` 세그먼트의 `segments[].output.remove_silence_ms`로 전달합니다. 반환 타임스탬프는 처리 후 오디오를 기준으로 하며, 명시적인 `pause` 세그먼트는 유지됩니다.

스트리밍의 기본 앞부분 무음 트림은 별개입니다. 특히 `0`처럼 작은 값에서는 재생 가능한 청크 수신에 간격이 생길 수 있으므로 충분한 재생 버퍼를 확보하고 실제 콘텐츠로 확인하세요.

아래 출력 설정을 해당 요청의 `output`에 전달하세요. 스트리밍은 스트리밍 전용 출력 타입을 사용합니다.

```php
$output = new \Neosapience\Typecast\Models\Output(removeSilenceMs: 300);
$streamOutput = new \Neosapience\Typecast\Models\OutputStream(removeSilenceMs: 300);
```
