Files
voiceagent/src/voice_assistant/audio_gateway/app/session.py

70 lines
2.0 KiB
Python

from dataclasses import dataclass, field
from uuid import uuid4
@dataclass
class SessionState:
session_id: str = field(default_factory=lambda: str(uuid4()))
active_turn_id: int | None = None
next_turn_id: int = 1
expected_audio_sequence: int = 0
closed: bool = False
def start_turn(self) -> int:
if self.closed:
raise RuntimeError("Session is closed.")
if self.active_turn_id is not None:
raise RuntimeError("A turn is already active.")
self.active_turn_id = self.next_turn_id
self.next_turn_id += 1
self.expected_audio_sequence = 0
return self.active_turn_id
def accept_audio_chunk(
self,
turn_id: int,
sequence_number: int,
payload_size: int,
) -> None:
if self.closed:
raise RuntimeError("Session is closed.")
if self.active_turn_id != turn_id:
raise ValueError(
f"Unexpected turn_id={turn_id}; "
f"active_turn_id={self.active_turn_id}."
)
if sequence_number != self.expected_audio_sequence:
raise ValueError(
f"Expected sequence_number="
f"{self.expected_audio_sequence}, "
f"received={sequence_number}."
)
if payload_size == 0:
raise ValueError("Audio chunk cannot be empty.")
self.expected_audio_sequence += 1
def end_turn(self, turn_id: int) -> None:
if self.active_turn_id != turn_id:
raise ValueError(
f"Cannot end turn {turn_id}; "
f"active_turn_id={self.active_turn_id}."
)
self.active_turn_id = None
self.expected_audio_sequence = 0
def interrupt(self, turn_id: int) -> None:
if self.active_turn_id == turn_id:
self.active_turn_id = None
self.expected_audio_sequence = 0
def close(self) -> None:
self.active_turn_id = None
self.closed = True