> ## 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.

# Javascript/Typescript

[타입캐스트 API](https://studio.typecast.ai/developers/api)를 위한 공식 Node.js 라이브러리입니다. AI 기반 음성을 사용하여 텍스트를 생동감 있는 음성으로 변환하세요.

Javascript와 TypeScript 모두에서 작동합니다. 전체 TypeScript 타입이 포함되어 있습니다.

ESM 및 CommonJS를 지원합니다. Node.js 18+ 및 최신 브라우저에서 작동합니다. Node.js 16/17 사용자는 `isomorphic-fetch` 폴리필을 설치해야 합니다.

<CardGroup cols={2}>
<Card title="패키지" icon="npm" href="https://www.npmjs.com/package/@neosapience/typecast-js">
Typecast Javascript/Typescript SDK
</Card>

<Card title="소스 코드" icon="github" href="https://github.com/neosapience/typecast-sdk/tree/main/typecast-js">
Typecast Javascript/Typescript SDK 소스 코드
</Card>
</CardGroup>

## 설치

<Tabs>
  <Tab title="npm">
    ```bash
    npm install @neosapience/typecast-js@latest
    ```
  </Tab>
  
  <Tab title="pnpm">
    ```bash
    pnpm add @neosapience/typecast-js@latest
    ```
  </Tab>
  
  <Tab title="yarn">
    ```bash
    yarn add @neosapience/typecast-js@latest
    ```
  </Tab>
</Tabs>

<Warning>
최신 등록 버전은 npm 기준 **0.4.13**입니다. **버전 0.4.13 이상**이 설치되어 있는지 확인하세요. `npm list @neosapience/typecast-js`로 버전을 확인할 수 있습니다. 이전 버전이 있다면 `npm update @neosapience/typecast-js`를 실행하여 업데이트하세요.
</Warning>

## 빠른 시작

<Tabs>
  <Tab title="TypeScript (ESM)">
    ```typescript
    import { TypecastClient } from '@neosapience/typecast-js';
    import fs from 'fs';

    async function main() {
      const client = new TypecastClient({ apiKey: 'YOUR_API_KEY' });
      const audio = await client.textToSpeech({
        text: "Hello there! I'm your friendly text-to-speech agent.",
        model: "ssfm-v30",
        voice_id: "tc_672c5f5ce59fac2a48faeaee"
      });
      await fs.promises.writeFile(`output.${audio.format}`, Buffer.from(audio.audioData));
      console.log(`Audio saved! Duration: ${audio.duration}s, Format: ${audio.format}`);
    }

    main();
    ```
  </Tab>

  <Tab title="Javascript (CommonJS)">
    ```javascript
    const { TypecastClient } = require('@neosapience/typecast-js');
    const fs = require('fs');

    async function main() {
      const client = new TypecastClient({ apiKey: 'YOUR_API_KEY' });
      const audio = await client.textToSpeech({
        text: "Hello there! I'm your friendly text-to-speech agent.",
        model: "ssfm-v30",
        voice_id: "tc_672c5f5ce59fac2a48faeaee"
      });
      await fs.promises.writeFile(`output.${audio.format}`, Buffer.from(audio.audioData));
      console.log(`Audio saved! Duration: ${audio.duration}s, Format: ${audio.format}`);
    }

    main();
    ```
  </Tab>
</Tabs>

## 기능

타입캐스트 Javascript/TypeScript SDK는 텍스트 음성 변환을 위한 강력한 기능을 제공합니다:

- **다중 음성 모델**: `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
- **TypeScript 지원**: 전체 타입 정의 포함
- **스트리밍**: 저지연 재생을 위한 실시간 청크 오디오 전송
- **타임스탬프 TTS**: 자막, 가라오케, 립싱크를 위한 단어·문자 단위 정렬 데이터
- **의존성 없음**: 네이티브 fetch API 사용 (Node.js 18+ 및 브라우저에서 작동)

## 보이스 추천

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

```typescript
const recommendations = await client.recommendVoices(
  'warm female voice for a product tutorial',
  3
);

for (const voice of recommendations) {
  console.log(voice.voice_id, voice.voice_name, voice.score);
}
```

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

## 설정

환경 변수 또는 생성자를 통해 API 키를 설정하세요:

```typescript
// 환경 변수 사용
// export TYPECAST_API_KEY="your-api-key-here"
const client = new TypecastClient({
  apiKey: process.env.TYPECAST_API_KEY!
});

// 또는 직접 전달
const client = new TypecastClient({
  apiKey: 'your-api-key-here'
});
```

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

```typescript API 키 없는 프록시
const client = new TypecastClient({
  baseHost: 'https://your-proxy.example.com'
});
```

## 고급 사용법

### 감정 조절 (ssfm-v30)

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

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

    ```typescript
    import { SmartPrompt } from '@neosapience/typecast-js';

    const audio = await client.textToSpeech({
      text: "Everything is going to be okay.",
      voice_id: "tc_672c5f5ce59fac2a48faeaee",
      model: "ssfm-v30",
      prompt: {
        emotion_type: "smart",
        previous_text: "I just got the best news!",  // 선택적 문맥
        next_text: "I can't wait to celebrate!"      // 선택적 문맥
      } as SmartPrompt
    });
    ```
  </Tab>

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

    ```typescript
    import { PresetPrompt } from '@neosapience/typecast-js';

    const audio = await client.textToSpeech({
      text: "I am so excited to show you these features!",
      voice_id: "tc_672c5f5ce59fac2a48faeaee",
      model: "ssfm-v30",
      prompt: {
        emotion_type: "preset",
        emotion_preset: "happy",    // normal, happy, sad, angry, whisper, toneup, tonedown
        emotion_intensity: 1.5      // 범위: 0.0 ~ 2.0
      } as PresetPrompt
    });
    ```
  </Tab>
</Tabs>

### 음성 조절

라우드니스, 피치, 템포 및 출력 형식을 제어합니다:

```typescript
const audio = await client.textToSpeech({
  text: "Customized audio output!",
  voice_id: "tc_672c5f5ce59fac2a48faeaee",
  model: "ssfm-v30",
  output: {
    target_lufs: -14.0,   // 범위: -70 ~ 0 (LUFS)
    audio_pitch: 2,       // 범위: -12 to +12 반음
    audio_tempo: 1.2,     // 범위: 0.5x to 2.0x
    audio_format: "mp3"   // 옵션: wav, mp3
  },
});

await fs.promises.writeFile(`output.${audio.format}`, Buffer.from(audio.audioData));
console.log(`Duration: ${audio.duration}s, Format: ${audio.format}`);
```

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

오디오 데이터를 직접 다루지 않고 파일까지 바로 저장하려면 `generateToFile`을 사용하세요. 모델은 기본적으로 `ssfm-v30`을 사용하며, `.mp3` / `.wav` 확장자는 `output.audio_format`이 없을 때 출력 포맷 추론에 사용됩니다. 사용할 보이스 ID는 [Voices](https://studio.typecast.ai/developers/api/voices) 페이지에서 확인할 수 있습니다.

```typescript
await client.generateToFile('output.mp3', {
  text: 'Hello from Typecast.',
  voice_id: 'tc_672c5f5ce59fac2a48faeaee' // voice_id는 https://studio.typecast.ai/developers/api/voices 에서 확인하세요.
});
```

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

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

```typescript
const audio = await client
  .composeSpeech()
  .defaults({ voice_id: 'tc_672c5f5ce59fac2a48faeaee', model: 'ssfm-v30' })
  .say('안녕하세요<|5s|>반갑습니다<|1s|>오늘<|2s|>날씨는 어떤 것 같으세요?')
  .generate();
```

### 다중 화자 합성

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

```typescript
import { TypecastClient } from '@neosapience/typecast-js';
import fs from 'fs/promises';

const client = new TypecastClient({ apiKey: 'YOUR_API_KEY' });

const audio = await client
  .composeSpeech()
  .defaults({ voice_id: 'tc_672c5f5ce59fac2a48faeaee', model: 'ssfm-v30' })
  .say('Hello there')
  .pause(5)
  .say('Nice to meet you', { voice_id: 'tc_60e5426de8b95f1d3000d7b5', output: { audio_pitch: 2 } })
  .say('Today')
  .pause(2)
  .say('How does the weather feel?')
  .generate();

await fs.writeFile('conversation.wav', Buffer.from(audio.audioData));
```

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

향상된 메타데이터로 사용 가능한 보이스를 나열하고 필터링합니다:

```typescript
// 모든 음성 가져오기
const voices = await client.getVoicesV2();

// 기준으로 필터링
const filtered = await client.getVoicesV2({
  model: 'ssfm-v30',
  gender: 'female',
  age: 'young_adult'
});

// 음성 정보 표시
voices.forEach(voice => {
  console.log(`ID: ${voice.voice_id}, Name: ${voice.voice_name}`);
  console.log(`Gender: ${voice.gender}, Age: ${voice.age}`);
  console.log(`Models: ${voice.models.map(m => m.version).join(', ')}`);
  console.log(`Use cases: ${voice.use_cases?.join(', ')}`);
});
```

### 다국어 콘텐츠

SDK는 자동 언어 감지와 함께 35+개 언어를 지원합니다:

```typescript
// 언어 자동 감지 (권장)
const audio = await client.textToSpeech({
  text: "こんにちは。お元気ですか。",
  voice_id: "tc_672c5f5ce59fac2a48faeaee",
  model: "ssfm-v30"
});

// 또는 명시적으로 언어 지정
const koreanAudio = await client.textToSpeech({
  text: "안녕하세요. 반갑습니다.",
  voice_id: "tc_672c5f5ce59fac2a48faeaee",
  model: "ssfm-v30",
  language: "kor"  // ISO 639-3 언어 코드
});

await fs.promises.writeFile(`output.${audio.format}`, Buffer.from(audio.audioData));
```


### 스트리밍

저지연 재생을 위한 실시간 오디오 청크 스트리밍:

```javascript
// Node 18+ (내장 fetch). 스트림을 ffplay로 파이핑하여 실시간 재생.
// 사전 설치: ffmpeg (brew/choco/apt install ffmpeg)
import { spawn } from "node:child_process";
import { TypecastClient } from '@neosapience/typecast-js';

const client = new TypecastClient({ apiKey: 'YOUR_API_KEY' });

const ffplay = spawn(
    "ffplay",
    ["-autoexit", "-nodisp", "-loglevel", "error", "-i", "pipe:0"],
    { stdio: ["pipe", "ignore", "ignore"] },
);

const stream = await client.textToSpeechStream({
    text: "이 텍스트를 실시간으로 오디오로 스트리밍합니다.",
    model: "ssfm-v30",
    voice_id: "tc_672c5f5ce59fac2a48faeaee",
    output: { audio_format: "wav" }
});

// ReadableStream - 청크가 도착하는 즉시 읽습니다
const reader = stream.getReader();
while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    ffplay.stdin.write(value);
}
ffplay.stdin.end();
await new Promise((resolve) => ffplay.on("close", resolve));
```

<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`를 래핑하여 오디오와 함께 단어·문자 단위 정렬 데이터를 반환합니다. 자막 생성, 가라오케 하이라이트, 립싱크 등에 활용할 수 있습니다.

### 기본 사용법

```typescript
import { TypecastClient } from '@neosapience/typecast-js';
import fs from 'fs';

const client = new TypecastClient({ apiKey: 'YOUR_API_KEY' });

const result = await client.textToSpeechWithTimestamps({
  text: "Hello. How are you?",
  model: "ssfm-v30",
  voice_id: "tc_60e5426de8b95f1d3000d7b5",
});

await fs.promises.writeFile("output.wav", result.audioBytes());

console.log(`Duration: ${result.audio_duration}s`);
result.words.forEach(w => {
  console.log(`  [${w.start_time.toFixed(3)}s – ${w.end_time.toFixed(3)}s] ${w.text}`);
});
```

### 자막 내보내기

```typescript
await fs.promises.writeFile("output.srt", result.toSrt(), "utf-8");
await fs.promises.writeFile("output.vtt", result.toVtt(), "utf-8");
```

<Note>
**일본어/중국어:** `granularity: "char"`를 사용하세요. 공백이 없는 언어에서는 단어 단위 세그먼트가 문장 전체로 나옵니다.
</Note>

## 지원 언어

SDK는 자동 언어 감지와 함께 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는 API 오류 처리를 위한 `TypecastAPIError`를 제공합니다:

```typescript
import { TypecastClient, TypecastAPIError } from '@neosapience/typecast-js';

try {
  const audio = await client.textToSpeech({
    text: "Hello world",
    voice_id: "tc_672c5f5ce59fac2a48faeaee",
    model: "ssfm-v30"
  });
} catch (error) {
  if (error instanceof TypecastAPIError) {
    // TypecastAPIError는 statusCode, message, response를 노출합니다
    switch (error.statusCode) {
      case 401:
        console.error('Invalid API key');
        break;
      case 402:
        console.error('Insufficient credits');
        break;
      case 422:
        console.error('Validation error:', error.response);
        break;
      case 429:
        console.error('Rate limit exceeded - please try again later');
        break;
      default:
        console.error(`API error (${error.statusCode}):`, error.message);
    }
  } else {
    console.error('Unexpected error:', error);
  }
}
```

## TypeScript 지원

이 SDK는 TypeScript로 작성되었으며 전체 타입 정의를 제공합니다:

```typescript
import type {
  TTSRequest,
  TTSResponse,
  TTSModel,
  LanguageCode,
  Prompt,
  PresetPrompt,
  SmartPrompt,
  Output,
  VoiceV2Response,
  VoicesV2Filter
} from '@neosapience/typecast-js';
```

## 무음 길이 조절

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

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

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

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

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

```typescript
const output = { remove_silence_ms: 300 };
```
