Skip to main content

Overview

The LiveKit AgentHuman plugin provides seamless integration between AgentHuman talking avatars and LiveKit’s real-time communication platform. Add lifelike AI avatars to your LiveKit rooms with just a few lines of code. Perfect for:
  • Video conferencing applications
  • Real-time collaboration tools
  • Live streaming platforms
  • Interactive webinars

Installation

pip install livekit-agenthuman

Quick Start

from livekit_agenthuman import AgentHumanPlugin
from livekit import Room

# Configure plugin
plugin = AgentHumanPlugin(
    api_key="ah_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    avatar_id="avat_01H3Z8G9YR3K2N5M6P7Q8W4T"
)

# Add to LiveKit room
room = Room()
await room.connect(
    url="wss://your-livekit-server.com",
    token="your-livekit-token"
)
await room.add_plugin(plugin)

# Avatar automatically joins and responds to audio
That’s it! The plugin handles:
  • ✅ AgentHuman session creation
  • ✅ WebSocket connection and authentication
  • ✅ Audio track processing and format conversion
  • ✅ Room participant management
  • ✅ Automatic avatar video streaming

Configuration Options

Plugin Parameters

ParameterTypeRequiredDescription
apiKeystringYesYour AgentHuman API key
avatarIdstringYesAvatar ID to use
displayNamestringNoAvatar display name in room (default: 'AI Avatar (AH)')
videoWidthnumberNoVideo width in pixels (default: 1280)
videoHeightnumberNoVideo height in pixels (default: 720)
aspectRatiostringNoVideo aspect ratio: '16:9', '9:16', '1:1' (default: '16:9')
autoConnectbooleanNoAuto-connect on room join (default: true)

Complete Examples

Python Example

import asyncio
from livekit import Room, RoomEvent
from livekit_agenthuman import AgentHumanPlugin

async def main():
    # Create and configure room
    room = Room()
    
    # Set up event handlers
    @room.on(RoomEvent.PARTICIPANT_CONNECTED)
    def on_participant_connected(participant):
        print(f"Participant joined: {participant.identity}")
    
    @room.on(RoomEvent.TRACK_SUBSCRIBED)
    def on_track_subscribed(track, publication, participant):
        print(f"Subscribed to {participant.identity}'s {track.kind} track")
    
    # Connect to LiveKit room
    await room.connect(
        url="wss://your-livekit-server.com",
        token="your-livekit-token"
    )
    print(f"Connected to room: {room.name}")
    
    # Add avatar plugin
    avatar_plugin = AgentHumanPlugin(
        api_key="ah_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        avatar_id="avat_01H3Z8G9YR3K2N5M6P7Q8W4T",
        display_name="AI Assistant",
        aspect_ratio="16:9"
    )
    
    await room.add_plugin(avatar_plugin)
    print("Avatar plugin added - avatar will join room shortly")
    
    # Keep room alive
    try:
        await asyncio.sleep(3600)  # Run for 1 hour
    except KeyboardInterrupt:
        print("Shutting down...")
    finally:
        await avatar_plugin.disconnect()
        await room.disconnect()

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

TypeScript/React Example

import { useEffect, useState } from 'react';
import { Room, RoomEvent } from 'livekit-client';
import { AgentHumanPlugin } from '@livekit/agenthuman';

function AvatarRoom() {
  const [room, setRoom] = useState<Room | null>(null);
  const [avatarConnected, setAvatarConnected] = useState(false);
  
  useEffect(() => {
    const connectRoom = async () => {
      // Create room
      const newRoom = new Room();
      
      // Handle events
      newRoom.on(RoomEvent.ParticipantConnected, (participant) => {
        console.log('Participant joined:', participant.identity);
        if (participant.identity.includes('Avatar')) {
          setAvatarConnected(true);
        }
      });
      
      // Connect to LiveKit
      await newRoom.connect(
        'wss://your-livekit-server.com',
        'your-livekit-token'
      );
      
      // Add avatar plugin
      const plugin = new AgentHumanPlugin({
        apiKey: 'ah_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
        avatarId: 'avat_01H3Z8G9YR3K2N5M6P7Q8W4T',
        displayName: 'AI Assistant'
      });
      
      await newRoom.addPlugin(plugin);
      setRoom(newRoom);
    };
    
    connectRoom();
    
    // Cleanup
    return () => {
      room?.disconnect();
    };
  }, []);
  
  return (
    <div>
      <h2>LiveKit Room with AI Avatar</h2>
      <p>Status: {avatarConnected ? 'Avatar Connected' : 'Waiting for avatar...'}</p>
      {/* Add LiveKit video components here */}
    </div>
  );
}

Plugin Features

Automatic Audio Processing

The plugin automatically:
  1. Listens to audio tracks in the room
  2. Converts audio to required format (16-bit mono PCM)
  3. Sends audio to AgentHuman WebSocket
  4. Avatar generates video
  5. Video appears in LiveKit room

Event Handling

# Listen for plugin events
@plugin.on("connected")
async def on_connected():
    print("Avatar connected to AgentHuman")

@plugin.on("audio_processed")
async def on_audio_processed(samples):
    print(f"Processed {samples} audio samples")

@plugin.on("error")
async def on_error(error):
    print(f"Plugin error: {error}")

Manual Control

# Manual plugin control
await plugin.connect()      # Connect avatar
await plugin.disconnect()   # Disconnect avatar
await plugin.send_audio(audio_data)  # Send specific audio

Room Configuration

Server-Side Room Creation

from livekit import api

# Create LiveKit API client
livekit_api = api.LiveKitAPI(
    url="wss://your-livekit-server.com",
    api_key="your-api-key",
    api_secret="your-api-secret"
)

# Create room
room_info = await livekit_api.room.create_room(
    name="avatar-demo-room",
    empty_timeout=300,  # 5 minutes
    max_participants=10
)

# Generate token for participant
token = await livekit_api.create_token(
    room_name=room_info.name,
    participant_identity="user-123",
    participant_name="John Doe"
)

print(f"Room URL: {room_info.name}")
print(f"Token: {token}")

Client-Side Connection

const room = new Room();

await room.connect(
  'wss://your-livekit-server.com',
  token,  // Token from server
  {
    autoSubscribe: true,
    dynacast: true
  }
);

Best Practices

1. Plugin Lifecycle Management

# Proper setup and teardown
async def run_avatar_session():
    plugin = AgentHumanPlugin(...)
    room = Room()
    
    try:
        await room.connect(...)
        await room.add_plugin(plugin)
        
        # Do work
        await asyncio.sleep(3600)
        
    finally:
        # Always cleanup
        await plugin.disconnect()
        await room.disconnect()

2. Error Handling

plugin.on('error', async (error) => {
  console.error('Plugin error:', error);
  
  if (error.message.includes('Session not found')) {
    // Reconnect plugin
    await plugin.reconnect();
  }
});

3. Multiple Avatars

# Add multiple avatars to same room
avatar1 = AgentHumanPlugin(
    api_key="...",
    avatar_id="avat_01H3Z8G9YR3K2N5M6P7Q8W4T",
    display_name="Avatar 1"
)

avatar2 = AgentHumanPlugin(
    api_key="...",
    avatar_id="avat_02H3Z8G9YR3K2N5M6P7Q8W4T",
    display_name="Avatar 2"
)

await room.add_plugin(avatar1)
await room.add_plugin(avatar2)

Troubleshooting

Plugin Not Connecting

Cause: Invalid API credentials or LiveKit connection issues Solution:
# Verify LiveKit connection first
await room.connect(url, token)
print(f"Room connected: {room.is_connected()}")

# Then add plugin
await room.add_plugin(plugin)

Avatar Not Appearing in Room

Cause: Plugin not initialized or room permissions issue Solution:
  1. Check LiveKit room has capacity
  2. Verify avatar participant permissions
  3. Wait 2-3 seconds for avatar to join
@room.on(RoomEvent.PARTICIPANT_CONNECTED)
def on_participant_connected(participant):
    print(f"Participant: {participant.identity}")
    # Avatar should appear here

Audio Not Processing

Cause: Audio track not subscribed or format issues Solution:
# Ensure auto-subscribe is enabled
await room.connect(url, token, RoomOptions(auto_subscribe=True))

# Or manually subscribe to tracks
@room.on(RoomEvent.TRACK_PUBLISHED)
async def on_track_published(publication, participant):
    await publication.set_subscribed(True)

Resources

Support

Need help with LiveKit integration?