Swift SDK

ElevenAgents SDK: Swift 애플리케이션에 맞춤형 대화형 음성 에이전트를 배포하세요.

완전히 작동하는 예제로 빠르게 시작하려면 전체 Swift 퀵스타트 프로젝트를 확인하세요.

설치

Swift Package Manager를 사용하여 프로젝트에 ElevenLabs Swift SDK를 추가하세요.

1

패키지 종속성 추가

dependencies: [ .package(url: "https://github.com/elevenlabs/elevenlabs-swift-sdk.git",
from: "2.0.0") ]

또는 Xcode에서 다음을 수행하세요.

  1. Xcode에서 프로젝트를 엽니다.
  2. File > Add Package Dependencies...로 이동합니다.
  3. 리포지토리 URL을 입력합니다: https://github.com/elevenlabs/elevenlabs-swift-sdk.git
  4. 버전 2.0.0 이상을 선택합니다.
2

SDK 가져오기

import ElevenLabs

사용자에게 마이크 접근을 설명하기 위해 Info.plist에 NSMicrophoneUsageDescription를 추가해야 합니다. SDK에는 iOS 14.0 이상/macOS 11.0 이상 및 Swift 5.9 이상이 필요합니다.

빠른 시작

몇 줄만으로 간단한 대화를 시작하세요. 선택 사항으로, 대화를 사용자에게 매핑하기 위해 자체 최종 사용자 ID를 전달하는 것을 권장합니다.

import ElevenLabs
// Start a conversation with your agent
let conversation = try await ElevenLabs.startConversation(
agentId: "your-agent-id",
userId: "your-end-user-id",
config: ConversationConfig()
)
// Observe conversation state and messages
conversation.$state
.sink { state in
print("Connection state: \(state)")
}
.store(in: &cancellables)
conversation.$messages
.sink { messages in
for message in messages {
print("\(message.role): \(message.content)")
}
}
.store(in: &cancellables)
// Send messages and control the conversation
try await conversation.sendMessage("Hello!")
try await conversation.toggleMute()
await conversation.endConversation()

인증

인증하고 대화를 시작하는 방법은 두 가지입니다.

공개 에이전트의 경우 에이전트 ID를 직접 사용하세요.

let conversation = try await ElevenLabs.startConversation(
agentId: "your-public-agent-id",
config: ConversationConfig()
)

핵심 기능

반응형 대화 관리

SDK는 반응형 UI 업데이트를 위해 @Published 속성을 갖춘 최신 Conversation 클래스를 제공합니다.

@MainActor
class ConversationManager: ObservableObject {
@Published var conversation: Conversation?
private var cancellables = Set<AnyCancellable>()
func startConversation(agentId: String) async throws {
let config = ConversationConfig(
conversationOverrides: ConversationOverrides(textOnly: false)
)
conversation = try await ElevenLabs.startConversation(
agentId: agentId,
config: config
)
setupObservers()
}
private func setupObservers() {
guard let conversation else { return }
// Monitor connection state
conversation.$state
.sink { state in print("State: \(state)") }
.store(in: &cancellables)
// Monitor messages
conversation.$messages
.sink { messages in print("Messages: \(messages.count)") }
.store(in: &cancellables)
}
}

음성 및 텍스트 모드

// Voice conversation (default)
let voiceConfig = ConversationConfig(
conversationOverrides: ConversationOverrides(textOnly: false)
)
// Text-only conversation
let textConfig = ConversationConfig(
conversationOverrides: ConversationOverrides(textOnly: true)
)

오디오 제어

// Microphone control
try await conversation.toggleMute()
try await conversation.setMuted(true)
// Check microphone state
let isMuted = conversation.isMuted
// Access audio tracks for advanced use cases
let inputTrack = conversation.inputTrack
let agentAudioTrack = conversation.agentAudioTrack

클라이언트 도구

클라이언트 도구를 사용하면 대화 중 AI 에이전트가 호출할 수 있는 맞춤 함수를 등록할 수 있습니다. 새 SDK는 향상된 매개변수 처리와 오류 관리를 제공합니다.

도구 호출 처리

전체 매개변수 지원으로 에이전트의 도구 호출을 처리하세요.

private func handleToolCall(_ toolCall: ClientToolCallEvent) async {
do {
let parameters = try toolCall.getParameters()
let result = await executeClientTool(
name: toolCall.toolName,
parameters: parameters
)
if toolCall.expectsResponse {
try await conversation?.sendToolResult(
for: toolCall.toolCallId,
result: result
)
} else {
conversation?.markToolCallCompleted(toolCall.toolCallId)
}
} catch {
// Handle tool execution errors
if toolCall.expectsResponse {
try? await conversation?.sendToolResult(
for: toolCall.toolCallId,
result: ["error": error.localizedDescription],
isError: true
)
}
}
}
// Example tool implementation
func executeClientTool(name: String, parameters: [String: Any]) async -> [String: Any] {
switch name {
case "get_weather":
guard let location = parameters["location"] as? String else {
return ["error": "Missing location parameter"]
}
// Fetch weather data
return ["temperature": "22°C", "condition": "Sunny"]
case "send_email":
guard let recipient = parameters["recipient"] as? String,
let subject = parameters["subject"] as? String else {
return ["error": "Missing required parameters"]
}
// Send email logic
return ["status": "sent", "messageId": "12345"]
default:
return ["error": "Unknown tool: \(name)"]
}
}

ElevenLabs UI에서 클라이언트 도구로 에이전트를 설정해야 합니다. 설정 방법은 클라이언트 도구 문서를 참조하세요.

연결 상태 관리

서로 다른 연결 단계를 처리할 수 있도록 대화 상태를 모니터링하세요.

conversation.$state
.sink { state in
switch state {
case .idle:
// Not connected
break
case .connecting:
// Show connecting indicator
break
case .active(let callInfo):
// Connected to agent: \(callInfo.agentId)
break
case .ended(let reason):
// Handle disconnection: \(reason)
break
case .error(let error):
// Handle error: \(error)
break
}
}
.store(in: &cancellables)

에이전트 상태 모니터링

에이전트가 듣고 있는지 또는 말하고 있는지 추적하세요.

conversation.$agentState
.sink { state in
switch state {
case .listening:
// Agent is listening, show listening indicator
break
case .speaking:
// Agent is speaking, show speaking indicator
break
}
}
.store(in: &cancellables)

메시지 처리

텍스트 메시지를 보내고 대화를 모니터링하세요.

// Send a text message
try await conversation.sendMessage("Hello, how can you help me today?")
// Monitor all messages in the conversation
conversation.$messages
.sink { messages in
for message in messages {
switch message.role {
case .user:
print("User: \(message.content)")
case .agent:
print("Agent: \(message.content)")
}
}
}
.store(in: &cancellables)

오디오 정렬

동기화된 텍스트 표시에 사용할 문자 수준 타이밍 데이터를 모니터링하세요.

// Using the callback
let config = ConversationConfig(
onAudioAlignment: { alignment in
// Character-level timing data
for (index, char) in alignment.chars.enumerated() {
let startMs = alignment.charStartTimesMs[index]
let durationMs = alignment.charDurationsMs[index]
print("'\(char)' at \(startMs)ms for \(durationMs)ms")
}
}
)
// Or observe the published property
conversation.$latestAudioAlignment
.compactMap { $0 }
.sink { alignment in
// Handle alignment updates
}
.store(in: &cancellables)

세션 관리

// End the conversation
await conversation.endConversation()
// Check if conversation is active
let isActive = conversation.state.isActive

SwiftUI 통합

새 SDK를 사용하는 포괄적인 SwiftUI 예시입니다.

import SwiftUI
import ElevenLabs
import Combine
struct ConversationView: View {
@StateObject private var viewModel = ConversationViewModel()
var body: some View {
VStack(spacing: 20) {
// Connection status
Text(viewModel.connectionStatus)
.font(.headline)
.foregroundColor(viewModel.isConnected ? .green : .red)
// Chat messages
ScrollView {
LazyVStack(alignment: .leading, spacing: 8) {
ForEach(viewModel.messages, id: \.id) { message in
MessageBubble(message: message)
}
}
}
.frame(maxHeight: 400)
// Controls
HStack(spacing: 16) {
Button(viewModel.isConnected ? "End" : "Start") {
Task {
if viewModel.isConnected {
await viewModel.endConversation()
} else {
await viewModel.startConversation()
}
}
}
.buttonStyle(.borderedProminent)
Button(viewModel.isMuted ? "Unmute" : "Mute") {
Task { await viewModel.toggleMute() }
}
.buttonStyle(.bordered)
.disabled(!viewModel.isConnected)
Button("Send Message") {
Task { await viewModel.sendTestMessage() }
}
.buttonStyle(.bordered)
.disabled(!viewModel.isConnected)
}
// Agent state indicator
if viewModel.isConnected {
HStack {
Circle()
.fill(viewModel.agentState == .speaking ? .blue : .gray)
.frame(width: 10, height: 10)
Text(viewModel.agentState == .speaking ? "Agent speaking" : "Agent listening")
.font(.caption)
}
}
}
.padding()
}
}
struct MessageBubble: View {
let message: Message
var body: some View {
HStack {
if message.role == .user { Spacer() }
VStack(alignment: .leading) {
Text(message.role == .user ? "You" : "Agent")
.font(.caption)
.foregroundColor(.secondary)
Text(message.content)
.padding()
.background(message.role == .user ? Color.blue : Color.gray.opacity(0.3))
.foregroundColor(message.role == .user ? .white : .primary)
.cornerRadius(12)
}
if message.role == .agent { Spacer() }
}
}
}
@MainActor
class ConversationViewModel: ObservableObject {
@Published var messages: [Message] = []
@Published var isConnected = false
@Published var isMuted = false
@Published var agentState: AgentState = .listening
@Published var connectionStatus = "Disconnected"
private var conversation: Conversation?
private var cancellables = Set<AnyCancellable>()
func startConversation() async {
do {
conversation = try await ElevenLabs.startConversation(
agentId: "your-agent-id",
config: ConversationConfig()
)
setupObservers()
} catch {
print("Failed to start conversation: \(error)")
connectionStatus = "Failed to connect"
}
}
func endConversation() async {
await conversation?.endConversation()
conversation = nil
cancellables.removeAll()
}
func toggleMute() async {
try? await conversation?.toggleMute()
}
func sendTestMessage() async {
try? await conversation?.sendMessage("Hello from the app!")
}
private func setupObservers() {
guard let conversation else { return }
conversation.$messages
.assign(to: &$messages)
conversation.$state
.map { state in
switch state {
case .idle: return "Disconnected"
case .connecting: return "Connecting..."
case .active: return "Connected"
case .ended: return "Ended"
case .error: return "Error"
}
}
.assign(to: &$connectionStatus)
conversation.$state
.map { $0.isActive }
.assign(to: &$isConnected)
conversation.$isMuted
.assign(to: &$isMuted)
conversation.$agentState
.assign(to: &$agentState)
}
}