container_integration.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. """
  2. Application Container Integration for Trixy ML Systems.
  3. This module provides comprehensive integration between the ML components and the
  4. main Trixy application container, enabling dependency injection, service management,
  5. lifecycle coordination, and seamless integration with the main application.
  6. Key Features:
  7. - Dependency injection for ML components
  8. - Service registry and discovery
  9. - Lifecycle management and coordination
  10. - Configuration management integration
  11. - Event bus integration
  12. - Health checking and monitoring
  13. - Resource management and cleanup
  14. - Plugin architecture support
  15. Usage:
  16. from trixy_core.ml import MLContainerManager, MLServiceRegistry
  17. # Create container manager
  18. container_manager = MLContainerManager(app_container)
  19. # Register ML services
  20. await container_manager.register_ml_services()
  21. # Start ML integration
  22. await container_manager.start_ml_services()
  23. """
  24. import asyncio
  25. import logging
  26. import weakref
  27. from abc import ABC, abstractmethod
  28. from dataclasses import dataclass, field
  29. from datetime import datetime, timedelta
  30. from enum import Enum
  31. from typing import Any, Dict, List, Optional, Type, Callable, Union, TypeVar, Generic
  32. import inspect
  33. from contextlib import asynccontextmanager
  34. class ServiceState(Enum):
  35. """Service lifecycle states."""
  36. UNINITIALIZED = "uninitialized"
  37. INITIALIZING = "initializing"
  38. INITIALIZED = "initialized"
  39. STARTING = "starting"
  40. RUNNING = "running"
  41. STOPPING = "stopping"
  42. STOPPED = "stopped"
  43. ERROR = "error"
  44. class ServiceScope(Enum):
  45. """Service scope definitions."""
  46. SINGLETON = "singleton"
  47. TRANSIENT = "transient"
  48. SCOPED = "scoped"
  49. class DependencyType(Enum):
  50. """Dependency injection types."""
  51. REQUIRED = "required"
  52. OPTIONAL = "optional"
  53. LAZY = "lazy"
  54. T = TypeVar('T')
  55. @dataclass
  56. class ServiceDefinition:
  57. """Service definition for dependency injection."""
  58. service_id: str
  59. service_type: Type
  60. implementation: Optional[Type] = None
  61. scope: ServiceScope = ServiceScope.SINGLETON
  62. factory: Optional[Callable] = None
  63. dependencies: List[str] = field(default_factory=list)
  64. config_key: Optional[str] = None
  65. auto_start: bool = True
  66. health_check: Optional[Callable] = None
  67. metadata: Dict[str, Any] = field(default_factory=dict)
  68. @dataclass
  69. class ServiceInstance:
  70. """Service instance metadata."""
  71. definition: ServiceDefinition
  72. instance: Any
  73. state: ServiceState = ServiceState.UNINITIALIZED
  74. created_at: datetime = field(default_factory=datetime.now)
  75. started_at: Optional[datetime] = None
  76. last_health_check: Optional[datetime] = None
  77. health_status: bool = True
  78. error: Optional[Exception] = None
  79. class ServiceError(Exception):
  80. """Base exception for service-related errors."""
  81. pass
  82. class DependencyError(ServiceError):
  83. """Exception for dependency resolution errors."""
  84. pass
  85. class LifecycleError(ServiceError):
  86. """Exception for service lifecycle errors."""
  87. pass
  88. class IService(ABC):
  89. """Interface for managed services."""
  90. @abstractmethod
  91. async def initialize(self, context: Dict[str, Any]) -> None:
  92. """Initialize the service."""
  93. pass
  94. @abstractmethod
  95. async def start(self) -> None:
  96. """Start the service."""
  97. pass
  98. @abstractmethod
  99. async def stop(self) -> None:
  100. """Stop the service."""
  101. pass
  102. @abstractmethod
  103. async def health_check(self) -> bool:
  104. """Check service health."""
  105. pass
  106. class IMLService(IService):
  107. """Interface for ML-specific services."""
  108. @abstractmethod
  109. async def process_audio(self, audio_data: Any) -> Any:
  110. """Process audio data."""
  111. pass
  112. @abstractmethod
  113. def get_performance_metrics(self) -> Dict[str, Any]:
  114. """Get performance metrics."""
  115. pass
  116. class ServiceRegistry:
  117. """Service registry for dependency injection and service discovery."""
  118. def __init__(self):
  119. self.services: Dict[str, ServiceDefinition] = {}
  120. self.instances: Dict[str, ServiceInstance] = {}
  121. self.factories: Dict[str, Callable] = {}
  122. self._locks: Dict[str, asyncio.Lock] = {}
  123. self.logger = logging.getLogger(__name__)
  124. def register_service(self, definition: ServiceDefinition) -> None:
  125. """Register a service definition."""
  126. if definition.service_id in self.services:
  127. raise ServiceError(f"Service {definition.service_id} already registered")
  128. self.services[definition.service_id] = definition
  129. self._locks[definition.service_id] = asyncio.Lock()
  130. self.logger.info(f"Registered service: {definition.service_id}")
  131. def register_factory(self, service_id: str, factory: Callable) -> None:
  132. """Register a factory function for a service."""
  133. self.factories[service_id] = factory
  134. self.logger.debug(f"Registered factory for service: {service_id}")
  135. async def get_service(self, service_id: str, context: Optional[Dict[str, Any]] = None) -> Any:
  136. """Get a service instance."""
  137. if service_id not in self.services:
  138. raise ServiceError(f"Service {service_id} not registered")
  139. definition = self.services[service_id]
  140. # Handle singleton scope
  141. if definition.scope == ServiceScope.SINGLETON:
  142. if service_id in self.instances:
  143. instance_data = self.instances[service_id]
  144. if instance_data.state in [ServiceState.RUNNING, ServiceState.INITIALIZED]:
  145. return instance_data.instance
  146. # Create new instance
  147. async with self._locks[service_id]:
  148. return await self._create_instance(service_id, context)
  149. async def _create_instance(self, service_id: str, context: Optional[Dict[str, Any]] = None) -> Any:
  150. """Create a new service instance."""
  151. definition = self.services[service_id]
  152. context = context or {}
  153. try:
  154. # Resolve dependencies
  155. dependencies = {}
  156. for dep_id in definition.dependencies:
  157. dependencies[dep_id] = await self.get_service(dep_id, context)
  158. # Create instance
  159. if definition.factory:
  160. instance = await self._call_factory(definition.factory, dependencies, context)
  161. elif service_id in self.factories:
  162. instance = await self._call_factory(self.factories[service_id], dependencies, context)
  163. elif definition.implementation:
  164. instance = self._create_from_type(definition.implementation, dependencies, context)
  165. else:
  166. instance = self._create_from_type(definition.service_type, dependencies, context)
  167. # Store instance
  168. instance_data = ServiceInstance(
  169. definition=definition,
  170. instance=instance,
  171. state=ServiceState.INITIALIZED
  172. )
  173. if definition.scope == ServiceScope.SINGLETON:
  174. self.instances[service_id] = instance_data
  175. self.logger.info(f"Created instance for service: {service_id}")
  176. return instance
  177. except Exception as e:
  178. self.logger.error(f"Error creating instance for service {service_id}: {e}")
  179. raise ServiceError(f"Failed to create service {service_id}: {e}")
  180. async def _call_factory(self, factory: Callable, dependencies: Dict[str, Any],
  181. context: Dict[str, Any]) -> Any:
  182. """Call a factory function with dependency injection."""
  183. signature = inspect.signature(factory)
  184. kwargs = {}
  185. for param_name, param in signature.parameters.items():
  186. if param_name in dependencies:
  187. kwargs[param_name] = dependencies[param_name]
  188. elif param_name in context:
  189. kwargs[param_name] = context[param_name]
  190. if asyncio.iscoroutinefunction(factory):
  191. return await factory(**kwargs)
  192. else:
  193. return factory(**kwargs)
  194. def _create_from_type(self, service_type: Type, dependencies: Dict[str, Any],
  195. context: Dict[str, Any]) -> Any:
  196. """Create instance from type with dependency injection."""
  197. try:
  198. signature = inspect.signature(service_type.__init__)
  199. kwargs = {}
  200. for param_name, param in signature.parameters.items():
  201. if param_name == 'self':
  202. continue
  203. if param_name in dependencies:
  204. kwargs[param_name] = dependencies[param_name]
  205. elif param_name in context:
  206. kwargs[param_name] = context[param_name]
  207. return service_type(**kwargs)
  208. except Exception as e:
  209. raise ServiceError(f"Failed to create instance of {service_type}: {e}")
  210. async def start_service(self, service_id: str) -> None:
  211. """Start a service."""
  212. if service_id not in self.instances:
  213. await self.get_service(service_id)
  214. instance_data = self.instances[service_id]
  215. if instance_data.state == ServiceState.RUNNING:
  216. return
  217. try:
  218. instance_data.state = ServiceState.STARTING
  219. if isinstance(instance_data.instance, IService):
  220. await instance_data.instance.start()
  221. instance_data.state = ServiceState.RUNNING
  222. instance_data.started_at = datetime.now()
  223. self.logger.info(f"Started service: {service_id}")
  224. except Exception as e:
  225. instance_data.state = ServiceState.ERROR
  226. instance_data.error = e
  227. self.logger.error(f"Error starting service {service_id}: {e}")
  228. raise LifecycleError(f"Failed to start service {service_id}: {e}")
  229. async def stop_service(self, service_id: str) -> None:
  230. """Stop a service."""
  231. if service_id not in self.instances:
  232. return
  233. instance_data = self.instances[service_id]
  234. if instance_data.state != ServiceState.RUNNING:
  235. return
  236. try:
  237. instance_data.state = ServiceState.STOPPING
  238. if isinstance(instance_data.instance, IService):
  239. await instance_data.instance.stop()
  240. instance_data.state = ServiceState.STOPPED
  241. self.logger.info(f"Stopped service: {service_id}")
  242. except Exception as e:
  243. instance_data.state = ServiceState.ERROR
  244. instance_data.error = e
  245. self.logger.error(f"Error stopping service {service_id}: {e}")
  246. async def health_check_service(self, service_id: str) -> bool:
  247. """Perform health check on a service."""
  248. if service_id not in self.instances:
  249. return False
  250. instance_data = self.instances[service_id]
  251. try:
  252. if isinstance(instance_data.instance, IService):
  253. health = await instance_data.instance.health_check()
  254. elif instance_data.definition.health_check:
  255. health = await instance_data.definition.health_check(instance_data.instance)
  256. else:
  257. health = instance_data.state == ServiceState.RUNNING
  258. instance_data.health_status = health
  259. instance_data.last_health_check = datetime.now()
  260. return health
  261. except Exception as e:
  262. self.logger.error(f"Health check failed for service {service_id}: {e}")
  263. instance_data.health_status = False
  264. return False
  265. def get_service_info(self, service_id: str) -> Optional[Dict[str, Any]]:
  266. """Get service information."""
  267. if service_id not in self.services:
  268. return None
  269. definition = self.services[service_id]
  270. instance_data = self.instances.get(service_id)
  271. info = {
  272. 'service_id': service_id,
  273. 'service_type': definition.service_type.__name__,
  274. 'scope': definition.scope.value,
  275. 'auto_start': definition.auto_start,
  276. 'dependencies': definition.dependencies,
  277. 'metadata': definition.metadata
  278. }
  279. if instance_data:
  280. info.update({
  281. 'state': instance_data.state.value,
  282. 'health_status': instance_data.health_status,
  283. 'created_at': instance_data.created_at.isoformat(),
  284. 'started_at': instance_data.started_at.isoformat() if instance_data.started_at else None,
  285. 'last_health_check': instance_data.last_health_check.isoformat() if instance_data.last_health_check else None,
  286. 'error': str(instance_data.error) if instance_data.error else None
  287. })
  288. return info
  289. def list_services(self) -> List[str]:
  290. """List all registered services."""
  291. return list(self.services.keys())
  292. class MLServiceRegistry(ServiceRegistry):
  293. """Specialized service registry for ML components."""
  294. def __init__(self):
  295. super().__init__()
  296. self._register_ml_services()
  297. def _register_ml_services(self) -> None:
  298. """Register default ML services."""
  299. # ML Manager
  300. self.register_service(ServiceDefinition(
  301. service_id="ml_manager",
  302. service_type=Any, # Will be replaced with actual MLManager
  303. scope=ServiceScope.SINGLETON,
  304. dependencies=["ml_config", "event_handler", "performance_monitor"],
  305. auto_start=True,
  306. metadata={"component": "core", "category": "ml"}
  307. ))
  308. # Audio Pipeline
  309. self.register_service(ServiceDefinition(
  310. service_id="audio_pipeline",
  311. service_type=Any, # Will be replaced with actual AudioPipeline
  312. scope=ServiceScope.SINGLETON,
  313. dependencies=["audio_config", "ml_manager"],
  314. auto_start=True,
  315. metadata={"component": "audio", "category": "ml"}
  316. ))
  317. # Performance Monitor
  318. self.register_service(ServiceDefinition(
  319. service_id="performance_monitor",
  320. service_type=Any, # Will be replaced with actual PerformanceMonitor
  321. scope=ServiceScope.SINGLETON,
  322. dependencies=["performance_config"],
  323. auto_start=True,
  324. metadata={"component": "monitoring", "category": "system"}
  325. ))
  326. # Event Integration
  327. self.register_service(ServiceDefinition(
  328. service_id="event_integration",
  329. service_type=Any, # Will be replaced with actual MLEventManager
  330. scope=ServiceScope.SINGLETON,
  331. dependencies=["event_config", "ml_manager"],
  332. auto_start=True,
  333. metadata={"component": "events", "category": "integration"}
  334. ))
  335. # Error Handler
  336. self.register_service(ServiceDefinition(
  337. service_id="error_handler",
  338. service_type=Any, # Will be replaced with actual MLErrorHandler
  339. scope=ServiceScope.SINGLETON,
  340. dependencies=["error_config"],
  341. auto_start=True,
  342. metadata={"component": "error_handling", "category": "system"}
  343. ))
  344. class MLContainerManager:
  345. """Container manager for ML integration with main application."""
  346. def __init__(self, app_container: Optional[Any] = None):
  347. self.app_container = app_container
  348. self.ml_registry = MLServiceRegistry()
  349. self.logger = logging.getLogger(__name__)
  350. self._running = False
  351. self._startup_tasks: List[Callable] = []
  352. self._shutdown_tasks: List[Callable] = []
  353. # Integration state
  354. self._event_bus_integration = False
  355. self._config_integration = False
  356. self._health_check_integration = False
  357. async def initialize(self) -> None:
  358. """Initialize the ML container integration."""
  359. try:
  360. self.logger.info("Initializing ML container integration...")
  361. # Setup integration with main container
  362. await self._setup_container_integration()
  363. # Register ML service factories
  364. await self._register_ml_factories()
  365. # Setup cross-cutting concerns
  366. await self._setup_cross_cutting_concerns()
  367. self.logger.info("ML container integration initialized")
  368. except Exception as e:
  369. self.logger.error(f"Error initializing ML container: {e}")
  370. raise ServiceError(f"ML container initialization failed: {e}")
  371. async def _setup_container_integration(self) -> None:
  372. """Setup integration with main application container."""
  373. if not self.app_container:
  374. self.logger.warning("No application container provided - running in standalone mode")
  375. return
  376. try:
  377. # Integrate with configuration system
  378. if hasattr(self.app_container, 'get_config'):
  379. self._config_integration = True
  380. self.logger.debug("Configuration integration enabled")
  381. # Integrate with event bus
  382. if hasattr(self.app_container, 'event_bus'):
  383. self._event_bus_integration = True
  384. self.logger.debug("Event bus integration enabled")
  385. # Integrate with health checking
  386. if hasattr(self.app_container, 'health_checker'):
  387. self._health_check_integration = True
  388. self.logger.debug("Health check integration enabled")
  389. except Exception as e:
  390. self.logger.error(f"Error setting up container integration: {e}")
  391. async def _register_ml_factories(self) -> None:
  392. """Register factory functions for ML services."""
  393. # ML Manager factory
  394. async def create_ml_manager(ml_config: Any, event_handler: Any,
  395. performance_monitor: Any) -> Any:
  396. from .ml_manager import MLManager
  397. return MLManager(ml_config, event_handler, None, self.logger)
  398. self.ml_registry.register_factory("ml_manager", create_ml_manager)
  399. # Audio Pipeline factory
  400. async def create_audio_pipeline(audio_config: Any, ml_manager: Any) -> Any:
  401. from .audio_pipeline import AudioPipeline
  402. return AudioPipeline(audio_config, ml_manager, self.logger)
  403. self.ml_registry.register_factory("audio_pipeline", create_audio_pipeline)
  404. # Performance Monitor factory
  405. async def create_performance_monitor(performance_config: Any) -> Any:
  406. from .performance_monitor import PerformanceMonitor
  407. return PerformanceMonitor(performance_config)
  408. self.ml_registry.register_factory("performance_monitor", create_performance_monitor)
  409. # Event Integration factory
  410. async def create_event_integration(event_config: Any, ml_manager: Any) -> Any:
  411. from .event_integration import MLEventManager
  412. return MLEventManager(event_config, ml_manager, self.logger)
  413. self.ml_registry.register_factory("event_integration", create_event_integration)
  414. # Error Handler factory
  415. async def create_error_handler(error_config: Any) -> Any:
  416. from .error_handling import MLErrorHandler
  417. return MLErrorHandler(error_config, self.logger)
  418. self.ml_registry.register_factory("error_handler", create_error_handler)
  419. async def _setup_cross_cutting_concerns(self) -> None:
  420. """Setup cross-cutting concerns like logging, monitoring, etc."""
  421. # Setup logging integration
  422. if self.app_container and hasattr(self.app_container, 'logger'):
  423. self.logger = self.app_container.logger.get_child("ml")
  424. # Setup monitoring integration
  425. if self._health_check_integration:
  426. self._startup_tasks.append(self._register_health_checks)
  427. # Setup event integration
  428. if self._event_bus_integration:
  429. self._startup_tasks.append(self._setup_event_integration)
  430. async def start_ml_services(self) -> None:
  431. """Start all ML services."""
  432. if self._running:
  433. return
  434. try:
  435. self.logger.info("Starting ML services...")
  436. # Execute startup tasks
  437. for task in self._startup_tasks:
  438. await task()
  439. # Start services in dependency order
  440. service_order = [
  441. "performance_monitor",
  442. "error_handler",
  443. "ml_manager",
  444. "audio_pipeline",
  445. "event_integration"
  446. ]
  447. for service_id in service_order:
  448. await self.ml_registry.start_service(service_id)
  449. self._running = True
  450. self.logger.info("ML services started successfully")
  451. except Exception as e:
  452. self.logger.error(f"Error starting ML services: {e}")
  453. await self.stop_ml_services()
  454. raise LifecycleError(f"Failed to start ML services: {e}")
  455. async def stop_ml_services(self) -> None:
  456. """Stop all ML services."""
  457. if not self._running:
  458. return
  459. try:
  460. self.logger.info("Stopping ML services...")
  461. # Stop services in reverse dependency order
  462. service_order = [
  463. "event_integration",
  464. "audio_pipeline",
  465. "ml_manager",
  466. "error_handler",
  467. "performance_monitor"
  468. ]
  469. for service_id in service_order:
  470. await self.ml_registry.stop_service(service_id)
  471. # Execute shutdown tasks
  472. for task in self._shutdown_tasks:
  473. await task()
  474. self._running = False
  475. self.logger.info("ML services stopped successfully")
  476. except Exception as e:
  477. self.logger.error(f"Error stopping ML services: {e}")
  478. async def _register_health_checks(self) -> None:
  479. """Register health checks with main application."""
  480. if not self.app_container or not hasattr(self.app_container, 'health_checker'):
  481. return
  482. try:
  483. health_checker = self.app_container.health_checker
  484. for service_id in self.ml_registry.list_services():
  485. async def check_service_health(sid=service_id):
  486. return await self.ml_registry.health_check_service(sid)
  487. health_checker.register_check(f"ml_{service_id}", check_service_health)
  488. self.logger.info("ML health checks registered")
  489. except Exception as e:
  490. self.logger.error(f"Error registering health checks: {e}")
  491. async def _setup_event_integration(self) -> None:
  492. """Setup event bus integration."""
  493. if not self.app_container or not hasattr(self.app_container, 'event_bus'):
  494. return
  495. try:
  496. event_bus = self.app_container.event_bus
  497. # Subscribe to relevant application events
  498. event_bus.subscribe("app.shutdown", self._handle_app_shutdown)
  499. event_bus.subscribe("app.config_changed", self._handle_config_change)
  500. self.logger.info("Event bus integration setup")
  501. except Exception as e:
  502. self.logger.error(f"Error setting up event integration: {e}")
  503. async def _handle_app_shutdown(self, event: Dict[str, Any]) -> None:
  504. """Handle application shutdown event."""
  505. self.logger.info("Received application shutdown event")
  506. await self.stop_ml_services()
  507. async def _handle_config_change(self, event: Dict[str, Any]) -> None:
  508. """Handle configuration change event."""
  509. self.logger.info("Received configuration change event")
  510. # Restart services that depend on configuration
  511. # Implementation would reload configurations and restart affected services
  512. def get_service(self, service_id: str) -> Any:
  513. """Get a service instance."""
  514. return asyncio.create_task(self.ml_registry.get_service(service_id))
  515. def get_ml_manager(self) -> Any:
  516. """Get the ML manager instance."""
  517. return self.get_service("ml_manager")
  518. def get_audio_pipeline(self) -> Any:
  519. """Get the audio pipeline instance."""
  520. return self.get_service("audio_pipeline")
  521. def get_performance_monitor(self) -> Any:
  522. """Get the performance monitor instance."""
  523. return self.get_service("performance_monitor")
  524. def get_service_status(self) -> Dict[str, Any]:
  525. """Get status of all ML services."""
  526. status = {
  527. 'running': self._running,
  528. 'services': {}
  529. }
  530. for service_id in self.ml_registry.list_services():
  531. service_info = self.ml_registry.get_service_info(service_id)
  532. if service_info:
  533. status['services'][service_id] = service_info
  534. return status
  535. @asynccontextmanager
  536. async def ml_context(self):
  537. """Context manager for ML services lifecycle."""
  538. try:
  539. await self.initialize()
  540. await self.start_ml_services()
  541. yield self
  542. finally:
  543. await self.stop_ml_services()
  544. # Convenience functions for common integration patterns
  545. async def create_ml_container(app_container: Optional[Any] = None,
  546. auto_start: bool = True) -> MLContainerManager:
  547. """
  548. Create and initialize ML container manager.
  549. Args:
  550. app_container: Main application container
  551. auto_start: Whether to auto-start services
  552. Returns:
  553. Initialized ML container manager
  554. """
  555. manager = MLContainerManager(app_container)
  556. await manager.initialize()
  557. if auto_start:
  558. await manager.start_ml_services()
  559. return manager
  560. def register_ml_service(registry: ServiceRegistry, service_id: str,
  561. service_type: Type, **kwargs) -> None:
  562. """
  563. Register a custom ML service.
  564. Args:
  565. registry: Service registry
  566. service_id: Unique service identifier
  567. service_type: Service type/class
  568. **kwargs: Additional service definition parameters
  569. """
  570. definition = ServiceDefinition(
  571. service_id=service_id,
  572. service_type=service_type,
  573. **kwargs
  574. )
  575. registry.register_service(definition)
  576. class MLServiceDecorator:
  577. """Decorator for ML service classes."""
  578. def __init__(self, service_id: str, scope: ServiceScope = ServiceScope.SINGLETON,
  579. dependencies: Optional[List[str]] = None, auto_start: bool = True):
  580. self.service_id = service_id
  581. self.scope = scope
  582. self.dependencies = dependencies or []
  583. self.auto_start = auto_start
  584. def __call__(self, cls: Type) -> Type:
  585. """Apply decorator to class."""
  586. # Store service metadata on the class
  587. cls._ml_service_id = self.service_id
  588. cls._ml_service_scope = self.scope
  589. cls._ml_service_dependencies = self.dependencies
  590. cls._ml_service_auto_start = self.auto_start
  591. return cls
  592. # Example usage decorator
  593. @MLServiceDecorator("custom_ml_service", dependencies=["ml_manager"])
  594. class CustomMLService(IMLService):
  595. """Example custom ML service."""
  596. def __init__(self, ml_manager: Any):
  597. self.ml_manager = ml_manager
  598. self.logger = logging.getLogger(__name__)
  599. async def initialize(self, context: Dict[str, Any]) -> None:
  600. """Initialize the service."""
  601. self.logger.info("Initializing custom ML service")
  602. async def start(self) -> None:
  603. """Start the service."""
  604. self.logger.info("Starting custom ML service")
  605. async def stop(self) -> None:
  606. """Stop the service."""
  607. self.logger.info("Stopping custom ML service")
  608. async def health_check(self) -> bool:
  609. """Check service health."""
  610. return True
  611. async def process_audio(self, audio_data: Any) -> Any:
  612. """Process audio data."""
  613. return await self.ml_manager.process_audio_chunk(audio_data)
  614. def get_performance_metrics(self) -> Dict[str, Any]:
  615. """Get performance metrics."""
  616. return {"processed_samples": 0, "latency_ms": 0.0}