Skip to content

Commit

Permalink
Merge pull request #6 from elevenlabs/feat/add-support-for-agent-over…
Browse files Browse the repository at this point in the history
…rides

feat: add support for agent overrides
  • Loading branch information
hikmet-demir authored Nov 22, 2024
2 parents 4fa7270 + e3d91eb commit 66716f8
Showing 1 changed file with 109 additions and 3 deletions.
112 changes: 109 additions & 3 deletions Sources/ElevenLabsSwift/ElevenLabsSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import os.log

/// Main class for ElevenLabsSwift package
public class ElevenLabsSDK {
public static let version = "1.0.0"
public static let version = "1.0.1"

private enum Constants {
static let defaultApiOrigin = "wss://api.elevenlabs.io"
Expand All @@ -18,6 +18,80 @@ public class ElevenLabsSDK {
static let bufferSize: AVAudioFrameCount = 1024
}

// MARK: - Session Config Utilities

public enum Language: String, Codable, Sendable {
case en, ja, zh, de, hi, fr, ko, pt, it, es, id, nl, tr, pl, sv, bg, ro, ar, cs, el, fi, ms, da, ta, uk, ru, hu, no, vi
}

public struct AgentPrompt: Codable, Sendable {
public var prompt: String?

public init(prompt: String? = nil) {
self.prompt = prompt
}
}

public struct TTSConfig: Codable, Sendable {
public var voiceId: String?

private enum CodingKeys: String, CodingKey {
case voiceId = "voice_id"
}

public init(voiceId: String? = nil) {
self.voiceId = voiceId
}
}

public struct ConversationConfigOverride: Codable, Sendable {
public var agent: AgentConfig?
public var tts: TTSConfig?

public init(agent: AgentConfig? = nil, tts: TTSConfig? = nil) {
self.agent = agent
self.tts = tts
}
}

public struct AgentConfig: Codable, Sendable {
public var prompt: AgentPrompt?
public var firstMessage: String?
public var language: Language?

private enum CodingKeys: String, CodingKey {
case prompt
case firstMessage = "first_message"
case language
}

public init(prompt: AgentPrompt? = nil, firstMessage: String? = nil, language: Language? = nil) {
self.prompt = prompt
self.firstMessage = firstMessage
self.language = language
}
}

public enum LlmExtraBodyValue: Codable, Sendable {
case string(String)
case number(Double)
case boolean(Bool)
case null
case array([LlmExtraBodyValue])
case dictionary([String: LlmExtraBodyValue])

var jsonValue: Any {
switch self {
case let .string(str): return str
case let .number(num): return num
case let .boolean(bool): return bool
case .null: return NSNull()
case let .array(arr): return arr.map { $0.jsonValue }
case let .dictionary(dict): return dict.mapValues { $0.jsonValue }
}
}
}

// MARK: - Audio Utilities

public static func arrayBufferToBase64(_ data: Data) -> String {
Expand Down Expand Up @@ -113,15 +187,21 @@ public class ElevenLabsSDK {
public struct SessionConfig: Sendable {
public let signedUrl: String?
public let agentId: String?
public let overrides: ConversationConfigOverride?
public let customLlmExtraBody: [String: LlmExtraBodyValue]?

public init(signedUrl: String) {
public init(signedUrl: String, overrides: ConversationConfigOverride? = nil, customLlmExtraBody: [String: LlmExtraBodyValue]? = nil) {
self.signedUrl = signedUrl
agentId = nil
self.overrides = overrides
self.customLlmExtraBody = customLlmExtraBody
}

public init(agentId: String) {
public init(agentId: String, overrides: ConversationConfigOverride? = nil, customLlmExtraBody: [String: LlmExtraBodyValue]? = nil) {
self.agentId = agentId
signedUrl = nil
self.overrides = overrides
self.customLlmExtraBody = customLlmExtraBody
}
}

Expand Down Expand Up @@ -157,6 +237,25 @@ public class ElevenLabsSDK {
let socket = session.webSocketTask(with: url)
socket.resume()

// Always send initialization event
var initEvent: [String: Any] = ["type": "conversation_initiation_client_data"]

// Add overrides if present
if let overrides = config.overrides,
let overridesDict = overrides.dictionary
{
initEvent["conversation_config_override"] = overridesDict
}

// Add custom body if present
if let customBody = config.customLlmExtraBody {
initEvent["custom_llm_extra_body"] = customBody.mapValues { $0.jsonValue }
}

let jsonData = try JSONSerialization.data(withJSONObject: initEvent)
let jsonString = String(data: jsonData, encoding: .utf8)!
try await socket.send(.string(jsonString))

let configData = try await receiveInitialMessage(socket: socket)
return Connection(socket: socket, conversationId: configData.conversationId, sampleRate: configData.sampleRate)
}
Expand Down Expand Up @@ -1012,3 +1111,10 @@ private extension Data {
self = buffer.withUnsafeBufferPointer { Data(buffer: $0) }
}
}

extension Encodable {
var dictionary: [String: Any]? {
guard let data = try? JSONEncoder().encode(self) else { return nil }
return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)) as? [String: Any]
}
}

0 comments on commit 66716f8

Please sign in to comment.