Kotlin SDK

ElevenAgents SDK: wdrażaj w kilka minut dostosowanych, interaktywnych agentów głosowych w aplikacjach na Androida.

Zobacz opis ElevenAgents, aby dowiedzieć się, jak działa ElevenAgents.

Instalacja

Dodaj SDK ElevenLabs do projektu Androida, umieszczając poniższą zależność w pliku build.gradle na poziomie aplikacji:

build.gradle.kts
dependencies {
// ElevenLabs Agents SDK (Android)
implementation("io.elevenlabs:elevenlabs-android:<latest>")
// Kotlin coroutines, AndroidX, etc., as needed by your app
}

Przykładową aplikację na Androida korzystającą z tego SDK znajdziesz tutaj

Wymagania

  • Android API na poziomie 21 (Android 5.0) lub wyższym
  • Uprawnienie do internetu dla wywołań API
  • Uprawnienie do mikrofonu dla wejścia głosowego
  • Konfiguracja zabezpieczeń sieciowych dla wywołań HTTPS

Konfiguracja

Konfiguracja manifestu

Dodaj wymagane uprawnienia do AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

Uprawnienia w czasie działania

W Androidzie 6.0 (API na poziomie 23) i nowszym musisz poprosić o uprawnienie do mikrofonu w czasie działania:

import android.Manifest
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
private fun requestMicrophonePermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
// Show explanation to the user
showPermissionExplanationDialog()
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.RECORD_AUDIO),
MICROPHONE_PERMISSION_REQUEST_CODE
)
}
}
}

Użycie

Zainicjuj SDK ElevenLabs w klasie Application lub głównej aktywności:

Rozpocznij sesję rozmowy, przekazując:

  • Agenta publicznego: przekaż agentId
  • Agenta prywatnego: przekaż conversationToken udostępniony przez backend (nigdy nie ujawniaj klucza API klientowi).
import io.elevenlabs.ConversationClient
import io.elevenlabs.ConversationConfig
import io.elevenlabs.ConversationSession
import io.elevenlabs.ClientTool
import io.elevenlabs.ClientToolResult
// Start a public agent session (token generated for you)
val config = ConversationConfig(
agentId = "<your_public_agent_id>", // OR conversationToken = "<token>"
userId = "your-user-id",
// Optional callbacks
onConnect = { conversationId ->
// Called when the conversation is connected and returns the conversation ID. You can access conversationId via session.getId() too
},
onMessage = { source, messageJson ->
// Raw JSON messages from data channel; useful for logging/telemetry
},
onModeChange = { mode ->
// "speaking" | "listening" — drive UI indicators
},
onStatusChange = { status ->
// "connected" | "connecting" | "disconnected"
},
onCanSendFeedbackChange = { canSend ->
// Enable/disable thumbs up/down buttons for feedback reporting
},
onUnhandledClientToolCall = { call ->
// Agent requested a client tool not registered on the device
},
onVadScore = { score ->
// Voice Activity Detection score, range from 0 to 1 where higher values indicate higher confidence of speech
},
onAudioAlignment = { alignment ->
// Character-level timing data for synchronized text display
val chars = alignment["chars"] as? List<*>
val startTimes = alignment["char_start_times_ms"] as? List<*>
val durations = alignment["char_durations_ms"] as? List<*>
Log.d("ExampleApp", "Audio alignment: $chars")
},
// List of client tools the agent can invoke
clientTools = mapOf(
"logMessage" to object : ClientTool {
override suspend fun execute(parameters: Map<String, Any>): ClientToolResult {
val message = parameters["message"] as? String
Log.d("ExampleApp", "[INFO] Client Tool Log: $message")
return ClientToolResult.success("Message logged successfully")
}
}
),
)
// In an Activity context
val session: ConversationSession = ConversationClient.startSession(config, this)

Pamiętaj, że ElevenAgents wymaga dostępu do mikrofonu. Rozważ wyjaśnienie tego i poproszenie o uprawnienia w interfejsie aplikacji przed rozpoczęciem rozmowy, szczególnie w Androidzie 6.0+, gdzie wymagane są uprawnienia w czasie działania.

Jeśli narzędzie ma na serwerze ustawione expects_response=false, zwróć null z execute, aby nie wysyłać wyniku narzędzia z powrotem do agenta.

Agenci publiczni i prywatni

  • Agenci publiczni (bez uwierzytelniania): Zainicjuj za pomocą agentId w ConversationConfig. SDK prosi ElevenLabs o token rozmowy bez potrzeby używania klucza API na urządzeniu.
  • Agenci prywatni (z uwierzytelnianiem): Zainicjuj za pomocą conversationToken w ConversationConfig. Twój serwer prosi ElevenLabs o token rozmowy, używając klucza API ElevenLabs.
Nigdy nie umieszczaj kluczy API w klientach. Łatwo je wyodrębnić i wykorzystać w złych celach.

Narzędzia klienta

Zarejestruj narzędzia klienta, aby agent mógł wywoływać lokalne funkcje urządzenia.

val config = ConversationConfig(
agentId = "<public_agent>",
clientTools = mapOf(
"logMessage" to object : io.elevenlabs.ClientTool {
override suspend fun execute(parameters: Map<String, Any>): io.elevenlabs.ClientToolResult? {
val message = parameters["message"] as? String ?: return io.elevenlabs.ClientToolResult.failure("Missing 'message'")
android.util.Log.d("ClientTool", "Log: $message")
return null // No response needed for fire-and-forget tools
}
}
)
)

Gdy agent wywoła client_tool_call, SDK uruchomi pasujące narzędzie i odpowie za pomocą client_tool_result. Jeśli narzędzie nie jest zarejestrowane, wywoływane jest onUnhandledClientToolCall, a agent otrzymuje wynik błędu (jeśli oczekiwana jest odpowiedź).

Przegląd callbacków

  • onConnect - Wywoływany po ustanowieniu połączenia WebRTC. Zwraca identyfikator rozmowy.
  • onMessage - Wywoływany po odebraniu nowej wiadomości. Mogą to być wstępne lub końcowe transkrypcje głosu użytkownika, odpowiedzi wygenerowane przez LLM albo komunikaty debugowania. Udostępnia źródło ("ai" lub "user") oraz surową wiadomość JSON.
  • onModeChange - Wywoływany przy zmianie trybu rozmowy. Przydaje się do wskazania, czy agent mówi ("speaking"), czy słucha ("listening").
  • onStatusChange - Wywoływany przy zmianie statusu rozmowy ("connected", "connecting" lub "disconnected").
  • onCanSendFeedbackChange - Wywoływany przy zmianie możliwości wysłania opinii. Włącza/wyłącza przyciski opinii.
  • onUnhandledClientToolCall - Wywoływany, gdy agent prosi o narzędzie klienta, które nie jest zarejestrowane na urządzeniu.
  • onVadScore - Wywoływany przy zmianie wyniku wykrywania aktywności głosowej. Zakres od 0 do 1, gdzie wyższe wartości oznaczają większą pewność wykrycia mowy.
  • onAudioAlignment - Wywoływany po otrzymaniu danych synchronizacji audio, które zawierają informacje o czasie na poziomie znaków dla mowy agenta.

Nie wszystkie zdarzenia klienta są domyślnie włączone dla agenta. Jeśli masz włączony callback, ale nie otrzymujesz zdarzeń, sprawdź, czy odpowiednie zdarzenie jest włączone dla agenta ElevenLabs. Możesz to zrobić na karcie „Advanced” w ustawieniach agenta w panelu ElevenLabs.

Metody

startSession

Metoda startSession inicjuje połączenie WebRTC i zaczyna korzystać z mikrofonu, aby komunikować się z agentem ElevenLabs Agents.

Agenci publiczni

W przypadku agentów publicznych (czyli agentów bez włączonego uwierzytelniania) wymagany jest tylko agentId. ID agenta znajdziesz w interfejsie ElevenLabs.

val session = ConversationClient.startSession(
config = ConversationConfig(
agentId = "your-agent-id"
),
context = this
)
Agenci prywatni

W przypadku agentów prywatnych musisz przekazać conversationToken uzyskany z API ElevenLabs. Wygenerowanie tego tokenu wymaga klucza API ElevenLabs.

conversationToken jest ważny przez 10 minut.
// Server-side token generation (Node.js example)
app.get("/conversation-token", yourAuthMiddleware, async (req, res) => {
const response = await fetch(
`https://api.elevenlabs.io/v1/convai/conversation/token?agent_id=${process.env.AGENT_ID}`,
{
headers: {
// Requesting a conversation token requires your ElevenLabs API key
// Do NOT expose your API key to the client!
"xi-api-key": process.env.ELEVENLABS_API_KEY,
},
}
);
if (!response.ok) {
return res.status(500).send("Failed to get conversation token");
}
const body = await response.json();
res.send(body.token);
});

Następnie przekaż token do metody startSession. Pamiętaj, że w przypadku agentów prywatnych wymagany jest tylko conversationToken.

// Get conversation token from your server
val conversationToken = fetchConversationTokenFromServer()
// For private agents, pass in the conversation token
val session = ConversationClient.startSession(
config = ConversationConfig(
conversationToken = conversationToken
),
context = this
)

Opcjonalnie możesz przekazać ID użytkownika, aby zidentyfikować go w rozmowie. Może to być twój własny identyfikator klienta. Zostanie on dołączony do danych inicjujących rozmowę wysyłanych na serwer.

val session = ConversationClient.startSession(
config = ConversationConfig(
agentId = "your-agent-id",
userId = "your-user-id"
),
context = this
)

endSession

Metoda ręcznego zakończenia rozmowy. Rozłącza i kończy rozmowę.

session.endSession()

sendUserMessage

Wyślij wiadomość tekstową do agenta podczas aktywnej rozmowy. Agent na nią odpowie.

session.sendUserMessage("Hello, how can you help me?")

sendContextualUpdate

Wysyła agentowi informacje kontekstowe, które nie wywołają odpowiedzi.

session.sendContextualUpdate(
"User navigated to the profile page. Consider this for next response."
)

sendFeedback

Przekaż opinię o jakości rozmowy. Pomaga to poprawiać działanie agenta. Użyj onCanSendFeedbackChange, aby włączyć interfejs z kciukiem w górę/dół, gdy opinie są dozwolone.

// Positive feedback
session.sendFeedback(true)
// Negative feedback
session.sendFeedback(false)

sendUserActivity

Informuje agenta o aktywności użytkownika, by zapobiec przerwaniu. Przydaje się, gdy użytkownik aktywnie korzysta z aplikacji, a agent powinien przestać mówić, np. gdy użytkownik pisze na czacie.

Agent przestanie mówić na około 2 sekundy po otrzymaniu tego sygnału.

session.sendUserActivity()

getId

Pobierz ID rozmowy.

val conversationId = session.getId()
Log.d("Conversation", "Conversation ID: $conversationId")
// e.g., "conv_123"

Wyciszanie / włączanie mikrofonu

session.toggleMute()
session.setMicMuted(true) // mute
session.setMicMuted(false) // unmute

Obserwuj session.isMuted, aby zaktualizować etykietę interfejsu między „Wycisz” a „Włącz mikrofon”.

Właściwości

status

Pobierz aktualny status rozmowy.

val status = session.status
Log.d("Conversation", "Current status: $status")
// Values: DISCONNECTED, CONNECTING, CONNECTED

ProGuard / R8

Jeśli zmniejszasz lub zaciemniasz kod, upewnij się, że modele Gson i LiveKit zostają zachowane. Przykładowe reguły (dostosuj w razie potrzeby):

-keep class io.elevenlabs.** { *; }
-keep class io.livekit.** { *; }
-keepattributes *Annotation*

Rozwiązywanie problemów

  • Upewnij się, że uprawnienie do mikrofonu zostało przyznane w czasie działania
  • Jeśli ponowne połączenie się zawiesza, sprawdź, czy aplikacja wywołuje session.endSession() i czy przed ponownym połączeniem uruchamiasz nową instancję sesji
  • W emulatorach sprawdź, czy działają ścieżki wejścia/wyjścia audio; urządzenia fizyczne są zwykle bardziej niezawodne

Przykładowa implementacja

Przykładową implementację znajdziesz w przykładowej aplikacji w repozytorium ElevenLabs Android SDK. Aplikacja pokazuje:

  • Łączenie/rozłączanie jednym stuknięciem
  • Wskaźnik mówienia/słuchania
  • Przyciski opinii z włączaniem/wyłączaniem w interfejsie
  • Wskaźnik pisania przez sendUserActivity()
  • Wiadomości kontekstowe i wiadomości użytkownika z pola wejściowego
  • Przycisk wyciszania/włączania mikrofonu