Merge pull request #856 from pipecat-ai/mb/daily-rest-helpers
Remove default 5 min exp time for created rooms, add docstrings
This commit is contained in:
@@ -13,6 +13,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
Tamil) and PlayHT (Afrikans, Albanian, Amharic, Arabic, Bengali, Croatian,
|
||||
Galician, Hebrew, Mandarin, Serbian, Tagalog, Urdu, Xhosa).
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed: Room expiration (`exp`) in `DailyRoomProperties` is now optional
|
||||
(None) by default instead of automatically setting a 5-minute expiration
|
||||
time. You must explicitly set expiration time if desired.
|
||||
|
||||
### Deprecated
|
||||
|
||||
- `AWSTTSService` is now deprecated, use `PollyTTSService` instead.
|
||||
|
||||
@@ -4,23 +4,29 @@
|
||||
# SPDX-License-Identifier: BSD 2-Clause License
|
||||
#
|
||||
|
||||
"""
|
||||
Daily REST Helpers
|
||||
"""Daily REST Helpers.
|
||||
|
||||
Methods that wrap the Daily API to create rooms, check room URLs, and get meeting tokens.
|
||||
|
||||
"""
|
||||
|
||||
import aiohttp
|
||||
import time
|
||||
|
||||
from typing import Literal, Optional
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from pydantic import Field, BaseModel, ValidationError
|
||||
from typing import Literal, Optional
|
||||
import aiohttp
|
||||
from pydantic import BaseModel, Field, ValidationError
|
||||
|
||||
|
||||
class DailyRoomSipParams(BaseModel):
|
||||
"""SIP configuration parameters for Daily rooms.
|
||||
|
||||
Attributes:
|
||||
display_name: Name shown for the SIP endpoint
|
||||
video: Whether video is enabled for SIP
|
||||
sip_mode: SIP connection mode, typically 'dial-in'
|
||||
num_endpoints: Number of allowed SIP endpoints
|
||||
"""
|
||||
|
||||
display_name: str = "sw-sip-dialin"
|
||||
video: bool = False
|
||||
sip_mode: str = "dial-in"
|
||||
@@ -28,7 +34,19 @@ class DailyRoomSipParams(BaseModel):
|
||||
|
||||
|
||||
class DailyRoomProperties(BaseModel, extra="allow"):
|
||||
exp: float = Field(default_factory=lambda: time.time() + 5 * 60)
|
||||
"""Properties for configuring a Daily room.
|
||||
|
||||
Attributes:
|
||||
exp: Optional Unix epoch timestamp for room expiration (e.g., time.time() + 300 for 5 minutes)
|
||||
enable_chat: Whether chat is enabled in the room
|
||||
enable_emoji_reactions: Whether emoji reactions are enabled
|
||||
eject_at_room_exp: Whether to remove participants when room expires
|
||||
enable_dialout: Whether SIP dial-out is enabled
|
||||
sip: SIP configuration parameters
|
||||
sip_uri: SIP URI information returned by Daily
|
||||
"""
|
||||
|
||||
exp: Optional[float] = None
|
||||
enable_chat: bool = False
|
||||
enable_emoji_reactions: bool = False
|
||||
eject_at_room_exp: bool = True
|
||||
@@ -38,6 +56,11 @@ class DailyRoomProperties(BaseModel, extra="allow"):
|
||||
|
||||
@property
|
||||
def sip_endpoint(self) -> str:
|
||||
"""Get the SIP endpoint URI if available.
|
||||
|
||||
Returns:
|
||||
str: SIP endpoint URI or empty string if not available
|
||||
"""
|
||||
if not self.sip_uri:
|
||||
return ""
|
||||
else:
|
||||
@@ -45,12 +68,32 @@ class DailyRoomProperties(BaseModel, extra="allow"):
|
||||
|
||||
|
||||
class DailyRoomParams(BaseModel):
|
||||
"""Parameters for creating a Daily room.
|
||||
|
||||
Attributes:
|
||||
name: Optional custom name for the room
|
||||
privacy: Room privacy setting ('private' or 'public')
|
||||
properties: Room configuration properties
|
||||
"""
|
||||
|
||||
name: Optional[str] = None
|
||||
privacy: Literal["private", "public"] = "public"
|
||||
properties: DailyRoomProperties = Field(default_factory=DailyRoomProperties)
|
||||
|
||||
|
||||
class DailyRoomObject(BaseModel):
|
||||
"""Represents a Daily room returned by the API.
|
||||
|
||||
Attributes:
|
||||
id: Unique room identifier
|
||||
name: Room name
|
||||
api_created: Whether room was created via API
|
||||
privacy: Room privacy setting ('private' or 'public')
|
||||
url: Full URL for joining the room
|
||||
created_at: Timestamp of room creation in ISO 8601 format (e.g., "2019-01-26T09:01:22.000Z").
|
||||
config: Room configuration properties
|
||||
"""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
api_created: bool
|
||||
@@ -61,6 +104,16 @@ class DailyRoomObject(BaseModel):
|
||||
|
||||
|
||||
class DailyRESTHelper:
|
||||
"""Helper class for interacting with Daily's REST API.
|
||||
|
||||
Provides methods for creating, managing, and accessing Daily rooms.
|
||||
|
||||
Args:
|
||||
daily_api_key: Your Daily API key
|
||||
daily_api_url: Daily API base URL (e.g. "https://api.daily.co/v1")
|
||||
aiohttp_session: Async HTTP session for making requests
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@@ -73,13 +126,40 @@ class DailyRESTHelper:
|
||||
self.aiohttp_session = aiohttp_session
|
||||
|
||||
def get_name_from_url(self, room_url: str) -> str:
|
||||
"""Extract room name from a Daily room URL.
|
||||
|
||||
Args:
|
||||
room_url: Full Daily room URL
|
||||
|
||||
Returns:
|
||||
str: Room name portion of the URL
|
||||
"""
|
||||
return urlparse(room_url).path[1:]
|
||||
|
||||
async def get_room_from_url(self, room_url: str) -> DailyRoomObject:
|
||||
"""Get room details from a Daily room URL.
|
||||
|
||||
Args:
|
||||
room_url: Full Daily room URL
|
||||
|
||||
Returns:
|
||||
DailyRoomObject: DailyRoomObject instance for the room
|
||||
"""
|
||||
room_name = self.get_name_from_url(room_url)
|
||||
return await self._get_room_from_name(room_name)
|
||||
|
||||
async def create_room(self, params: DailyRoomParams) -> DailyRoomObject:
|
||||
"""Create a new Daily room.
|
||||
|
||||
Args:
|
||||
params: Room configuration parameters
|
||||
|
||||
Returns:
|
||||
DailyRoomObject: DailyRoomObject instance for the created room
|
||||
|
||||
Raises:
|
||||
Exception: If room creation fails or response is invalid
|
||||
"""
|
||||
headers = {"Authorization": f"Bearer {self.daily_api_key}"}
|
||||
json = {**params.model_dump(exclude_none=True)}
|
||||
async with self.aiohttp_session.post(
|
||||
@@ -101,6 +181,19 @@ class DailyRESTHelper:
|
||||
async def get_token(
|
||||
self, room_url: str, expiry_time: float = 60 * 60, owner: bool = True
|
||||
) -> str:
|
||||
"""Generate a meeting token for user to join a Daily room.
|
||||
|
||||
Args:
|
||||
room_url: Daily room URL
|
||||
expiry_time: Token validity duration in seconds (default: 1 hour)
|
||||
owner: Whether token has owner privileges
|
||||
|
||||
Returns:
|
||||
str: Meeting token
|
||||
|
||||
Raises:
|
||||
Exception: If token generation fails or room URL is missing
|
||||
"""
|
||||
if not room_url:
|
||||
raise Exception(
|
||||
"No Daily room specified. You must specify a Daily room in order a token to be generated."
|
||||
@@ -124,10 +217,29 @@ class DailyRESTHelper:
|
||||
return data["token"]
|
||||
|
||||
async def delete_room_by_url(self, room_url: str) -> bool:
|
||||
"""Delete a room using its URL.
|
||||
|
||||
Args:
|
||||
room_url: Daily room URL
|
||||
|
||||
Returns:
|
||||
bool: True if deletion was successful
|
||||
"""
|
||||
room_name = self.get_name_from_url(room_url)
|
||||
return await self.delete_room_by_name(room_name)
|
||||
|
||||
async def delete_room_by_name(self, room_name: str) -> bool:
|
||||
"""Delete a room using its name.
|
||||
|
||||
Args:
|
||||
room_name: Name of the room to delete
|
||||
|
||||
Returns:
|
||||
bool: True if deletion was successful
|
||||
|
||||
Raises:
|
||||
Exception: If deletion fails (excluding 404 Not Found)
|
||||
"""
|
||||
headers = {"Authorization": f"Bearer {self.daily_api_key}"}
|
||||
async with self.aiohttp_session.delete(
|
||||
f"{self.daily_api_url}/rooms/{room_name}", headers=headers
|
||||
@@ -139,6 +251,17 @@ class DailyRESTHelper:
|
||||
return True
|
||||
|
||||
async def _get_room_from_name(self, room_name: str) -> DailyRoomObject:
|
||||
"""Internal method to get room details by name.
|
||||
|
||||
Args:
|
||||
room_name: Name of the room
|
||||
|
||||
Returns:
|
||||
DailyRoomObject: DailyRoomObject instance for the room
|
||||
|
||||
Raises:
|
||||
Exception: If room is not found or response is invalid
|
||||
"""
|
||||
headers = {"Authorization": f"Bearer {self.daily_api_key}"}
|
||||
async with self.aiohttp_session.get(
|
||||
f"{self.daily_api_url}/rooms/{room_name}", headers=headers
|
||||
|
||||
Reference in New Issue
Block a user