Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions components/livekit/examples/voice_agent/agent/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Python bytecode and artifacts
**/__pycache__/
**/*.py[cod]
**/*.pyo
**/*.pyd
**/*.egg-info/
**/dist/
**/build/

# Virtual environments
**/.venv/
**/venv/

# Caches and test output
**/.cache/
**/.pytest_cache/
**/.ruff_cache/
**/coverage/

# Logs and temp files
**/*.log
**/*.gz
**/*.tgz
**/.tmp
**/.cache

# Environment variables
**/.env
**/.env.*

# VCS, editor, OS
.git
.gitignore
.gitattributes
.github/
.idea/
.vscode/
.DS_Store

# Project docs and misc
README.md
LICENSE

# Project tests
test/
tests/
eval/
evals/
72 changes: 72 additions & 0 deletions components/livekit/examples/voice_agent/agent/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# This is an example Dockerfile that builds a minimal container for running LK Agents
# For more information on the build process, see https://docs.livekit.io/agents/ops/deployment/builds/
# syntax=docker/dockerfile:1

# Use the official UV Python base image with Python 3.13 on Debian Bookworm
# UV is a fast Python package manager that provides better performance than pip
# We use the slim variant to keep the image size smaller while still having essential tools
ARG PYTHON_VERSION=3.13
FROM ghcr.io/astral-sh/uv:python${PYTHON_VERSION}-bookworm-slim AS base

# Keeps Python from buffering stdout and stderr to avoid situations where
# the application crashes without emitting any logs due to buffering.
ENV PYTHONUNBUFFERED=1

# Create a non-privileged user that the app will run under.
# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/app" \
--shell "/sbin/nologin" \
--uid "${UID}" \
appuser

# Install build dependencies required for Python packages with native extensions
# gcc: C compiler needed for building Python packages with C extensions
# g++: C++ compiler needed for building Python packages with C++ extensions
# python3-dev: Python development headers needed for compilation
# We clean up the apt cache after installation to keep the image size down
RUN apt-get update && apt-get install -y \
gcc \
g++ \
python3-dev \
&& rm -rf /var/lib/apt/lists/*

# Create a new directory for our application code
# And set it as the working directory
WORKDIR /app

# Copy just the dependency files first, for more efficient layer caching
COPY pyproject.toml uv.lock ./
RUN mkdir -p src

# Install Python dependencies using UV's lock file
# --locked ensures we use exact versions from uv.lock for reproducible builds
# This creates a virtual environment and installs all dependencies
# Ensure your uv.lock file is checked in for consistency across environments
RUN uv sync --locked

# Copy all remaining pplication files into the container
# This includes source code, configuration files, and dependency specifications
# (Excludes files specified in .dockerignore)
COPY . .

# Change ownership of all app files to the non-privileged user
# This ensures the application can read/write files as needed
RUN chown -R appuser:appuser /app

# Switch to the non-privileged user for all subsequent operations
# This improves security by not running as root
USER appuser

# Pre-download any ML models or files the agent needs
# This ensures the container is ready to run immediately without downloading
# dependencies at runtime, which improves startup time and reliability
RUN uv run "agent.py" download-files

# Run the application using UV
# UV will activate the virtual environment and run the agent.
# The "start" command tells the worker to connect to LiveKit and begin waiting for jobs.
CMD ["uv", "run", "agent.py", "start"]
25 changes: 9 additions & 16 deletions components/livekit/examples/voice_agent/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,8 @@
)
from livekit.plugins import (
openai,
cartesia,
deepgram,
silero,
noise_cancellation
)
from livekit.plugins.turn_detector.multilingual import MultilingualModel

# If enabled, RPC calls will not be performed.
TEST_MODE = False
Expand All @@ -31,18 +28,13 @@ class LEDColor(str, Enum):
class Assistant(Agent):
def __init__(self) -> None:
super().__init__(
instructions="""You are a helpful voice AI assistant running on an ESP-32 dev board.
instructions="""You are a helpful voice AI assistant running on an ESP32 dev board.
You answer user's questions about the hardware state and control the hardware based on their requests.
The board has discrete LEDs that can be controlled independently. Each LED has a static color
that cannot be changed. While you are able to set the state of the LEDs, you are not able to read the
state which could be changed without your knowledge. No markdown is allowed in your responses.
"""
)
async def on_enter(self) -> None:
await self.session.say(
"Hi, how can I help you today?",
allow_interruptions=False
)

@function_tool()
async def set_led_state(self, _: RunContext, led: LEDColor, state: bool) -> None:
Expand Down Expand Up @@ -92,16 +84,17 @@ async def get_cpu_temp(self, _: RunContext) -> float:

async def entrypoint(ctx: agents.JobContext):
session = AgentSession(
stt=deepgram.STT(model="nova-3", language="multi"),
llm=openai.LLM(model="gpt-4o-mini"),
tts=cartesia.TTS(model="sonic-2", voice="c99d36f3-5ffd-4253-803a-535c1bc9c306"),
vad=silero.VAD.load(),
turn_detection=MultilingualModel(),
llm=openai.realtime.RealtimeModel(
voice="echo",
model="gpt-4o-mini-realtime-preview-2024-12-17"
)
)
await session.start(
room=ctx.room,
agent=Assistant(),
room_input_options=RoomInputOptions()
room_input_options=RoomInputOptions(
noise_cancellation=noise_cancellation.BVC()
)
)
await ctx.connect()

Expand Down
7 changes: 4 additions & 3 deletions components/livekit/examples/voice_agent/agent/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
[project]
name = "esp-example-agent"
version = "0.1.0"
description = "Example agent for interacting with the ESP-32 voice chat example."
description = "Example agent for ESP32 voice agent example."
readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.13"
dependencies = [
"livekit-agents[cartesia,deepgram,openai,silero,turn-detector]~=1.0",
"livekit-agents[openai]~=1.2.14",
"livekit-plugins-noise-cancellation~=0.2",
"python-dotenv>=1.1.1"
]
]
Loading