# Gemini with LiveKit

> Gemini in a LiveKit agent: through our plugin, or through LiveKit's Gemini plugin pointed at the router.

## With our plugin

Gemini’s speech models with every setting of LiveKit’s Gemini plugin, from version 0.5.0 of our plugin. Gemini speaks the language of the text, at 24000 Hz, and takes no `language` or `speed`: ask for a pace or a tone in `instructions`. The 3.8 and 3.1 models stream a sentence’s audio as they make it; the 2.5 models send it once it is complete, so their first audio takes a few seconds longer.

```shell
pip install livekit-plugins-tts-cache-router
```

**agent.py**

```python
from livekit.plugins import tts_cache_router as tcr

# The API key comes from TTS_CACHE_ROUTER_API_KEY.
tts = tcr.TTS(
    model="gemini/gemini-3.8-flash-tts",
    voice="Kore",
)
```

Pass `tts` to `AgentSession(tts=tts)`. Set `TTS_CACHE_ROUTER_API_KEY` in the agent’s environment, and store your Gemini key under [Provider keys](https://app.ttscacherouter.dev/app/provider-keys). `TTS`’s own arguments are on [the plugin’s page](https://docs.ttscacherouter.dev/livekit.md#tts).

### Options

`tcr.TTS(...)`’s settings for Gemini, in the router’s names: `model`, `voice`, `language` and `speed` as arguments, and the rest in the `options` dict (`options={"name": value}`). The router checks them; the languages per model are in [Models and options](https://docs.ttscacherouter.dev/reference/models.md#gemini).

| Field | Type | Required or default | Values | Description |
| --- | --- | --- | --- | --- |
| `model` | string | Required | gemini/gemini-3.8-flash-tts, gemini/gemini-3.8-flash-lite-tts, gemini/gemini-3.1-flash-tts-preview, gemini/gemini-2.5-flash-preview-tts, gemini/gemini-2.5-pro-preview-tts | Which model synthesizes the replies, with its provider. |
| `voice` | str \| None | Required, unless `options.speakers` |  | A voice of the chosen model, passed to Gemini as given. See [models and voices](https://docs.ttscacherouter.dev/reference/models.md#gemini-models). With `options.speakers`, `None`. |
| `sample_rate` | int | Default `24000` | 24000 | Of the audio you receive, in Hz. |
| `options.instructions` | string \| null | Default `null` |  | How to speak: style, tone, accent, pace. Null: for gemini-2.5 and gemini-3.1, LiveKit's plugin's default ("Say the text with a proper tone, don't omit or add any words"), which keeps them reading the text; for gemini-3.8, none. |
| `options.speakers` | object \| null | `gemini-3.8-flash-tts` , `gemini-3.8-flash-lite-tts` only. Default `null` |  | Two speakers' names, each with a voice (a multi-speaker voice config); replaces voice. Requires speaker. |
| `options.speaker` | string \| null | `gemini-3.8-flash-tts` , `gemini-3.8-flash-lite-tts` only. Default `null` |  | Which of speakers voices this request. |

### Changing settings

Replies that start afterwards use the new settings:

```python
tts.update_options(options={"instructions": "Speak calmly and slowly."})

# Two speakers (the 3.8 models): no voice, and the speaker of each reply in options.
tts = tcr.TTS(
    model="gemini/gemini-3.8-flash-tts",
    voice=None,
    options={"speakers": {"Joe": "Kore", "Jane": "Puck"}, "speaker": "Jane"},
)
tts.update_options(options={"speakers": {"Joe": "Kore", "Jane": "Puck"}, "speaker": "Joe"})
```

## With LiveKit's Gemini plugin

Keep `livekit-plugins-google` and point it at the router: your router API key in place of your Gemini key, and the router’s address.

```shell
pip install livekit-plugins-google
```

**agent.py**

```python
import os

from livekit.plugins import google

os.environ["GOOGLE_GEMINI_BASE_URL"] = "https://api.ttscacherouter.dev/gemini"

tts = google.beta.GeminiTTS(
    model="gemini-3.8-flash-tts",
    voice_name="Kore",
    api_key=os.environ["TTS_CACHE_ROUTER_API_KEY"],
)
```

The plugin has no `base_url`: Google’s GenAI SDK reads `GOOGLE_GEMINI_BASE_URL` when the plugin creates its client, so set it before creating the TTS, in code as above or in the agent’s environment. It applies to every Gemini API client the process creates, so in an agent that also uses Gemini as its LLM, use our plugin instead. Vertex AI (`vertexai=True`) doesn’t go through the router.

The plugin doesn’t stream text, so an `AgentSession` sends it one sentence at a time, and each sentence is cached on its own. With the 3.8 models, its requests are the ones our plugin makes, so the two share cached sentences. The other differences from calling Google are on [Gemini API drop-in](https://docs.ttscacherouter.dev/clients/gemini.md#caching).

Requests, responses and errors keep Gemini’s own shape; the endpoints are on [Gemini API drop-in](https://docs.ttscacherouter.dev/clients/gemini.md).

## Which to choose

Both use your org's cache and your stored provider key, and sound the same.

- **Our plugin** reports only the characters Gemini billed in `TTSMetrics` (cache hits count zero), and switches provider with `update_options`.
- **Gemini’s plugin** is the smallest change to an agent that already uses it. Its metrics count every character, cached or not; [Usage](https://docs.ttscacherouter.dev/dashboard.md#usage) has the real split.
