70 lines
2.0 KiB
Python
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 |