타입캐스트 API를 위한 공식 Zig 라이브러리입니다. AI 음성을 사용하여 텍스트를 자연스러운 음성으로 변환합니다.
순수 Zig 구현 — C 의존성 없음. Zig 표준 라이브러리의 std.http.Client와 std.json만 사용합니다.
zig fetch로 의존성을 추가합니다:
zig fetch --save "https://github.com/neosapience/typecast-sdk/archive/refs/tags/typecast-zig/v0.1.0.tar.gz"
그런 다음 build.zig에 import를 추가합니다:
const typecast_dep = b.dependency("typecast_zig", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("typecast", typecast_dep.module("typecast"));
빠른 시작
const std = @import("std");
const typecast = @import("typecast");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// 클라이언트 초기화 (환경변수에서 TYPECAST_API_KEY 읽기)
var client = typecast.Client.init(allocator, .{
.api_key = std.posix.getenv("TYPECAST_API_KEY") orelse return error.MissingApiKey,
});
defer client.deinit();
// 텍스트를 음성으로 변환
const response = try client.textToSpeech(.{
.voice_id = "tc_672c5f5ce59fac2a48faeaee",
.text = "안녕하세요! 타입캐스트 Zig SDK입니다.",
.model = .ssfm_v30,
});
defer allocator.free(response.audio_data);
// 오디오 파일 저장
const file = try std.fs.cwd().createFile("output.wav", .{});
defer file.close();
try file.writeAll(response.audio_data);
std.debug.print("{d} 바이트 저장, 재생 시간: {d:.1}초\n", .{
response.audio_data.len, response.duration,
});
}
- 다중 음성 모델:
ssfm-v30 (최신) 및 ssfm-v21 AI 음성 모델 지원
- 다국어 지원: 영어, 한국어, 스페인어, 일본어, 중국어 등 37개 언어
- 감정 제어: 프리셋 감정 (normal, happy, sad, angry, whisper, toneup, tonedown) 또는 스마트 문맥 인식 추론
- 오디오 커스터마이징: 음량 (LUFS -70 to 0), 피치 (-12 to +12 세미톤), 템포 (0.5x to 2.0x), 포맷 (WAV/MP3) 제어
- 보이스 탐색: V2 Voices API로 모델, 성별, 나이, 용도별 필터링
- 순수 Zig: 외부 의존성 없이 표준 라이브러리만 사용
- 스트리밍: 저지연 재생을 위한 실시간 청크 오디오 전송 (콜백 기반)
- 명시적 메모리 관리: 호출자 제공 allocator로 명확한 소유권 관리
환경변수 또는 직접 API 키를 전달할 수 있습니다:
const typecast = @import("typecast");
// 환경변수 사용 (권장)
// export TYPECAST_API_KEY="your-api-key-here"
var client = typecast.Client.init(allocator, .{
.api_key = std.posix.getenv("TYPECAST_API_KEY") orelse return error.MissingApiKey,
});
defer client.deinit();
// 직접 전달
var client = typecast.Client.init(allocator, .{
.api_key = "your-api-key-here",
});
defer client.deinit();
고급 사용법
감정 제어 (ssfm-v30)
ssfm-v30은 두 가지 감정 제어 모드를 제공합니다: 프리셋 및 스마트.
AI가 문맥에서 감정을 추론합니다:const response = try client.textToSpeech(.{
.voice_id = "tc_672c5f5ce59fac2a48faeaee",
.text = "모든 것이 잘 될 거예요.",
.model = .ssfm_v30,
.prompt = .{ .smart = .{
.previous_text = "방금 최고의 소식을 들었어요!",
.next_text = "축하하고 싶어요!",
} },
});
defer allocator.free(response.audio_data);
프리셋 값으로 감정을 명시적으로 설정합니다:const response = try client.textToSpeech(.{
.voice_id = "tc_672c5f5ce59fac2a48faeaee",
.text = "이 기능들을 보여드리게 되어 정말 기쁩니다!",
.model = .ssfm_v30,
.prompt = .{ .preset = .{
.emotion_preset = .happy,
.emotion_intensity = 1.5,
} },
});
defer allocator.free(response.audio_data);
오디오 커스터마이징
음량, 피치, 템포, 출력 포맷을 제어합니다:
const response = try client.textToSpeech(.{
.voice_id = "tc_672c5f5ce59fac2a48faeaee",
.text = "커스터마이징된 오디오 출력!",
.model = .ssfm_v30,
.output = .{
.target_lufs = -14.0,
.audio_pitch = 2,
.audio_tempo = 1.2,
.audio_format = .mp3,
},
.seed = 42,
});
defer allocator.free(response.audio_data);
보이스 탐색 (V2 API)
향상된 메타데이터와 함께 사용 가능한 보이스를 조회합니다:
// 모든 보이스 조회
const voices = try client.getVoicesV2(null);
defer allocator.free(voices);
// 모델별 필터링
const filtered = try client.getVoicesV2(.{ .model = .ssfm_v30 });
defer allocator.free(filtered);
for (voices) |voice| {
std.debug.print("ID: {s}, 이름: {s}\n", .{ voice.voice_id, voice.voice_name });
}
스트리밍
콜백을 통해 실시간으로 오디오 청크를 스트리밍합니다:
try client.textToSpeechStream(.{
.voice_id = "tc_672c5f5ce59fac2a48faeaee",
.text = "이 텍스트를 실시간으로 오디오로 스트리밍합니다.",
.model = .ssfm_v30,
}, struct {
var first = true;
fn onChunk(chunk: []const u8) anyerror!void {
var data = chunk;
if (first) {
data = chunk[44..]; // 44바이트 WAV 헤더 건너뛰기
first = false;
}
// data는 32000 Hz 16비트 모노 원시 PCM
// 오디오 출력으로 전달
}
}.onChunk);
WAV 스트리밍 형식: 32000 Hz, 16비트, 모노 PCM. 첫 번째 청크에 44바이트 WAV 헤더(size = 0xFFFFFFFF)가 포함되며, 이후 청크는 원시 PCM 데이터만 포함합니다. MP3 형식: 320 kbps, 44100 Hz, 각 청크는 독립적으로 디코딩 가능합니다. 스트리밍 엔드포인트는 volume 및 target_lufs를 지원하지 않습니다.
지원 언어
37개 언어를 지원하며 자동 언어 감지 기능을 제공합니다:
| 코드 | 언어 | 코드 | 언어 | 코드 | 언어 |
|---|
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 | 광둥어 | | | | |
언어를 지정하지 않으면 입력 텍스트에서 자동으로 감지됩니다.
에러 처리
SDK는 API 에러 처리를 위해 Zig의 error union을 사용합니다:
const response = client.textToSpeech(.{
.voice_id = "tc_672c5f5ce59fac2a48faeaee",
.text = "안녕하세요",
.model = .ssfm_v30,
}) catch |err| switch (err) {
error.Unauthorized => {
std.debug.print("유효하지 않은 API 키\n", .{});
return err;
},
error.PaymentRequired => {
std.debug.print("크레딧 부족\n", .{});
return err;
},
error.RateLimited => {
std.debug.print("요청 한도 초과 - 잠시 후 재시도\n", .{});
return err;
},
else => return err,
};
defer allocator.free(response.audio_data);
에러 유형
| 에러 | 상태 코드 | 설명 |
|---|
error.BadRequest | 400 | 잘못된 요청 파라미터 |
error.Unauthorized | 401 | 유효하지 않거나 누락된 API 키 |
error.PaymentRequired | 402 | 크레딧 부족 |
error.NotFound | 404 | 리소스를 찾을 수 없음 |
error.UnprocessableEntity | 422 | 유효성 검사 오류 |
error.RateLimited | 429 | 요청 한도 초과 |
error.InternalServerError | 500 | 서버 오류 |
error.JsonParseError | - | JSON 파싱 오류 |
API 레퍼런스
클라이언트 메서드
| 메서드 | 설명 |
|---|
init(allocator, config) | 설정으로 클라이언트 생성 |
deinit() | 클라이언트 리소스 정리 |
textToSpeech(request) | 텍스트를 음성 오디오로 변환 |
textToSpeechStream(request, callback) | 콜백을 통한 오디오 청크 스트리밍 |
getMySubscription() | 구독 정보 조회 |
getVoices(model) | 사용 가능한 보이스 조회 (V1) |
getVoicesV2(filter) | 메타데이터와 함께 보이스 조회 (V2) |
getVoiceV2(voice_id, model) | 특정 보이스 조회 |