타입캐스트 API를 위한 공식 Dart 및 Flutter SDK입니다. Dart 또는 Flutter 애플리케이션에서 텍스트를 음성으로 변환하고, 스트리밍, 타임스탬프, 보이스 조회, 커스텀 보이스 생성 기능을 사용할 수 있습니다.
설치
pub.dev에서 설치합니다:
dart pub add typecast_dart
Flutter 프로젝트에서는 다음 명령을 사용합니다:
flutter pub add typecast_dart
flutter pub add audioplayers
빠른 시작
import 'package:audioplayers/audioplayers.dart';
import 'package:typecast_dart/typecast_dart.dart';
final client = TypecastClient(apiKey: 'YOUR_API_KEY');
final player = AudioPlayer();
Future<void> speakAndPlay() async {
final response = await client.textToSpeech(
const TtsRequest(
voiceId: 'tc_672c5f5ce59fac2a48faeaee',
text: '안녕하세요! 타입캐스트 Dart SDK입니다.',
model: TtsModel.ssfmV30,
language: LanguageCode.kor,
output: Output(audioFormat: AudioFormat.wav),
),
);
await player.play(BytesSource(response.audioData));
print('재생 시간: ${response.duration}초, 포맷: ${response.format.value}');
}
Flutter에서 오디오 재생하기
Dart SDK는 생성된 오디오를 바이트 데이터로 반환합니다. Flutter에서는 audioplayers 같은 오디오 재생 패키지에 이 바이트 데이터를 전달해 바로 재생할 수 있습니다.
하나의 AudioPlayer 인스턴스를 공유하고, 각 응답을 메모리에서 바로 재생합니다:
import 'package:audioplayers/audioplayers.dart';
import 'package:typecast_dart/typecast_dart.dart';
final client = TypecastClient(apiKey: 'YOUR_API_KEY');
final player = AudioPlayer();
Future<void> playTts(String text) async {
final response = await client.textToSpeech(
TtsRequest(
voiceId: 'tc_672c5f5ce59fac2a48faeaee',
text: text,
model: TtsModel.ssfmV30,
language: LanguageCode.kor,
output: const Output(audioFormat: AudioFormat.wav),
),
);
await player.play(BytesSource(response.audioData));
}
기능
- 다중 음성 모델:
ssfm-v30및ssfm-v21AI 음성 모델 지원 - 다국어 지원: 영어, 한국어, 일본어, 중국어, 스페인어 등 37개 언어
- 감정 제어: 프리셋 감정 또는 스마트 문맥 인식 추론
- 오디오 커스터마이징: 음량, 피치, 템포, 출력 포맷 제어
- 보이스 탐색: V2 Voices API로 모델, 성별, 나이, 용도별 필터링
- 스트리밍: Dart
Stream<List<int>>로 스트리밍 TTS 응답 사용 - 타임스탬프 TTS: SRT/VTT 헬퍼가 포함된 단어·문자 단위 정렬 데이터
- 즉시 보이스 클로닝: WAV 샘플을 업로드해 커스텀 보이스 ID 생성
- Dart 및 Flutter 지원: Dart CLI, 서버, Flutter 프로젝트에서 동일 패키지 사용
보이스 추천
원하는 스타일은 알지만 정확한 voice_id를 모를 때 recommendVoices를 사용합니다.
final voices = await client.recommendVoices(
'warm female voice for a product tutorial',
count: 3,
);
for (final voice in voices) {
print('${voice.voiceId} ${voice.voiceName} ${voice.score}');
}
추천 결과에는 voiceId, voiceName, score만 포함됩니다. 지원 모델, 감정, 성별, 연령대, 사용 사례 같은 상세 메타데이터가 필요하면 getVoiceV2 또는 getVoicesV2로 추가 조회하세요.
설정
환경변수 또는 생성자에 API 키를 직접 전달할 수 있습니다:
export TYPECAST_API_KEY="your-api-key-here"
final client = TypecastClient(
baseUrl: 'https://your-proxy.example.com',
);
고급 사용법
감정 제어 (ssfm-v30)
ssfm-v30은 두 가지 감정 제어 모드를 제공합니다: 프리셋 및 스마트.
AI가 문맥에서 감정을 추론합니다:
final response = await client.textToSpeech(
const TtsRequest(
voiceId: 'tc_672c5f5ce59fac2a48faeaee',
text: '모든 것이 잘 될 거예요.',
model: TtsModel.ssfmV30,
prompt: SmartPrompt(
previousText: '방금 최고의 소식을 들었어요!',
nextText: '축하하고 싶어요!',
),
),
);
await player.play(BytesSource(response.audioData));
오디오 커스터마이징
음량, 피치, 템포, 출력 포맷을 제어합니다:
final response = await client.textToSpeech(
const TtsRequest(
voiceId: 'tc_672c5f5ce59fac2a48faeaee',
text: '커스터마이징된 오디오 출력!',
model: TtsModel.ssfmV30,
output: Output(
targetLufs: -14.0,
audioPitch: 2,
audioTempo: 1.2,
audioFormat: AudioFormat.mp3,
),
seed: 42,
),
);
await player.play(BytesSource(response.audioData));
파일로 바로 생성하기
generateToFile은 음성 합성과 파일 저장을 한 번에 처리합니다. model은 기본값으로 ssfm-v30을 사용하고, .mp3 또는 .wav 확장자로 출력 형식을 결정합니다.
await client.generateToFile(
'output.mp3',
GenerateToFileRequest(
text: '안녕하세요, 타입캐스트입니다.',
voiceId: 'tc_672c5f5ce59fac2a48faeaee', // voice_id는 https://studio.typecast.ai/developers/api/voices 에서 확인하세요.
),
);
텍스트만으로 쉼 표현
한 voice로 읽는 문장 안에 쉼만 넣고 싶다면 텍스트에 pause markup을 직접 작성합니다. <|5s|>, <|1s|>, <|0.3s|>, <|0.34413s|>처럼 쓰며 값은 초 단위이고 반드시 s로 끝납니다. 별도 pause 함수를 호출하지 않아도 텍스트만 보고 쉼 위치를 확인할 수 있습니다.
final audio = await client
.composeSpeech()
.defaults(ComposerSettings(voiceId: 'tc_672c5f5ce59fac2a48faeaee', model: TTSModel.ssfmV30))
.say('안녕하세요<|5s|>반갑습니다<|1s|>오늘<|2s|>날씨는 어떤 것 같으세요?')
.generate();
다중 화자 합성
한 파일 안에서 서로 다른 voice나 구간별 pitch, tempo, prompt, seed 같은 옵션을 조합해야 할 때 사용합니다. composer는 각 구간을 WAV로 생성하고 앞뒤 무음 PCM 샘플을 trim한 뒤 합성합니다. MP3가 필요하면 먼저 WAV를 생성한 다음 앱 또는 서버 파이프라인에서 변환하세요.
final audio = await client
.composeSpeech()
.defaults(const ComposerSettings(voiceId: 'tc_672c5f5ce59fac2a48faeaee', model: TtsModel.ssfmV30))
.say('Hello there')
.pause(5)
.say(
'Nice to meet you',
overrides: const ComposerSettings(
voiceId: 'tc_60e5426de8b95f1d3000d7b5',
output: Output(audioPitch: 2),
),
)
.say('Today')
.pause(2)
.say('How does the weather feel?')
.generate();
await File('conversation.wav').writeAsBytes(audio.audioData);
보이스 탐색 (V2 API)
향상된 메타데이터와 함께 사용 가능한 보이스를 조회합니다:
final voices = await client.getVoicesV2();
final filtered = await client.getVoicesV2(
const VoicesV2Filter(
model: TtsModel.ssfmV30,
gender: 'female',
age: 'young_adult',
),
);
for (final voice in voices) {
print('ID: ${voice.voiceId}, 이름: ${voice.voiceName}');
print('성별: ${voice.gender}, 나이: ${voice.age}');
}
final voice = await client.getVoiceV2('tc_672c5f5ce59fac2a48faeaee');
print(voice.voiceName);
스트리밍
Dart 스트림으로 오디오를 수신하고 파일 저장 없이 재생합니다:
import 'dart:typed_data';
final stream = await client.textToSpeechStream(
const TtsRequestStream(
voiceId: 'tc_672c5f5ce59fac2a48faeaee',
text: '이 텍스트를 실시간으로 오디오로 스트리밍합니다.',
model: TtsModel.ssfmV30,
output: OutputStream(audioFormat: AudioFormat.wav),
),
);
final audioBytes = <int>[];
await for (final chunk in stream) {
audioBytes.addAll(chunk);
}
await player.play(BytesSource(Uint8List.fromList(audioBytes)));
타임스탬프 TTS
textToSpeechWithTimestamps()는 POST /v1/text-to-speech/with-timestamps를 래핑하며, 오디오와 함께 단어·문자 단위 정렬 데이터를 반환합니다.
final result = await client.textToSpeechWithTimestamps(
const TtsRequest(
voiceId: 'tc_60e5426de8b95f1d3000d7b5',
text: '안녕하세요. 반갑습니다.',
model: TtsModel.ssfmV30,
language: LanguageCode.kor,
),
);
await player.play(BytesSource(result.audioBytes()));
print('재생 시간: ${result.audioDuration}초');
for (final word in result.words) {
print('[${word.startTime}초 - ${word.endTime}초] ${word.word}');
}
정밀도(Granularity) 설정
granularity: 'word'(기본값) 또는 granularity: 'char'를 설정해 정렬 단위를 제어합니다.
final result = await client.textToSpeechWithTimestamps(
const TtsRequest(
voiceId: 'tc_60e5426de8b95f1d3000d7b5',
text: '안녕하세요. 반갑습니다.',
model: TtsModel.ssfmV30,
language: LanguageCode.kor,
),
granularity: 'char',
);
자막 내보내기
await File('output.srt').writeAsString(result.toSrt());
await File('output.vtt').writeAsString(result.toVtt());
즉시 보이스 클로닝
짧은 WAV 샘플을 업로드해 커스텀 보이스를 생성합니다:
final voice = await client.cloneVoice(
audio: await File('sample.wav').readAsBytes(),
filename: 'sample.wav',
name: 'My Voice',
model: TtsModel.ssfmV30,
);
print('커스텀 보이스 ID: ${voice.voiceId}');