SDK Swift

SDK ElevenAgents : déployez des agents vocaux interactifs et personnalisés dans vos applications Swift.

Consultez notre projet de démarrage rapide Swift complet pour démarrer rapidement avec un exemple complet et fonctionnel.

Installation

Ajoutez le SDK Swift ElevenLabs à votre projet avec Swift Package Manager :

1

Ajouter la dépendance du package

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

Ou avec Xcode :

  1. Ouvrez votre projet dans Xcode
  2. Accédez à File > Add Package Dependencies...
  3. Saisissez l’URL du dépôt : https://github.com/elevenlabs/elevenlabs-swift-sdk.git
  4. Sélectionnez la version 2.0.0 ou une version ultérieure
2

Importer le SDK

import ElevenLabs

Veillez à ajouter NSMicrophoneUsageDescription à votre Info.plist afin d’expliquer l’accès au microphone aux utilisateurs. Le SDK nécessite iOS 14.0+ / macOS 11.0+ et Swift 5.9+.

Démarrage rapide

Démarrez une conversation simple en quelques lignes seulement. Nous vous recommandons également de transmettre vos propres ID d’utilisateurs finaux pour associer les conversations à vos utilisateurs.

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()

Authentification

Il existe deux façons de vous authentifier et de démarrer une conversation :

Pour les agents publics, utilisez directement l’ID de l’agent :

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

Fonctionnalités principales

Gestion réactive des conversations

Le SDK fournit une classe Conversation moderne avec des propriétés @Published pour les mises à jour réactives de l’interface :

@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)
}
}

Modes vocal et texte

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

Contrôles audio

// 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

Outils client

Les outils client vous permettent d’enregistrer des fonctions personnalisées pouvant être appelées par votre agent IA pendant les conversations. Le nouveau SDK améliore la gestion des paramètres et des erreurs.

Gérer les appels d’outils

Gérez les appels d’outils de votre agent avec une prise en charge complète des paramètres :

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)"]
}
}

N’oubliez pas de configurer votre agent avec les outils client dans l’interface ElevenLabs. Consultez la documentation des outils client pour connaître les instructions de configuration.

Gestion de l’état de connexion

Surveillez l’état de la conversation afin de gérer les différentes phases de connexion :

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)

Suivi de l’état de l’agent

Suivez les moments où l’agent écoute ou parle :

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)

Gestion des messages

Envoyez des messages texte et surveillez la conversation :

// 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)

Alignement audio

Surveillez les données de synchronisation au niveau des caractères pour un affichage de texte synchronisé :

// 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)

Gestion des sessions

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

Intégration SwiftUI

Voici un exemple SwiftUI complet utilisant le nouveau SDK :

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)
}
}