let request = TTSRequest( voiceId: "tc_672c5f5ce59fac2a48faeaee", text: "모든 것이 잘 될 거예요.", model: .ssfmV30, prompt: .smart(SmartPrompt( previousText: "방금 최고의 소식을 들었어요!", // 선택적 문맥 nextText: "축하할 수 있어서 너무 기다려져요!" // 선택적 문맥 )))let response = try await client.textToSpeech(request)
프리셋 값으로 감정을 명시적으로 설정합니다:
let request = TTSRequest( voiceId: "tc_672c5f5ce59fac2a48faeaee", text: "이 기능들을 보여드리게 되어 정말 기대됩니다!", model: .ssfmV30, prompt: .preset(PresetPrompt( emotionPreset: .happy, // normal, happy, sad, angry, whisper, toneup, tonedown emotionIntensity: 1.5 // 범위: 0.0 ~ 2.0 )))let response = try await client.textToSpeech(request)
import AVFoundationimport Typecastlet engine = AVAudioEngine()let playerNode = AVAudioPlayerNode()let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 32000, channels: 1, interleaved: true)!engine.attach(playerNode)engine.connect(playerNode, to: engine.mainMixerNode, format: format)try engine.start()playerNode.play()let stream = try await client.textToSpeechStream(request)var first = truefor try await chunk in stream { var pcmData = chunk if first { pcmData = chunk.dropFirst(44) // 44바이트 WAV 헤더 건너뛰기 first = false } let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(pcmData.count / 2))! buffer.frameLength = buffer.frameCapacity pcmData.withUnsafeBytes { ptr in buffer.int16ChannelData!.pointee.update(from: ptr.bindMemory(to: Int16.self).baseAddress!, count: Int(buffer.frameLength)) } playerNode.scheduleBuffer(buffer)}
WAV 스트리밍 형식: 32000 Hz, 16비트, 모노 PCM. 첫 번째 청크에 44바이트 WAV 헤더(size = 0xFFFFFFFF)가 포함되며, 이후 청크는 원시 PCM 데이터만 포함합니다. MP3 형식: 320 kbps, 44100 Hz, 각 청크는 독립적으로 디코딩 가능합니다. Foundation.OutputStream과의 이름 충돌을 피하려면 Typecast.OutputStream을 사용하세요. 스트리밍 엔드포인트는 volume 및 targetLufs를 지원하지 않습니다.
import Typecastdo { let response = try await client.textToSpeech(request)} catch let error as TypecastError { switch error { case .unauthorized(let message): // 401: 잘못된 API 키 print("Invalid API key: \(message)") case .paymentRequired(let message): // 402: 크레딧 부족 print("Insufficient credits: \(message)") case .notFound(let message): // 404: 리소스를 찾을 수 없음 print("Voice not found: \(message)") case .validationError(let message): // 422: 유효성 검사 오류 print("Validation error: \(message)") case .rateLimitExceeded(let message): // 429: 요청 한도 초과 print("Rate limit exceeded: \(message)") case .serverError(let message): // 500: 서버 오류 print("Server error: \(message)") case .networkError(let underlyingError): // 네트워크 연결 문제 print("Network error: \(underlyingError.localizedDescription)") case .invalidResponse(let message): // 서버의 잘못된 응답 print("Invalid response: \(message)") default: print("Error: \(error.localizedDescription)") } // 사용 가능한 경우 상태 코드에 액세스 if let statusCode = error.statusCode { print("HTTP status: \(statusCode)") }}