__init__.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. """
  2. Trixy Arbitration System
  3. This package provides comprehensive arbitration functionality for resolving wakeword
  4. conflicts between multiple satellites in the Trixy voice assistant system.
  5. The arbitration system implements the workflow specified in CLAUDE.md:
  6. 1. Multiple satellites detect wakeword simultaneously
  7. 2. Server waits 1 second to collect all wakeword reports
  8. 3. Server selects satellite with highest volume (or other algorithm)
  9. 4. Selected satellite gets conversation session
  10. 5. Non-selected satellites are notified to ignore
  11. Key Components:
  12. - ArbitrationManager: Main arbitration coordinator
  13. - ArbitrationConfig: Configuration management
  14. - ArbitrationAlgorithms: Satellite selection algorithms
  15. - ArbitrationSession: Session tracking and management
  16. - Event integration: Full integration with Trixy event system
  17. Features:
  18. - Multiple algorithms: volume-based (primary), distance-based, priority-based, round-robin, hybrid
  19. - 1-second collection window for wakeword reports
  20. - Thread-safe concurrent processing
  21. - Comprehensive analytics and history tracking
  22. - Plugin support for custom algorithms
  23. - Real-time monitoring and debugging
  24. Usage:
  25. from trixy_core.arbitration import (
  26. ArbitrationManager, ArbitrationConfig, ArbitrationAlgorithm
  27. )
  28. # Create configuration
  29. config = ArbitrationConfig()
  30. config.primary_algorithm = ArbitrationAlgorithm.VOLUME_BASED
  31. config.collection_window_seconds = 1.0
  32. # Create and start arbitration manager
  33. arbitration_manager = ArbitrationManager(application, config)
  34. arbitration_manager.start()
  35. # The manager automatically handles wakeword_received events
  36. # and coordinates satellite selection
  37. Event Integration:
  38. The arbitration system automatically handles these events:
  39. - wakeword_received: Triggers arbitration process
  40. And generates these events:
  41. - arbitration_started: When session begins
  42. - arbitration_completed: When satellite is selected
  43. - satellite_selected: For selected satellite
  44. - satellite_ignored: For non-selected satellites
  45. """
  46. # Core arbitration classes
  47. from .arbitration_manager import (
  48. ArbitrationManager,
  49. ArbitrationManagerError,
  50. ArbitrationManagerNotStartedError,
  51. ArbitrationManagerConfigError,
  52. ArbitrationStats,
  53. create_arbitration_manager,
  54. create_arbitration_manager_with_defaults
  55. )
  56. from .arbitration_config import (
  57. ArbitrationConfig,
  58. ArbitrationAlgorithm,
  59. ArbitrationMode,
  60. SatellitePriority,
  61. RoomSettings,
  62. AlgorithmWeights,
  63. ArbitrationConfigError,
  64. InvalidConfigurationError,
  65. ConfigurationFileError,
  66. create_default_config,
  67. load_config_from_file,
  68. create_config_with_overrides
  69. )
  70. from .arbitration_algorithms import (
  71. ArbitrationAlgorithms,
  72. WakewordReport,
  73. SelectionResult,
  74. SelectionCriteria,
  75. BaseAlgorithm,
  76. VolumeBasedAlgorithm,
  77. DistanceBasedAlgorithm,
  78. PriorityBasedAlgorithm,
  79. RoundRobinAlgorithm,
  80. HybridAlgorithm,
  81. create_test_reports
  82. )
  83. from .arbitration_session import (
  84. ArbitrationSession,
  85. ArbitrationSessionManager,
  86. SessionState,
  87. SessionPhase,
  88. SessionTiming,
  89. SessionMetrics,
  90. SessionError,
  91. SessionTimeoutError,
  92. SessionStateError,
  93. SessionConfigurationError,
  94. create_session_manager
  95. )
  96. # Version information
  97. __version__ = "1.0.0"
  98. __author__ = "Trixy Development Team"
  99. # Public API
  100. __all__ = [
  101. # Main arbitration manager
  102. "ArbitrationManager",
  103. "ArbitrationManagerError",
  104. "ArbitrationManagerNotStartedError",
  105. "ArbitrationManagerConfigError",
  106. "ArbitrationStats",
  107. "create_arbitration_manager",
  108. "create_arbitration_manager_with_defaults",
  109. # Configuration management
  110. "ArbitrationConfig",
  111. "ArbitrationAlgorithm",
  112. "ArbitrationMode",
  113. "SatellitePriority",
  114. "RoomSettings",
  115. "AlgorithmWeights",
  116. "ArbitrationConfigError",
  117. "InvalidConfigurationError",
  118. "ConfigurationFileError",
  119. "create_default_config",
  120. "load_config_from_file",
  121. "create_config_with_overrides",
  122. # Arbitration algorithms
  123. "ArbitrationAlgorithms",
  124. "WakewordReport",
  125. "SelectionResult",
  126. "SelectionCriteria",
  127. "BaseAlgorithm",
  128. "VolumeBasedAlgorithm",
  129. "DistanceBasedAlgorithm",
  130. "PriorityBasedAlgorithm",
  131. "RoundRobinAlgorithm",
  132. "HybridAlgorithm",
  133. "create_test_reports",
  134. # Session management
  135. "ArbitrationSession",
  136. "ArbitrationSessionManager",
  137. "SessionState",
  138. "SessionPhase",
  139. "SessionTiming",
  140. "SessionMetrics",
  141. "SessionError",
  142. "SessionTimeoutError",
  143. "SessionStateError",
  144. "SessionConfigurationError",
  145. "create_session_manager",
  146. ]
  147. def pprint(message: str) -> None:
  148. """
  149. Arbitration system logging function.
  150. Adapts based on debug mode as specified in CLAUDE.md.
  151. """
  152. print(f"[ARBITRATION] {message}")
  153. def get_arbitration_documentation() -> dict:
  154. """
  155. Get comprehensive documentation for the arbitration system.
  156. Returns:
  157. dict: Documentation mapping with descriptions of components
  158. """
  159. return {
  160. "overview": "Multi-satellite wakeword conflict resolution system",
  161. "workflow": [
  162. "1. Multiple satellites detect wakeword simultaneously",
  163. "2. Server waits 1 second to collect all wakeword reports",
  164. "3. Server selects satellite with highest volume (or other algorithm)",
  165. "4. Selected satellite gets conversation session",
  166. "5. Non-selected satellites are notified to ignore"
  167. ],
  168. "algorithms": {
  169. "volume_based": "Select satellite with highest wakeword volume (primary)",
  170. "distance_based": "Select satellite closest to speaker (estimated)",
  171. "priority_based": "Select based on room/satellite priority settings",
  172. "round_robin": "Fair rotation among available satellites",
  173. "hybrid": "Weighted combination of multiple algorithms",
  174. "custom": "Plugin-based custom arbitration algorithms"
  175. },
  176. "features": [
  177. "1-second collection window for wakeword reports",
  178. "Thread-safe concurrent processing",
  179. "Comprehensive analytics and history tracking",
  180. "Plugin support for custom algorithms",
  181. "Real-time monitoring and debugging capabilities",
  182. "Full integration with Trixy event system",
  183. "Configurable timing and algorithm parameters"
  184. ],
  185. "events": {
  186. "handled": ["wakeword_received"],
  187. "generated": [
  188. "arbitration_started",
  189. "arbitration_completed",
  190. "arbitration_cancelled",
  191. "arbitration_timed_out",
  192. "arbitration_report_added",
  193. "satellite_selected",
  194. "satellite_ignored"
  195. ]
  196. }
  197. }
  198. def get_default_arbitration_config() -> ArbitrationConfig:
  199. """
  200. Get default arbitration configuration for quick setup.
  201. Returns:
  202. ArbitrationConfig: Default configuration instance
  203. """
  204. return create_default_config()
  205. def setup_arbitration_system(
  206. application,
  207. algorithm: ArbitrationAlgorithm = ArbitrationAlgorithm.VOLUME_BASED,
  208. collection_window: float = 1.0,
  209. enable_analytics: bool = True,
  210. debug_mode: bool = False
  211. ) -> ArbitrationManager:
  212. """
  213. Set up a complete arbitration system with specified parameters.
  214. Args:
  215. application: Trixy application container
  216. algorithm: Primary arbitration algorithm to use
  217. collection_window: Collection window in seconds
  218. enable_analytics: Enable analytics and history tracking
  219. debug_mode: Enable debug logging
  220. Returns:
  221. ArbitrationManager: Configured and ready-to-use arbitration manager
  222. """
  223. config = ArbitrationConfig()
  224. config.primary_algorithm = algorithm
  225. config.collection_window_seconds = collection_window
  226. config.enable_analytics = enable_analytics
  227. config.enable_debug_logging = debug_mode
  228. manager = ArbitrationManager(application, config)
  229. pprint(f"Set up arbitration system: algorithm={algorithm.value}, "
  230. f"window={collection_window}s, analytics={enable_analytics}")
  231. return manager
  232. def validate_arbitration_setup(application) -> list:
  233. """
  234. Validate that all required components are available for arbitration.
  235. Args:
  236. application: Trixy application container
  237. Returns:
  238. list: List of validation issues (empty if all valid)
  239. """
  240. issues = []
  241. try:
  242. # Check for event handler
  243. if not hasattr(application, 'get_event_handler'):
  244. issues.append("Application missing get_event_handler method")
  245. else:
  246. event_handler = application.get_event_handler()
  247. if not event_handler:
  248. issues.append("Event handler not initialized")
  249. # Check for satellite manager
  250. if not hasattr(application, 'get_satellite_manager'):
  251. issues.append("Application missing get_satellite_manager method")
  252. else:
  253. satellite_manager = application.get_satellite_manager()
  254. if not satellite_manager:
  255. issues.append("Satellite manager not initialized")
  256. # Check for conversation manager
  257. if not hasattr(application, 'get_conversation_manager'):
  258. issues.append("Application missing get_conversation_manager method")
  259. else:
  260. conversation_manager = application.get_conversation_manager()
  261. if not conversation_manager:
  262. issues.append("Conversation manager not initialized")
  263. except Exception as e:
  264. issues.append(f"Error during validation: {e}")
  265. return issues
  266. def get_supported_algorithms() -> list:
  267. """
  268. Get list of all supported arbitration algorithms.
  269. Returns:
  270. list: List of ArbitrationAlgorithm enum values
  271. """
  272. return list(ArbitrationAlgorithm)
  273. def get_algorithm_descriptions() -> dict:
  274. """
  275. Get descriptions of all arbitration algorithms.
  276. Returns:
  277. dict: Mapping of algorithm names to descriptions
  278. """
  279. return {
  280. ArbitrationAlgorithm.VOLUME_BASED.value:
  281. "Select satellite with highest wakeword detection volume",
  282. ArbitrationAlgorithm.DISTANCE_BASED.value:
  283. "Select satellite closest to speaker based on audio analysis",
  284. ArbitrationAlgorithm.PRIORITY_BASED.value:
  285. "Select satellite based on configured room/satellite priorities",
  286. ArbitrationAlgorithm.ROUND_ROBIN.value:
  287. "Fair rotation among available satellites for equal opportunity",
  288. ArbitrationAlgorithm.HYBRID.value:
  289. "Weighted combination of multiple algorithms for sophisticated selection",
  290. ArbitrationAlgorithm.CUSTOM.value:
  291. "Plugin-based custom arbitration algorithm"
  292. }
  293. # Module-level configuration defaults
  294. ARBITRATION_DEFAULTS = {
  295. "algorithm": ArbitrationAlgorithm.VOLUME_BASED,
  296. "fallback_algorithm": ArbitrationAlgorithm.PRIORITY_BASED,
  297. "collection_window_seconds": 1.0,
  298. "arbitration_timeout_seconds": 2.0,
  299. "volume_threshold": 0.1,
  300. "enable_analytics": True,
  301. "enable_debug_logging": False,
  302. "max_concurrent_arbitrations": 10,
  303. "thread_pool_size": 4,
  304. }
  305. def get_arbitration_defaults() -> dict:
  306. """
  307. Get default configuration values for arbitration system.
  308. Returns:
  309. dict: Default configuration values
  310. """
  311. return ARBITRATION_DEFAULTS.copy()
  312. # Initialize logging for the arbitration package
  313. def _init_arbitration_logging():
  314. """Initialize logging for the arbitration system."""
  315. # This will be enhanced when integrated with proper logging system
  316. pass
  317. # Initialize the package
  318. _init_arbitration_logging()
  319. # Export additional utility functions
  320. __all__.extend([
  321. "pprint",
  322. "get_arbitration_documentation",
  323. "get_default_arbitration_config",
  324. "setup_arbitration_system",
  325. "validate_arbitration_setup",
  326. "get_supported_algorithms",
  327. "get_algorithm_descriptions",
  328. "get_arbitration_defaults",
  329. ])
  330. # Package-level convenience function for common use case
  331. def create_simple_arbitration_manager(application) -> ArbitrationManager:
  332. """
  333. Create arbitration manager with sensible defaults for most use cases.
  334. Args:
  335. application: Trixy application container
  336. Returns:
  337. ArbitrationManager: Ready-to-use arbitration manager
  338. """
  339. return setup_arbitration_system(
  340. application,
  341. algorithm=ArbitrationAlgorithm.VOLUME_BASED,
  342. collection_window=1.0,
  343. enable_analytics=True,
  344. debug_mode=False
  345. )
  346. # Add convenience function to exports
  347. __all__.append("create_simple_arbitration_manager")