| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- """
- Event data structures for the Trixy application.
- This module defines the data classes that encapsulate information passed with events
- throughout the Trixy system. All event data classes inherit from TrixyEventData
- and provide structured, type-safe event information.
- """
- from abc import ABC
- from dataclasses import dataclass, field
- from datetime import datetime
- from typing import Any, Dict, List, Optional, Union
- from enum import Enum
- class EventType(Enum):
- """Enumeration of all supported Trixy event types."""
-
- # Satellite Management Events
- SATELLITE_CONNECTED = "satellite_connected"
- SATELLITE_DISCONNECTED = "satellite_disconnected"
- SATELLITE_REGISTERED = "satellite_registered"
-
- # Wakeword & Audio Events
- WAKEWORD_RECEIVED = "wakeword_received"
- RAW_AUDIO_INPUT_RECEIVED = "raw_audio_input_received"
-
- # Processing Events
- TEXT_RECEIVED = "text_received"
- INTENT_RECEIVED = "intent_received"
- TTS_RECEIVED = "tts_received"
-
- # Conversation Events
- CONVERSATION_STARTED = "conversation_started"
- CONVERSATION_ENDED = "conversation_ended"
- CONVERSATION_STATE_CHANGED = "conversation_state_changed"
- CONVERSATION_TURN_ADDED = "conversation_turn_added"
- CONVERSATION_CONTEXT_UPDATED = "conversation_context_updated"
-
- # Arbitration Events
- ARBITRATION_STARTED = "arbitration_started"
- ARBITRATION_COMPLETED = "arbitration_completed"
- ARBITRATION_CANCELLED = "arbitration_cancelled"
- ARBITRATION_TIMED_OUT = "arbitration_timed_out"
- ARBITRATION_REPORT_ADDED = "arbitration_report_added"
- SATELLITE_SELECTED = "satellite_selected"
- SATELLITE_IGNORED = "satellite_ignored"
-
- # System Events
- SYSTEM_STARTUP = "system_startup"
- SYSTEM_SHUTDOWN = "system_shutdown"
- PLUGIN_LOADED = "plugin_loaded"
- PLUGIN_UNLOADED = "plugin_unloaded"
- TRAINING_STARTED = "training_started"
- TRAINING_COMPLETED = "training_completed"
- SCHEDULE_TRIGGERED = "schedule_triggered"
- @dataclass
- class TrixyEventData(ABC):
- """
- Base class for all Trixy event data.
-
- All event data classes should inherit from this class to provide
- consistent timestamp tracking and metadata support.
- """
- timestamp: datetime = field(default_factory=datetime.now)
- metadata: Dict[str, Any] = field(default_factory=dict)
-
- def to_dict(self) -> Dict[str, Any]:
- """Convert event data to dictionary representation."""
- result = {}
- for key, value in self.__dict__.items():
- if isinstance(value, datetime):
- result[key] = value.isoformat()
- elif hasattr(value, 'to_dict'):
- result[key] = value.to_dict()
- else:
- result[key] = value
- return result
- @dataclass
- class SatelliteInfo:
- """Information about a satellite device."""
- satellite_id: str
- mac_address: str
- room_id: str
- alias: str
- version: str
- audio_ports: Dict[str, int] = field(default_factory=dict)
- capabilities: List[str] = field(default_factory=list)
-
- def to_dict(self) -> Dict[str, Any]:
- """Convert satellite info to dictionary."""
- return {
- 'satellite_id': self.satellite_id,
- 'mac_address': self.mac_address,
- 'room_id': self.room_id,
- 'alias': self.alias,
- 'version': self.version,
- 'audio_ports': self.audio_ports,
- 'capabilities': self.capabilities
- }
- @dataclass
- class SpeakerInfo:
- """Information about a detected speaker."""
- speaker_id: str
- speaker_name: str
- confidence: float = 0.0
- embedding: Optional[List[float]] = None
-
- def to_dict(self) -> Dict[str, Any]:
- """Convert speaker info to dictionary."""
- return {
- 'speaker_id': self.speaker_id,
- 'speaker_name': self.speaker_name,
- 'confidence': self.confidence,
- 'embedding': self.embedding
- }
- # Satellite Management Event Data Classes
- @dataclass
- class SatelliteConnectedEventData(TrixyEventData):
- """Data for satellite_connected event."""
- satellite_info: SatelliteInfo = field(default=None)
- connection_time: datetime = field(default_factory=datetime.now)
- server_assigned_ports: Dict[str, int] = field(default_factory=dict)
- @dataclass
- class SatelliteDisconnectedEventData(TrixyEventData):
- """Data for satellite_disconnected event."""
- satellite_id: str = field(default="")
- satellite_info: Optional[SatelliteInfo] = None
- disconnection_reason: str = "unknown"
- was_clean_disconnect: bool = False
- @dataclass
- class SatelliteRegisteredEventData(TrixyEventData):
- """Data for satellite_registered event."""
- satellite_info: SatelliteInfo = field(default=None)
- registration_file_path: str = field(default="")
- registration_mode_timeout: int = 60
- # Wakeword & Audio Event Data Classes
- @dataclass
- class WakewordReceivedEventData(TrixyEventData):
- """Data for wakeword_received event."""
- wakeword_id: str = field(default="")
- wakeword_type: str = field(default="") # "custom", "system_command"
- speaker_info: SpeakerInfo = field(default=None)
- satellite_info: SatelliteInfo = field(default=None)
- volume: float = field(default=0.0)
- confidence: float = 0.0
- raw_scores: Dict[str, float] = field(default_factory=dict)
- processing_time_ms: float = 0.0
- audio_buffer_length: float = 0.0 # seconds
- chunk_id: int = 0
- features_shape: List[int] = field(default_factory=list)
- model_name: str = field(default="")
- temporal_filtered: bool = False
- @dataclass
- class RawAudioInputReceivedEventData(TrixyEventData):
- """Data for raw_audio_input_received event."""
- conversation_id: str = field(default="")
- audio_data: bytes = field(default=b"")
- speaker_info: SpeakerInfo = field(default=None)
- satellite_info: SatelliteInfo = field(default=None)
- sample_rate: int = 16000
- channels: int = 1
- bit_depth: int = 16
- duration_seconds: float = 0.0
- # Processing Event Data Classes
- @dataclass
- class TextReceivedEventData(TrixyEventData):
- """Data for text_received event."""
- conversation_id: str = field(default="")
- text: str = field(default="")
- confidence: float = field(default=0.0)
- speaker_info: SpeakerInfo = field(default=None)
- satellite_info: Optional[SatelliteInfo] = None
- language_code: str = "en-US"
- processing_time_ms: float = 0.0
- @dataclass
- class IntentReceivedEventData(TrixyEventData):
- """Data for intent_received event."""
- conversation_id: str = field(default="")
- intent: str = field(default="")
- entities: Dict[str, Any] = field(default_factory=dict)
- confidence: float = field(default=0.0)
- original_text: str = field(default="")
- speaker_info: SpeakerInfo = field(default=None)
- satellite_info: Optional[SatelliteInfo] = None
- processing_time_ms: float = 0.0
- @dataclass
- class TTSReceivedEventData(TrixyEventData):
- """Data for tts_received event."""
- conversation_id: str = field(default="")
- audio_data: bytes = field(default=b"")
- text: str = field(default="")
- voice_settings: Dict[str, Any] = field(default_factory=dict)
- sample_rate: int = 16000
- channels: int = 1
- bit_depth: int = 16
- duration_seconds: float = 0.0
- target_satellite_id: Optional[str] = None
- # System Event Data Classes
- @dataclass
- class SystemStartupEventData(TrixyEventData):
- """Data for system_startup event."""
- mode: str = field(default="") # "server", "client", "standalone"
- version: str = field(default="")
- config_file: str = field(default="")
- debug_mode: bool = False
- startup_time_ms: float = 0.0
- @dataclass
- class SystemShutdownEventData(TrixyEventData):
- """Data for system_shutdown event."""
- reason: str = "user_requested"
- graceful_shutdown: bool = True
- uptime_seconds: float = 0.0
- @dataclass
- class PluginEventData(TrixyEventData):
- """Base data for plugin-related events."""
- plugin_name: str = field(default="")
- plugin_path: str = field(default="")
- plugin_version: str = "unknown"
- config_data: Dict[str, Any] = field(default_factory=dict)
- @dataclass
- class PluginLoadedEventData(PluginEventData):
- """Data for plugin_loaded event."""
- load_time_ms: float = 0.0
- enabled: bool = True
- @dataclass
- class PluginUnloadedEventData(PluginEventData):
- """Data for plugin_unloaded event."""
- unload_reason: str = "user_requested"
- was_enabled: bool = False
- @dataclass
- class TrainingStartedEventData(TrixyEventData):
- """Data for training_started event."""
- training_type: str = field(default="") # "wakeword", "voice_recognition"
- model_name: str = field(default="")
- dataset_size: int = field(default=0)
- estimated_duration_minutes: float = 0.0
- training_parameters: Dict[str, Any] = field(default_factory=dict)
- @dataclass
- class TrainingCompletedEventData(TrixyEventData):
- """Data for training_completed event."""
- training_type: str = field(default="")
- model_name: str = field(default="")
- success: bool = field(default=False)
- final_accuracy: float = 0.0
- training_duration_minutes: float = 0.0
- model_save_path: str = ""
- error_message: str = ""
- @dataclass
- class ScheduleTriggeredEventData(TrixyEventData):
- """Data for schedule_triggered event."""
- schedule_id: str = field(default="")
- schedule_name: str = field(default="")
- trigger_type: str = field(default="") # "date", "time", "event", "weekday"
- trigger_value: str = field(default="")
- action_type: str = field(default="") # "trigger_event", "start_training", "call_function"
- action_data: Dict[str, Any] = field(default_factory=dict)
- next_trigger_time: Optional[datetime] = None
- # Conversation Event Data Classes
- @dataclass
- class ConversationStartedEventData(TrixyEventData):
- """Data for conversation_started event."""
- conversation_id: str = field(default="")
- trigger_event: str = field(default="")
- speaker_info: Optional[SpeakerInfo] = None
- satellite_info: Optional[SatelliteInfo] = None
- timeout_seconds: float = 300.0
- max_turns: int = 50
- @dataclass
- class ConversationEndedEventData(TrixyEventData):
- """Data for conversation_ended event."""
- conversation_id: str = field(default="")
- end_reason: str = field(default="") # "completed", "timeout", "cancelled", "error"
- final_state: str = field(default="")
- duration_seconds: float = 0.0
- turn_count: int = 0
- speaker_info: Optional[SpeakerInfo] = None
- satellite_info: Optional[SatelliteInfo] = None
- final_response: Optional[str] = None
- error_message: Optional[str] = None
- @dataclass
- class ConversationStateChangedEventData(TrixyEventData):
- """Data for conversation_state_changed event."""
- conversation_id: str = field(default="")
- from_state: str = field(default="")
- to_state: str = field(default="")
- trigger: str = field(default="")
- source: str = field(default="")
- duration_ms: float = 0.0
- metadata: Dict[str, Any] = field(default_factory=dict)
- @dataclass
- class ConversationTurnAddedEventData(TrixyEventData):
- """Data for conversation_turn_added event."""
- conversation_id: str = field(default="")
- turn_id: str = field(default="")
- turn_number: int = 0
- role: str = field(default="") # "user", "assistant", "system", "plugin"
- input_type: str = field(default="")
- input_text: Optional[str] = None
- input_confidence: float = 0.0
- speaker_info: Optional[SpeakerInfo] = None
- satellite_info: Optional[SatelliteInfo] = None
- plugin_name: Optional[str] = None
- @dataclass
- class ConversationContextUpdatedEventData(TrixyEventData):
- """Data for conversation_context_updated event."""
- conversation_id: str = field(default="")
- context_key: str = field(default="")
- context_scope: str = field(default="") # "session", "speaker", "satellite", "room", "global", "plugin"
- operation: str = field(default="") # "set", "update", "delete", "clear"
- source: str = field(default="")
- metadata: Dict[str, Any] = field(default_factory=dict)
- # Arbitration Event Data Classes
- @dataclass
- class ArbitrationStartedEventData(TrixyEventData):
- """Data for arbitration_started event."""
- arbitration_session_id: str = field(default="")
- trigger_satellite_id: str = field(default="")
- trigger_wakeword_id: str = field(default="")
- collection_window_seconds: float = 1.0
- algorithm: str = field(default="volume_based")
- expected_participants: int = 1
- @dataclass
- class ArbitrationCompletedEventData(TrixyEventData):
- """Data for arbitration_completed event."""
- arbitration_session_id: str = field(default="")
- selected_satellite_id: str = field(default="")
- selection_algorithm: str = field(default="")
- selection_score: float = 0.0
- selection_confidence: float = 0.0
- total_participants: int = 0
- collection_duration_ms: float = 0.0
- arbitration_duration_ms: float = 0.0
- conversation_id: Optional[str] = None
- selection_reason: str = field(default="")
- alternative_selections: Dict[str, float] = field(default_factory=dict)
- @dataclass
- class ArbitrationCancelledEventData(TrixyEventData):
- """Data for arbitration_cancelled event."""
- arbitration_session_id: str = field(default="")
- cancellation_reason: str = field(default="")
- participants_count: int = 0
- duration_ms: float = 0.0
- cancelled_by: str = field(default="system")
- @dataclass
- class ArbitrationTimedOutEventData(TrixyEventData):
- """Data for arbitration_timed_out event."""
- arbitration_session_id: str = field(default="")
- timeout_duration_ms: float = 0.0
- participants_count: int = 0
- reports_received: int = 0
- timeout_phase: str = field(default="") # "collection", "arbitration", "session"
- @dataclass
- class ArbitrationReportAddedEventData(TrixyEventData):
- """Data for arbitration_report_added event."""
- arbitration_session_id: str = field(default="")
- satellite_id: str = field(default="")
- wakeword_id: str = field(default="")
- volume: float = 0.0
- confidence: float = 0.0
- speaker_info: Optional[SpeakerInfo] = None
- satellite_info: Optional[SatelliteInfo] = None
- report_timestamp: datetime = field(default_factory=datetime.now)
- estimated_distance: Optional[float] = None
- room_id: str = field(default="")
- total_reports_in_session: int = 1
- @dataclass
- class SatelliteSelectedEventData(TrixyEventData):
- """Data for satellite_selected event."""
- arbitration_session_id: str = field(default="")
- selected_satellite_id: str = field(default="")
- satellite_info: Optional[SatelliteInfo] = None
- selection_algorithm: str = field(default="")
- selection_score: float = 0.0
- selection_confidence: float = 0.0
- conversation_id: str = field(default="")
- selection_metadata: Dict[str, Any] = field(default_factory=dict)
- @dataclass
- class SatelliteIgnoredEventData(TrixyEventData):
- """Data for satellite_ignored event."""
- arbitration_session_id: str = field(default="")
- ignored_satellite_id: str = field(default="")
- satellite_info: Optional[SatelliteInfo] = None
- selected_satellite_id: str = field(default="")
- ignore_reason: str = field(default="not_selected")
- original_report_volume: float = 0.0
- original_report_confidence: float = 0.0
- # Event Data Factory
- class EventDataFactory:
- """Factory class for creating event data instances."""
-
- _event_data_classes = {
- EventType.SATELLITE_CONNECTED: SatelliteConnectedEventData,
- EventType.SATELLITE_DISCONNECTED: SatelliteDisconnectedEventData,
- EventType.SATELLITE_REGISTERED: SatelliteRegisteredEventData,
- EventType.WAKEWORD_RECEIVED: WakewordReceivedEventData,
- EventType.RAW_AUDIO_INPUT_RECEIVED: RawAudioInputReceivedEventData,
- EventType.TEXT_RECEIVED: TextReceivedEventData,
- EventType.INTENT_RECEIVED: IntentReceivedEventData,
- EventType.TTS_RECEIVED: TTSReceivedEventData,
- EventType.CONVERSATION_STARTED: ConversationStartedEventData,
- EventType.CONVERSATION_ENDED: ConversationEndedEventData,
- EventType.CONVERSATION_STATE_CHANGED: ConversationStateChangedEventData,
- EventType.CONVERSATION_TURN_ADDED: ConversationTurnAddedEventData,
- EventType.CONVERSATION_CONTEXT_UPDATED: ConversationContextUpdatedEventData,
- EventType.ARBITRATION_STARTED: ArbitrationStartedEventData,
- EventType.ARBITRATION_COMPLETED: ArbitrationCompletedEventData,
- EventType.ARBITRATION_CANCELLED: ArbitrationCancelledEventData,
- EventType.ARBITRATION_TIMED_OUT: ArbitrationTimedOutEventData,
- EventType.ARBITRATION_REPORT_ADDED: ArbitrationReportAddedEventData,
- EventType.SATELLITE_SELECTED: SatelliteSelectedEventData,
- EventType.SATELLITE_IGNORED: SatelliteIgnoredEventData,
- EventType.SYSTEM_STARTUP: SystemStartupEventData,
- EventType.SYSTEM_SHUTDOWN: SystemShutdownEventData,
- EventType.PLUGIN_LOADED: PluginLoadedEventData,
- EventType.PLUGIN_UNLOADED: PluginUnloadedEventData,
- EventType.TRAINING_STARTED: TrainingStartedEventData,
- EventType.TRAINING_COMPLETED: TrainingCompletedEventData,
- EventType.SCHEDULE_TRIGGERED: ScheduleTriggeredEventData,
- }
-
- @classmethod
- def create_event_data(cls, event_type: Union[EventType, str], **kwargs) -> TrixyEventData:
- """
- Create an event data instance for the specified event type.
-
- Args:
- event_type: The type of event (EventType enum or string)
- **kwargs: Arguments to pass to the event data constructor
-
- Returns:
- TrixyEventData: An instance of the appropriate event data class
-
- Raises:
- ValueError: If the event type is not supported
- """
- if isinstance(event_type, str):
- try:
- event_type = EventType(event_type)
- except ValueError:
- raise ValueError(f"Unknown event type: {event_type}")
-
- if event_type not in cls._event_data_classes:
- raise ValueError(f"No event data class registered for event type: {event_type}")
-
- event_data_class = cls._event_data_classes[event_type]
- return event_data_class(**kwargs)
-
- @classmethod
- def get_supported_events(cls) -> List[EventType]:
- """Get a list of all supported event types."""
- return list(cls._event_data_classes.keys())
-
- @classmethod
- def is_supported_event(cls, event_type: Union[EventType, str]) -> bool:
- """Check if an event type is supported."""
- if isinstance(event_type, str):
- try:
- event_type = EventType(event_type)
- except ValueError:
- return False
- return event_type in cls._event_data_classes
|