Merge branch 'main' into feat/async-tts

This commit is contained in:
Mark Backman
2025-07-29 12:06:56 -07:00
committed by GitHub
811 changed files with 102 additions and 102724 deletions

View File

@@ -111,8 +111,6 @@ class OpenAILLMContext:
context = OpenAILLMContext()
for message in messages:
if "name" not in message:
message["name"] = message["role"]
context.add_message(message)
return context

View File

@@ -140,11 +140,13 @@ class AssistantTranscriptProcessor(BaseTranscriptProcessor):
Result: "Hello there how are you"
"""
if self._current_text_parts and self._aggregation_start_time:
# Check specifically for space characters, previously isspace() was used
# but that includes all whitespace characters (e.g. \n), not just spaces.
has_leading_spaces = any(
part and part[0].isspace() for part in self._current_text_parts[1:]
part and part[0] == " " for part in self._current_text_parts[1:]
)
has_trailing_spaces = any(
part and part[-1].isspace() for part in self._current_text_parts[:-1]
part and part[-1] == " " for part in self._current_text_parts[:-1]
)
# If there are embedded spaces in the fragments, use direct concatenation

View File

@@ -226,6 +226,8 @@ class DailyCallbacks(BaseModel):
on_participant_left: Called when a participant leaves.
on_participant_updated: Called when participant info is updated.
on_transcription_message: Called when receiving transcription.
on_transcription_stopped: Called when transcription is stopped.
on_transcription_error: Called when transcription encounters an error.
on_recording_started: Called when recording starts.
on_recording_stopped: Called when recording stops.
on_recording_error: Called when recording encounters an error.
@@ -253,6 +255,8 @@ class DailyCallbacks(BaseModel):
on_participant_left: Callable[[Mapping[str, Any], str], Awaitable[None]]
on_participant_updated: Callable[[Mapping[str, Any]], Awaitable[None]]
on_transcription_message: Callable[[Mapping[str, Any]], Awaitable[None]]
on_transcription_stopped: Callable[[str, bool], Awaitable[None]]
on_transcription_error: Callable[[str], Awaitable[None]]
on_recording_started: Callable[[Mapping[str, Any]], Awaitable[None]]
on_recording_stopped: Callable[[str], Awaitable[None]]
on_recording_error: Callable[[str, str], Awaitable[None]]
@@ -1233,6 +1237,9 @@ class DailyTransportClient(EventHandler):
stopped_by_error: Whether stopped due to error.
"""
logger.debug("Transcription stopped")
self._call_event_callback(
self._callbacks.on_transcription_stopped, stopped_by, stopped_by_error
)
def on_transcription_error(self, message):
"""Handle transcription error events.
@@ -1241,6 +1248,7 @@ class DailyTransportClient(EventHandler):
message: Error message.
"""
logger.error(f"Transcription error: {message}")
self._call_event_callback(self._callbacks.on_transcription_error, message)
def on_transcription_message(self, message):
"""Handle transcription message events.
@@ -1834,6 +1842,8 @@ class DailyTransport(BaseTransport):
on_participant_left=self._on_participant_left,
on_participant_updated=self._on_participant_updated,
on_transcription_message=self._on_transcription_message,
on_transcription_stopped=self._on_transcription_stopped,
on_transcription_error=self._on_transcription_error,
on_recording_started=self._on_recording_started,
on_recording_stopped=self._on_recording_stopped,
on_recording_error=self._on_recording_error,
@@ -2318,6 +2328,14 @@ class DailyTransport(BaseTransport):
if self._input:
await self._input.push_transcription_frame(frame)
async def _on_transcription_stopped(self, stopped_by, stopped_by_error):
"""Handle transcription stopped events."""
await self._call_event_handler("on_transcription_stopped", stopped_by, stopped_by_error)
async def _on_transcription_error(self, message):
"""Handle transcription error events."""
await self._call_event_handler("on_transcription_error", message)
async def _on_recording_started(self, status):
"""Handle recording started events."""
await self._call_event_handler("on_recording_started", status)

View File

@@ -52,6 +52,25 @@ class RecordingsBucketConfig(BaseModel):
allow_api_access: bool = False
class TranscriptionBucketConfig(BaseModel):
"""Configuration for storing Daily transcription in a custom S3 bucket.
Refer to the Daily API documentation for more information:
https://docs.daily.co/guides/products/live-streaming-recording/storing-recordings-in-a-custom-s3-bucket
Parameters:
bucket_name: Name of the S3 bucket for storing transcription.
bucket_region: AWS region where the S3 bucket is located.
assume_role_arn: ARN of the IAM role to assume for S3 access.
allow_api_access: Whether to allow API access to the transcription.
"""
bucket_name: str
bucket_region: str
assume_role_arn: str
allow_api_access: bool = False
class DailyRoomProperties(BaseModel, extra="allow"):
"""Properties for configuring a Daily room.
@@ -65,9 +84,11 @@ class DailyRoomProperties(BaseModel, extra="allow"):
eject_at_room_exp: Whether to remove participants when room expires.
enable_dialout: Whether SIP dial-out is enabled.
enable_recording: Recording settings ('cloud', 'local', 'raw-tracks').
enable_transcription_storage: Whether transcription storage is enabled.
geo: Geographic region for room.
max_participants: Maximum number of participants allowed in the room.
recordings_bucket: Configuration for custom S3 bucket recordings.
transcription_bucket: Configuration for custom S3 bucket transcription.
sip: SIP configuration parameters.
sip_uri: SIP URI information returned by Daily.
start_video_off: Whether video is off by default.
@@ -80,9 +101,11 @@ class DailyRoomProperties(BaseModel, extra="allow"):
eject_at_room_exp: bool = False
enable_dialout: Optional[bool] = None
enable_recording: Optional[Literal["cloud", "local", "raw-tracks"]] = None
enable_transcription_storage: Optional[bool] = None
geo: Optional[str] = None
max_participants: Optional[int] = None
recordings_bucket: Optional[RecordingsBucketConfig] = None
transcription_bucket: Optional[TranscriptionBucketConfig] = None
sip: Optional[DailyRoomSipParams] = None
sip_uri: Optional[dict] = None
start_video_off: bool = False

View File

@@ -63,7 +63,7 @@ class WatchdogPriorityQueue(asyncio.PriorityQueue):
get_result = await super().get()
if isinstance(get_result, _WatchdogPriorityCancelSentinel):
logger.debug(
logger.trace(
"Received WatchdogPriorityCancelSentinel, throwing CancelledError to force cancelling"
)
raise asyncio.CancelledError("Cancelling watchdog queue get() call.")

View File

@@ -62,7 +62,7 @@ class WatchdogQueue(asyncio.Queue):
get_result = await super().get()
if isinstance(get_result, _WatchdogQueueCancelSentinel):
logger.debug(
logger.trace(
"Received WatchdogQueueCancelFrame, throwing CancelledError to force cancelling"
)
raise asyncio.CancelledError("Cancelling watchdog queue get() call.")