cjm-transcription-plugin-system
A flexible plugin system for audio transcription intended to make it easy to add support for multiple backends.
Install
$ pip install cjm_transcription_plugin_system
Project Structure
nbs/
├── core.ipynb # Core data structures for audio transcription
├── plugin_interface.ipynb # Abstract base class defining the interface for transcription plugins
└── plugin_manager.ipynb # Plugin discovery, loading, and lifecycle management system
Total: 3 notebooks
Module Dependencies
graph LR
core[core<br/>core]
plugin_interface[plugin_interface<br/>plugin interface]
plugin_manager[plugin_manager<br/>plugin manager]
plugin_interface --> core
plugin_manager --> plugin_interface
plugin_manager --> core
3 cross-module dependencies detected
CLI Reference
No CLI commands found in this project.
Module Overview
Detailed documentation for each module in the project:
core (core.ipynb
)
Core data structures for audio transcription
Import
from cjm_transcription_plugin_system.core import (
AudioData,
TranscriptionResult )
Classes
@dataclass
class AudioData:
"Container for audio data and metadata."
# Audio sample data as a numpy array
samples: np.ndarray int # Sample rate in Hz (e.g., 16000, 44100)
sample_rate: float # Duration of the audio in seconds
duration: # Audio file path
filepath: Optional[Path] str, Any] = field(...) # Additional metadata metadata: Dict[
@dataclass
class TranscriptionResult:
"Standardized transcription output."
str # The transcribed text
text: float] # Overall confidence score (0.0 to 1.0)
confidence: Optional[= field(...) # List of transcription segments with timestamps and text
segments: Optional[List[Dict]] = field(...) # Transcription metadata metadata: Optional[Dict]
plugin interface (plugin_interface.ipynb
)
Abstract base class defining the interface for transcription plugins
Import
from cjm_transcription_plugin_system.plugin_interface import (
PluginInterface,
PluginInterface_supports_streaming,
PluginInterface_execute_stream,
PluginMeta )
Functions
def PluginInterface_supports_streaming(self) -> bool:
"""Check if this plugin supports streaming transcription.
Returns:
bool: True if execute_stream is implemented and streaming is supported
"""
# Default: check if execute_stream is overridden from the base class
"""
Check if this plugin supports streaming transcription.
Returns:
bool: True if execute_stream is implemented and streaming is supported
"""
def PluginInterface_execute_stream(
self,
str, Path], # Audio data or path to audio file
audio: Union[AudioData, **kwargs # Additional plugin-specific parameters
-> Generator[str, None, TranscriptionResult]: # Yields text chunks, returns final result
) """
Stream transcription results chunk by chunk.
Default implementation falls back to execute() without streaming.
Plugins can override this to provide real streaming capabilities.
Args:
audio: Audio data or path to audio file
**kwargs: Additional plugin-specific parameters
Yields:
str: Partial transcription text chunks as they become available
Returns:
TranscriptionResult: Final complete transcription with metadata
Example:
>>> # Stream transcription chunks in real-time
>>> for chunk in plugin.execute_stream(audio_file):
... print(chunk, end="", flush=True)
>>>
>>> # Or collect all chunks and get final result
>>> generator = plugin.execute_stream(audio_file)
>>> chunks = []
>>> for chunk in generator:
... chunks.append(chunk)
>>> result = generator.value # Final TranscriptionResult
"""
Classes
class PluginInterface(ABC):
"Base interface that all transcription plugins must implement."
def name(
self
-> str: # The unique identifier for this plugin
) "Unique plugin identifier."
def version(
self
-> str: # The semantic version string (e.g., "1.0.0")
) "Plugin version."
def supported_formats(
self
-> List[str]: # List of file extensions this plugin can process
) "List of supported audio formats (e.g., ['wav', 'mp3'])."
def initialize(
self,
str, Any]] = None # Configuration dictionary for plugin-specific settings
config: Optional[Dict[-> None
) "Initialize the plugin with configuration."
def execute(
self,
*args,
**kwargs
-> Any: # Returns transcription result or plugin-specific output
) "Transcribe audio to text."
def is_available(
self
-> bool: # True if all required dependencies are available
) "Check if the plugin's dependencies are available."
def get_config_schema(
-> Dict[str, Any]: # JSON Schema describing configuration options
) "Return JSON Schema describing the plugin's configuration options.
The schema should follow JSON Schema Draft 7 specification.
and validation.
This enables automatic UI generation
Example:
{"type": "object",
"properties": {
"model": {
"type": "string",
"enum": ["tiny", "base", "small"],
"default": "base",
"description": "Model size to use"
}
},"required": ["model"]
"
}
def get_current_config(
self
-> Dict[str, Any]: # Current configuration state
) "Return the current configuration state.
This should return the actual configuration being used by the plugin,
not explicitly set by the user."
which may include defaults
def validate_config(
self,
str, Any] # Configuration to validate
config: Dict[-> Tuple[bool, Optional[str]]: # (is_valid, error_message)
) "Validate a configuration dictionary against the schema.
Returns:
Tuple of (is_valid, error_message).is None."
If valid, error_message
def get_config_defaults(
self
-> Dict[str, Any]: # Default values from schema
) "Extract default values from the configuration schema.
Returns a dictionary of default values for all properties
in the schema."
that have defaults defined
def cleanup(
self
-> None
) "Optional cleanup when plugin is unloaded."
@dataclass
class PluginMeta:
"Metadata about a plugin."
str # The plugin's unique identifier
name: str # The plugin's version string
version: str = '' # A brief description of the plugin's functionality
description: str = '' # The plugin author's name or organization
author: str = '' # The Python package name containing the plugin
package_name: # The plugin instance
instance: Optional[PluginInterface] bool = True # Whether the plugin is enabled enabled:
plugin manager (plugin_manager.ipynb
)
Plugin discovery, loading, and lifecycle management system
Import
from cjm_transcription_plugin_system.plugin_manager import (
PluginManager,
get_plugin_config_schema,
get_plugin_config,
update_plugin_config,
validate_plugin_config,
get_all_plugin_schemas,
reload_plugin,
execute_plugin_stream,
check_streaming_support,
get_streaming_plugins )
Functions
def get_plugin_config_schema(
self,
str # Name of the plugin
plugin_name: -> Optional[Dict[str, Any]]: # Configuration schema or None if plugin not found
) """
Get the configuration schema for a plugin.
Returns the JSON Schema that describes all configuration options
available for the specified plugin.
"""
def get_plugin_config(
self,
str # Name of the plugin
plugin_name: -> Optional[Dict[str, Any]]: # Current configuration or None if plugin not found
) """
Get the current configuration of a plugin.
Returns the actual configuration values being used by the plugin,
including any defaults.
"""
def update_plugin_config(
self,
str, # Name of the plugin
plugin_name: str, Any], # New configuration
config: Dict[bool = True # Whether to merge with existing config or replace entirely
merge: -> bool: # True if successful, False otherwise
) """
Update a plugin's configuration and reinitialize it.
Args:
plugin_name: Name of the plugin to update
config: New configuration dictionary
merge: If True, merge with existing config. If False, replace entirely.
Returns:
True if configuration was successfully updated, False otherwise.
"""
def validate_plugin_config(
self,
str, # Name of the plugin
plugin_name: str, Any] # Configuration to validate
config: Dict[-> Tuple[bool, Optional[str]]: # (is_valid, error_message)
) """
Validate a configuration dictionary for a plugin without applying it.
Returns:
Tuple of (is_valid, error_message). If valid, error_message is None.
"""
def get_all_plugin_schemas(
self
-> Dict[str, Dict[str, Any]]: # Dictionary mapping plugin names to their schemas
) """
Get configuration schemas for all loaded plugins.
Returns a dictionary where keys are plugin names and values are
their configuration schemas.
"""
def reload_plugin(
self,
str, # Name of the plugin to reload
plugin_name: str, Any]] = None # Optional new configuration
config: Optional[Dict[-> bool: # True if successful, False otherwise
) """
Reload a plugin with optional new configuration.
This is useful when you want to completely restart a plugin,
for example after updating its code during development.
"""
def execute_plugin_stream(
self,
str, # Name of the plugin to execute
plugin_name: # Audio data or path
audio: Any, **kwargs # Additional arguments to pass to the plugin
-> Generator[str, None, Any]: # Generator yielding text chunks, returns final result
) """
Execute a plugin with streaming support if available.
This method will use the plugin's execute_stream method if the plugin
supports streaming, otherwise it falls back to the regular execute method.
Args:
plugin_name: Name of the plugin to execute
audio: Audio data or path to audio file
**kwargs: Additional plugin-specific parameters
Yields:
str: Partial transcription text chunks as they become available
Returns:
Final transcription result from the plugin
Example:
>>> # Stream transcription in real-time
>>> for chunk in manager.execute_plugin_stream("gemini", audio_file):
... print(chunk, end="", flush=True)
"""
def check_streaming_support(
self,
str # Name of the plugin to check
plugin_name: -> bool: # True if plugin supports streaming
) """
Check if a plugin supports streaming transcription.
Returns:
True if the plugin implements execute_stream and supports streaming,
False otherwise.
"""
def get_streaming_plugins(
self
-> List[str]: # List of plugin names that support streaming
) """
Get a list of all loaded plugins that support streaming.
Returns:
List of plugin names that have streaming capabilities.
"""
Classes
class PluginManager:
def __init__(self,
= PluginInterface, # The base class/interface plugins must implement
plugin_interface: Type[PluginInterface] str = "transcription.plugins" # The entry point group name for plugin discovery
entry_point_group:
)"Manages plugin discovery, loading, and lifecycle."
def __init__(self,
= PluginInterface, # The base class/interface plugins must implement
plugin_interface: Type[PluginInterface] str = "transcription.plugins" # The entry point group name for plugin discovery
entry_point_group:
)"Initialize the plugin manager."
def get_entry_points(
self
->importlib.metadata.EntryPoints
)"Get plugin entry points"
def discover_plugins(
self
-> List[PluginMeta]: # List of discovered plugin metadata objects
) "Discover all installed plugins via entry points.
This method looks for plugins installed as packages that declare
in the specified group."
entry points
def load_plugin(
self,
# The plugin metadata
plugin_meta: PluginMeta, str, Any]] = None # Optional configuration for the plugin
config: Optional[Dict[-> bool: # True if successfully loaded, False otherwise
) "Load and initialize a plugin."
def load_plugin_from_module(
self,
str, # Path to the Python module
module_path: str, Any]] = None # Optional configuration for the plugin
config: Optional[Dict[-> bool: # True if successfully loaded, False otherwise
) "Load a plugin directly from a Python module file or package.
Useful for development or local plugins."
def unload_plugin(
self,
str # Name of the plugin to unload
plugin_name: -> bool: # True if successfully unloaded, False otherwise
) "Unload a plugin and call its cleanup method."
def get_plugin(
self,
str # The name of the plugin to retrieve
plugin_name: -> Optional[PluginInterface]: # The plugin instance if found, None otherwise
) "Get a loaded plugin instance by name."
def list_plugins(
self
-> List[PluginMeta]: # List of metadata for all loaded plugins
) "List all loaded plugins."
def execute_plugin(
self,
str, # Name of the plugin to execute
plugin_name: *args, # Arguments to pass to the plugin
**kwargs # Key word arguments to pass to the plugin
-> Any: # The result of the plugin execution
) "Execute a plugin's main functionality."
def enable_plugin(
self,
str # The name of the plugin to enable
plugin_name: -> bool: # True if plugin was enabled, False if not found
) "Enable a plugin."
def disable_plugin(
self,
str # The name of the plugin to disable
plugin_name: -> bool: # True if plugin was disabled, False if not found
) "Disable a plugin without unloading it."