Skip to main content

Typed voice-activity-detection task-adapter interface — VADAdapter ABC + GenericVADAdapter (cache/persist bookends around a pure-compute tool), the VADToolProtocol, and VAD persistence helpers. The VADResult data noun lives in cjm-capability-primitives.

Project description

cjm-vad-adapter-interface

Install

pip install cjm_vad_adapter_interface

Project Structure

nbs/
├── adapter.ipynb # The typed voice-activity-detection task contract — the `VADAdapter` ABC + the `VADToolProtocol` structural contract (capability-unit Option C, pass-2 Thread 3).
├── generic.ipynb # The generic (tool-agnostic) VAD adapter — cache-check, invoke the bound tool's pure-compute `detect_speech`, persist. Reused across every tool capability satisfying `VADToolProtocol`, exactly as `GenericTranscriptionAdapter` is reused across transcribers.
└── storage.ipynb # Standardized SQLite storage for voice-activity-detection results with content hashing.

Total: 3 notebooks

Module Dependencies

graph LR
    adapter["adapter<br/>VAD Adapter"]
    generic["generic<br/>Generic VAD Adapter"]
    storage["storage<br/>VAD Storage"]

    generic --> adapter
    generic --> storage

2 cross-module dependencies detected

CLI Reference

No CLI commands found in this project.

Module Overview

Detailed documentation for each module in the project:

VAD Adapter (adapter.ipynb)

The typed voice-activity-detection task contract — the VADAdapter ABC + the VADToolProtocol structural contract (capability-unit Option C, pass-2 Thread 3).

Import

from cjm_vad_adapter_interface.adapter import (
    VADToolProtocol,
    VADAdapter
)

Classes

@runtime_checkable
class VADToolProtocol(Protocol):
    """
    Structural contract for voice-activity-detection tool capabilities
    (born-final at stage 8 — derived from the native tool surface).
    
    Pure compute: `detect_speech` reads the model-ready audio + runs inference +
    builds the typed result. `get_current_config` supplies the effective config
    the generic adapter hashes for its cache key. Persistence is NOT here — the
    adapter owns it (the native-surface seam).
    """
    
    def detect_speech(self, audio: Union[str, Path], **kwargs) -> VADResult: ...
        def get_current_config(self) -> Dict[str, Any]: ...
    
    def get_current_config(self) -> Dict[str, Any]: ...
class VADAdapter:
    def __init__(
        self,
        tool: VADToolProtocol,  # The bound tool capability instance (worker-side binding)
    )
    """
    Typed voice-activity-detection task adapter: model-ready audio in,
    `VADResult` out.
    
    Input contract: the caller guarantees MODEL-READY audio — format /
    sample-rate / channel handling happens upstream (ffmpeg `convert`), never
    in the adapter or tool.
    
    Native-surface model (stage 8 / PILLAR 1c): the TOOL is pure compute; the
    ADAPTER owns the cache + persistence bookends (see `GenericVADAdapter`) +
    the per-call `force` control. Storage resolves from the substrate-injected
    `PLUGIN_DATA_DIR`; `db_path` is not on the tool protocol.
    
    Implementations run in-worker beside their tool capability and are
    constructed with the bound tool instance: `AdapterClass(tool)` (mirrors
    `GraphStorageAdapter`). The result DTO is wire-registered ("vad.result"):
    returned values cross the worker boundary typed.
    """
    
    def __init__(
            self,
            tool: VADToolProtocol,  # The bound tool capability instance (worker-side binding)
        )
    
    def detect_speech(
            self,
            audio: Union[str, Path],  # Path to MODEL-READY audio (converted upstream)
            **kwargs,                 # Provenance + tool options
        ) -> VADResult:               # Typed VAD output
        "Detect speech segments in model-ready audio."

Generic VAD Adapter (generic.ipynb)

The generic (tool-agnostic) VAD adapter — cache-check, invoke the bound tool’s pure-compute detect_speech, persist. Reused across every tool capability satisfying VADToolProtocol, exactly as GenericTranscriptionAdapter is reused across transcribers.

Import

from cjm_vad_adapter_interface.generic import (
    GenericVADAdapter
)

Classes

class GenericVADAdapter(VADAdapter):
    """
    Generic VAD adapter: cache-check -> pure-compute tool -> persist.
    
    Works against ANY tool satisfying `VADToolProtocol`. The bookends:
    
      1. cache check (file_path + file_hash + config_hash) BEFORE invoking the
         tool, so a hit never loads the model;
      2. the tool's pure-compute `detect_speech` on a miss / forced call;
      3. `save_with_logging` (upsert by file_path + config_hash).
    
    `config_hash` reuses `hash_dict_canonical(get_current_config())` (the SAME
    canonical hash the fused-era plugin used). `force` rides
    `CallEnvelope.control` (not a task kwarg, keeping `detect_speech(audio)`
    pure). Storage lives at `<PLUGIN_DATA_DIR>/vad.db`; the substrate injects
    the per-capability `PLUGIN_DATA_DIR` at spawn, so the adapter neither
    hard-codes a path nor asks the tool for one.
    """
    
    def detect_speech(
            self,
            audio: Union[str, Path],  # Path to MODEL-READY audio (converted upstream)
            **kwargs,                 # Provenance + tool options
        ) -> VADResult:               # Typed VAD output
        "Cache-check, invoke the bound tool's pure-compute `detect_speech`, persist."

VAD Storage (storage.ipynb)

Standardized SQLite storage for voice-activity-detection results with content hashing.

Import

from cjm_vad_adapter_interface.storage import (
    VADRow,
    VADStorage
)

Classes

@dataclass
class VADRow:
    "A single row from the vad_results table."
    
    file_path: str  # Path to the analyzed (model-ready) audio file
    file_hash: str  # Hash of the analyzed file in "algo:hexdigest" format
    config_hash: str  # Hash of the VAD detection config used
    ranges: Optional[List[Dict[str, Any]]]  # Detected speech segments (serialized TimeRanges)
    metadata: Optional[Dict[str, Any]]  # VAD metadata
    created_at: Optional[float]  # Unix timestamp
class VADStorage:
    def __init__(
        self,
        db_path: str  # Absolute path to the SQLite database file
    )
    "Standardized SQLite storage for voice-activity-detection results."
    
    def __init__(
            self,
            db_path: str  # Absolute path to the SQLite database file
        )
        "Initialize storage and create table if needed."
    
    def save(
            self,
            file_path: str,     # Path to the analyzed audio file
            file_hash: str,     # Hash of the analyzed file in "algo:hexdigest" format
            config_hash: str,   # Hash of the VAD detection config
            ranges: Optional[List[Dict[str, Any]]] = None,  # Detected speech segments
            metadata: Optional[Dict[str, Any]] = None        # VAD metadata
        ) -> None
        "Save or replace a VAD result (upsert by file_path + config_hash)."
    
    def save_with_logging(
            self,
            *,
            file_path: str,     # Path to the analyzed audio file
            file_hash: str,     # Hash of the analyzed file in "algo:hexdigest" format
            config_hash: str,   # Hash of the VAD detection config
            ranges: Optional[List[Dict[str, Any]]] = None,  # Detected speech segments
            metadata: Optional[Dict[str, Any]] = None,       # VAD metadata
            logger: Optional[logging.Logger] = None           # Optional logger for success/failure messages
        ) -> bool:  # True if saved; False if the save failed (error logged, not raised)
        "Save a result, logging success/failure. Failures are logged and swallowed (returns False).

CR-14 follow-up: records a RESULT_SAVED account either way (ok flag +
file/config references  the journal never carries content) so saves AND
swallowed save-failures become auditable journal rows."
    
    def get_cached(
            self,
            file_path: str,   # Path to the audio file
            file_hash: str,   # Content hash of the file (cache miss if the file changed)
            config_hash: str  # Config hash to match
        ) -> Optional[VADRow]:  # Cached row or None
        "Retrieve a content-correct cached VAD result.

Matches on file_path + file_hash + config_hash, so a changed file (new
file_hash) misses the cache even though a stale row may still exist at the
same (file_path, config_hash)  the next save() replaces it.

CR-14 follow-up: a hit records a CACHE_HIT account (the cache-serving
decision is an account-of-action)."
    
    def list_jobs(
            self,
            limit: int = 100  # Maximum number of rows to return
        ) -> List[VADRow]:  # List of VAD rows
        "List VAD results ordered by creation time (newest first)."
    
    def verify_file(
            self,
            file_path: str,   # Path to the audio file
            config_hash: str  # Config hash to look up
        ) -> Optional[bool]:  # True if file matches, False if changed, None if not found
        "Verify the analyzed file still matches the hash stored for (file_path, config_hash)."

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cjm_vad_adapter_interface-0.0.4.tar.gz (12.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cjm_vad_adapter_interface-0.0.4-py3-none-any.whl (15.8 kB view details)

Uploaded Python 3

File details

Details for the file cjm_vad_adapter_interface-0.0.4.tar.gz.

File metadata

File hashes

Hashes for cjm_vad_adapter_interface-0.0.4.tar.gz
Algorithm Hash digest
SHA256 34fda0afd589f58a885f1ed284f7ea41582b5fab6e0a4fd78d20519b6dc3e8b2
MD5 9a02cd98ded1f41a841ad26d28e04594
BLAKE2b-256 206c6c60adc02c65ac9b111dc380590fc22c7020541ea0a9ac314ed8be47b23e

See more details on using hashes here.

File details

Details for the file cjm_vad_adapter_interface-0.0.4-py3-none-any.whl.

File metadata

File hashes

Hashes for cjm_vad_adapter_interface-0.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 894cd21f3829fde5f5a16399e94853f054aa57a5dc2d8cc286d33bf68049ac3f
MD5 d9cf5dc32a7b3288ccd6b34b87b93907
BLAKE2b-256 2947c5da01a62db3dadb007c3a71683155a659f5215e6bed73f915f2c478a9e3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page