Vai alla navigazione

SDK Kotlin

SDK ElevenAgents: distribuisci in pochi minuti agenti vocali interattivi e personalizzati per app Android.

Consulta la panoramica di ElevenAgents per una spiegazione di come funziona ElevenAgents.

Installazione

Aggiungi l’SDK ElevenLabs al tuo progetto Android includendo la seguente dipendenza nel file build.gradle a livello di app:

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

Puoi trovare un’app Android di esempio che usa questo SDK qui

Requisiti

  • Livello API Android 21 (Android 5.0) o superiore
  • Autorizzazione Internet per le chiamate API
  • Autorizzazione del microfono per l’input vocale
  • Configurazione della sicurezza di rete per le chiamate HTTPS

Configurazione

Configurazione del manifest

Aggiungi le autorizzazioni necessarie al tuo 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" />

Autorizzazioni di runtime

Per Android 6.0 (livello API 23) e versioni successive, devi richiedere l’autorizzazione del microfono in fase di runtime:

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

Utilizzo

Inizializza l’SDK ElevenLabs nella classe Application o nell’attività principale:

Avvia una sessione di conversazione con una delle seguenti opzioni:

  • Agente pubblico: passa agentId
  • Agente privato: passa conversationToken fornito dal tuo backend (non esporre mai la tua chiave API al client).
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)

Tieni presente che ElevenAgents richiede l’accesso al microfono. Prima dell’avvio della conversazione, valuta di spiegare e richiedere le autorizzazioni nell’interfaccia della tua app, soprattutto su Android 6.0+ dove sono richieste le autorizzazioni di runtime.

Se uno strumento è configurato con expects_response=false sul server, restituisci null da execute per non inviare un risultato dello strumento all’agente.

Agenti pubblici e privati

  • Agenti pubblici (senza autenticazione): inizializza con agentId in ConversationConfig. L’SDK richiede un token di conversazione a ElevenLabs senza richiedere una chiave API sul dispositivo.
  • Agenti privati (con autenticazione): inizializza con conversationToken in ConversationConfig. Il tuo server richiede un token di conversazione a ElevenLabs usando la tua chiave API ElevenLabs.
Non incorporare mai chiavi API nei client. Possono essere estratte facilmente e usate in modo dannoso.

Strumenti client

Registra strumenti client per consentire all’agente di richiamare funzionalità locali sul dispositivo.

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

Quando l’agente emette una client_tool_call, l’SDK esegue lo strumento corrispondente e risponde con un client_tool_result. Se lo strumento non è registrato, viene richiamato onUnhandledClientToolCall e viene restituito all’agente un risultato di errore, se è prevista una risposta.

Panoramica dei callback

  • onConnect - Chiamato quando viene stabilita la connessione WebRTC. Restituisce l’ID della conversazione.
  • onMessage - Chiamato quando viene ricevuto un nuovo messaggio. Può trattarsi di trascrizioni provvisorie o finali della voce dell’utente, risposte prodotte dall’LLM o messaggi di debug. Fornisce l’origine ("ai" o "user") e il messaggio JSON non elaborato.
  • onModeChange - Chiamato quando cambia la modalità della conversazione. È utile per indicare se l’agente sta parlando ("speaking") o ascoltando ("listening").
  • onStatusChange - Chiamato quando cambia lo stato della conversazione ("connected", "connecting" o "disconnected").
  • onCanSendFeedbackChange - Chiamato quando cambia la possibilità di inviare feedback. Abilita o disabilita i pulsanti di feedback.
  • onUnhandledClientToolCall - Chiamato quando l’agente richiede uno strumento client non registrato sul dispositivo.
  • onVadScore - Chiamato quando cambia il punteggio del rilevamento dell’attività vocale. Intervallo da 0 a 1, dove valori più alti indicano una maggiore affidabilità della presenza di parlato.
  • onAudioAlignment - Chiamato quando vengono ricevuti dati di allineamento audio, che forniscono informazioni temporali a livello di carattere per il parlato dell’agente.

Non tutti gli eventi client sono abilitati per impostazione predefinita per un agente. Se hai abilitato un callback ma non ricevi eventi, assicurati che il tuo agente ElevenLabs abbia abilitato l’evento corrispondente. Puoi farlo nella scheda “Advanced” delle impostazioni dell’agente nella dashboard di ElevenLabs.

Metodi

startSession

Il metodo startSession avvia la connessione WebRTC e inizia a usare il microfono per comunicare con l’agente ElevenLabs Agents.

Agenti pubblici

Per gli agenti pubblici, ovvero gli agenti che non hanno l’autenticazione abilitata, è richiesto solo agentId. Puoi ottenere l’ID dell’agente tramite l’interfaccia di ElevenLabs.

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

Per gli agenti privati, devi passare un conversationToken ottenuto dall’API ElevenLabs. Per generare questo token è necessaria una chiave API ElevenLabs.

Il conversationToken è valido per 10 minuti.
// 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);
});

Quindi, passa il token al metodo startSession. Tieni presente che per gli agenti privati è richiesto solo 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
)

Facoltativamente, puoi passare un ID utente per identificare l’utente nella conversazione. Può essere il tuo identificatore cliente. Verrà incluso nei dati di avvio della conversazione inviati al server.

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

endSession

Un metodo per terminare manualmente la conversazione. Il metodo disconnette e termina la conversazione.

session.endSession()

sendUserMessage

Invia un messaggio di testo all’agente durante una conversazione attiva. Questo attiverà una risposta dell’agente.

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

sendContextualUpdate

Invia informazioni contestuali all’agente senza attivare una risposta.

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

sendFeedback

Fornisci feedback sulla qualità della conversazione. Questo aiuta a migliorare le prestazioni dell’agente. Usa onCanSendFeedbackChange per abilitare l’interfaccia con pollice su/giù quando è consentito inviare feedback.

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

sendUserActivity

Notifica all’agente l’attività dell’utente per evitare interruzioni. È utile quando l’utente sta usando attivamente l’app e l’agente dovrebbe smettere di parlare, ad esempio quando l’utente sta digitando in una chat.

L’agente smetterà di parlare per circa 2 secondi dopo aver ricevuto questo segnale.

session.sendUserActivity()

getId

Ottieni l’ID della conversazione.

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

Attiva/disattiva audio

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

Osserva session.isMuted per aggiornare l’etichetta dell’interfaccia tra “Disattiva audio” e “Attiva audio”.

Proprietà

status

Ottieni lo stato attuale della conversazione.

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

ProGuard / R8

Se riduci/offuschi il codice, assicurati che i modelli Gson e LiveKit vengano mantenuti. Esempi di regole, da adattare in base alle necessità:

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

Risoluzione dei problemi

  • Assicurati che l’autorizzazione del microfono sia concessa in fase di runtime
  • Se la riconnessione si blocca, verifica che la tua app chiami session.endSession() e che avvii una nuova istanza di sessione prima di riconnettersi
  • Per gli emulatori, verifica che le route di input/output audio funzionino; i dispositivi fisici tendono a comportarsi in modo più affidabile

Implementazione di esempio

Per un’implementazione di esempio, consulta l’app di esempio nel repository dell’SDK Android di ElevenLabs. L’app mostra:

  • Connessione/disconnessione con un tocco
  • Indicatore di parlato/ascolto
  • Pulsanti di feedback con abilitazione/disabilitazione dell’interfaccia
  • Indicatore di digitazione tramite sendUserActivity()
  • Messaggi contestuali e dell’utente da un input
  • Pulsante per attivare/disattivare l’audio del microfono