# PyAI LiveKit starter

Add Hear and Speak to an existing LiveKit Agents session.

## Requirements

Python 3.10–3.13. Only a PyAI key for the included speech.wav smoke test. A complete room agent also needs LiveKit credentials and your chosen LLM; the linked guide covers that setup.

## Run

```sh
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements.txt
cp .env.example .env
# Fill in .env, then export its values in this shell:
set -a
. ./.env
set +a
python main.py
```

This starter tests the TTS adapter without opening a room. LiveKit continues to own your agent loop; the adapter does not create an Omni session.

Select a voice from `GET https://api.pyai.com/v1/voices`. Use the current voice/language support table rather than assuming every voice supports every language. PCM, WAV and G.711 support streaming; MP3 and Opus are buffered.

Keep `.env` out of Git. These starters use server-side credentials.

[Full guide](https://docs.pyai.com/guides/livekit-agents) · [Agent setup](https://pyai.com/build-with-ai) · [API contract](https://api.pyai.com/openapi.json)

## Download from your terminal

```sh
curl -fSL https://pyai.com/starters/pyai-livekit.tar.gz -o pyai-livekit.tar.gz
tar -xzf pyai-livekit.tar.gz
cd pyai-livekit
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements.txt
cp .env.example .env
# Fill in .env, then export its values in this shell:
set -a
. ./.env
set +a
python main.py
```

## .env.example

```text
PYAI_API_KEY=replace_me
PYAI_VOICE=stock_emma_en_gb
```

## main.py

```python
"""Exercise the LiveKit TTS adapter without a room or LLM account."""
import asyncio
import aiohttp
import os
import time
import wave
from livekit.plugins import pyai


async def main():
    session = aiohttp.ClientSession()
    tts = pyai.TTS(voice=os.getenv("PYAI_VOICE", "stock_emma_en_gb"), http_session=session)
    received = 0
    started = time.perf_counter()
    try:
        with wave.open("speech.wav", "wb") as output:
            output.setparams((1, 2, 24000, 0, "NONE", "not compressed"))
            async with tts.synthesize("Hello from PyAI and LiveKit.") as stream:
                async for event in stream:
                    if not received:
                        print(f"First audio frame: {(time.perf_counter() - started) * 1000:.0f} ms")
                    output.writeframesraw(bytes(event.frame.data))
                    received += len(event.frame.data)
        if not received:
            raise RuntimeError("No audio frames received")
        print("Saved speech.wav")
    finally:
        await tts.aclose()
        await session.close()


if __name__ == "__main__":
    asyncio.run(main())
```

## requirements.txt

```text
livekit-plugins-pyai==0.1.2
livekit-agents==1.8.0
```
