External plugins

July 31, 2026 · View on GitHub

Third-party media classifiers integrate through OPM (the OVOS Plugin Manager). A classifier is any subclass of AbstractMediaClassifier registered under the opm.media.classifier entry-point group. AbstractMediaClassifier is the contract the host relies on.

Registering a classifier

# my_pkg/__init__.py
from ovos_media_classifier import AbstractMediaClassifier, MediaType

class MyMediaClassifier(AbstractMediaClassifier):
    def __init__(self, config=None):
        self.config = config or {}

    def classify(self, query, lang, valid_labels=None):
        ...
        return MediaType.MUSIC, 0.9
# my_pkg's pyproject.toml
[project.entry-points."opm.media.classifier"]
my-classifier = "my_pkg:MyMediaClassifier"

The entry-point name (my-classifier) is how the host selects the plugin. A companion group opm.media.classifier.config mirrors other OPM types for shipping default per-plugin config.

Loading a classifier

Via the factory, by setting media_classifier_plugin in config:

from ovos_media_classifier import load_media_classifier

clf = load_media_classifier(config={"media_classifier_plugin": "my-classifier"})

The whole config dict is forwarded to the plugin constructor as config=…. If the plugin fails to load, the factory logs a warning and falls through to the built-in backends, an external plugin never hard-fails the pipeline.

Or load one directly:

from ovos_media_classifier import (
    load_media_classifier_plugin,
    find_media_classifier_plugins,
)

find_media_classifier_plugins()                 # {name: class} for installed plugins
clf = load_media_classifier_plugin("my-classifier", config={})

load_media_classifier_plugin raises ValueError if no plugin with that name is installed (the message lists the available names). It tolerates classifiers whose __init__ takes no config kwarg. find_media_classifier_plugins() never raises, it returns {} when the plugin manager is unavailable.

Implementing the contract

A plugin must implement classify(). It may override classify_domain(), is_ocp_query(), and classify_genres() when it has cheaper or richer signal, e.g. a dedicated domain head, control-intent support, or genre detection so the content filter can block on it. See stable-api.md for the full contract and the default implementations.

A trained plugin SHOULD also override the coarse-axis methods (classify_playback_type(), classify_structure(), classify_full()) to predict each axis with its own head and soft-gate the leaf, rather than relying on the derive-from-leaf defaults, that is the whole point of the multi-axis model and is what the TigreGotico/ocp-media-intents dataset's per-axis columns are for. See classification-model.md.


← Content filtering · Home · Stable API →