Skip to main content

LiveKit Integration

Build real-time voice agents with LiveKit Agents powered by 60db’s speech and language services — STT, TTS, and LLM all in one plugin.

Speech-to-Text

Real-time streaming transcription via WebSocket with interim results

Text-to-Speech

Low-latency streaming synthesis with chunked audio delivery

LLM Chat

OpenAI-compatible chat completions with tool-call support

Installation

1

Install the plugin

Requires Python 3.10+.
pip install livekit-plugins-60db
2

Set your API key

Choose one of the following methods:Option A — Environment variable (recommended):
export SIXTY_DB_API_KEY="your-api-key"
Option B — .env.local file:
SIXTY_DB_API_KEY=your-api-key
Option C — Pass it directly in code:
from livekit.plugins._60db import _60dbClient

client = _60dbClient("your-api-key")  # sets global default

Quick Start

Wire all three services together in a VoicePipelineAgent:
import asyncio
from livekit.agents import VoicePipelineAgent, cli, WorkerType
from livekit.plugins import silero
from livekit.plugins._60db import _60dbClient, STT, TTS, LLM

client = _60dbClient("your-api-key")  # sets global default


async def entrypoint(ctx):
    await ctx.connect()

    agent = VoicePipelineAgent(
        vad=silero.VAD.load(),   # voice activity detection
        stt=STT(),               # 60db speech-to-text
        llm=LLM(),               # 60db language model
        tts=TTS(),               # 60db text-to-speech
    )

    agent.start(ctx.room)


if __name__ == "__main__":
    cli.run_app(worker_type=WorkerType.ROOM, entrypoint_fnc=entrypoint)

Configuration

Environment Variables

All services read from the same environment variables by default. You only need to override them if you use a custom deployment.
VariableDefaultDescription
SIXTY_DB_API_KEYYour 60db API key (required)
SIXTY_DB_STT_URLwss://api.60db.ai/ws/sttSTT WebSocket endpoint
SIXTY_DB_TTS_URLwss://api.60db.ai/ws/ttsTTS WebSocket endpoint
SIXTY_DB_LLM_URLhttps://api.60db.ai/v1/chat/completionsLLM HTTP endpoint
Each service also accepts a direct ws_url (or api_url) constructor argument which takes precedence over environment variables.

Services

Speech-to-Text

The STT service streams audio to 60db over WebSocket and returns transcriptions in real time — including interim (partial) results as the speaker is still talking.

Parameters

NameTypeDefaultDescription
api_keystr | Noneglobal client / env varYour 60db API key
ws_urlstr | Noneenv varWebSocket endpoint URL
languageslist[str] | None["en"]Language codes for recognition
encodingstr"mulaw"Audio encoding format
sample_rateint8000Audio sample rate in Hz
continuous_modeboolTrueKeep the session open for continuous recognition

Example

from livekit.plugins._60db import STT

stt = STT()  # picks up api_key from global client or env var

async with stt.stream() as stream:
    stream.push_frame(audio_frame)  # push raw audio frames

    async for event in stream:
        if event.type == stt.SpeechEventType.FINAL_TRANSCRIPT:
            print(event.alternatives[0].text)

Audio Formats

The plugin automatically handles audio conversion for you — no manual preprocessing needed.
StepWhat happens
Stereo → MonoDownmix via audioop.tomono
ResamplingAny input rate → target rate via audioop.ratecv
EncodingLINEAR16 PCM → mulaw via audioop.lin2ulaw (when encoding="mulaw")
ParameterDefaultSupported
Encodingmulawmulaw, LINEAR16
Sample rate8000 HzAny rate (auto-resampled)

Timeouts

Control timeouts per-request by passing APIConnectOptions:
from livekit.agents import APIConnectOptions

opts = APIConnectOptions(timeout=30.0)

# STT
async with stt.stream(conn_options=opts) as s:
    ...

# TTS
async for chunk in tts.synthesize("Hello", conn_options=opts):
    ...

# LLM
async for chunk in model.chat(chat_ctx=ctx, conn_options=opts):
    ...

Error Handling

All three services raise standard LiveKit Agents exceptions:
ExceptionWhen it’s raised
APIConnectionErrorWebSocket handshake failure, HTTP error, or unexpected protocol message
APITimeoutErrorRequest exceeds the configured timeout
ValueErrorMissing API key or service URL at construction time

Common HTTP Error Codes (LLM)

StatusMeaning
401Invalid or missing API key
429Rate limit exceeded
500Server error
503Service unavailable

Retry Tips

  • STT: If you receive an error message during the handshake, reconnect with a short delay. A connecting status before connection_established is normal.
  • TTS: Retry connection failures with exponential backoff.
  • LLM: httpx.TimeoutExceptionAPITimeoutError; httpx.HTTPStatusErrorAPIConnectionError.

WebSocket Protocol Reference

Connect:
wss://api.60db.ai/ws/stt?apiKey={API_KEY}
Handshake:Server → {"connection_established": true}Client → start command:
{
  "type": "start",
  "languages": ["en"],
  "config": {
    "encoding": "mulaw",
    "sample_rate": 8000,
    "continuous_mode": true
  }
}
Server → {"type": "connected"}Audio: Send raw audio as binary WebSocket frames.Transcription response:
{
  "type": "transcription",
  "text": "Hello, world",
  "is_final": false,
  "language": "en"
}
Stop:Client → {"type": "stop"}Server →
{
  "type": "session_stopped",
  "billing_summary": { "total_cost": "..." }
}
Connect:
wss://api.60db.ai/ws/tts?apiKey={API_KEY}
Create context:
{
  "create_context": {
    "context_id": "unique-id",
    "voice_id": "fbb75ed2-975a-40c7-9e06-38e30524a9a1",
    "audio_config": {
      "audio_encoding": "LINEAR16",
      "sample_rate_hertz": 16000
    }
  }
}
Send text:
{ "send_text": { "context_id": "unique-id", "text": "Hello!" } }
Flush (trigger audio generation):
{ "flush_context": { "context_id": "unique-id" } }
Audio response:
{ "audio_chunk": { "audioContent": "<base64 PCM>" } }
Followed by {"flush_completed": true} when all audio has been delivered.Close context:
{ "close_context": { "context_id": "unique-id" } }