> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Kotlin SDK

> **Info**
>
> Se [översikten över ElevenAgents](/docs/sv/eleven-agents/overview) för en förklaring av hur
> ElevenAgents fungerar.

## Installation

Lägg till ElevenLabs SDK i ditt Android-projekt genom att inkludera följande beroende i appens `build.gradle`-fil:

**`build.gradle.kts`**

```kotlin build.gradle.kts
dependencies {
    // ElevenLabs Agents SDK (Android)
    implementation("io.elevenlabs:elevenlabs-android:<latest>")

    // Kotlin coroutines, AndroidX, etc., as needed by your app
}
```

> **Tip**
>
> En exempelapp för Android som använder detta SDK finns
> [här](https://github.com/elevenlabs/elevenlabs-android/tree/main/example-app)

## Krav

* Android API-nivå 21 (Android 5.0) eller högre
* Internetbehörighet för API-anrop
* Mikrofonbehörighet för röstinmatning
* Nätverkssäkerhetskonfiguration för HTTPS-anrop

## Konfiguration

### Manifestkonfiguration

Lägg till nödvändiga behörigheter i din `AndroidManifest.xml`:

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

### Körningsbehörigheter

För Android 6.0 (API-nivå 23) och senare måste du begära mikrofonbehörighet vid körning:

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

## Användning

Initiera ElevenLabs SDK i din `Application`-klass eller huvudaktivitet:

Starta en konversationssession med antingen:

* Offentlig agent: skicka `agentId`
* Privat agent: skicka `conversationToken` som har tillhandahållits från din backend (exponera aldrig din API-nyckel för klienten).

```kotlin
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)
```

Observera att ElevenAgents kräver mikrofonåtkomst. Överväg att förklara och begära behörigheter i appens gränssnitt innan konversationen börjar, särskilt på Android 6.0+ där körningsbehörigheter krävs.

> **Note**
>
> Om ett verktyg är konfigurerat med `expects_response=false` på servern ska du returnera `null` från `execute`
> för att hoppa över att skicka ett verktygsresultat tillbaka till agenten.

## Offentliga och privata agenter

* **Offentliga agenter** (ingen autentisering): Initiera med `agentId` i `ConversationConfig`. SDK:t begär en konversationstoken från ElevenLabs utan att behöva en API-nyckel på enheten.
* **Privata agenter** (autentisering): Initiera med `conversationToken` i `ConversationConfig`. Din server begär en konversationstoken från ElevenLabs med din ElevenLabs API-nyckel.

> **Error**
>
> Bädda aldrig in API-nycklar i klienter. De kan enkelt extraheras och användas i skadligt syfte.

## Klientverktyg

Registrera klientverktyg för att låta agenten anropa lokala funktioner på enheten.

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

När agenten utfärdar ett `client_tool_call` kör SDK:t det matchande verktyget och svarar med ett `client_tool_result`. Om verktyget inte är registrerat anropas `onUnhandledClientToolCall` och ett felresultat skickas tillbaka till agenten (om ett svar förväntas).

### Översikt över callbacks

* **onConnect** - Anropas när WebRTC-anslutningen har upprättats. Returnerar konversations-ID:t.
* **onMessage** - Anropas när ett nytt meddelande tas emot. Det kan vara preliminära eller slutliga transkriberingar av användarens röst, svar som producerats av LLM eller felsökningsmeddelanden. Anger källa (`"ai"` eller `"user"`) och rått JSON-meddelande.
* **onModeChange** - Anropas när konversationsläget ändras. Detta är användbart för att visa om agenten talar (`"speaking"`) eller lyssnar (`"listening"`).
* **onStatusChange** - Anropas när konversationsstatusen ändras (`"connected"`, `"connecting"` eller `"disconnected"`).
* **onCanSendFeedbackChange** - Anropas när möjligheten att skicka feedback ändras. Aktiverar eller inaktiverar feedbackknappar.
* **onUnhandledClientToolCall** - Anropas när agenten begär ett klientverktyg som inte är registrerat på enheten.
* **onVadScore** - Anropas när poängen för röstaktivitetsdetektering ändras. Omfång från 0 till 1 där högre värden indikerar högre säkerhet för tal.
* **onAudioAlignment** - Anropas när ljudjusteringsdata tas emot och ger tidsinformation på teckennivå för agentens tal.

> **Warning**
>
> Alla klienthändelser är inte aktiverade som standard för en agent. Om du har aktiverat en callback men
> inte ser att några händelser kommer fram ska du kontrollera att din ElevenLabs-agent har motsvarande händelse
> aktiverad. Du kan göra detta på fliken "Advanced" i agentinställningarna i ElevenLabs-instrumentpanelen.

### Metoder

#### startSession

Metoden `startSession` initierar WebRTC-anslutningen och börjar använda mikrofonen för att kommunicera med ElevenLabs Agents-agenten.

##### Offentliga agenter

För offentliga agenter (det vill säga agenter som inte har autentisering aktiverad) krävs endast `agentId`. Agent-ID:t kan hämtas via [ElevenLabs-gränssnittet](https://elevenlabs.io/app/agents).

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

##### Privata agenter

För privata agenter måste du skicka med en `conversationToken` som hämtats från ElevenLabs API. För att skapa denna token krävs en ElevenLabs API-nyckel.

> **Tip**
>
> `conversationToken` är giltig i 10 minuter.

```typescript maxLines=0
// 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);
});
```

Skicka sedan tokenen till metoden `startSession`. Observera att endast `conversationToken` krävs för privata agenter.

```kotlin

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

Du kan valfritt skicka med ett användar-ID för att identifiera användaren i konversationen. Detta kan vara din egen kundidentifierare. Det inkluderas i konversationsstartdata som skickas till servern.

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

#### endSession

En metod för att avsluta konversationen manuellt. Metoden kopplar från och avslutar konversationen.

```kotlin
session.endSession()
```

#### sendUserMessage

Skicka ett textmeddelande till agenten under en aktiv konversation. Detta utlöser ett svar från agenten.

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

#### sendContextualUpdate

Skickar kontextuell information till agenten som inte utlöser ett svar.

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

#### sendFeedback

Ge feedback om konversationens kvalitet. Detta hjälper till att förbättra agentens prestanda. Använd `onCanSendFeedbackChange` för att aktivera ditt gränssnitt för tumme upp eller ner när feedback är tillåten.

```kotlin
// Positive feedback
session.sendFeedback(true)

// Negative feedback
session.sendFeedback(false)
```

#### sendUserActivity

Meddelar agenten om användaraktivitet för att förhindra avbrott. Användbart när användaren aktivt använder appen och agenten bör pausa sitt tal, till exempel när användaren skriver i en chatt.

Agenten pausar talet i cirka 2 sekunder efter att ha tagit emot denna signal.

```kotlin
session.sendUserActivity()
```

#### getId

Hämta konversations-ID:t.

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

#### Stäng av/slå på ljudet

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

Övervaka `session.isMuted` för att uppdatera gränssnittsetiketten mellan "Stäng av ljud" och "Slå på ljud".

### Egenskaper

#### status

Hämta konversationens aktuella status.

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

## ProGuard / R8

Om du minskar storlek/förvanskar ska du se till att Gson-modeller och LiveKit behålls. Exempelregler (anpassa efter behov):

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

## Felsökning

* Kontrollera att mikrofonbehörighet beviljas vid körning
* Om återanslutningen hänger sig ska du kontrollera att appen anropar `session.endSession()` och att du startar en ny sessionsinstans innan du återansluter
* För emulatorer ska du kontrollera att ljudets in- och utmatningsvägar fungerar; fysiska enheter tenderar att fungera mer tillförlitligt

## Exempelimplementering

Se exempelappen i [ElevenLabs Android SDK-repositoryt](https://github.com/elevenlabs/elevenlabs-android/tree/main/example-app) för en exempelimplementering. Appen visar:

* Anslut/koppla från med ett tryck
* Indikator för talar/lyssnar
* Feedbackknappar med aktivering/inaktivering i gränssnittet
* Skrivindikator via `sendUserActivity()`
* Kontextuella meddelanden och användarmeddelanden från ett inmatningsfält
* Knapp för att stänga av/slå på mikrofonen