""" Base Plugin Class Defines the interface that all plugins must implement. """ from abc import ABC, abstractmethod from dataclasses import dataclass from typing import Dict, Any, Optional, List from pathlib import Path from PIL import Image import numpy as np from loguru import logger @dataclass class PluginMetadata: """Metadata for a plugin.""" name: str version: str description: str author: str requires: List[str] = None # Required dependencies category: str = "general" # Plugin category enabled: bool = True priority: int = 50 # Execution priority (lower = earlier) def __post_init__(self): if self.requires is None: self.requires = [] class BasePlugin(ABC): """ Base class for all DeepVision plugins. All plugins must inherit from this class and implement the analyze() method. """ def __init__(self): """Initialize plugin.""" self._metadata: Optional[PluginMetadata] = None self._initialized = False self._enabled = True logger.debug(f"Plugin {self.__class__.__name__} created") @property @abstractmethod def metadata(self) -> PluginMetadata: """ Return plugin metadata. Returns: PluginMetadata instance """ pass @abstractmethod def initialize(self) -> None: """ Initialize the plugin. This method is called when the plugin is loaded. Use it to load models, initialize resources, etc. """ pass @abstractmethod def analyze( self, media: Any, media_path: Path ) -> Dict[str, Any]: """ Analyze media and return results. Args: media: Processed media (PIL Image or numpy array) media_path: Path to the media file Returns: Dictionary with analysis results """ pass def cleanup(self) -> None: """ Clean up resources when plugin is unloaded. Override this method to release resources like model memory, file handles, etc. """ logger.debug(f"Cleaning up plugin {self.metadata.name}") def validate_input(self, media: Any) -> bool: """ Validate input media. Args: media: Media to validate Returns: True if valid, False otherwise """ if isinstance(media, Image.Image): return True elif isinstance(media, np.ndarray): return True else: logger.warning( f"Plugin {self.metadata.name} received unsupported media type: " f"{type(media)}" ) return False def get_config(self) -> Dict[str, Any]: """ Get plugin configuration. Returns: Configuration dictionary """ return { "name": self.metadata.name, "version": self.metadata.version, "enabled": self._enabled, "initialized": self._initialized, } def set_enabled(self, enabled: bool) -> None: """ Enable or disable the plugin. Args: enabled: True to enable, False to disable """ self._enabled = enabled logger.info( f"Plugin {self.metadata.name} " f"{'enabled' if enabled else 'disabled'}" ) def is_enabled(self) -> bool: """ Check if plugin is enabled. Returns: True if enabled """ return self._enabled def is_initialized(self) -> bool: """ Check if plugin is initialized. Returns: True if initialized """ return self._initialized def __repr__(self) -> str: """String representation.""" return ( f"{self.__class__.__name__}(" f"name={self.metadata.name}, " f"version={self.metadata.version}, " f"enabled={self._enabled})" )