add livekit helper
This commit is contained in:
@@ -112,6 +112,7 @@ webrtc = [ "aiortc>=1.13.0,<2", "opencv-python>=4.11.0.86,<5" ]
|
|||||||
websocket = [ "pipecat-ai[websockets-base]", "fastapi>=0.115.6,<0.122.0" ]
|
websocket = [ "pipecat-ai[websockets-base]", "fastapi>=0.115.6,<0.122.0" ]
|
||||||
websockets-base = [ "websockets>=13.1,<16.0" ]
|
websockets-base = [ "websockets>=13.1,<16.0" ]
|
||||||
whisper = [ "faster-whisper~=1.1.1" ]
|
whisper = [ "faster-whisper~=1.1.1" ]
|
||||||
|
auth = [ "pyjwt>=2.10.1" ]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = [
|
dev = [
|
||||||
|
|||||||
96
src/pipecat/transports/livekit/utils.py
Normal file
96
src/pipecat/transports/livekit/utils.py
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024–2025, Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
|
"""LiveKit REST Helpers.
|
||||||
|
|
||||||
|
Methods that wrap the LiveKit API for room management.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
|
|
||||||
|
class LiveKitRESTHelper:
|
||||||
|
"""Helper class for interacting with LiveKit's REST API.
|
||||||
|
|
||||||
|
Provides methods for managing LiveKit rooms.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
api_key: str,
|
||||||
|
api_secret: str,
|
||||||
|
api_url: str = "https://your-livekit-host.com",
|
||||||
|
aiohttp_session: aiohttp.ClientSession,
|
||||||
|
):
|
||||||
|
"""Initialize the LiveKit REST helper.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
api_key: Your LiveKit API key.
|
||||||
|
api_secret: Your LiveKit API secret.
|
||||||
|
api_url: LiveKit server URL (e.g. "https://your-livekit-host.com").
|
||||||
|
aiohttp_session: Async HTTP session for making requests.
|
||||||
|
"""
|
||||||
|
self.api_key = api_key
|
||||||
|
self.api_secret = api_secret
|
||||||
|
self.api_url = api_url.rstrip("/")
|
||||||
|
self.aiohttp_session = aiohttp_session
|
||||||
|
|
||||||
|
def _create_access_token(self, room_create: bool = True) -> str:
|
||||||
|
"""Create a signed access token for LiveKit API authentication.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
room_create: Whether to grant roomCreate permission.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Signed JWT access token.
|
||||||
|
"""
|
||||||
|
import time
|
||||||
|
|
||||||
|
import jwt
|
||||||
|
|
||||||
|
claims = {
|
||||||
|
"iss": self.api_key,
|
||||||
|
"sub": self.api_key,
|
||||||
|
"nbf": int(time.time()),
|
||||||
|
"exp": int(time.time()) + 60, # Token valid for 60 seconds
|
||||||
|
"video": {
|
||||||
|
"roomCreate": room_create,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return jwt.encode(claims, self.api_secret, algorithm="HS256")
|
||||||
|
|
||||||
|
async def delete_room_by_name(self, room_name: str) -> bool:
|
||||||
|
"""Delete a LiveKit room by name.
|
||||||
|
|
||||||
|
This will forcibly disconnect all participants currently in the room.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
room_name: Name of the room to delete.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if deletion was successful.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
Exception: If deletion fails.
|
||||||
|
"""
|
||||||
|
token = self._create_access_token(room_create=True)
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
async with self.aiohttp_session.post(
|
||||||
|
f"{self.api_url}/twirp/livekit.RoomService/DeleteRoom",
|
||||||
|
headers=headers,
|
||||||
|
json={"room": room_name},
|
||||||
|
) as r:
|
||||||
|
if r.status != 200:
|
||||||
|
text = await r.text()
|
||||||
|
raise Exception(f"Failed to delete room [{room_name}] (status: {r.status}): {text}")
|
||||||
|
|
||||||
|
return True
|
||||||
6
uv.lock
generated
6
uv.lock
generated
@@ -4442,6 +4442,9 @@ assemblyai = [
|
|||||||
asyncai = [
|
asyncai = [
|
||||||
{ name = "websockets" },
|
{ name = "websockets" },
|
||||||
]
|
]
|
||||||
|
auth = [
|
||||||
|
{ name = "pyjwt" },
|
||||||
|
]
|
||||||
aws = [
|
aws = [
|
||||||
{ name = "aioboto3" },
|
{ name = "aioboto3" },
|
||||||
{ name = "websockets" },
|
{ name = "websockets" },
|
||||||
@@ -4721,6 +4724,7 @@ requires-dist = [
|
|||||||
{ name = "pyaudio", marker = "extra == 'local'", specifier = "~=0.2.14" },
|
{ name = "pyaudio", marker = "extra == 'local'", specifier = "~=0.2.14" },
|
||||||
{ name = "pydantic", specifier = ">=2.10.6,<3" },
|
{ name = "pydantic", specifier = ">=2.10.6,<3" },
|
||||||
{ name = "pygobject", marker = "extra == 'gstreamer'", specifier = "~=3.50.0" },
|
{ name = "pygobject", marker = "extra == 'gstreamer'", specifier = "~=3.50.0" },
|
||||||
|
{ name = "pyjwt", marker = "extra == 'auth'", specifier = ">=2.10.1" },
|
||||||
{ name = "pyloudnorm", specifier = "~=0.1.1" },
|
{ name = "pyloudnorm", specifier = "~=0.1.1" },
|
||||||
{ name = "python-dotenv", marker = "extra == 'runner'", specifier = ">=1.0.0,<2.0.0" },
|
{ name = "python-dotenv", marker = "extra == 'runner'", specifier = ">=1.0.0,<2.0.0" },
|
||||||
{ name = "pyvips", extras = ["binary"], marker = "extra == 'moondream'", specifier = "~=3.0.0" },
|
{ name = "pyvips", extras = ["binary"], marker = "extra == 'moondream'", specifier = "~=3.0.0" },
|
||||||
@@ -4745,7 +4749,7 @@ requires-dist = [
|
|||||||
{ name = "wait-for2", marker = "python_full_version < '3.12'", specifier = ">=0.4.1" },
|
{ name = "wait-for2", marker = "python_full_version < '3.12'", specifier = ">=0.4.1" },
|
||||||
{ name = "websockets", marker = "extra == 'websockets-base'", specifier = ">=13.1,<16.0" },
|
{ name = "websockets", marker = "extra == 'websockets-base'", specifier = ">=13.1,<16.0" },
|
||||||
]
|
]
|
||||||
provides-extras = ["aic", "anthropic", "assemblyai", "asyncai", "aws", "aws-nova-sonic", "azure", "cartesia", "cerebras", "deepseek", "daily", "deepgram", "elevenlabs", "fal", "fireworks", "fish", "gladia", "google", "grok", "groq", "gstreamer", "heygen", "hume", "inworld", "krisp", "koala", "langchain", "livekit", "lmnt", "local", "mcp", "mem0", "mistral", "mlx-whisper", "moondream", "nim", "neuphonic", "noisereduce", "openai", "openpipe", "openrouter", "perplexity", "playht", "qwen", "rime", "riva", "runner", "sambanova", "sarvam", "sentry", "local-smart-turn", "local-smart-turn-v3", "remote-smart-turn", "silero", "simli", "soniox", "soundfile", "speechmatics", "strands", "tavus", "together", "tracing", "ultravox", "webrtc", "websocket", "websockets-base", "whisper"]
|
provides-extras = ["aic", "anthropic", "assemblyai", "asyncai", "aws", "aws-nova-sonic", "azure", "cartesia", "cerebras", "deepseek", "daily", "deepgram", "elevenlabs", "fal", "fireworks", "fish", "gladia", "google", "grok", "groq", "gstreamer", "heygen", "hume", "inworld", "krisp", "koala", "langchain", "livekit", "lmnt", "local", "mcp", "mem0", "mistral", "mlx-whisper", "moondream", "nim", "neuphonic", "noisereduce", "openai", "openpipe", "openrouter", "perplexity", "playht", "qwen", "rime", "riva", "runner", "sambanova", "sarvam", "sentry", "local-smart-turn", "local-smart-turn-v3", "remote-smart-turn", "silero", "simli", "soniox", "soundfile", "speechmatics", "strands", "tavus", "together", "tracing", "ultravox", "webrtc", "websocket", "websockets-base", "whisper", "auth"]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
dev = [
|
dev = [
|
||||||
|
|||||||
Reference in New Issue
Block a user