Transformer Plugins¶
In a nutshell
Your voice travels through the assistant: from raw sound, to written words, to a matched request, to the spoken reply. Transformer plugins are optional helpers that can tidy or tweak the information at each step. Think of them as filters on an assembly line. One might clean up background noise. Another might fix a misheard word before the system tries to understand it. They don't take over any step. They just polish what passes between steps. See the Glossary for related terms.
Formal specification
The transformer subsystem is specified by OVOS-TRANSFORM-1: Transformer Plugins (one of the formal architecture specs). It defines six ordered chains: audio, utterance, metadata, intent, dialog, tts. These run at fixed points in the utterance lifecycle. It also defines the per-type input/output contract for each, the per-session ordering and denylist overrides, and the utterance-cancellation signal. A transformer is identified by its (type, transformer_id) pair. Where this manual or the current code diverges from the spec, the spec is canonical.
Ordering. OVOS-TRANSFORM-1 §4 orders each chain by ascending priority. A lower number runs earlier, and the default is 50. The current OVOS code follows this: a plugin with priority=1 runs first, and later plugins see and may override its output. A legacy descending order is still available as an explicit opt-in (sort_ascending=False, marked deprecated in ovos_plugin_manager/transformer_services.py) for deployments that depend on the old behavior.
Transformer plugins let you intercept and modify data as it flows through the transformer chain. Each type is a small class with a transform() method that runs at a fixed stage. Examples are turning raw audio into cleaner audio, fixing transcribed text before intent matching, enriching a matched intent, or post-processing speech before playback.
A transformer never replaces a stage. It sits between two stages and reshapes what passes through. Several plugins of the same type can be active at once. They run in sequence, lowest priority first, so each one builds on the output of the previous.
Synchronous contract: keep transformers fast
transform() (and on_audio()/on_speech()) are plain synchronous methods. The chain
runner calls each one inline, in order, on the thread that owns the chain. A slow
transformer blocks the owning service for its full duration. There is no background
execution or timeout. This matters most for AudioTransformer, which sits on the
real-time audio path. Keep its work fast, and offload anything heavy (model inference,
network calls) to a background thread/process instead of doing it inside transform().
There is no async return path back into the chain. transform() is called inline and
must return before the chain can proceed, so it cannot await a background job's result
mid-chain. "Offload the heavy work" only helps if transform() can return
cached/previous data immediately on each call, while the background thread/process
updates that cache for the next call to pick up. The current call never blocks on
the background job finishing.
Transformer Types¶
All base classes live in ovos_plugin_manager.templates.transformers and share the same constructor: __init__(self, name, priority=50, config=None), plus bind(bus) and initialize(). The loader (TransformersService.load_plugins() in ovos_plugin_manager.transformer_services) only ever instantiates a plugin as plug(config=plugin_config). It does not pass name or priority. Since the base class has no default for name, every plugin must override __init__ to supply its own name (and usually a default priority). Each plugin must call super().__init__(name, priority, config) so the base class still gets them.
A "priority" key in a plugin's mycroft.conf block is not applied automatically. The plugin must read it back out of self.config itself if it wants deployments to override priority (see Utterance Transformers: Config-driven priority).
Config shape (the six chained types)¶
Six of the seven sections below are chains: every loaded plugin runs, one after
another. The seventh, typed_slots_transformers, reads its section the same way
but runs only one plugin; see Typed-slots transformers
for where it differs.
Every chain's mycroft.conf section follows the same rules (TransformersService.load_plugins() in ovos_plugin_manager.transformer_services):
- Each key in the section is an enabled plugin's entry-point name, except the two
reserved keys
orderandblacklisted_skills, which are not plugin entries. - A plugin block with
"active": falseis still loaded but skipped when the chain runs. - An
"order"key, if present, is a list of plugin names giving the run order explicitly. It wins over ascending-priority sorting; a loaded plugin absent from the list is not run. Plugins named inorderare treated as enabled even with no config block of their own.
Two runtime behaviors from OVOS-TRANSFORM-1 apply in the shared service bases
(transformer_services.py):
- Provenance stamping (§1.3), utterance and metadata chains only: as each transformer
runs, its name is appended to a list in the message context
(
utterance_transformer_ids,metadata_transformer_ids), so downstream consumers can see which plugins touched the data and in what order. The intent chain does not stamp provenance. - Wrong-shape rejection (§7): a transformer that returns the wrong tuple shape or a
non-dict context is logged with a warning and its output discarded — the chain
continues with the previous output. An intent transformer that mutates
match_typeorskill_idis discarded the same way (§3.4). If your transformer seems to have no effect, check the service log for a "returned wrong shape" warning.
{
"utterance_transformers": {
"order": ["ovos-utterance-cancel-plugin", "ovos-utterance-normalizer"],
"ovos-utterance-cancel-plugin": {},
"ovos-utterance-normalizer": {}
}
}
| Type | Stage | Base Class | Entry-point group |
|---|---|---|---|
| Audio | Before STT | AudioTransformer |
opm.transformer.audio |
| Utterance | After STT, before Intent | UtteranceTransformer |
opm.transformer.text |
| Metadata | After Utterance, before Intent | MetadataTransformer |
opm.transformer.metadata |
| Intent | After Intent match, before Skill | IntentTransformer |
opm.transformer.intent |
| Dialog | Before TTS | DialogTransformer |
opm.transformer.dialog |
| TTS | After TTS, before Playback | TTSTransformer |
opm.transformer.tts |
| Typed slots | After Metadata, before the first matcher | TypedSlotsTransformer |
opm.transformer.typed_slots |
ovos-plugin-manager also honors the deprecated Neon entry-point groups neon.plugin.text,
neon.plugin.metadata and neon.plugin.audio as aliases for opm.transformer.text,
opm.transformer.metadata and opm.transformer.audio (with a deprecation warning). There is
no such alias for the intent, dialog, TTS or typed-slots groups — a plugin registered only
under a legacy name for those four groups is not discovered.
The runner classes that load and chain these plugins live in ovos-plugin-manager (ovos_plugin_manager.transformer_services): UtteranceTransformersService, MetadataTransformersService, IntentTransformersService, AudioTransformersService, DialogTransformersService, TTSTransformersService. Each consumer imports the one it needs. ovos-core runs the utterance/metadata/intent chains, the listener runs the audio chain, and the audio/TTS stacks run the dialog/TTS chains. The typed-slots stage has its own runner, TypedSlotsTransformersService in ovos_core.transformers, because it selects rather than chains.
1. Audio Transformers¶
Entry point: opm.transformer.audio
Used to process or transform raw audio before it reaches the STT engine. Common use cases include noise reduction, volume normalization, or streaming language detection.
Template¶
from ovos_plugin_manager.templates.transformers import AudioTransformer
class MyAudioTransformer(AudioTransformer):
def on_audio(self, audio_data):
# Process non-speech chunks
return audio_data
def on_speech(self, audio_data):
# Process speech chunks during recording
return audio_data
def transform(self, audio_data):
# Final transformation and optional context injection
return audio_data, {"extra_metadata": "value"}
2. Utterance Transformers¶
Entry point: opm.transformer.text
Used to modify the transcribed text (utterances) before they are sent to the intent service. Common use cases include spelling correction, filtering, or expansion. See Utterance Transformers for details.
Template¶
from ovos_plugin_manager.templates.transformers import UtteranceTransformer
class MyUtteranceTransformer(UtteranceTransformer):
def transform(self, utterances, context=None):
# utterances is a list of strings
transformed = [u.upper() for u in utterances]
return transformed, context
3. Metadata Transformers¶
Entry point: opm.transformer.metadata
Used to inject or modify metadata in the message context. This runs after utterance transformers but before intent matching. transform(context) returns a (possibly modified) context dict.
4. Intent Transformers¶
Entry point: opm.transformer.intent
Used to modify the IntentHandlerMatch object. This runs after a pipeline match is found but before the skill is triggered. See Intent Transformers for details.
5. Dialog Transformers¶
Entry point: opm.transformer.dialog
Used to modify the text that OVOS is about to speak, just before it is sent to the TTS engine.
6. TTS Transformers¶
Entry point: opm.transformer.tts
Used to process the generated WAV file after TTS synthesis but before it is played back.
7. Typed-slots Transformers¶
Entry point: opm.transformer.typed_slots
Computes the typed-slots map for an utterance: the number, date, duration and
colour spans that intents ask for with the {type:name} syntax. It runs after the
utterance and metadata chains and before the first matcher, so a matcher and a
skill handler both see the same resolved values. Skill authors read the result
with self.typed_slot(), described in
Padatious Intents: Typed slots.
ovos-typed-slots-transformer is the plugin that ships in the bundled
mycroft.conf, and it uses the OVOS parser libraries to do the work.
This stage reads its config section like the six chains above, but it does not chain. Four differences matter to a plugin author:
- One plugin runs, not all of them. The stage produces a single map, so the
runner picks one plugin and ignores the rest: the first name in an explicit
orderlist, or otherwise the lowestprioritynumber. Two plugins loaded at the same priority with noorderlist is a warning, and the choice between them is stable but unspecified. - A different
transform()signature. It takes the candidate utterances, the set of types the registered intents declared, and theSession, and it returns a map of type name to a list of{"span": [start, end], "surface": str, "value": ...}entries. It must not touchutterancesorMessage.context; that is an utterance or metadata transformer's job. supported_typesdescribes, it does not gate. A plugin declares the types it can compute, and the runner reads that as documentation only. It never withholds the call from a plugin whose declared types look irrelevant. A transformer may compute every registered type where the deployment asks for that, so skipping it on the strength of its declaration would discard values it was entitled to produce.- No provenance stamping. Like the intent chain, this stage appends nothing to the message context.
A plugin that raises, or returns anything that is not a dictionary, is treated as having produced nothing. That is not the same as producing an empty map: an absent map means the value was never computed, while an empty one means the plugin looked and found nothing.
Standalone Usage¶
You can use transformers independently of the full OVOS stack. Here is an example with an UtteranceTransformer:
from ovos_plugin_manager.text_transformers import find_utterance_transformer_plugins
# Find and load the plugin (returns {plugin_name: class})
plugins = find_utterance_transformer_plugins()
transformer_class = plugins["ovos-utterance-normalizer"]
transformer = transformer_class() # base __init__ supplies the name
# Transform an utterance (utterances is a list of strings)
utterances = ["hello world"]
transformed, context = transformer.transform(utterances)
print(f"Transformed: {transformed}")
The discovery helpers (find_*_transformer_plugins, load_*_transformer_plugin) live in
ovos_plugin_manager.text_transformers, .intent_transformers, .metadata_transformers,
.audio_transformers, and .dialog_transformers.
find_tts_transformer_plugins / load_tts_transformer_plugin live in their own
ovos_plugin_manager.tts_transformers module. ovos_plugin_manager.dialog_transformers
re-exports both names for backwards compatibility, but that module is not their canonical
home.
Writing a plugin instead of choosing one? See Writing a Transformer Plugin, which covers inheriting from the base class, registering the entry point, packaging, and testing.
Transformer plugins Reference¶
| Plugin | Description | Maturity |
|---|---|---|
| ovos-dialog-normalizer-plugin | a dialog transformer plugins for OVOS | Stable |
| ovos-bidirectional-translation-plugin | This package includes a UtteranceTransformer plugin and a DialogTransformer plugin, they work together to allow OVOS to speak in ANY language | Stable |
| ovos-audio-transformer-plugin-speechbrain-langdetect | spoken language detector for ovos | Stable |
| ovos-utterance-corrections-plugin | This plugin provides tools to correct or adjust speech-to-text (STT) outputs for better intent matching or improved user experience. | Stable |
| ovos-utterance-normalizer | normalizes utterances before intent parsing | Stable |
| ovos-utterance-plugin-cancel | looks at the end of the transcribed phrase and ignores it if it ends with "nevermind that", "cancel it", or "ignore that". | Stable |
| ovos-audio-transformer-plugin-ggwave | plugin for ggwave | Mature |
| ovos-tts-transformer-sox-plugin | A Text-to-Speech (TTS) transformer that uses SoX (Sound eXchange) for audio processing. The transformer applies various effects to the generated audio before playback. | Beta |
| ovos_tts_transformer_FlashSR | ONNX-based audio super-resolution that upsamples synthesized TTS audio before playback (not yet on PyPI). | Proof-of-concept |
| ovos_tts_transformer_NovaSR | torch-based audio super-resolution upsampler for synthesized TTS audio (not yet on PyPI). | Proof-of-concept |
Maturity reflects repository health (age, activity, open issues/PRs, in-repo docs), not version. See the Maturity Scale.
ovos-dialog-normalizer-plugin¶
-
Description: a dialog transformer plugins for OVOS
ovos-bidirectional-translation-plugin¶
-
Description: This package includes a UtteranceTransformer plugin and a DialogTransformer plugin, they work together to allow OVOS to speak in ANY language
ovos-audio-transformer-plugin-speechbrain-langdetect¶
-
GitHub: OpenVoiceOS/ovos-audio-transformer-plugin-speechbrain-langdetect
-
Description: spoken language detector for ovos
ovos-utterance-corrections-plugin¶
-
Description: This plugin provides tools to correct or adjust speech-to-text (STT) outputs for better intent matching or improved user experience.
ovos-utterance-normalizer¶
-
Description: normalizes utterances before intent parsing
ovos-utterance-plugin-cancel¶
-
Description: looks at the end of the transcribed phrase and ignores it if it ends with "nevermind that", "cancel it", or "ignore that".
ovos-audio-transformer-plugin-ggwave¶
-
Description: plugin for ggwave
ovos-tts-transformer-sox-plugin¶
-
Description: A Text-to-Speech (TTS) transformer that uses SoX (Sound eXchange) for audio processing. The transformer applies various effects to the generated audio before playback.
ovos_tts_transformer_FlashSR¶
-
Description: ONNX-based audio super-resolution TTS transformer (
FlashSRTTSTransformer). It upsamples synthesized audio before playback, downloading its model from the Hugging Face Hub. Entry pointovos-tts-transformer-FlashSRunderopm.transformer.tts. Upcoming: not yet published to PyPI.
ovos_tts_transformer_NovaSR¶
-
Description: torch-based super-resolution upsampler TTS transformer (
NovaSRTTSTransformer). Entry pointovos-tts-transformer-NovaSRunderopm.transformer.tts. Upcoming: not yet published to PyPI.
Read next: Utterance Transformers Related: Pipelines Overview · Dialog Transformers · LLM Transformers