|
|
""" |
|
|
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 |
|
|
category: str = "general" |
|
|
enabled: bool = True |
|
|
priority: int = 50 |
|
|
|
|
|
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})" |
|
|
) |
|
|
|