"""Voice mode state machine for controlling STT/TTS components."""
from enum import Enum
from statemachine import StateMachine, State
class VoiceMode(Enum):
"""Available voice modes."""
FULL_VOICE = "full_voice" # STT + TTS enabled
TTS_ONLY = "tts_only" # TTS enabled, STT disabled
STT_ONLY = "stt_only" # STT enabled, TTS disabled
SILENT = "silent" # Both disabled
class ModeStateMachine(StateMachine):
"""
Controls which voice components are active.
Layer 1 of two-layer state architecture:
- This layer: Controls WHAT is enabled (STT, TTS, or both)
- Layer 2 (TurnStateMachine): Controls WHEN audio flows (turn-taking)
"""
# States (names match VoiceMode enum values)
full_voice = State(initial=True)
tts_only = State()
stt_only = State()
silent = State()
# Mode switch events - all-to-all transitions
set_full_voice = (
tts_only.to(full_voice) |
stt_only.to(full_voice) |
silent.to(full_voice) |
full_voice.to.itself() # Idempotent
)
set_tts_only = (
full_voice.to(tts_only) |
stt_only.to(tts_only) |
silent.to(tts_only) |
tts_only.to.itself()
)
set_stt_only = (
full_voice.to(stt_only) |
tts_only.to(stt_only) |
silent.to(stt_only) |
stt_only.to.itself()
)
set_silent = (
full_voice.to(silent) |
tts_only.to(silent) |
stt_only.to(silent) |
silent.to.itself()
)
def __init__(self):
super().__init__()
# Initialize component flags
self.stt_enabled = True
self.tts_enabled = True
def on_enter_state(self, target, source):
"""Update component flags when entering any state."""
self._update_component_flags()
def _update_component_flags(self):
"""Map current state to component enable flags."""
mode_flags = {
"full_voice": (True, True), # (stt_enabled, tts_enabled)
"tts_only": (False, True),
"stt_only": (True, False),
"silent": (False, False),
}
self.stt_enabled, self.tts_enabled = mode_flags[self.current_state.id]
@property
def mode(self) -> VoiceMode:
"""Get current mode as VoiceMode enum."""
return VoiceMode(self.current_state.id)
@property
def mode_name(self) -> str:
"""Get current mode name as string."""
return self.current_state.id