From 1f81731fc2843b8b9285154a28bf30539a657a97 Mon Sep 17 00:00:00 2001 From: JarbasAi Date: Fri, 6 Oct 2023 04:58:24 +0100 Subject: [PATCH] feat/ovos_dialog_tts_transformers listener has AudioTransformers core has MetadataTransformers and UtteranceTransformers this PR extends the concept to ovos-audio for text before TTS stage, and wav file after TTS but before playback use case demonstration https://gist.github.com/JarbasAl/16788bdcff3fa5bfb3634d6f2116cc04 this ties into https://github.com/OpenVoiceOS/ovos-persona/issues/4 --- .gitignore | 1 + ovos_plugin_manager/dialog_transformers.py | 41 +++++++++++ ovos_plugin_manager/templates/transformers.py | 68 ++++++++++++++++++- ovos_plugin_manager/utils/__init__.py | 4 ++ 4 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 ovos_plugin_manager/dialog_transformers.py diff --git a/.gitignore b/.gitignore index 9595be50..c8ece8cf 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ dist # Created by unit tests .pytest_cache/ +/.gtm/ diff --git a/ovos_plugin_manager/dialog_transformers.py b/ovos_plugin_manager/dialog_transformers.py new file mode 100644 index 00000000..ef0b6f8d --- /dev/null +++ b/ovos_plugin_manager/dialog_transformers.py @@ -0,0 +1,41 @@ +from ovos_plugin_manager.templates.transformers import DialogTransformer, TTSTransformer +from ovos_plugin_manager.utils import PluginTypes +from ovos_plugin_manager.utils import load_plugin, find_plugins + + +def find_dialog_transformer_plugins() -> dict: + """ + Find all installed plugins + @return: dict plugin names to entrypoints + """ + return find_plugins(PluginTypes.DIALOG_TRANSFORMER) + + +def load_dialog_transformer_plugin(module_name: str) -> type(DialogTransformer): + """Wrapper function for loading dialog_transformer plugin. + + Arguments: + (str) Mycroft dialog_transformer module name from config + Returns: + class: found dialog_transformer plugin class + """ + return load_plugin(module_name, PluginTypes.DIALOG_TRANSFORMER) + + +def find_tts_transformer_plugins() -> dict: + """ + Find all installed plugins + @return: dict plugin names to entrypoints + """ + return find_plugins(PluginTypes.TTS_TRANSFORMER) + + +def load_tts_transformer_plugin(module_name: str) -> type(TTSTransformer): + """Wrapper function for loading dialog_transformer plugin. + + Arguments: + (str) Mycroft dialog_transformer module name from config + Returns: + class: found dialog_transformer plugin class + """ + return load_plugin(module_name, PluginTypes.TTS_TRANSFORMER) diff --git a/ovos_plugin_manager/templates/transformers.py b/ovos_plugin_manager/templates/transformers.py index 363ff614..06fcb9d6 100644 --- a/ovos_plugin_manager/templates/transformers.py +++ b/ovos_plugin_manager/templates/transformers.py @@ -7,7 +7,7 @@ class MetadataTransformer: - + """ runs after utterance transformers and before intent service""" def __init__(self, name, priority=50, config=None): self.name = name self.bus = None @@ -41,7 +41,7 @@ def default_shutdown(self): class UtteranceTransformer: - + """ runs before metadata transformers and intent service""" def __init__(self, name, priority=50, config=None): self.name = name self.bus = None @@ -165,3 +165,67 @@ def transform(self, audio_data): def default_shutdown(self): """ perform any shutdown actions """ pass + + +class DialogTransformer: + """ runs before TTS stage""" + def __init__(self, name, priority=50, config=None): + self.name = name + self.bus = None + self.priority = priority + if not config: + config_core = dict(Configuration()) + config = config_core.get("dialog_transformers", {}).get(self.name) + self.config = config or {} + + def bind(self, bus=None): + """ attach messagebus """ + self.bus = bus or get_mycroft_bus() + + def initialize(self): + """ perform any initialization actions """ + pass + + def transform(self, dialog: str) -> str: + """ + Optionally transform passed dialog and/or return additional context + :param dialog: str utterance to mutate before TTS + :returns: str mutated dialog + """ + return dialog, {} + + def default_shutdown(self): + """ perform any shutdown actions """ + pass + + +class TTSTransformer: + """ runs after TTS stage but before playback""" + def __init__(self, name, priority=50, config=None): + self.name = name + self.bus = None + self.priority = priority + if not config: + config_core = dict(Configuration()) + config = config_core.get("dialog_transformers", {}).get(self.name) + self.config = config or {} + + def bind(self, bus=None): + """ attach messagebus """ + self.bus = bus or get_mycroft_bus() + + def initialize(self): + """ perform any initialization actions """ + pass + + def transform(self, wav_file: str, context: dict = None) -> str: + """ + Optionally transform passed wav_file and return path to transformed file + :param wav_file: path to wav file generated in TTS stage + :returns: path to transformed wav file for playback + """ + return wav_file + + def default_shutdown(self): + """ perform any shutdown actions """ + pass diff --git a/ovos_plugin_manager/utils/__init__.py b/ovos_plugin_manager/utils/__init__.py index 350823a6..bb0f8d85 100644 --- a/ovos_plugin_manager/utils/__init__.py +++ b/ovos_plugin_manager/utils/__init__.py @@ -39,6 +39,8 @@ class PluginTypes(str, Enum): UTTERANCE_TRANSFORMER = "neon.plugin.text" METADATA_TRANSFORMER = "neon.plugin.metadata" AUDIO_TRANSFORMER = "neon.plugin.audio" + DIALOG_TRANSFORMER = "opm.transformer.dialog" + TTS_TRANSFORMER = "opm.transformer.tts" QUESTION_SOLVER = "neon.plugin.solver" TLDR_SOLVER = "opm.solver.summarization" ENTAILMENT_SOLVER = "opm.solver.entailment" @@ -71,6 +73,8 @@ class PluginConfigTypes(str, Enum): UTTERANCE_TRANSFORMER = "neon.plugin.text.config" METADATA_TRANSFORMER = "neon.plugin.metadata.config" AUDIO_TRANSFORMER = "neon.plugin.audio.config" + DIALOG_TRANSFORMER = "opm.transformer.dialog.config" + TTS_TRANSFORMER = "opm.transformer.tts.config" QUESTION_SOLVER = "neon.plugin.solver.config" TLDR_SOLVER = "opm.solver.summarization.config" ENTAILMENT_SOLVER = "opm.solver.entailment.config"