diff --git a/CHANGELOG.md b/CHANGELOG.md index e167f643..116b0278 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [2.1.0a1](https://github.com/OpenVoiceOS/ovos-plugin-manager/tree/2.1.0a1) (2025-11-04) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/2.0.1a1...2.1.0a1) + +**Merged pull requests:** + +- feat: ww verifier [\#341](https://github.com/OpenVoiceOS/ovos-plugin-manager/pull/341) ([JarbasAl](https://github.com/JarbasAl)) + ## [2.0.1a1](https://github.com/OpenVoiceOS/ovos-plugin-manager/tree/2.0.1a1) (2025-10-07) [Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/2.0.0a2...2.0.1a1) @@ -27,19 +35,19 @@ ## [2.0.0a1](https://github.com/OpenVoiceOS/ovos-plugin-manager/tree/2.0.0a1) (2025-07-22) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/1.0.4a3...2.0.0a1) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/1.0.4a2...2.0.0a1) **Breaking changes:** - feat!: add collections and batch operations support to embeddings plu… [\#333](https://github.com/OpenVoiceOS/ovos-plugin-manager/pull/333) ([JarbasAl](https://github.com/JarbasAl)) -## [1.0.4a3](https://github.com/OpenVoiceOS/ovos-plugin-manager/tree/1.0.4a3) (2025-07-22) +## [1.0.4a2](https://github.com/OpenVoiceOS/ovos-plugin-manager/tree/1.0.4a2) (2025-07-22) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/1.0.4a2...1.0.4a3) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/1.0.4a3...1.0.4a2) -## [1.0.4a2](https://github.com/OpenVoiceOS/ovos-plugin-manager/tree/1.0.4a2) (2025-07-22) +## [1.0.4a3](https://github.com/OpenVoiceOS/ovos-plugin-manager/tree/1.0.4a3) (2025-07-22) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/1.0.4a1...1.0.4a2) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/1.0.4a1...1.0.4a3) **Merged pull requests:** diff --git a/downstream_report.txt b/downstream_report.txt index ccd06e82..ec0c4349 100644 --- a/downstream_report.txt +++ b/downstream_report.txt @@ -6,6 +6,8 @@ ovos-plugin-manager==1.0.4a2 ├── ovos-adapt-parser==1.0.8 [requires: ovos-plugin-manager>=0.5.0,<2.0.0] ├── ovos-solver-failure-plugin==0.0.2 [requires: ovos-plugin-manager>=0.0.26,<2.0.0] │ └── ovos-persona==0.6.23 [requires: ovos-solver-failure-plugin] +├── ovos-audio==1.1.0a1 [requires: ovos-plugin-manager>=0.0.26,<2.0.0] +│ └── ovos-skill-laugh==0.2.3 [requires: ovos-audio] ├── ovos-translate-server-plugin==0.0.4 [requires: ovos-plugin-manager>=1.0.0,<2.0.0] │ ├── ovos-skill-ddg==0.3.6a2 [requires: ovos-translate-server-plugin] │ └── ovos-skill-wordnet==0.2.6a1 [requires: ovos-translate-server-plugin] @@ -18,17 +20,16 @@ ovos-plugin-manager==1.0.4a2 ├── ovos-dinkum-listener==0.4.2a3 [requires: ovos-plugin-manager>=1.0.2,<2.0.0] ├── ovos-media-plugin-chromecast==0.1.2 [requires: ovos-plugin-manager>=0.0.26,<2.0.0] ├── ovos-tts-plugin-server==0.0.4 [requires: ovos-plugin-manager>=1.0.0,<2.0.0] -├── ovos-common-query-pipeline-plugin==1.1.9a1 [requires: ovos-plugin-manager>=1.0.0,<2.0.0] ├── ovos-dialog-normalizer-plugin==0.0.1 [requires: ovos-plugin-manager] ├── ovos-persona==0.6.23 [requires: ovos-plugin-manager>=0.8.3,<2.0.0] ├── ovos-utterance-corrections-plugin==0.1.1 [requires: ovos-plugin-manager>=0.0.1,<2.0.0] -├── ovos-ocp-pipeline-plugin==1.1.18a1 [requires: ovos-plugin-manager>=1.0.0,<2.0.0] ├── ovos-utterance-normalizer==0.2.2 [requires: ovos-plugin-manager>=0.0.25,<2.0.0] -│ ├── ovos-skill-volume==0.1.17a2 [requires: ovos-utterance-normalizer>=0.0.1,<1.0.0] │ ├── ovos-skill-date-time==1.1.6a1 [requires: ovos-utterance-normalizer>=0.0.1,<1.0.0] │ ├── ovos-skill-weather==1.0.8a3 [requires: ovos-utterance-normalizer>=0.0.1,<1.0.0] +│ ├── ovos-skill-volume==0.1.17a3 [requires: ovos-utterance-normalizer>=0.0.1,<1.0.0] │ └── ovos-skill-alerts==0.1.28a1 [requires: ovos-utterance-normalizer>=0.0.1,<1.0.0] ├── ovos-phal-plugin-ipgeo==0.1.6 [requires: ovos-plugin-manager>=0.0.1,<2.0.0] +├── ovos-core==2.1.0 [requires: ovos-plugin-manager>=1.0.3,<2.0.0] ├── ovos-m2v-pipeline==0.0.6 [requires: ovos-plugin-manager>=0.5.0,<2.0.0] ├── ovos-PHAL==0.2.10 [requires: ovos-plugin-manager>=0.0.25,<2.0.0] ├── ovos-gui==1.3.4a1 [requires: ovos-plugin-manager>=0.5.5,<2.0.0] @@ -50,37 +51,37 @@ ovos-plugin-manager==1.0.4a2 │ ├── ovos-skill-fuster-quotes==0.0.4 [requires: ovos-workshop] │ ├── ovos-skill-local-media==0.2.13a1 [requires: ovos-workshop>=2.4.0,<8.0.0] │ ├── ovos-skill-pyradios==0.1.5 [requires: ovos-workshop>=0.0.16,<8.0.0] -│ ├── ovos-common-query-pipeline-plugin==1.1.9a1 [requires: ovos-workshop>=0.1.7,<8.0.0] -│ ├── ovos-skill-volume==0.1.17a2 [requires: ovos-workshop>=0.0.15,<8.0.0] -│ ├── ovos-ocp-pipeline-plugin==1.1.18a1 [requires: ovos-workshop>=0.1.7,<8.0.0] │ ├── ovos-skill-date-time==1.1.6a1 [requires: ovos-workshop>=0.0.16,<8.0.0] │ ├── ovos-skill-dictation==0.2.20a1 [requires: ovos-workshop>=7.0.0,<8.0.0] +│ ├── ovos-skill-camera==1.0.5a6 [requires: ovos-workshop>=0.0.12] +│ ├── ovos-core==2.1.0 [requires: ovos-workshop>=7.0.6,<8.0.0] │ ├── ovos-m2v-pipeline==0.0.6 [requires: ovos-workshop>=0.1.7,<8.0.0] │ ├── ovos-skill-ip==0.2.8 [requires: ovos-workshop] │ ├── ovos-skill-ddg==0.3.6a2 [requires: ovos-workshop>=3.4.0,<8.0.0] │ ├── ovos-skill-weather==1.0.8a3 [requires: ovos-workshop>=2.2.0,<8.0.0] │ ├── ovos-skill-cmd==0.2.11 [requires: ovos-workshop>=0.0.15,<8.0.0] │ ├── ovos-skill-naptime==0.3.16a1 [requires: ovos-workshop>=0.0.15,<8.0.0] +│ ├── ovos-skill-volume==0.1.17a3 [requires: ovos-workshop>=0.0.15,<8.0.0] │ ├── ovos-skill-personal==0.1.20a1 [requires: ovos-workshop>=0.0.15,<8.0.0] │ ├── ovos-skill-number-facts==0.1.12 [requires: ovos-workshop>=0.0.15,<8.0.0] │ ├── ovos-skill-randomness==0.1.2 [requires: ovos-workshop] │ ├── ovos-skill-alerts==0.1.28a1 [requires: ovos-workshop>=7.0.0,<8.0.0] +│ ├── ovos-skill-speedtest==0.3.7a1 [requires: ovos-workshop>=0.0.12,<8.0.0] │ ├── ovos-skill-iss-location==0.2.16 [requires: ovos-workshop>=0.0.12,<8.0.0] │ ├── ovos-skill-somafm==0.1.6a1 [requires: ovos-workshop>=0.0.16] │ ├── ovos-skill-wordnet==0.2.6a1 [requires: ovos-workshop>=3.3.0,<8.0.0] -│ ├── ovos-core==2.0.5a1 [requires: ovos-workshop>=7.0.6,<8.0.0] │ ├── ovos-skill-homescreen==3.0.3 [requires: ovos-workshop>=2.4.0,<8.0.0] │ ├── ovos-skill-wikihow==0.3.3 [requires: ovos-workshop>=3.4.0a1,<8.0.0] +│ ├── ovos-ocp-pipeline-plugin==1.1.18a3 [requires: ovos-workshop>=0.1.7,<8.0.0] │ ├── ovos-skill-word-of-the-day==0.2.0 [requires: ovos-workshop] │ ├── ovos-skill-wolfie==0.5.8 [requires: ovos-workshop>=3.4.0a1,<8.0.0] │ ├── ovos-skill-diagnostics==0.0.8 [requires: ovos-workshop>=0.0.12] │ ├── ovos-skill-color-picker==0.0.7 [requires: ovos-workshop] │ ├── ovos-padatious==1.4.2 [requires: ovos-workshop>=0.1.7,<8.0.0] │ ├── ovos-skill-news==0.4.6a1 [requires: ovos-workshop>=0.0.16,<8.0.0] -│ ├── ovos-skill-speedtest==0.3.6 [requires: ovos-workshop>=0.0.12,<8.0.0] -│ ├── ovos-skill-camera==1.0.5a5 [requires: ovos-workshop>=0.0.12] │ ├── ovos-skill-confucius-quotes==0.1.13 [requires: ovos-workshop>=0.0.15,<8.0.0] │ ├── ovos-skill-youtube-music==0.1.7 [requires: ovos-workshop>=0.0.16,<8.0.0] +│ ├── ovos-common-query-pipeline-plugin==1.1.9a3 [requires: ovos-workshop>=0.1.7,<8.0.0] │ ├── ovos-skill-wikipedia==0.8.13 [requires: ovos-workshop>=3.4.0,<8.0.0] │ ├── ovos-skill-moviemaster==0.0.12 [requires: ovos-workshop>=0.0.11,<8.0.0] │ └── ovos-skill-days-in-history==0.3.11 [requires: ovos-workshop>=3.1.0,<8.0.0] @@ -90,16 +91,14 @@ ovos-plugin-manager==1.0.4a2 ├── ovos-PHAL-plugin-system==1.3.4a1 [requires: ovos-plugin-manager>=0.0.26,<2.0.0] ├── ovos-ocp-news-plugin==0.1.1 [requires: ovos-plugin-manager>=0.0.1,<2.0.0] ├── ovos-stt-plugin-chromium==0.1.2 [requires: ovos-plugin-manager>=0.0.1a7] -├── ovos-audio==1.0.2a2 [requires: ovos-plugin-manager>=0.0.26,<2.0.0] -│ └── ovos-skill-laugh==0.2.3 [requires: ovos-audio] ├── ovos-PHAL-plugin-hotkeys==0.1.1 [requires: ovos-plugin-manager>=0.0.1] ├── ovos-skill-wordnet==0.2.6a1 [requires: ovos-plugin-manager>=0.0.26,<2.0.0] ├── ovos-audio-plugin-simple==0.1.2 [requires: ovos-plugin-manager>=0.0.1,<2.0.0] ├── ovos-PHAL-plugin-mk1==0.1.3 [requires: ovos-plugin-manager>=0.0.24] ├── ovos-gui-plugin-shell-companion==1.0.5 [requires: ovos-plugin-manager>=0.5.5,<2.0.0] -├── ovos-core==2.0.5a1 [requires: ovos-plugin-manager>=1.0.3,<2.0.0] ├── ovos-PHAL-plugin-network-manager==1.0.1a2 [requires: ovos-plugin-manager>=0.0.1] ├── ovos-audio-plugin-mpv==0.2.1 [requires: ovos-plugin-manager>=0.0.26a29] +├── ovos-ocp-pipeline-plugin==1.1.18a3 [requires: ovos-plugin-manager>=1.0.0,<2.0.0] ├── ovos-PHAL-plugin-wifi-setup==1.1.1a1 [requires: ovos-plugin-manager>=0.0.1] ├── ovos-ww-plugin-vosk==0.1.7 [requires: ovos-plugin-manager>=1.0.0,<2.0.0] ├── ovos-padatious==1.4.2 [requires: ovos-plugin-manager>=0.5.0,<2.0.0] @@ -112,5 +111,6 @@ ovos-plugin-manager==1.0.4a2 │ └── ovos-skill-wikipedia==0.8.13 [requires: ovos-wikipedia-solver>=0.0.1,<1.0.0] ├── ovos-wolfram-alpha-solver==0.0.3 [requires: ovos-plugin-manager>=0.0.26,<2.0.0] │ └── ovos-skill-wolfie==0.5.8 [requires: ovos-wolfram-alpha-solver>=0.0.2,<1.0.0] -└── ovos-ocp-rss-plugin==0.1.1 [requires: ovos-plugin-manager>=0.0.1,<2.0.0] - └── ovos-ocp-news-plugin==0.1.1 [requires: ovos-ocp-rss-plugin>=0.0.2,<1.0.0] +├── ovos-ocp-rss-plugin==0.1.1 [requires: ovos-plugin-manager>=0.0.1,<2.0.0] +│ └── ovos-ocp-news-plugin==0.1.1 [requires: ovos-ocp-rss-plugin>=0.0.2,<1.0.0] +└── ovos-common-query-pipeline-plugin==1.1.9a3 [requires: ovos-plugin-manager>=1.0.0,<2.0.0] diff --git a/ovos_plugin_manager/templates/hotwords.py b/ovos_plugin_manager/templates/hotwords.py index bc066efb..24e6fde7 100644 --- a/ovos_plugin_manager/templates/hotwords.py +++ b/ovos_plugin_manager/templates/hotwords.py @@ -1,11 +1,10 @@ import abc from typing import Optional, Dict, Any +from ovos_config import Configuration from ovos_utils import classproperty from ovos_utils.process_utils import RuntimeRequirements -from ovos_config import Configuration - def msec_to_sec(msecs): """Convert milliseconds to seconds. @@ -86,7 +85,7 @@ def reset(self): pass @abc.abstractmethod - def update(self, chunk): + def update(self, chunk: bytes): """Updates the hotword engine with new audio data. The engine should process the data and update internal trigger state. @@ -108,3 +107,16 @@ def shutdown(self): Compatibility wrapper for `self.stop` """ self.stop() + + +class HotWordVerifier: + """hotword verifier plugins double check predictions from wakeword detections. + Their main job is to filter false activations + """ + def __init__(self, config: Optional[Dict[str, Any]] = None): + self.config = config or {} + + @abc.abstractmethod + def verify(self, chunk: bytes) -> bool: + """chunk is the audio from a wake word detection""" + raise NotImplementedError() diff --git a/ovos_plugin_manager/utils/__init__.py b/ovos_plugin_manager/utils/__init__.py index 3478e7a7..387cb655 100644 --- a/ovos_plugin_manager/utils/__init__.py +++ b/ovos_plugin_manager/utils/__init__.py @@ -68,6 +68,7 @@ class PluginTypes(str, Enum): STT = 'opm.stt' TTS = 'opm.tts' WAKEWORD = 'opm.wake_word' + WAKEWORD_VERIFIER = 'opm.wake_word.verifier' TRANSLATE = "opm.lang.translate" LANG_DETECT = "opm.lang.detect" UTTERANCE_TRANSFORMER = "opm.transformer.text" @@ -114,6 +115,7 @@ class PluginConfigTypes(str, Enum): STT = 'opm.stt.config' TTS = 'opm.tts.config' WAKEWORD = 'opm.wake_word.config' + WAKEWORD_VERIFIER = 'opm.wake_word.verifier.config' TRANSLATE = "opm.lang.translate.config" LANG_DETECT = "opm.lang.detect.config" UTTERANCE_TRANSFORMER = "opm.transformer.text.config" diff --git a/ovos_plugin_manager/version.py b/ovos_plugin_manager/version.py index 238f9285..1c75e7a1 100644 --- a/ovos_plugin_manager/version.py +++ b/ovos_plugin_manager/version.py @@ -1,6 +1,6 @@ # START_VERSION_BLOCK VERSION_MAJOR = 2 -VERSION_MINOR = 0 -VERSION_BUILD = 1 +VERSION_MINOR = 1 +VERSION_BUILD = 0 VERSION_ALPHA = 1 # END_VERSION_BLOCK diff --git a/ovos_plugin_manager/wakewords.py b/ovos_plugin_manager/wakewords.py index 0828be4b..665d2af3 100644 --- a/ovos_plugin_manager/wakewords.py +++ b/ovos_plugin_manager/wakewords.py @@ -1,12 +1,12 @@ import json import os from hashlib import md5 -from typing import Optional +from typing import Optional, Type from ovos_utils.log import LOG from ovos_utils.xdg_utils import xdg_data_home -from ovos_plugin_manager.templates.hotwords import HotWordEngine +from ovos_plugin_manager.templates.hotwords import HotWordEngine, HotWordVerifier from ovos_plugin_manager.utils import PluginTypes, PluginConfigTypes @@ -19,7 +19,7 @@ def find_wake_word_plugins() -> dict: return find_plugins(PluginTypes.WAKEWORD) -def load_wake_word_plugin(module_name: str) -> type(HotWordEngine): +def load_wake_word_plugin(module_name: str) -> Type[HotWordEngine]: """ Get an uninstantiated class for the requested module_name @param module_name: Plugin entrypoint name to load @@ -29,6 +29,25 @@ def load_wake_word_plugin(module_name: str) -> type(HotWordEngine): return load_plugin(module_name, PluginTypes.WAKEWORD) +def find_wake_word_verifier_plugins() -> dict: + """ + Find all installed plugins + @return: dict plugin names to entrypoints + """ + from ovos_plugin_manager.utils import find_plugins + return find_plugins(PluginTypes.WAKEWORD_VERIFIER) + + +def load_wake_word_verifier_plugin(module_name: str) -> Type[HotWordVerifier]: + """ + Get an uninstantiated class for the requested module_name + @param module_name: Plugin entrypoint name to load + @return: Uninstantiated class + """ + from ovos_plugin_manager.utils import load_plugin + return load_plugin(module_name, PluginTypes.WAKEWORD_VERIFIER) + + def get_ww_configs() -> dict: """ Get valid plugin configurations by plugin name