From 863e711c81318ec2be8b859557d5b3161c5171b0 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Sat, 30 Dec 2023 02:37:17 +0000 Subject: [PATCH 01/91] fix/log spam (#73) * refactor/remove_compat_kludge remove the compat layer that was needed when this was in ovos-utils. now ovos-config is a direct dependency * fix/log_spam supress deprecation logs, pass config --- ovos_bus_client/apis/gui.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/ovos_bus_client/apis/gui.py b/ovos_bus_client/apis/gui.py index 94b3101..499c1c4 100644 --- a/ovos_bus_client/apis/gui.py +++ b/ovos_bus_client/apis/gui.py @@ -6,7 +6,7 @@ from ovos_utils.log import LOG, log_deprecation from ovos_bus_client.util import get_mycroft_bus from ovos_utils.gui import can_use_gui - +from ovos_config import Configuration from ovos_bus_client.message import Message @@ -91,14 +91,7 @@ def __init__(self, skill_id: str, bus=None, `all` key should reference a `gui` directory containing all specific resource subdirectories """ - if not config: - log_deprecation(f"Expected a dict config and got None.", "0.1.0") - try: - from ovos_config.config import read_mycroft_config - config = read_mycroft_config().get("gui", {}) - except ImportError: - LOG.warning("Config not provided and ovos_config not available") - config = dict() + config = config or Configuration().get("gui", {}) self.config = config if remote_server: self.config["remote-server"] = remote_server @@ -364,8 +357,8 @@ def _pages2uri(self, page_names: List[str]) -> List[str]: # Prefer plugin-specific resources first, then fallback to core page = resolve_ovos_resource_file(name, extra_dirs) or \ resolve_ovos_resource_file(join('ui', name), extra_dirs) or \ - resolve_resource_file(name, self.config) or \ - resolve_resource_file(join('ui', name), self.config) + resolve_resource_file(name, config=self.config) or \ + resolve_resource_file(join('ui', name), config=self.config) if page: if self.remote_url: From a5692d027a197c07e1e14acf7d7f86647df68aef Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 30 Dec 2023 02:37:34 +0000 Subject: [PATCH 02/91] Increment Version to 0.0.9a1 --- ovos_bus_client/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index e157dbf..8775b03 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -1,6 +1,6 @@ # START_VERSION_BLOCK VERSION_MAJOR = 0 VERSION_MINOR = 0 -VERSION_BUILD = 8 -VERSION_ALPHA = 0 +VERSION_BUILD = 9 +VERSION_ALPHA = 1 # END_VERSION_BLOCK From 5cabccd19e3eaadeaa2e699f0ca5342ff617e033 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 30 Dec 2023 02:38:01 +0000 Subject: [PATCH 03/91] Update Changelog --- CHANGELOG.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04a1cf3..32f623c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,12 @@ # Changelog -## [V0.0.8a2](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.8a2) (2023-12-29) +## [0.0.9a1](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a1) (2023-12-30) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.8a1...V0.0.8a2) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.8...0.0.9a1) **Fixed bugs:** -- fix/get\_message\_lang [\#71](https://github.com/OpenVoiceOS/ovos-bus-client/pull/71) ([JarbasAl](https://github.com/JarbasAl)) - -## [V0.0.8a1](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.8a1) (2023-12-29) - -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.7...V0.0.8a1) +- fix/log spam [\#73](https://github.com/OpenVoiceOS/ovos-bus-client/pull/73) ([JarbasAl](https://github.com/JarbasAl)) From 376d7eae369078dd923b6dc6ccfddf46fce05896 Mon Sep 17 00:00:00 2001 From: NeonJarbas <59943014+NeonJarbas@users.noreply.github.com> Date: Sat, 6 Jan 2024 01:09:41 +0000 Subject: [PATCH 04/91] fix/ocp api (#74) * fix/ocp api OCPInterface accidentally deleted some methods, this commit adds them back adds OCPQuery bus api helper class * fix/ocp api OCPInterface accidentally deleted some methods, this commit adds them back adds OCPQuery bus api helper class --------- Co-authored-by: JarbasAi --- ovos_bus_client/apis/ocp.py | 306 +++++++++++++++++++++++++++++++++++- requirements.txt | 2 +- 2 files changed, 304 insertions(+), 4 deletions(-) diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index 0174720..aa84732 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -12,13 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. # - +import time from datetime import timedelta - from os.path import abspath +from threading import Lock +from typing import List -from ovos_bus_client.util import get_mycroft_bus from ovos_bus_client.message import Message, dig_for_message +from ovos_bus_client.util import get_mycroft_bus +from ovos_utils.gui import is_gui_connected, is_gui_running +from ovos_utils.log import LOG +from ovos_utils.messagebus import Message +from ovos_utils.ocp import MediaType, PlaybackType, PlaybackMode, available_extractors def ensure_uri(s: str): @@ -270,3 +275,298 @@ def play(self, tracks, utterance=None): "playlist": tracks, "utterance": utterance}) self.bus.emit(msg) + + def stop(self): + """Stop the track.""" + msg = self._format_msg("ovos.common_play.stop") + self.bus.emit(msg) + + def next(self): + """Change to next track.""" + msg = self._format_msg("ovos.common_play.next") + self.bus.emit(msg) + + def prev(self): + """Change to previous track.""" + msg = self._format_msg("ovos.common_play.previous") + self.bus.emit(msg) + + def pause(self): + """Pause playback.""" + msg = self._format_msg("ovos.common_play.pause") + self.bus.emit(msg) + + def resume(self): + """Resume paused playback.""" + msg = self._format_msg("ovos.common_play.resume") + self.bus.emit(msg) + + def seek_forward(self, seconds=1): + """Skip ahead X seconds. + Args: + seconds (int): number of seconds to skip + """ + if isinstance(seconds, timedelta): + seconds = seconds.total_seconds() + msg = self._format_msg('ovos.common_play.seek', + {"seconds": seconds}) + self.bus.emit(msg) + + def seek_backward(self, seconds=1): + """Rewind X seconds + Args: + seconds (int): number of seconds to rewind + """ + if isinstance(seconds, timedelta): + seconds = seconds.total_seconds() + msg = self._format_msg('ovos.common_play.seek', + {"seconds": seconds * -1}) + self.bus.emit(msg) + + def get_track_length(self): + """ + getting the duration of the audio in miliseconds + """ + length = 0 + msg = self._format_msg('ovos.common_play.get_track_length') + info = self.bus.wait_for_response(msg, timeout=1) + if info: + length = info.data.get("length", 0) + return length + + def get_track_position(self): + """ + get current position in miliseconds + """ + pos = 0 + msg = self._format_msg('ovos.common_play.get_track_position') + info = self.bus.wait_for_response(msg, timeout=1) + if info: + pos = info.data.get("position", 0) + return pos + + def set_track_position(self, miliseconds): + """Go to X position. + Arguments: + miliseconds (int): position to go to in miliseconds + """ + msg = self._format_msg('ovos.common_play.set_track_position', + {"position": miliseconds}) + self.bus.emit(msg) + + def track_info(self): + """Request information of current playing track. + Returns: + Dict with track info. + """ + msg = self._format_msg('ovos.common_play.track_info') + response = self.bus.wait_for_response(msg) + return response.data if response else {} + + def available_backends(self): + """Return available audio backends. + Returns: + dict with backend names as keys + """ + msg = self._format_msg('ovos.common_play.list_backends') + response = self.bus.wait_for_response(msg) + return response.data if response else {} + + +class OCPQuery: + cast2audio = [ + MediaType.MUSIC, + MediaType.PODCAST, + MediaType.AUDIOBOOK, + MediaType.RADIO, + MediaType.RADIO_THEATRE, + MediaType.VISUAL_STORY, + MediaType.NEWS + ] + + def __init__(self, query, bus, media_type=MediaType.GENERIC, config=None): + LOG.debug(f"Created {media_type.name} query: {query}") + self.query = query + self.media_type = media_type + self.bus = bus + self.config = config or {} + self.reset() + + def reset(self): + self.active_skills = {} + self.active_skills_lock = Lock() + self.query_replies = [] + self.searching = False + self.search_start = 0 + self.query_timeouts = self.config.get("min_timeout", 5) + if self.config.get("playback_mode") in [PlaybackMode.AUDIO_ONLY]: + self.has_gui = False + else: + self.has_gui = is_gui_running() or is_gui_connected(self.bus) + + def send(self): + self.query_replies = [] + self.query_timeouts = self.config.get("min_timeout", 5) + self.search_start = time.time() + self.searching = True + self.register_events() + self.bus.emit(Message('ovos.common_play.query', + {"phrase": self.query, + "question_type": self.media_type})) + + def wait(self): + # if there is no match type defined, lets increase timeout a bit + # since all skills need to search + if self.media_type == MediaType.GENERIC: + timeout = self.config.get("max_timeout", 15) + 3 # timeout bonus + else: + timeout = self.config.get("max_timeout", 15) + while self.searching and time.time() - self.search_start <= timeout: + time.sleep(0.1) + self.searching = False + self.remove_events() + + @property + def results(self) -> List[dict]: + return [s for s in self.query_replies + if s.get("results")] + + def register_events(self): + LOG.debug("Registering Search Bus Events") + self.bus.on("ovos.common_play.skill.search_start", self.handle_skill_search_start) + self.bus.on("ovos.common_play.skill.search_end", self.handle_skill_search_end) + self.bus.on("ovos.common_play.query.response", self.handle_skill_response) + + def remove_events(self): + LOG.debug("Removing Search Bus Events") + self.bus.remove_all_listeners("ovos.common_play.skill.search_start") + self.bus.remove_all_listeners("ovos.common_play.skill.search_end") + self.bus.remove_all_listeners("ovos.common_play.query.response") + + def handle_skill_search_start(self, message): + skill_id = message.data["skill_id"] + LOG.debug(f"{message.data['skill_id']} is searching") + with self.active_skills_lock: + if skill_id not in self.active_skills: + self.active_skills[skill_id] = Lock() + + def handle_skill_response(self, message): + search_phrase = message.data["phrase"] + if search_phrase != self.query: + # not an answer for this search query + return + timeout = message.data.get("timeout") + skill_id = message.data['skill_id'] + # LOG.debug(f"OVOSCommonPlay result: {skill_id}") + + # in case this handler fires before the search start handler + with self.active_skills_lock: + if skill_id not in self.active_skills: + self.active_skills[skill_id] = Lock() + with self.active_skills[skill_id]: + if message.data.get("searching"): + # extend the timeout by N seconds + if timeout and self.config.get("allow_extensions", True): + self.query_timeouts += timeout + # else -> expired search + + else: + # Collect replies until the timeout + if not self.searching and not len(self.query_replies): + LOG.debug(" too late!! ignored in track selection process") + LOG.warning( + f"{message.data['skill_id']} is not answering fast " + "enough!") + + # populate search playlist + results = message.data.get("results", []) + for idx, res in enumerate(results): + if self.media_type not in [MediaType.ADULT, MediaType.HENTAI]: + # skip adult content results unless explicitly enabled + if not self.config.get("adult_content", False) and \ + res.get("media_type", MediaType.GENERIC) in \ + [MediaType.ADULT, MediaType.HENTAI]: + continue + + # filter uris we can play, usually files and http streams, but some + # skills might return results that depend on additional packages, + # eg. soundcloud, rss, youtube, deezer.... + uri = res.get("uri", "") + if res.get("playlist") and not uri: + res["playlist"] = [ + r for r in res["playlist"] + if r.get("uri") and any(r.get("uri").startswith(e) + for e in + available_extractors())] + if not len(res["playlist"]): + results[idx] = None # can't play this search result! + LOG.error(f"Empty playlist for {res}") + continue + elif uri and res.get("playback") not in [ + PlaybackType.SKILL, PlaybackType.UNDEFINED] and \ + not any( + uri.startswith(e) for e in available_extractors()): + results[idx] = None # can't play this search result! + LOG.error(f"stream handler not available for {res}") + continue + + # filter video results if GUI not connected + if not self.has_gui: + # force allowed stream types to be played audio only + if res.get("media_type", "") in self.cast2audio: + LOG.debug("unable to use GUI, " + "forcing result to play audio only") + res["playback"] = PlaybackType.AUDIO + res["match_confidence"] -= 10 + results[idx] = res + + # remove filtered results + message.data["results"] = [r for r in results if r is not None] + LOG.debug(f'got {len(message.data["results"])} results from {skill_id}') + self.query_replies.append(message.data) + + # abort searching if we gathered enough results + # TODO ensure we have a decent confidence match, if all matches + # are < 50% conf extend timeout instead + if time.time() - self.search_start > self.query_timeouts: + if self.searching: + self.searching = False + LOG.debug("common play query timeout, parsing results") + + elif self.searching: + for res in message.data.get("results", []): + if res.get("match_confidence", 0) >= \ + self.config.get("early_stop_thresh", 85): + # got a really good match, dont search further + LOG.info( + "Receiving very high confidence match, stopping " + "search early") + + # allow other skills to "just miss" + early_stop_grace = \ + self.config.get("early_stop_grace_period", 0.5) + if early_stop_grace: + LOG.debug( + f" - grace period: {early_stop_grace} seconds") + time.sleep(early_stop_grace) + self.searching = False + return + + def handle_skill_search_end(self, message): + skill_id = message.data["skill_id"] + LOG.debug(f"{message.data['skill_id']} finished search") + with self.active_skills_lock: + if skill_id in self.active_skills: + with self.active_skills[skill_id]: + del self.active_skills[skill_id] + + # if this was the last skill end searching period + time.sleep(0.5) + # TODO this sleep is hacky, but avoids a race condition in + # case some skill just decides to respond before the others even + # acknowledge search is starting, this gives more than enough time + # for self.active_skills to be populated, a better approach should + # be employed but this works fine for now + if not self.active_skills and self.searching: + LOG.info("Received search responses from all skills!") + self.searching = False diff --git a/requirements.txt b/requirements.txt index 17c6bbc..6a6feee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ ovos-config >= 0.0.12, < 0.2.0 -ovos-utils >= 0.0.37, < 0.2.0 +ovos-utils >= 0.1.0a7, < 0.2.0 websocket-client>=0.54.0 pyee>=8.1.0, < 9.0.0 From 2416198c9ba345ea055fcbb28340b1b8217af724 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 6 Jan 2024 01:09:54 +0000 Subject: [PATCH 05/91] Increment Version to 0.0.9a2 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 8775b03..3098bab 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 1 +VERSION_ALPHA = 2 # END_VERSION_BLOCK From 51c05407279f53cade71046add2c27a72bdda183 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 6 Jan 2024 01:10:18 +0000 Subject: [PATCH 06/91] Update Changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32f623c..16429aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # Changelog -## [0.0.9a1](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a1) (2023-12-30) +## [0.0.9a2](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a2) (2024-01-06) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.8...0.0.9a1) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a1...0.0.9a2) + +**Implemented enhancements:** + +- fix/ocp api [\#74](https://github.com/OpenVoiceOS/ovos-bus-client/pull/74) ([NeonJarbas](https://github.com/NeonJarbas)) + +## [V0.0.9a1](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a1) (2023-12-30) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.8...V0.0.9a1) **Fixed bugs:** From cf7de4d5fbffca1e9da68a4ccfdcccfde1cbcb93 Mon Sep 17 00:00:00 2001 From: NeonJarbas <59943014+NeonJarbas@users.noreply.github.com> Date: Mon, 8 Jan 2024 06:18:58 +0000 Subject: [PATCH 07/91] fix/ocp api (#77) * update OCP api --------- Co-authored-by: JarbasAi --- ovos_bus_client/apis/ocp.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index aa84732..c304fff 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -23,7 +23,7 @@ from ovos_utils.gui import is_gui_connected, is_gui_running from ovos_utils.log import LOG from ovos_utils.messagebus import Message -from ovos_utils.ocp import MediaType, PlaybackType, PlaybackMode, available_extractors +from ovos_utils.ocp import MediaType, PlaybackType, PlaybackMode def ensure_uri(s: str): @@ -392,7 +392,18 @@ def __init__(self, query, bus, media_type=MediaType.GENERIC, config=None): self.config = config or {} self.reset() + def _get_available_extractors(self): + # TODO - implement a bus api, + # in containers the plugins wont be installed + # in the code using this api + try: # optional import + from ovos_plugin_manager.ocp import available_extractors + self.valid_uris = available_extractors() + except: + self.valid_uris = ["/", "http:", "https:", "file:"] + def reset(self): + self._get_available_extractors() self.active_skills = {} self.active_skills_lock = Lock() self.query_replies = [] @@ -496,8 +507,7 @@ def handle_skill_response(self, message): res["playlist"] = [ r for r in res["playlist"] if r.get("uri") and any(r.get("uri").startswith(e) - for e in - available_extractors())] + for e in self.valid_uris)] if not len(res["playlist"]): results[idx] = None # can't play this search result! LOG.error(f"Empty playlist for {res}") @@ -505,7 +515,7 @@ def handle_skill_response(self, message): elif uri and res.get("playback") not in [ PlaybackType.SKILL, PlaybackType.UNDEFINED] and \ not any( - uri.startswith(e) for e in available_extractors()): + uri.startswith(e) for e in self.valid_uris): results[idx] = None # can't play this search result! LOG.error(f"stream handler not available for {res}") continue From dd2b60db43e0e85002a44a551400ac8a8127e4e8 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Mon, 8 Jan 2024 06:19:14 +0000 Subject: [PATCH 08/91] Increment Version to 0.0.9a3 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 3098bab..1812527 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 2 +VERSION_ALPHA = 3 # END_VERSION_BLOCK From bad51fa3bc38e65e9b5b2e1c2f8054bcde4b055a Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Mon, 8 Jan 2024 06:19:42 +0000 Subject: [PATCH 09/91] Update Changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16429aa..a4f3e84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # Changelog -## [0.0.9a2](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a2) (2024-01-06) +## [0.0.9a3](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a3) (2024-01-08) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a1...0.0.9a2) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a2...0.0.9a3) + +**Fixed bugs:** + +- fix/ocp api [\#77](https://github.com/OpenVoiceOS/ovos-bus-client/pull/77) ([NeonJarbas](https://github.com/NeonJarbas)) + +## [V0.0.9a2](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a2) (2024-01-06) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a1...V0.0.9a2) **Implemented enhancements:** From 9bc9ae8688d7075ba4dce58028e6077dff205613 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Tue, 9 Jan 2024 17:13:44 +0000 Subject: [PATCH 10/91] hotfix/avoid_c++_crash (#76) partially mitigates https://github.com/OpenVoiceOS/ovos-bus-server/issues/2 not a proper fix, but makes it more usable, at least in buildroot it seems functional low impact in latency since these scripts are not meant to be real time, they start a new bus connection etc and are already slow --- ovos_bus_client/scripts.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ovos_bus_client/scripts.py b/ovos_bus_client/scripts.py index 997d489..6a12937 100644 --- a/ovos_bus_client/scripts.py +++ b/ovos_bus_client/scripts.py @@ -4,6 +4,7 @@ from ovos_bus_client import MessageBusClient, Message from ovos_config import Configuration import sys +import time def ovos_speak(): @@ -22,6 +23,7 @@ def ovos_speak(): if not client.connected_event.is_set(): client.connected_event.wait() client.emit(Message("speak", {"utterance": utt, "lang": lang})) + time.sleep(0.5) # avoids crash in c++ bus server client.close() @@ -41,6 +43,7 @@ def ovos_say_to(): if not client.connected_event.is_set(): client.connected_event.wait() client.emit(Message("recognizer_loop:utterance", {"utterances": [utt], "lang": lang})) + time.sleep(0.5) # avoids crash in c++ bus server client.close() @@ -50,6 +53,7 @@ def ovos_listen(): if not client.connected_event.is_set(): client.connected_event.wait() client.emit(Message("mycroft.mic.listen")) + time.sleep(0.5) # avoids crash in c++ bus server client.close() @@ -80,6 +84,7 @@ def simple_cli(): client.emit(Message("recognizer_loop:utterance", {"utterances": [utt], "lang": lang}, {"session": sess.serialize()})) + time.sleep(0.5) # avoids crash in c++ bus server except KeyboardInterrupt: break @@ -87,4 +92,4 @@ def simple_cli(): if __name__ == "__main__": - simple_cli() \ No newline at end of file + simple_cli() From 01b8a2d667c385b56ea7df1b96421f30e9fd74f2 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Tue, 9 Jan 2024 17:14:02 +0000 Subject: [PATCH 11/91] Increment Version to 0.0.9a4 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 1812527..463408d 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 3 +VERSION_ALPHA = 4 # END_VERSION_BLOCK From 64ecb52813c0646758df29896386c43ff449059f Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Tue, 9 Jan 2024 17:14:35 +0000 Subject: [PATCH 12/91] Update Changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4f3e84..c8f7786 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # Changelog -## [0.0.9a3](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a3) (2024-01-08) +## [0.0.9a4](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a4) (2024-01-09) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a2...0.0.9a3) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a3...0.0.9a4) + +**Fixed bugs:** + +- hotfix/avoid\_c++\_crash [\#76](https://github.com/OpenVoiceOS/ovos-bus-client/pull/76) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.9a3](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a3) (2024-01-08) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a2...V0.0.9a3) **Fixed bugs:** From 7bf470435ab93c9ab708887ea4f7d8c655c740be Mon Sep 17 00:00:00 2001 From: NeonJarbas <59943014+NeonJarbas@users.noreply.github.com> Date: Fri, 12 Jan 2024 01:02:22 +0000 Subject: [PATCH 13/91] feat/ovos-media (#78) * feat/OCP - add some missed methods in the OCPInterface class - add apis for ovos-media - support MediaEntry and Playlist objects in the apis * Update ocp.py * Update ocp.py * Update ocp.py * Update requirements.txt --------- Co-authored-by: JarbasAi Co-authored-by: JarbasAI <33701864+JarbasAl@users.noreply.github.com> --- .github/workflows/publish_alpha.yml | 2 +- .github/workflows/unit_tests.yml | 4 +- ovos_bus_client/apis/ocp.py | 624 +++++++++++++++++++++++----- requirements.txt | 2 +- 4 files changed, 522 insertions(+), 110 deletions(-) diff --git a/.github/workflows/publish_alpha.yml b/.github/workflows/publish_alpha.yml index a7fde29..86dcaca 100644 --- a/.github/workflows/publish_alpha.yml +++ b/.github/workflows/publish_alpha.yml @@ -14,7 +14,7 @@ on: - 'LICENSE' - 'CHANGELOG.md' - 'MANIFEST.in' - - 'readme.md' + - 'README.md' - 'scripts/**' workflow_dispatch: diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index e56a8cd..f151381 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -11,7 +11,7 @@ on: - 'LICENSE' - 'CHANGELOG.md' - 'MANIFEST.in' - - 'readme.md' + - 'README.md' - 'scripts/**' push: branches: @@ -25,7 +25,7 @@ on: - 'LICENSE' - 'CHANGELOG.md' - 'MANIFEST.in' - - 'readme.md' + - 'README.md' - 'scripts/**' workflow_dispatch: diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index c304fff..03c47a2 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -1,5 +1,3 @@ -# Copyright 2017 Mycroft AI Inc. -# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -18,12 +16,13 @@ from threading import Lock from typing import List -from ovos_bus_client.message import Message, dig_for_message -from ovos_bus_client.util import get_mycroft_bus from ovos_utils.gui import is_gui_connected, is_gui_running -from ovos_utils.log import LOG -from ovos_utils.messagebus import Message -from ovos_utils.ocp import MediaType, PlaybackType, PlaybackMode +from ovos_utils.log import LOG, deprecated +from ovos_utils.ocp import MediaType, PlaybackMode, Playlist, MediaEntry + +from ovos_bus_client.message import Message +from ovos_bus_client.message import dig_for_message +from ovos_bus_client.util import get_mycroft_bus def ensure_uri(s: str): @@ -53,13 +52,18 @@ def ensure_uri(s: str): class ClassicAudioServiceInterface: """AudioService class for interacting with the audio subsystem - Audio is managed by OCP in the default implementation, - usually this class should not be directly used, see OCPInterface instead + DEPRECATED: only works in ovos-core <= 0.0.8 + + it has been removed from ovos-audio with the move to ovos-media + + use OCPInterface instead Args: - bus: Mycroft messagebus connection + bus: OpenVoiceOS messagebus connection """ + @deprecated("removed from ovos-audio with the adoption of ovos-media service, " + "use OCPInterface instead", "0.1.0") def __init__(self, bus=None): self.bus = bus or get_mycroft_bus() @@ -223,7 +227,7 @@ def is_playing(self): class OCPInterface: """bus api interface for OCP subsystem Args: - bus: Mycroft messagebus connection + bus: OpenVoiceOS messagebus connection """ def __init__(self, bus=None): @@ -245,31 +249,45 @@ def _format_msg(self, msg_type, msg_data=None): return msg # OCP bus api - def queue(self, tracks): + @staticmethod + def norm_tracks(tracks: list): + """ensures a list of tracks contains only MediaEntry or Playlist items""" + assert isinstance(tracks, list) + # support Playlist and MediaEntry objects in tracks + for idx, track in enumerate(tracks): + if isinstance(track, dict): + tracks[idx] = MediaEntry.from_dict(track) + elif isinstance(track, list) and not isinstance(track, Playlist): + tracks[idx] = OCPInterface.norm_tracks(tracks) + else: + # TODO - support string uris + # let it fail in next assert + # log all bad entries before failing + LOG.error(f"Bad track, invalid type: {track}") + assert all(isinstance(t, (MediaEntry, Playlist)) for t in tracks) + return tracks + + def queue(self, tracks: list): """Queue up a track to OCP playing playlist. Args: tracks: track dict or list of track dicts (OCP result style) """ - - assert isinstance(tracks, list) - assert all(isinstance(t, dict) for t in tracks) - + tracks = self.norm_tracks(tracks) msg = self._format_msg('ovos.common_play.playlist.queue', {'tracks': tracks}) self.bus.emit(msg) - def play(self, tracks, utterance=None): + def play(self, tracks: list, utterance=None): """Start playback. Args: tracks: track dict or list of track dicts (OCP result style) utterance: forward utterance for further processing by OCP """ - assert isinstance(tracks, list) - assert all(isinstance(t, dict) for t in tracks) + tracks = self.norm_tracks(tracks) utterance = utterance or '' - + tracks = [t.as_dict for t in tracks] msg = self._format_msg('ovos.common_play.play', {"media": tracks[0], "playlist": tracks, @@ -373,6 +391,453 @@ def available_backends(self): return response.data if response else {} +class OCPAudioServiceInterface: + """Internal OCP audio subsystem + most likely you should use OCPInterface instead + NOTE: this class operates with uris not with MediaEntry/Playlist/dict entries + """ + + def __init__(self, bus=None): + self.bus = bus or get_mycroft_bus() + + def play(self, tracks=None, utterance=None, repeat=None): + """Start playback. + + Args: + tracks: track uri or list of track uri's + Each track can be added as a tuple with (uri, mime) + to give a hint of the mime type to the system + utterance: forward utterance for further processing by the + audio service. + repeat: if the playback should be looped + """ + repeat = repeat or False + tracks = tracks or [] + utterance = utterance or '' + if isinstance(tracks, (str, tuple)): + tracks = [tracks] + elif not isinstance(tracks, list): + raise ValueError + tracks = [ensure_uri(t) for t in tracks] + self.bus.emit(Message('ovos.audio.service.play', + data={'tracks': tracks, + 'utterance': utterance, + 'repeat': repeat})) + + def stop(self): + """Stop the track.""" + self.bus.emit(Message('ovos.audio.service.stop')) + + def next(self): + """Change to next track.""" + self.bus.emit(Message('ovos.audio.service.next')) + + def prev(self): + """Change to previous track.""" + self.bus.emit(Message('ovos.audio.service.prev')) + + def pause(self): + """Pause playback.""" + self.bus.emit(Message('ovos.audio.service.pause')) + + def resume(self): + """Resume paused playback.""" + self.bus.emit(Message('ovos.audio.service.resume')) + + def get_track_length(self): + """ + getting the duration of the audio in seconds + """ + length = 0 + info = self.bus.wait_for_response( + Message('ovos.audio.service.get_track_length'), + timeout=1) + if info: + length = info.data.get("length") or 0 + return length / 1000 # convert to seconds + + def get_track_position(self): + """ + get current position in seconds + """ + pos = 0 + info = self.bus.wait_for_response( + Message('ovos.audio.service.get_track_position'), + timeout=1) + if info: + pos = info.data.get("position") or 0 + return pos / 1000 # convert to seconds + + def set_track_position(self, seconds): + """Seek X seconds. + + Arguments: + seconds (int): number of seconds to seek, if negative rewind + """ + self.bus.emit(Message('ovos.audio.service.set_track_position', + {"position": seconds * 1000})) # convert to ms + + def seek(self, seconds=1): + """Seek X seconds. + + Args: + seconds (int): number of seconds to seek, if negative rewind + """ + if isinstance(seconds, timedelta): + seconds = seconds.total_seconds() + if seconds < 0: + self.seek_backward(abs(seconds)) + else: + self.seek_forward(seconds) + + def seek_forward(self, seconds=1): + """Skip ahead X seconds. + + Args: + seconds (int): number of seconds to skip + """ + if isinstance(seconds, timedelta): + seconds = seconds.total_seconds() + self.bus.emit(Message('ovos.audio.service.seek_forward', + {"seconds": seconds})) + + def seek_backward(self, seconds=1): + """Rewind X seconds + + Args: + seconds (int): number of seconds to rewind + """ + if isinstance(seconds, timedelta): + seconds = seconds.total_seconds() + self.bus.emit(Message('ovos.audio.service.seek_backward', + {"seconds": seconds})) + + def track_info(self): + """Request information of current playing track. + + Returns: + Dict with track info. + """ + info = self.bus.wait_for_response( + Message('ovos.audio.service.track_info'), + reply_type='ovos.audio.service.track_info_reply', + timeout=1) + return info.data if info else {} + + def available_backends(self): + """Return available audio backends. + + Returns: + dict with backend names as keys + """ + msg = Message('ovos.audio.service.list_backends') + response = self.bus.wait_for_response(msg) + return response.data if response else {} + + @property + def is_playing(self): + """True if the audioservice is playing, else False.""" + return self.track_info() != {} + + +class OCPVideoServiceInterface: + """Internal OCP video subsystem + most likely you should use OCPInterface instead + NOTE: this class operates with uris not with MediaEntry/Playlist/dict entries + """ + + def __init__(self, bus=None): + self.bus = bus or get_mycroft_bus() + + def play(self, tracks=None, utterance=None, repeat=None): + """Start playback. + + Args: + tracks: track uri or list of track uri's + Each track can be added as a tuple with (uri, mime) + to give a hint of the mime type to the system + utterance: forward utterance for further processing by the + video service. + repeat: if the playback should be looped + """ + repeat = repeat or False + tracks = tracks or [] + utterance = utterance or '' + if isinstance(tracks, (str, tuple)): + tracks = [tracks] + elif not isinstance(tracks, list): + raise ValueError + tracks = [ensure_uri(t) for t in tracks] + self.bus.emit(Message('ovos.video.service.play', + data={'tracks': tracks, + 'utterance': utterance, + 'repeat': repeat})) + + def stop(self): + """Stop the track.""" + self.bus.emit(Message('ovos.video.service.stop')) + + def next(self): + """Change to next track.""" + self.bus.emit(Message('ovos.video.service.next')) + + def prev(self): + """Change to previous track.""" + self.bus.emit(Message('ovos.video.service.prev')) + + def pause(self): + """Pause playback.""" + self.bus.emit(Message('ovos.video.service.pause')) + + def resume(self): + """Resume paused playback.""" + self.bus.emit(Message('ovos.video.service.resume')) + + def get_track_length(self): + """ + getting the duration of the video in seconds + """ + length = 0 + info = self.bus.wait_for_response( + Message('ovos.video.service.get_track_length'), + timeout=1) + if info: + length = info.data.get("length") or 0 + return length / 1000 # convert to seconds + + def get_track_position(self): + """ + get current position in seconds + """ + pos = 0 + info = self.bus.wait_for_response( + Message('ovos.video.service.get_track_position'), + timeout=1) + if info: + pos = info.data.get("position") or 0 + return pos / 1000 # convert to seconds + + def set_track_position(self, seconds): + """Seek X seconds. + + Arguments: + seconds (int): number of seconds to seek, if negative rewind + """ + self.bus.emit(Message('ovos.video.service.set_track_position', + {"position": seconds * 1000})) # convert to ms + + def seek(self, seconds=1): + """Seek X seconds. + + Args: + seconds (int): number of seconds to seek, if negative rewind + """ + if isinstance(seconds, timedelta): + seconds = seconds.total_seconds() + if seconds < 0: + self.seek_backward(abs(seconds)) + else: + self.seek_forward(seconds) + + def seek_forward(self, seconds=1): + """Skip ahead X seconds. + + Args: + seconds (int): number of seconds to skip + """ + if isinstance(seconds, timedelta): + seconds = seconds.total_seconds() + self.bus.emit(Message('ovos.video.service.seek_forward', + {"seconds": seconds})) + + def seek_backward(self, seconds=1): + """Rewind X seconds + + Args: + seconds (int): number of seconds to rewind + """ + if isinstance(seconds, timedelta): + seconds = seconds.total_seconds() + self.bus.emit(Message('ovos.video.service.seek_backward', + {"seconds": seconds})) + + def track_info(self): + """Request information of current playing track. + + Returns: + Dict with track info. + """ + info = self.bus.wait_for_response( + Message('ovos.video.service.track_info'), + reply_type='ovos.video.service.track_info_reply', + timeout=1) + return info.data if info else {} + + def available_backends(self): + """Return available video backends. + + Returns: + dict with backend names as keys + """ + msg = Message('ovos.video.service.list_backends') + response = self.bus.wait_for_response(msg) + return response.data if response else {} + + @property + def is_playing(self): + """True if the videoservice is playing, else False.""" + return self.track_info() != {} + + +class OCPWebServiceInterface: + """Internal OCP web view subsystem + most likely you should use OCPInterface instead + NOTE: this class operates with uris not with MediaEntry/Playlist/dict entries + """ + + def __init__(self, bus=None): + self.bus = bus or get_mycroft_bus() + + def play(self, tracks=None, utterance=None, repeat=None): + """Start playback. + + Args: + tracks: track uri or list of track uri's + Each track can be added as a tuple with (uri, mime) + to give a hint of the mime type to the system + utterance: forward utterance for further processing by the + web service. + repeat: if the playback should be looped + """ + repeat = repeat or False + tracks = tracks or [] + utterance = utterance or '' + if isinstance(tracks, (str, tuple)): + tracks = [tracks] + elif not isinstance(tracks, list): + raise ValueError + tracks = [ensure_uri(t) for t in tracks] + self.bus.emit(Message('ovos.web.service.play', + data={'tracks': tracks, + 'utterance': utterance, + 'repeat': repeat})) + + def stop(self): + """Stop the track.""" + self.bus.emit(Message('ovos.web.service.stop')) + + def next(self): + """Change to next track.""" + self.bus.emit(Message('ovos.web.service.next')) + + def prev(self): + """Change to previous track.""" + self.bus.emit(Message('ovos.web.service.prev')) + + def pause(self): + """Pause playback.""" + self.bus.emit(Message('ovos.web.service.pause')) + + def resume(self): + """Resume paused playback.""" + self.bus.emit(Message('ovos.web.service.resume')) + + def get_track_length(self): + """ + getting the duration of the web in seconds + """ + length = 0 + info = self.bus.wait_for_response( + Message('ovos.web.service.get_track_length'), + timeout=1) + if info: + length = info.data.get("length") or 0 + return length / 1000 # convert to seconds + + def get_track_position(self): + """ + get current position in seconds + """ + pos = 0 + info = self.bus.wait_for_response( + Message('ovos.web.service.get_track_position'), + timeout=1) + if info: + pos = info.data.get("position") or 0 + return pos / 1000 # convert to seconds + + def set_track_position(self, seconds): + """Seek X seconds. + + Arguments: + seconds (int): number of seconds to seek, if negative rewind + """ + self.bus.emit(Message('ovos.web.service.set_track_position', + {"position": seconds * 1000})) # convert to ms + + def seek(self, seconds=1): + """Seek X seconds. + + Args: + seconds (int): number of seconds to seek, if negative rewind + """ + if isinstance(seconds, timedelta): + seconds = seconds.total_seconds() + if seconds < 0: + self.seek_backward(abs(seconds)) + else: + self.seek_forward(seconds) + + def seek_forward(self, seconds=1): + """Skip ahead X seconds. + + Args: + seconds (int): number of seconds to skip + """ + if isinstance(seconds, timedelta): + seconds = seconds.total_seconds() + self.bus.emit(Message('ovos.web.service.seek_forward', + {"seconds": seconds})) + + def seek_backward(self, seconds=1): + """Rewind X seconds + + Args: + seconds (int): number of seconds to rewind + """ + if isinstance(seconds, timedelta): + seconds = seconds.total_seconds() + self.bus.emit(Message('ovos.web.service.seek_backward', + {"seconds": seconds})) + + def track_info(self): + """Request information of current playing track. + + Returns: + Dict with track info. + """ + info = self.bus.wait_for_response( + Message('ovos.web.service.track_info'), + reply_type='ovos.web.service.track_info_reply', + timeout=1) + return info.data if info else {} + + def available_backends(self): + """Return available web backends. + + Returns: + dict with backend names as keys + """ + msg = Message('ovos.web.service.list_backends') + response = self.bus.wait_for_response(msg) + return response.data if response else {} + + @property + def is_playing(self): + """True if the webservice is playing, else False.""" + return self.track_info() != {} + + class OCPQuery: cast2audio = [ MediaType.MUSIC, @@ -392,18 +857,7 @@ def __init__(self, query, bus, media_type=MediaType.GENERIC, config=None): self.config = config or {} self.reset() - def _get_available_extractors(self): - # TODO - implement a bus api, - # in containers the plugins wont be installed - # in the code using this api - try: # optional import - from ovos_plugin_manager.ocp import available_extractors - self.valid_uris = available_extractors() - except: - self.valid_uris = ["/", "http:", "https:", "file:"] - def reset(self): - self._get_available_extractors() self.active_skills = {} self.active_skills_lock = Lock() self.query_replies = [] @@ -439,8 +893,7 @@ def wait(self): @property def results(self) -> List[dict]: - return [s for s in self.query_replies - if s.get("results")] + return [s for s in self.query_replies if s.get("results")] def register_events(self): LOG.debug("Registering Search Bus Events") @@ -485,82 +938,41 @@ def handle_skill_response(self, message): # Collect replies until the timeout if not self.searching and not len(self.query_replies): LOG.debug(" too late!! ignored in track selection process") - LOG.warning( - f"{message.data['skill_id']} is not answering fast " - "enough!") + LOG.warning(f"{skill_id} is not answering fast enough!") + return # populate search playlist - results = message.data.get("results", []) - for idx, res in enumerate(results): - if self.media_type not in [MediaType.ADULT, MediaType.HENTAI]: - # skip adult content results unless explicitly enabled - if not self.config.get("adult_content", False) and \ - res.get("media_type", MediaType.GENERIC) in \ - [MediaType.ADULT, MediaType.HENTAI]: - continue - - # filter uris we can play, usually files and http streams, but some - # skills might return results that depend on additional packages, - # eg. soundcloud, rss, youtube, deezer.... - uri = res.get("uri", "") - if res.get("playlist") and not uri: - res["playlist"] = [ - r for r in res["playlist"] - if r.get("uri") and any(r.get("uri").startswith(e) - for e in self.valid_uris)] - if not len(res["playlist"]): - results[idx] = None # can't play this search result! - LOG.error(f"Empty playlist for {res}") - continue - elif uri and res.get("playback") not in [ - PlaybackType.SKILL, PlaybackType.UNDEFINED] and \ - not any( - uri.startswith(e) for e in self.valid_uris): - results[idx] = None # can't play this search result! - LOG.error(f"stream handler not available for {res}") - continue - - # filter video results if GUI not connected - if not self.has_gui: - # force allowed stream types to be played audio only - if res.get("media_type", "") in self.cast2audio: - LOG.debug("unable to use GUI, " - "forcing result to play audio only") - res["playback"] = PlaybackType.AUDIO - res["match_confidence"] -= 10 - results[idx] = res - - # remove filtered results - message.data["results"] = [r for r in results if r is not None] - LOG.debug(f'got {len(message.data["results"])} results from {skill_id}') - self.query_replies.append(message.data) - - # abort searching if we gathered enough results - # TODO ensure we have a decent confidence match, if all matches - # are < 50% conf extend timeout instead - if time.time() - self.search_start > self.query_timeouts: - if self.searching: - self.searching = False - LOG.debug("common play query timeout, parsing results") - - elif self.searching: - for res in message.data.get("results", []): - if res.get("match_confidence", 0) >= \ - self.config.get("early_stop_thresh", 85): - # got a really good match, dont search further - LOG.info( - "Receiving very high confidence match, stopping " - "search early") - - # allow other skills to "just miss" - early_stop_grace = \ - self.config.get("early_stop_grace_period", 0.5) - if early_stop_grace: - LOG.debug( - f" - grace period: {early_stop_grace} seconds") - time.sleep(early_stop_grace) + res = message.data.get("results", []) + LOG.debug(f'got {len(res)} results from {skill_id}') + if res: + self.query_replies.append(message.data) + + # abort searching if we gathered enough results + # TODO ensure we have a decent confidence match, if all matches + # are < 50% conf extend timeout instead + if time.time() - self.search_start > self.query_timeouts: + if self.searching: self.searching = False - return + LOG.debug("common play query timeout, parsing results") + + elif self.searching: + for res in message.data.get("results", []): + if res.get("match_confidence", 0) >= \ + self.config.get("early_stop_thresh", 85): + # got a really good match, dont search further + LOG.info( + "Receiving very high confidence match, stopping " + "search early") + + # allow other skills to "just miss" + early_stop_grace = \ + self.config.get("early_stop_grace_period", 0.5) + if early_stop_grace: + LOG.debug( + f" - grace period: {early_stop_grace} seconds") + time.sleep(early_stop_grace) + self.searching = False + return def handle_skill_search_end(self, message): skill_id = message.data["skill_id"] diff --git a/requirements.txt b/requirements.txt index 6a6feee..c78a134 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ ovos-config >= 0.0.12, < 0.2.0 -ovos-utils >= 0.1.0a7, < 0.2.0 +ovos-utils >= 0.1.0a9, < 0.2.0 websocket-client>=0.54.0 pyee>=8.1.0, < 9.0.0 From 63b37178c263eb719d4f11244f4dad158c29bd54 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 12 Jan 2024 01:02:38 +0000 Subject: [PATCH 14/91] Increment Version to 0.0.9a5 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 463408d..1a9c4ae 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 4 +VERSION_ALPHA = 5 # END_VERSION_BLOCK From b5ab3bd66d4d6bdf5ba4ad9fc1ed0c4df02ceeb3 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 12 Jan 2024 01:03:05 +0000 Subject: [PATCH 15/91] Update Changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8f7786..edaf272 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # Changelog -## [0.0.9a4](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a4) (2024-01-09) +## [0.0.9a5](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a5) (2024-01-12) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a3...0.0.9a4) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a4...0.0.9a5) + +**Implemented enhancements:** + +- feat/ovos-media [\#78](https://github.com/OpenVoiceOS/ovos-bus-client/pull/78) ([NeonJarbas](https://github.com/NeonJarbas)) + +## [V0.0.9a4](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a4) (2024-01-09) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a3...V0.0.9a4) **Fixed bugs:** From e2b4c51e95871eb553b05a9751ddd36890e708a1 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Fri, 12 Jan 2024 01:09:09 +0000 Subject: [PATCH 16/91] typo_and_docstr (#79) typo and docstr --- ovos_bus_client/apis/ocp.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index 03c47a2..6163fe5 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -50,11 +50,13 @@ def ensure_uri(s: str): class ClassicAudioServiceInterface: - """AudioService class for interacting with the audio subsystem + """AudioService class for interacting with the classic mycroft audio subsystem DEPRECATED: only works in ovos-core <= 0.0.8 it has been removed from ovos-audio with the move to ovos-media + + "mycroft.audio.XXX" has been replaced by "ovos.audio.XXX" namespace use OCPInterface instead @@ -258,7 +260,7 @@ def norm_tracks(tracks: list): if isinstance(track, dict): tracks[idx] = MediaEntry.from_dict(track) elif isinstance(track, list) and not isinstance(track, Playlist): - tracks[idx] = OCPInterface.norm_tracks(tracks) + tracks[idx] = OCPInterface.norm_tracks(track) else: # TODO - support string uris # let it fail in next assert From 35f0f8c41341f2fdbc7cdb90d6eac1df7cfda4a0 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 12 Jan 2024 01:09:26 +0000 Subject: [PATCH 17/91] Increment Version to 0.0.9a6 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 1a9c4ae..cd88a7c 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 5 +VERSION_ALPHA = 6 # END_VERSION_BLOCK From 2ffdeb47deb282920d5041fa87abc0050feb625f Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 12 Jan 2024 01:09:48 +0000 Subject: [PATCH 18/91] Update Changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edaf272..9fa8833 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # Changelog -## [0.0.9a5](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a5) (2024-01-12) +## [0.0.9a6](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a6) (2024-01-12) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a4...0.0.9a5) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a5...0.0.9a6) + +**Fixed bugs:** + +- typo\_and\_docstr [\#79](https://github.com/OpenVoiceOS/ovos-bus-client/pull/79) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.9a5](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a5) (2024-01-12) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a4...V0.0.9a5) **Implemented enhancements:** From 850890e8d791bbec820111a0f1109b089ed609fb Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Sat, 13 Jan 2024 12:34:54 +0000 Subject: [PATCH 19/91] refactor/orjson (#75) * refactor/orjson move all message serialization and deserialization to orjson this brings extra performance * ret type * ret type --- ovos_bus_client/client/client.py | 6 +++--- ovos_bus_client/message.py | 14 +++++++------- ovos_bus_client/util/__init__.py | 8 ++++---- requirements.txt | 1 + 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/ovos_bus_client/client/client.py b/ovos_bus_client/client/client.py index 9747fa1..ecd5e22 100644 --- a/ovos_bus_client/client/client.py +++ b/ovos_bus_client/client/client.py @@ -1,4 +1,4 @@ -import json +import orjson import time import traceback from os import getpid @@ -184,7 +184,7 @@ def emit(self, message: Message): if hasattr(message, 'serialize'): msg = message.serialize() else: - msg = json.dumps(message.__dict__) + msg = orjson.dumps(message.__dict__).decode("utf-8") try: self.client.send(msg) except WebSocketConnectionClosedException: @@ -417,7 +417,7 @@ def emit(self, message: GUIMessage): if hasattr(message, 'serialize'): self.client.send(message.serialize()) else: - self.client.send(json.dumps(message.__dict__)) + self.client.send(orjson.dumps(message.__dict__).decode("utf-8")) except WebSocketConnectionClosedException: LOG.warning('Could not send %s message because connection ' 'has been closed', message.msg_type) diff --git a/ovos_bus_client/message.py b/ovos_bus_client/message.py index ef3e824..6afa7fa 100644 --- a/ovos_bus_client/message.py +++ b/ovos_bus_client/message.py @@ -21,7 +21,7 @@ """ import inspect -import json +import orjson import re from copy import deepcopy from typing import Optional @@ -118,15 +118,15 @@ def serialize(self) -> str: data = self._json_dump(self.data) ctxt = self._json_dump(self.context) - msg = json.dumps({'type': self.msg_type, 'data': data, 'context': ctxt}) + msg = orjson.dumps({'type': self.msg_type, 'data': data, 'context': ctxt}).decode("utf-8") if self._secret_key: payload = encrypt_as_dict(self._secret_key, msg) - return json.dumps(payload) + return orjson.dumps(payload).decode("utf-8") return msg @property def as_dict(self) -> dict: - return json.loads(self.serialize()) + return orjson.loads(self.serialize()) @staticmethod def _json_dump(value): @@ -153,7 +153,7 @@ def serialize_item(x): @staticmethod def _json_load(value): if isinstance(value, str): - obj = json.loads(value) + obj = orjson.loads(value) else: obj = value assert isinstance(obj, dict) @@ -446,10 +446,10 @@ def serialize(self) -> str: str: a json string representation of the message. """ data = self._json_dump(self.data) - msg = json.dumps({'type': self.msg_type, **data}) + msg = orjson.dumps({'type': self.msg_type, **data}).decode("utf-8") if self._secret_key: payload = encrypt_as_dict(self._secret_key, msg) - return json.dumps(payload) + return orjson.dumps(payload).decode("utf-8") return msg @staticmethod diff --git a/ovos_bus_client/util/__init__.py b/ovos_bus_client/util/__init__.py index 9f67b26..5316f83 100644 --- a/ovos_bus_client/util/__init__.py +++ b/ovos_bus_client/util/__init__.py @@ -15,7 +15,7 @@ """ Tools and constructs that are useful together with the messagebus. """ -import json +import orjson from ovos_config.config import read_mycroft_config from ovos_config.locale import get_default_lang @@ -117,7 +117,7 @@ def wait_for_reply(message, reply_type=None, timeout=3.0, bus=None): bus = bus or get_mycroft_bus() if isinstance(message, str): try: - message = json.loads(message) + message = orjson.loads(message) except: pass if isinstance(message, str): @@ -142,7 +142,7 @@ def send_message(message, data=None, context=None, bus=None): message = Message(message, data, context) else: try: - message = json.loads(message) + message = orjson.loads(message) except: message = Message(message) if isinstance(message, dict): @@ -179,7 +179,7 @@ def send_binary_file_message(filepath, msg_type="mycroft.binary.file", def decode_binary_message(message): if isinstance(message, str): try: # json string - message = json.loads(message) + message = orjson.loads(message) binary_data = message.get("binary") or message["data"]["binary"] except: # hex string binary_data = message diff --git a/requirements.txt b/requirements.txt index c78a134..fce3fce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ ovos-config >= 0.0.12, < 0.2.0 ovos-utils >= 0.1.0a9, < 0.2.0 websocket-client>=0.54.0 pyee>=8.1.0, < 9.0.0 +orjson \ No newline at end of file From b1576591148040ea37abbd5e8c887899edfb38fe Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 13 Jan 2024 12:35:11 +0000 Subject: [PATCH 20/91] Increment Version to 0.0.9a7 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index cd88a7c..1573912 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 6 +VERSION_ALPHA = 7 # END_VERSION_BLOCK From f24fe07d3c7c3977f194d9dc8ccc45d3184f30cc Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 13 Jan 2024 12:35:45 +0000 Subject: [PATCH 21/91] Update Changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fa8833..adfdcc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # Changelog -## [0.0.9a6](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a6) (2024-01-12) +## [0.0.9a7](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a7) (2024-01-13) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a5...0.0.9a6) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a6...0.0.9a7) + +**Merged pull requests:** + +- refactor/orjson [\#75](https://github.com/OpenVoiceOS/ovos-bus-client/pull/75) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.9a6](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a6) (2024-01-12) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a5...V0.0.9a6) **Fixed bugs:** From 536f5b38f02d55a5dddb6780984dfc744f4fea6e Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Sat, 13 Jan 2024 22:49:31 +0000 Subject: [PATCH 22/91] remove "Component licenses for mycroft-core:" fix bad copy pasted license file --- LICENSE.md => LICENSE | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) rename LICENSE.md => LICENSE (96%) diff --git a/LICENSE.md b/LICENSE similarity index 96% rename from LICENSE.md rename to LICENSE index b2719d2..617e3cd 100644 --- a/LICENSE.md +++ b/LICENSE @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2024 Casimiro Ferreira Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -200,12 +200,4 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - -======================================================================= -Component licenses for mycroft-core: - -The mycroft-core software references various Python Packages (via PIP), -each of which has a separate license. All are compatible with the -Apache 2.0 license. See the referenced packages listed in the -"requirements.txt" file for specific terms and conditions. From 477caa659ac7b6574f5da5ecdd7168e6939f3e5b Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 13 Jan 2024 22:49:45 +0000 Subject: [PATCH 23/91] Increment Version to 0.0.9a8 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 1573912..8530c5b 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 7 +VERSION_ALPHA = 8 # END_VERSION_BLOCK From c397e14b612caf73219b5d8ade5346f713be2a16 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 13 Jan 2024 22:50:10 +0000 Subject: [PATCH 24/91] Update Changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adfdcc3..fdc8f00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [0.0.9a7](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a7) (2024-01-13) +## [V0.0.9a7](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a7) (2024-01-13) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a6...0.0.9a7) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a6...V0.0.9a7) **Merged pull requests:** From 3e6fb248991ffba12982d544494107ceba1ee7cc Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Tue, 23 Jan 2024 16:17:43 +0000 Subject: [PATCH 25/91] fix/info_leak (#81) remove log line that leaks keys for TTS/STT --- ovos_bus_client/session.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ovos_bus_client/session.py b/ovos_bus_client/session.py index beca8d6..c6e66ae 100644 --- a/ovos_bus_client/session.py +++ b/ovos_bus_client/session.py @@ -543,7 +543,9 @@ def update(sess: Session, make_default: bool = False): if make_default: sess.session_id = "default" - LOG.debug(f"replacing default session with: {sess.serialize()}") + # this log is dangerous, session may contain things like passwords and access keys + # this comment is here to avoid reintroducing it by accident + # LOG.debug(f"replacing default session with: {sess.serialize()}") # DO NOT re-enable in production if sess.session_id == "default": SessionManager.default_session = sess From 7e75d0ab1a85660f6398e85d273032c827394c91 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Tue, 23 Jan 2024 16:17:59 +0000 Subject: [PATCH 26/91] Increment Version to 0.0.9a9 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 8530c5b..c899e3e 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 8 +VERSION_ALPHA = 9 # END_VERSION_BLOCK From df49bf74ee88c142fc04d8745087922ee3c9f3fd Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Tue, 23 Jan 2024 16:18:26 +0000 Subject: [PATCH 27/91] Update Changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdc8f00..494245f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [0.0.9a9](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a9) (2024-01-23) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a8...0.0.9a9) + +**Fixed bugs:** + +- fix/info\_leak [\#81](https://github.com/OpenVoiceOS/ovos-bus-client/pull/81) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.9a8](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a8) (2024-01-13) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a7...V0.0.9a8) + ## [V0.0.9a7](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a7) (2024-01-13) [Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a6...V0.0.9a7) From b9fee5014539b7d12f4cdeccc1a44628fc9a7365 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Sun, 28 Jan 2024 13:46:16 +0000 Subject: [PATCH 28/91] Create dependabot.yml --- .github/dependabot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..9d866e3 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "pip" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" From 990e5136b16c0a57df9a614451a442729a99bf8f Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Mon, 29 Jan 2024 03:03:59 +0000 Subject: [PATCH 29/91] Update default values (#83) edge case when config is missing / older ovos-config installed sync with https://github.com/OpenVoiceOS/ovos-core/pull/402 --- ovos_bus_client/session.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ovos_bus_client/session.py b/ovos_bus_client/session.py index c6e66ae..018dabd 100644 --- a/ovos_bus_client/session.py +++ b/ovos_bus_client/session.py @@ -291,14 +291,17 @@ def __init__(self, session_id: str = None, expiration_seconds: int = None, self.expiration_seconds = expiration_seconds or \ Configuration().get('session', {}).get("ttl", -1) self.pipeline = pipeline or Configuration().get('intents', {}).get("pipeline") or [ + "stop_high", "converse", "padatious_high", - "adapt", - "common_qa", + "adapt_high", "fallback_high", + "stop_medium", "padatious_medium", + "adapt_medium", + "adapt_low", + "common_qa", "fallback_medium", - "padatious_low", "fallback_low" ] self.context = context or IntentContextManager() From 2b0debcfd15df55570beb3f0374eb2f4a21db203 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Mon, 29 Jan 2024 03:04:14 +0000 Subject: [PATCH 30/91] Increment Version to 0.0.9a10 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index c899e3e..69c8321 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 9 +VERSION_ALPHA = 10 # END_VERSION_BLOCK From 34de9d3f2f8f68046604de2530dbf7bf638001d4 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Mon, 29 Jan 2024 03:04:44 +0000 Subject: [PATCH 31/91] Update Changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 494245f..adf7a9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # Changelog -## [0.0.9a9](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a9) (2024-01-23) +## [0.0.9a10](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a10) (2024-01-29) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a8...0.0.9a9) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a9...0.0.9a10) + +**Fixed bugs:** + +- Update default values [\#83](https://github.com/OpenVoiceOS/ovos-bus-client/pull/83) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.9a9](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a9) (2024-01-23) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a8...V0.0.9a9) **Fixed bugs:** From aa7a4ed96b7f4eb3e93f61bd8a0fcd15cd48e38d Mon Sep 17 00:00:00 2001 From: NeonJarbas <59943014+NeonJarbas@users.noreply.github.com> Date: Fri, 2 Feb 2024 01:34:33 +0000 Subject: [PATCH 32/91] feat/remove_all_pages (#84) allow GUI to remove pages before displaying new ones --- ovos_bus_client/apis/gui.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/ovos_bus_client/apis/gui.py b/ovos_bus_client/apis/gui.py index 499c1c4..3286999 100644 --- a/ovos_bus_client/apis/gui.py +++ b/ovos_bus_client/apis/gui.py @@ -146,7 +146,9 @@ def page(self) -> Optional[str]: """ Return the active GUI page name to show """ - return self._pages[self.current_page_idx] if len(self._pages) else None + if not len(self._pages) or self.current_page_idx >= len(self._pages): + return None + return self._pages[self.current_page_idx] @property def connected(self) -> bool: @@ -396,7 +398,8 @@ def _normalize_page_name(page_name: str) -> str: # base gui interactions def show_page(self, name: str, override_idle: Union[bool, int] = None, - override_animations: bool = False): + override_animations: bool = False, index: int = 0, + remove_others=False): """ Request to show a page in the GUI. @param name: page resource requested @@ -404,11 +407,12 @@ def show_page(self, name: str, override_idle: Union[bool, int] = None, if True, override display indefinitely @param override_animations: if True, disables all GUI animations """ - self.show_pages([name], 0, override_idle, override_animations) + self.show_pages([name], index, override_idle, override_animations, remove_others) def show_pages(self, page_names: List[str], index: int = 0, override_idle: Union[bool, int] = None, - override_animations: bool = False): + override_animations: bool = False, + remove_others=False): """ Request to show a list of pages in the GUI. @param page_names: list of page resources requested @@ -432,6 +436,9 @@ def show_pages(self, page_names: List[str], index: int = 0, page_urls = self._pages2uri(page_names) page_names = [self._normalize_page_name(n) for n in page_names] + if remove_others: + self.remove_all_pages(except_pages=page_names) + self._pages = page_names self.current_page_idx = index @@ -477,6 +484,17 @@ def remove_pages(self, page_names: List[str]): "page_names": page_names, "__from": self.skill_id})) + def remove_all_pages(self, except_pages=None): + """ + Request to remove all pages from the GUI. + @param except_pages: list of optional page resources to keep + """ + if not self.bus: + raise RuntimeError("bus not set, did you call self.bind() ?") + self.bus.emit(Message("gui.page.delete.all", + {"__from": self.skill_id, + "except": except_pages or []})) + # Utils / Templates # backport - PR https://github.com/MycroftAI/mycroft-core/pull/2862 From ed578bebbba4e0c7ed2d5e8afbbb4b822df77b27 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 2 Feb 2024 01:34:48 +0000 Subject: [PATCH 33/91] Increment Version to 0.0.9a11 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 69c8321..562e922 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 10 +VERSION_ALPHA = 11 # END_VERSION_BLOCK From c14f127bc434b04dd8bfe15df4bc87fc054e666e Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 2 Feb 2024 01:35:11 +0000 Subject: [PATCH 34/91] Update Changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adf7a9a..a12bcb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # Changelog -## [0.0.9a10](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a10) (2024-01-29) +## [0.0.9a11](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a11) (2024-02-02) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a9...0.0.9a10) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a10...0.0.9a11) + +**Merged pull requests:** + +- feat/remove\_all\_pages [\#84](https://github.com/OpenVoiceOS/ovos-bus-client/pull/84) ([NeonJarbas](https://github.com/NeonJarbas)) + +## [V0.0.9a10](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a10) (2024-01-29) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a9...V0.0.9a10) **Fixed bugs:** From 4b67d0cf83da7fde545dcd2b3bf2e7127ed4c737 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Wed, 21 Feb 2024 03:38:32 +0000 Subject: [PATCH 35/91] feat/session_location (#85) --- ovos_bus_client/session.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/ovos_bus_client/session.py b/ovos_bus_client/session.py index 018dabd..714a387 100644 --- a/ovos_bus_client/session.py +++ b/ovos_bus_client/session.py @@ -261,14 +261,17 @@ def get_context(self, max_frames: int = None, class Session: - def __init__(self, session_id: str = None, expiration_seconds: int = None, + def __init__(self, session_id: str = None, + expiration_seconds: int = None, active_skills: List[List[Union[str, float]]] = None, - utterance_states: Dict = None, lang: str = None, + utterance_states: Dict = None, + lang: str = None, context: IntentContextManager = None, site_id: str = "unknown", pipeline: List[str] = None, stt_prefs: Dict = None, - tts_prefs: Dict = None): + tts_prefs: Dict = None, + location_prefs: Dict = None): """ Construct a session identifier @param session_id: string UUID for the session @@ -282,7 +285,7 @@ def __init__(self, session_id: str = None, expiration_seconds: int = None, self.lang = lang or get_default_lang() - self.site_id = site_id or "unknown" # indoors placement info + self.site_id = site_id or Configuration().get("site_id") or "unknown" # indoors placement info self.active_skills = active_skills or [] # [skill_id , timestamp]# (Message , timestamp) self.utterance_states = utterance_states or {} # {skill_id: UtteranceState} @@ -319,6 +322,7 @@ def __init__(self, session_id: str = None, expiration_seconds: int = None, tts_prefs = {"plugin_id": ttsm, "config": tts.get(ttsm) or {}} self.tts_preferences = tts_prefs + self.location_preferences = location_prefs or Configuration().get("location", {}) @property def active(self) -> bool: @@ -415,7 +419,8 @@ def serialize(self) -> dict: "site_id": self.site_id, "pipeline": self.pipeline, "stt": self.stt_preferences, - "tts": self.tts_preferences + "tts": self.tts_preferences, + "location": self.location_preferences } def update_history(self, message: Message = None): @@ -440,8 +445,9 @@ def deserialize(data: Dict): context = IntentContextManager.deserialize(data.get("context", {})) site_id = data.get("site_id", "unknown") pipeline = data.get("pipeline", []) - tts = data.get("tts_preferences", {}) - stt = data.get("stt_preferences", {}) + tts = data.get("tts", {}) + stt = data.get("stt", {}) + location = data.get("location", {}) return Session(uid, active_skills=active, utterance_states=states, @@ -450,7 +456,8 @@ def deserialize(data: Dict): pipeline=pipeline, site_id=site_id, tts_prefs=tts, - stt_prefs=stt) + stt_prefs=stt, + location_prefs=location) @staticmethod def from_message(message: Message = None): From 226fcd84125ebbf06d6fdd2b55e73fc5489f6589 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Wed, 21 Feb 2024 03:38:46 +0000 Subject: [PATCH 36/91] Increment Version to 0.0.9a12 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 562e922..d0cd9af 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 11 +VERSION_ALPHA = 12 # END_VERSION_BLOCK From 9ba0f2b89a1cb144cd7c5eb74ac4b17f1013234a Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Wed, 21 Feb 2024 03:39:14 +0000 Subject: [PATCH 37/91] Update Changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a12bcb7..94abfab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # Changelog -## [0.0.9a11](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a11) (2024-02-02) +## [0.0.9a12](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a12) (2024-02-21) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a10...0.0.9a11) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a11...0.0.9a12) + +**Implemented enhancements:** + +- feat/session\_location [\#85](https://github.com/OpenVoiceOS/ovos-bus-client/pull/85) ([JarbasAl](https://github.com/JarbasAl)) + +## [V0.0.9a11](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a11) (2024-02-02) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a10...V0.0.9a11) **Merged pull requests:** From d90f7ef33356545fa762deac03f740dfec84f5df Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 9 Mar 2024 22:23:38 -0600 Subject: [PATCH 38/91] chore(docs): add a long description to PyPi (#86) --- setup.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 7eb8b4d..1de4307 100644 --- a/setup.py +++ b/setup.py @@ -42,6 +42,8 @@ def get_version(): version += f"a{alpha}" return version +with open("README.md", "r") as f: + long_description = f.read() setup( name='ovos-bus-client', @@ -58,17 +60,16 @@ def get_version(): url='https://github.com/OpenVoiceOS/ovos-bus-client', license='Apache-2.0', author='JarbasAI', - author_email='jarbasai@mailfence.com', + author_email='jarbas@openvoiceos.com', description='OVOS Messagebus Client', + long_description=long_description, + long_description_content_type="text/markdown", classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3', ], entry_points={ 'console_scripts': [ From 4c312d120ff652f624cbbcfbd1ed69277ee00ad5 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sun, 10 Mar 2024 04:23:52 +0000 Subject: [PATCH 39/91] Increment Version to --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index d0cd9af..694da14 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 12 +VERSION_ALPHA = 13 # END_VERSION_BLOCK From 56f66aa3f9a7ecaaa9658d5dcee5c1613f510360 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sun, 10 Mar 2024 04:24:20 +0000 Subject: [PATCH 40/91] Update Changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94abfab..8c9f203 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # Changelog -## [0.0.9a12](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a12) (2024-02-21) +## [Unreleased](https://github.com/OpenVoiceOS/ovos-bus-client/tree/HEAD) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a11...0.0.9a12) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a12...HEAD) + +**Merged pull requests:** + +- chore\(docs\): add a long description to PyPi [\#86](https://github.com/OpenVoiceOS/ovos-bus-client/pull/86) ([mikejgray](https://github.com/mikejgray)) + +## [V0.0.9a12](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V0.0.9a12) (2024-02-21) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a11...V0.0.9a12) **Implemented enhancements:** From 04752ec282fad1af416f9a101c9b5a87e19864df Mon Sep 17 00:00:00 2001 From: miro Date: Tue, 9 Apr 2024 02:03:21 +0100 Subject: [PATCH 41/91] fix/ocp_norm_tracks fix bug, method is not handling MediaEntry objects --- ovos_bus_client/apis/ocp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index 6163fe5..19f3235 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -261,7 +261,7 @@ def norm_tracks(tracks: list): tracks[idx] = MediaEntry.from_dict(track) elif isinstance(track, list) and not isinstance(track, Playlist): tracks[idx] = OCPInterface.norm_tracks(track) - else: + elif not isinstance(track, MediaEntry): # TODO - support string uris # let it fail in next assert # log all bad entries before failing From 25bfe33553afb9b1f0861b0e89effe7bc4a108d3 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Tue, 9 Apr 2024 01:03:44 +0000 Subject: [PATCH 42/91] Increment Version to --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 694da14..9d26e1d 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 13 +VERSION_ALPHA = 14 # END_VERSION_BLOCK From bd491af7f4926126c53eb6499cdb2a2e048a59ec Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Tue, 9 Apr 2024 01:04:29 +0000 Subject: [PATCH 43/91] Update Changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c9f203..487401e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [Unreleased](https://github.com/OpenVoiceOS/ovos-bus-client/tree/HEAD) +## [V](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V) (2024-03-10) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a12...HEAD) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a12...V) **Merged pull requests:** From 92450917892b25e429ae8c3cdb18c64ea8c879fc Mon Sep 17 00:00:00 2001 From: NeonJarbas <59943014+NeonJarbas@users.noreply.github.com> Date: Tue, 9 Apr 2024 18:57:11 +0100 Subject: [PATCH 44/91] feat/targeted OCP queries (#88) allows ovos-media to query individual OCP skills Co-authored-by: miro --- ovos_bus_client/apis/ocp.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index 19f3235..296498c 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -871,15 +871,20 @@ def reset(self): else: self.has_gui = is_gui_running() or is_gui_connected(self.bus) - def send(self): + def send(self, skill_id: str = None): self.query_replies = [] self.query_timeouts = self.config.get("min_timeout", 5) self.search_start = time.time() self.searching = True self.register_events() - self.bus.emit(Message('ovos.common_play.query', - {"phrase": self.query, - "question_type": self.media_type})) + if skill_id: + self.bus.emit(Message(f'ovos.common_play.query.{skill_id}', + {"phrase": self.query, + "question_type": self.media_type})) + else: + self.bus.emit(Message('ovos.common_play.query', + {"phrase": self.query, + "question_type": self.media_type})) def wait(self): # if there is no match type defined, lets increase timeout a bit From 9caac7e8ce83df6601369fba3528e135f5a34ff2 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Tue, 9 Apr 2024 17:57:28 +0000 Subject: [PATCH 45/91] Increment Version to --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 9d26e1d..d6dc909 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 14 +VERSION_ALPHA = 15 # END_VERSION_BLOCK From d23388d0942548b54442069b20b068bd38d8ba5e Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Tue, 9 Apr 2024 17:57:58 +0000 Subject: [PATCH 46/91] Update Changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 487401e..4d3b916 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [Unreleased](https://github.com/OpenVoiceOS/ovos-bus-client/tree/HEAD) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...HEAD) + +**Implemented enhancements:** + +- feat/targeted OCP queries [\#88](https://github.com/OpenVoiceOS/ovos-bus-client/pull/88) ([NeonJarbas](https://github.com/NeonJarbas)) + ## [V](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V) (2024-03-10) [Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a12...V) From 277d2dbf24e05a27402f71480f8355f91c8d9809 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Sun, 21 Apr 2024 00:01:13 +0100 Subject: [PATCH 47/91] feat/add_units_to_session (#90) allow unit preferences in session --- ovos_bus_client/session.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/ovos_bus_client/session.py b/ovos_bus_client/session.py index 714a387..d3ec34c 100644 --- a/ovos_bus_client/session.py +++ b/ovos_bus_client/session.py @@ -271,7 +271,10 @@ def __init__(self, session_id: str = None, pipeline: List[str] = None, stt_prefs: Dict = None, tts_prefs: Dict = None, - location_prefs: Dict = None): + location_prefs: Dict = None, + system_unit: str = None, + time_format: str = None, + date_format: str = None): """ Construct a session identifier @param session_id: string UUID for the session @@ -284,6 +287,9 @@ def __init__(self, session_id: str = None, self.session_id = session_id or str(uuid4()) self.lang = lang or get_default_lang() + self.system_unit = system_unit or Configuration().get("system_unit", "metric") + self.date_format = date_format or Configuration().get("date_format", "DMY") + self.time_format = time_format or Configuration().get("time_format", "full") self.site_id = site_id or Configuration().get("site_id") or "unknown" # indoors placement info @@ -420,7 +426,10 @@ def serialize(self) -> dict: "pipeline": self.pipeline, "stt": self.stt_preferences, "tts": self.tts_preferences, - "location": self.location_preferences + "location": self.location_preferences, + "system_unit": self.system_unit, + "time_format": self.time_format, + "date_format": self.date_format } def update_history(self, message: Message = None): @@ -448,6 +457,9 @@ def deserialize(data: Dict): tts = data.get("tts", {}) stt = data.get("stt", {}) location = data.get("location", {}) + system_unit = data.get("system_unit") + date_format = data.get("date_format") + time_format = data.get("time_format") return Session(uid, active_skills=active, utterance_states=states, @@ -457,7 +469,10 @@ def deserialize(data: Dict): site_id=site_id, tts_prefs=tts, stt_prefs=stt, - location_prefs=location) + location_prefs=location, + system_unit=system_unit, + date_format=date_format, + time_format=time_format) @staticmethod def from_message(message: Message = None): From 8593080f40c4be0e087c495874b00a5439412036 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 20 Apr 2024 23:01:28 +0000 Subject: [PATCH 48/91] Increment Version to --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index d6dc909..4e09339 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 15 +VERSION_ALPHA = 16 # END_VERSION_BLOCK From b51d1fdb8da708b7075722f04891b2a371f7209a Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 20 Apr 2024 23:01:52 +0000 Subject: [PATCH 49/91] Update Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d3b916..de356d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ **Implemented enhancements:** +- feat/add\_units\_to\_session [\#90](https://github.com/OpenVoiceOS/ovos-bus-client/pull/90) ([JarbasAl](https://github.com/JarbasAl)) - feat/targeted OCP queries [\#88](https://github.com/OpenVoiceOS/ovos-bus-client/pull/88) ([NeonJarbas](https://github.com/NeonJarbas)) ## [V](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V) (2024-03-10) From 629f9ae8709ddd219312deeb276a7c130b96350b Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Sun, 21 Apr 2024 00:07:07 +0100 Subject: [PATCH 50/91] hotfix/skip_github_releases --- .github/workflows/publish_alpha.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.github/workflows/publish_alpha.yml b/.github/workflows/publish_alpha.yml index 86dcaca..1e09747 100644 --- a/.github/workflows/publish_alpha.yml +++ b/.github/workflows/publish_alpha.yml @@ -34,20 +34,6 @@ jobs: runs-on: ubuntu-latest needs: update_version steps: - - name: Create Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token - with: - tag_name: V${{ needs.update_version.outputs.version }} - release_name: Release ${{ needs.update_version.outputs.version }} - body: | - Changes in this Release - ${{ needs.update_version.outputs.changelog }} - draft: false - prerelease: true - commitish: dev - name: Checkout Repository uses: actions/checkout@v2 with: From aa7fe2fb96f02535d2b9773ae43dc1a0e5ce6996 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 20 Apr 2024 23:07:35 +0000 Subject: [PATCH 51/91] Increment Version to --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 4e09339..fb28f11 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 16 +VERSION_ALPHA = 17 # END_VERSION_BLOCK From 25e4b4d87ac55cef64890c346f3362fac8fe5be7 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Thu, 25 Apr 2024 19:43:58 +0100 Subject: [PATCH 52/91] refactor/remove_stt+tts_prefs (#91) * refactor/remove_stt+tts_prefs deeper changes are needed in listener/audio to support this properly, removing from session until this is more fleshed out there will be some overlap with user_id later and maybe makes more sense to retrieve this out of bounds instead of passing full plugin configs in message.context perhaps in the future ovos-audio/listener can load multiple plugins at once and this functionality restored * deprecation --- ovos_bus_client/session.py | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/ovos_bus_client/session.py b/ovos_bus_client/session.py index d3ec34c..c892283 100644 --- a/ovos_bus_client/session.py +++ b/ovos_bus_client/session.py @@ -284,6 +284,10 @@ def __init__(self, session_id: str = None, @param lang: language associated with this Session @param context: IntentContextManager for this Session """ + if tts_prefs: + LOG.warning("tts_prefs have been deprecated! value will be ignored and fully removed in 0.1.0") + if stt_prefs: + LOG.warning("stt_prefs have been deprecated! value will be ignored and fully removed in 0.1.0") self.session_id = session_id or str(uuid4()) self.lang = lang or get_default_lang() @@ -315,19 +319,6 @@ def __init__(self, session_id: str = None, ] self.context = context or IntentContextManager() - if not stt_prefs: - stt = Configuration().get("stt", {}) - sttm = stt.get("module", "ovos-stt-plugin-server") - stt_prefs = {"plugin_id": sttm, - "config": stt.get(sttm) or {}} - self.stt_preferences = stt_prefs - - if not tts_prefs: - tts = Configuration().get("tts", {}) - ttsm = tts.get("module", "ovos-tts-plugin-server") - tts_prefs = {"plugin_id": ttsm, - "config": tts.get(ttsm) or {}} - self.tts_preferences = tts_prefs self.location_preferences = location_prefs or Configuration().get("location", {}) @property @@ -424,8 +415,6 @@ def serialize(self) -> dict: "context": self.context.serialize(), "site_id": self.site_id, "pipeline": self.pipeline, - "stt": self.stt_preferences, - "tts": self.tts_preferences, "location": self.location_preferences, "system_unit": self.system_unit, "time_format": self.time_format, @@ -454,8 +443,6 @@ def deserialize(data: Dict): context = IntentContextManager.deserialize(data.get("context", {})) site_id = data.get("site_id", "unknown") pipeline = data.get("pipeline", []) - tts = data.get("tts", {}) - stt = data.get("stt", {}) location = data.get("location", {}) system_unit = data.get("system_unit") date_format = data.get("date_format") @@ -467,8 +454,6 @@ def deserialize(data: Dict): context=context, pipeline=pipeline, site_id=site_id, - tts_prefs=tts, - stt_prefs=stt, location_prefs=location, system_unit=system_unit, date_format=date_format, From 005192de10b3e5e76cae9ce97da87e0e83bcb3fd Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Thu, 25 Apr 2024 18:44:14 +0000 Subject: [PATCH 53/91] Increment Version to --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index fb28f11..a2af5f1 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 17 +VERSION_ALPHA = 18 # END_VERSION_BLOCK From c6d089ee06d7c86ec3f780e78eb01a75e36e6fe6 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Thu, 25 Apr 2024 18:44:39 +0000 Subject: [PATCH 54/91] Update Changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index de356d9..61f2419 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ [Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...HEAD) +**Breaking changes:** + +- refactor/remove\_stt+tts\_prefs [\#91](https://github.com/OpenVoiceOS/ovos-bus-client/pull/91) ([JarbasAl](https://github.com/JarbasAl)) + **Implemented enhancements:** - feat/add\_units\_to\_session [\#90](https://github.com/OpenVoiceOS/ovos-bus-client/pull/90) ([JarbasAl](https://github.com/JarbasAl)) From e67b6302d63cbacdf6a12e3a837100ae9934c332 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Fri, 3 May 2024 18:37:44 +0100 Subject: [PATCH 55/91] feat/track_speaking+recording_per_session (#93) keep track of is_speaking and is_recording per session brings back `is_speaking` and `wait_while_speaking` per Session, allowing HiveMind integration --- ovos_bus_client/session.py | 125 ++++++++++++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 10 deletions(-) diff --git a/ovos_bus_client/session.py b/ovos_bus_client/session.py index c892283..ae19141 100644 --- a/ovos_bus_client/session.py +++ b/ovos_bus_client/session.py @@ -1,6 +1,6 @@ import enum import time -from threading import Lock +from threading import Lock, Event from typing import Optional, List, Tuple, Union, Iterable, Dict from uuid import uuid4 @@ -274,7 +274,9 @@ def __init__(self, session_id: str = None, location_prefs: Dict = None, system_unit: str = None, time_format: str = None, - date_format: str = None): + date_format: str = None, + is_speaking: bool = False, + is_recording: bool = False): """ Construct a session identifier @param session_id: string UUID for the session @@ -295,6 +297,8 @@ def __init__(self, session_id: str = None, self.date_format = date_format or Configuration().get("date_format", "DMY") self.time_format = time_format or Configuration().get("time_format", "full") + self.is_recording = is_recording + self.is_speaking = is_speaking self.site_id = site_id or Configuration().get("site_id") or "unknown" # indoors placement info self.active_skills = active_skills or [] # [skill_id , timestamp]# (Message , timestamp) @@ -418,7 +422,9 @@ def serialize(self) -> dict: "location": self.location_preferences, "system_unit": self.system_unit, "time_format": self.time_format, - "date_format": self.date_format + "date_format": self.date_format, + "is_speaking": self.is_speaking, + "is_recording": self.is_recording } def update_history(self, message: Message = None): @@ -447,6 +453,8 @@ def deserialize(data: Dict): system_unit = data.get("system_unit") date_format = data.get("date_format") time_format = data.get("time_format") + is_recording = data.get("is_recording", False) + is_speaking = data.get("is_speaking", False) return Session(uid, active_skills=active, utterance_states=states, @@ -457,7 +465,9 @@ def deserialize(data: Dict): location_prefs=location, system_unit=system_unit, date_format=date_format, - time_format=time_format) + time_format=time_format, + is_recording=is_recording, + is_speaking=is_speaking) @staticmethod def from_message(message: Message = None): @@ -508,14 +518,13 @@ def sync(cls, message=None): @classmethod def connect_to_bus(cls, bus): cls.bus = bus - cls.bus.on("ovos.session.sync", - cls.handle_default_session_request) + cls.bus.on("recognizer_loop:record_begin", cls.handle_recording_start) + cls.bus.on("recognizer_loop:record_end", cls.handle_recording_end) + cls.bus.on("recognizer_loop:audio_output_start", cls.handle_audio_output_start) + cls.bus.on("recognizer_loop:audio_output_end", cls.handle_audio_output_end) + cls.bus.on("ovos.session.sync", cls.handle_default_session_request) cls.sync() - @classmethod - def handle_default_session_request(cls, message=None): - cls.sync(message) - @staticmethod def prune_sessions(): """ @@ -595,3 +604,99 @@ def touch(message: Message = None): """ sess = SessionManager.get(message) sess.touch() + + ############################## + # util methods for skill consumption + @classmethod + def is_speaking(cls, session: Session = None): + session = session or SessionManager.get() + return session.is_speaking + + @classmethod + def wait_while_speaking(cls, timeout=15, session: Session = None): + """ wait until audio service reports end of audio output """ + if not cls.bus: + LOG.error("SessionManager not connected to bus, can not monitor speech state") + return + + session = session or SessionManager.get() + if not cls.is_speaking(session): + return + + # wait until end of speech + event = Event() + sessid = session.session_id + + def handle_output_end(msg): + nonlocal sessid, event + sess = SessionManager.get(msg) + if sessid == sess.session_id: + event.set() + + cls.bus.on("recognizer_loop:audio_output_end", handle_output_end) + event.wait(timeout=timeout) + cls.bus.remove("recognizer_loop:audio_output_end", handle_output_end) + + @classmethod + def is_recording(cls, session: Session = None): + session = session or SessionManager.get() + return session.is_recording + + @classmethod + def wait_while_recording(cls, timeout=45, session: Session = None): + """ wait until listener service reports end of recording""" + if not cls.bus: + LOG.error("SessionManager not connected to bus, can not monitor recording state") + return + + session = session or SessionManager.get() + if not cls.is_recording(session): + return + + # wait until end of recording + event = Event() + sessid = session.session_id + + def handle_rec_end(msg): + nonlocal sessid, event + sess = SessionManager.get(msg) + if sessid == sess.session_id: + event.set() + + cls.bus.on("recognizer_loop:record_end", handle_rec_end) + event.wait(timeout=timeout) + cls.bus.remove("recognizer_loop:record_end", handle_rec_end) + + ############################### + # State tracking events + @classmethod + def handle_recording_start(cls, message): + """track when a session is recording audio""" + sess = cls.get(message) + sess.is_recording = True + cls.update(sess) + + @classmethod + def handle_recording_end(cls, message): + """track when a session stops recording audio""" + sess = cls.get(message) + sess.is_recording = False + cls.update(sess) + + @classmethod + def handle_audio_output_start(cls, message): + """track when a session is outputting audio""" + sess = cls.get(message) + sess.is_speaking = True + cls.update(sess) + + @classmethod + def handle_audio_output_end(cls, message): + """track when a session stops outputting audio""" + sess = cls.get(message) + sess.is_speaking = False + cls.update(sess) + + @classmethod + def handle_default_session_request(cls, message=None): + cls.sync(message) From 06d558593156c2cfc00f0789430aab3c57f4b4a9 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 3 May 2024 17:37:59 +0000 Subject: [PATCH 56/91] Increment Version to --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index a2af5f1..d9732a8 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 18 +VERSION_ALPHA = 19 # END_VERSION_BLOCK From 77c3aaa9d7ac12bd709628fe5751e1ddae8b585e Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 3 May 2024 17:38:25 +0000 Subject: [PATCH 57/91] Update Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61f2419..29a1dba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ **Implemented enhancements:** +- feat/track\_speaking+recording\_per\_session [\#93](https://github.com/OpenVoiceOS/ovos-bus-client/pull/93) ([JarbasAl](https://github.com/JarbasAl)) - feat/add\_units\_to\_session [\#90](https://github.com/OpenVoiceOS/ovos-bus-client/pull/90) ([JarbasAl](https://github.com/JarbasAl)) - feat/targeted OCP queries [\#88](https://github.com/OpenVoiceOS/ovos-bus-client/pull/88) ([NeonJarbas](https://github.com/NeonJarbas)) From 2ba3c1f6c927745bd06cf92150fe0c04d4735960 Mon Sep 17 00:00:00 2001 From: Daniel McKnight <34697904+NeonDaniel@users.noreply.github.com> Date: Tue, 7 May 2024 09:31:58 -0700 Subject: [PATCH 58/91] Update imports to support ovos-utils~=0.0.x with compat. warnings (#94) * Update imports to support ovos-utils~=0.0.x with compat. warnings * Refactor to resolve reference error https://github.com/NeonGeckoCom/NeonCore/actions/runs/8976886241/job/24654634811?pr=641 * Add type annotations to resolve warnings Remove patched OCP imports and move imports into classes/methods as requested * Refactor to allow initialization without ovos-utils 0.1 --------- Co-authored-by: Daniel McKnight --- ovos_bus_client/apis/ocp.py | 67 +++++++++++++++++++++++++------------ requirements.txt | 2 +- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index 296498c..05a8e4f 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -14,11 +14,10 @@ from datetime import timedelta from os.path import abspath from threading import Lock -from typing import List +from typing import List, Union from ovos_utils.gui import is_gui_connected, is_gui_running from ovos_utils.log import LOG, deprecated -from ovos_utils.ocp import MediaType, PlaybackMode, Playlist, MediaEntry from ovos_bus_client.message import Message from ovos_bus_client.message import dig_for_message @@ -163,7 +162,7 @@ def set_track_position(self, seconds): self.bus.emit(Message('mycroft.audio.service.set_track_position', {"position": seconds * 1000})) # convert to ms - def seek(self, seconds=1): + def seek(self, seconds: Union[int, float, timedelta] = 1): """Seek X seconds. Args: @@ -176,7 +175,7 @@ def seek(self, seconds=1): else: self.seek_forward(seconds) - def seek_forward(self, seconds=1): + def seek_forward(self, seconds: Union[int, float, timedelta] = 1): """Skip ahead X seconds. Args: @@ -187,7 +186,7 @@ def seek_forward(self, seconds=1): self.bus.emit(Message('mycroft.audio.service.seek_forward', {"seconds": seconds})) - def seek_backward(self, seconds=1): + def seek_backward(self, seconds: Union[int, float, timedelta] = 1): """Rewind X seconds Args: @@ -253,6 +252,11 @@ def _format_msg(self, msg_type, msg_data=None): # OCP bus api @staticmethod def norm_tracks(tracks: list): + try: + from ovos_utils.ocp import Playlist, MediaEntry + except ImportError as e: + raise RuntimeError("This method requires ovos-utils ~=0.1") from e + """ensures a list of tracks contains only MediaEntry or Playlist items""" assert isinstance(tracks, list) # support Playlist and MediaEntry objects in tracks @@ -479,7 +483,7 @@ def set_track_position(self, seconds): self.bus.emit(Message('ovos.audio.service.set_track_position', {"position": seconds * 1000})) # convert to ms - def seek(self, seconds=1): + def seek(self, seconds: Union[int, float, timedelta] = 1): """Seek X seconds. Args: @@ -492,7 +496,7 @@ def seek(self, seconds=1): else: self.seek_forward(seconds) - def seek_forward(self, seconds=1): + def seek_forward(self, seconds: Union[int, float, timedelta] = 1): """Skip ahead X seconds. Args: @@ -503,7 +507,7 @@ def seek_forward(self, seconds=1): self.bus.emit(Message('ovos.audio.service.seek_forward', {"seconds": seconds})) - def seek_backward(self, seconds=1): + def seek_backward(self, seconds: Union[int, float, timedelta] = 1): """Rewind X seconds Args: @@ -641,7 +645,7 @@ def seek(self, seconds=1): else: self.seek_forward(seconds) - def seek_forward(self, seconds=1): + def seek_forward(self, seconds: Union[int, float, timedelta] = 1): """Skip ahead X seconds. Args: @@ -652,7 +656,7 @@ def seek_forward(self, seconds=1): self.bus.emit(Message('ovos.video.service.seek_forward', {"seconds": seconds})) - def seek_backward(self, seconds=1): + def seek_backward(self, seconds: Union[int, float, timedelta] = 1): """Rewind X seconds Args: @@ -777,7 +781,7 @@ def set_track_position(self, seconds): self.bus.emit(Message('ovos.web.service.set_track_position', {"position": seconds * 1000})) # convert to ms - def seek(self, seconds=1): + def seek(self, seconds: Union[int, float, timedelta] = 1): """Seek X seconds. Args: @@ -790,7 +794,7 @@ def seek(self, seconds=1): else: self.seek_forward(seconds) - def seek_forward(self, seconds=1): + def seek_forward(self, seconds: Union[int, float, timedelta] = 1): """Skip ahead X seconds. Args: @@ -801,7 +805,7 @@ def seek_forward(self, seconds=1): self.bus.emit(Message('ovos.web.service.seek_forward', {"seconds": seconds})) - def seek_backward(self, seconds=1): + def seek_backward(self, seconds: Union[int, float, timedelta] = 1): """Rewind X seconds Args: @@ -841,17 +845,28 @@ def is_playing(self): class OCPQuery: - cast2audio = [ - MediaType.MUSIC, - MediaType.PODCAST, - MediaType.AUDIOBOOK, - MediaType.RADIO, - MediaType.RADIO_THEATRE, - MediaType.VISUAL_STORY, - MediaType.NEWS - ] + try: + from ovos_utils.ocp import MediaType + cast2audio = [ + MediaType.MUSIC, + MediaType.PODCAST, + MediaType.AUDIOBOOK, + MediaType.RADIO, + MediaType.RADIO_THEATRE, + MediaType.VISUAL_STORY, + MediaType.NEWS + ] + except ImportError as e: + from enum import IntEnum + + class MediaType(IntEnum): + GENERIC = 0 # nothing else matches + + cast2audio = None def __init__(self, query, bus, media_type=MediaType.GENERIC, config=None): + if self.cast2audio is None: + raise RuntimeError("This class requires ovos-utils ~=0.1") LOG.debug(f"Created {media_type.name} query: {query}") self.query = query self.media_type = media_type @@ -860,6 +875,10 @@ def __init__(self, query, bus, media_type=MediaType.GENERIC, config=None): self.reset() def reset(self): + try: + from ovos_utils.ocp import PlaybackMode + except ImportError as e: + raise RuntimeError("This method requires ovos-utils ~=0.1") from e self.active_skills = {} self.active_skills_lock = Lock() self.query_replies = [] @@ -887,6 +906,10 @@ def send(self, skill_id: str = None): "question_type": self.media_type})) def wait(self): + try: + from ovos_utils.ocp import MediaType + except ImportError as e: + raise RuntimeError("This method requires ovos-utils ~=0.1") from e # if there is no match type defined, lets increase timeout a bit # since all skills need to search if self.media_type == MediaType.GENERIC: diff --git a/requirements.txt b/requirements.txt index fce3fce..3b1195e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ ovos-config >= 0.0.12, < 0.2.0 -ovos-utils >= 0.1.0a9, < 0.2.0 +ovos-utils >= 0.0.38, < 0.2.0 websocket-client>=0.54.0 pyee>=8.1.0, < 9.0.0 orjson \ No newline at end of file From b5669161f16f774685afbb7b484ca41bd972b830 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Tue, 7 May 2024 16:32:12 +0000 Subject: [PATCH 59/91] Increment Version to --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index d9732a8..20a34c3 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 19 +VERSION_ALPHA = 20 # END_VERSION_BLOCK From ffc3d40d7e08f8226bfe774682f0a96f6881550a Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Tue, 7 May 2024 16:32:43 +0000 Subject: [PATCH 60/91] Update Changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29a1dba..b6d834f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ - feat/add\_units\_to\_session [\#90](https://github.com/OpenVoiceOS/ovos-bus-client/pull/90) ([JarbasAl](https://github.com/JarbasAl)) - feat/targeted OCP queries [\#88](https://github.com/OpenVoiceOS/ovos-bus-client/pull/88) ([NeonJarbas](https://github.com/NeonJarbas)) +**Merged pull requests:** + +- Update imports to support ovos-utils~=0.0.x with compat. warnings [\#94](https://github.com/OpenVoiceOS/ovos-bus-client/pull/94) ([NeonDaniel](https://github.com/NeonDaniel)) + ## [V](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V) (2024-03-10) [Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V0.0.9a12...V) From 8420d7a8d678d01200405d1f6f84a4158c7c2e96 Mon Sep 17 00:00:00 2001 From: Daniel McKnight <34697904+NeonDaniel@users.noreply.github.com> Date: Wed, 8 May 2024 15:39:14 -0700 Subject: [PATCH 61/91] Update setup.py to resolve version automation bug (#95) Co-authored-by: Daniel McKnight --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 1de4307..24e9718 100644 --- a/setup.py +++ b/setup.py @@ -8,8 +8,7 @@ def required(requirements_file): """ Read requirements file and remove comments and empty lines. """ - base_dir = os.path.abspath(os.path.dirname(__file__)) - with open(os.path.join(base_dir, requirements_file), 'r') as f: + with open(os.path.join(BASEDIR, requirements_file), 'r') as f: requirements = f.read().splitlines() if 'MYCROFT_LOOSE_REQUIREMENTS' in os.environ: print('USING LOOSE REQUIREMENTS!') @@ -42,7 +41,8 @@ def get_version(): version += f"a{alpha}" return version -with open("README.md", "r") as f: + +with open(os.path.join(BASEDIR, "README.md"), "r") as f: long_description = f.read() setup( From e5369e4b4c2e9aa012b7546955aa277f419258b4 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Wed, 8 May 2024 22:39:30 +0000 Subject: [PATCH 62/91] Increment Version to 0.0.9a21 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 20a34c3..3c3a4cc 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 20 +VERSION_ALPHA = 21 # END_VERSION_BLOCK From 93363fbf4dd6cac73b8a6b6ac50f13a6edd47b54 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Wed, 8 May 2024 22:40:01 +0000 Subject: [PATCH 63/91] Update Changelog --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6d834f..cd101da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [Unreleased](https://github.com/OpenVoiceOS/ovos-bus-client/tree/HEAD) +## [0.0.9a21](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a21) (2024-05-08) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...HEAD) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a21) **Breaking changes:** @@ -14,6 +14,10 @@ - feat/add\_units\_to\_session [\#90](https://github.com/OpenVoiceOS/ovos-bus-client/pull/90) ([JarbasAl](https://github.com/JarbasAl)) - feat/targeted OCP queries [\#88](https://github.com/OpenVoiceOS/ovos-bus-client/pull/88) ([NeonJarbas](https://github.com/NeonJarbas)) +**Fixed bugs:** + +- Update setup.py to resolve version automation bug [\#95](https://github.com/OpenVoiceOS/ovos-bus-client/pull/95) ([NeonDaniel](https://github.com/NeonDaniel)) + **Merged pull requests:** - Update imports to support ovos-utils~=0.0.x with compat. warnings [\#94](https://github.com/OpenVoiceOS/ovos-bus-client/pull/94) ([NeonDaniel](https://github.com/NeonDaniel)) From 9776d6ee8aba54fbb631b36108c1ace632cfbabe Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Wed, 5 Jun 2024 03:17:13 +0100 Subject: [PATCH 64/91] feat/blacklist_from_session (#98) allow skill_id and intents to be blacklisted in the Session, these will be ignored during the matching process this allows finetuning utterances and permissions per client, taking it into account during the match process instead of filtering before/after the handling of the utterance needed for hivemind RBAC companion to https://github.com/OpenVoiceOS/ovos-core/pull/492 --- ovos_bus_client/session.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/ovos_bus_client/session.py b/ovos_bus_client/session.py index ae19141..723c50f 100644 --- a/ovos_bus_client/session.py +++ b/ovos_bus_client/session.py @@ -276,7 +276,9 @@ def __init__(self, session_id: str = None, time_format: str = None, date_format: str = None, is_speaking: bool = False, - is_recording: bool = False): + is_recording: bool = False, + blacklisted_intents: Optional[List[str]] = None, + blacklisted_skills: Optional[List[str]] = None): """ Construct a session identifier @param session_id: string UUID for the session @@ -291,7 +293,10 @@ def __init__(self, session_id: str = None, if stt_prefs: LOG.warning("stt_prefs have been deprecated! value will be ignored and fully removed in 0.1.0") self.session_id = session_id or str(uuid4()) - + self.blacklisted_skills = (blacklisted_skills or + Configuration().get("skills", {}).get("blacklisted_skills", [])) + self.blacklisted_intents = (blacklisted_intents or + Configuration().get("intents", {}).get("blacklisted_intents", [])) self.lang = lang or get_default_lang() self.system_unit = system_unit or Configuration().get("system_unit", "metric") self.date_format = date_format or Configuration().get("date_format", "DMY") @@ -424,7 +429,9 @@ def serialize(self) -> dict: "time_format": self.time_format, "date_format": self.date_format, "is_speaking": self.is_speaking, - "is_recording": self.is_recording + "is_recording": self.is_recording, + "blacklisted_skills": self.blacklisted_skills, + "blacklisted_intents": self.blacklisted_intents } def update_history(self, message: Message = None): @@ -455,6 +462,8 @@ def deserialize(data: Dict): time_format = data.get("time_format") is_recording = data.get("is_recording", False) is_speaking = data.get("is_speaking", False) + blacklisted_skills = data.get("blacklisted_skills", []) + blacklisted_intents = data.get("blacklisted_intents", []) return Session(uid, active_skills=active, utterance_states=states, @@ -467,7 +476,9 @@ def deserialize(data: Dict): date_format=date_format, time_format=time_format, is_recording=is_recording, - is_speaking=is_speaking) + is_speaking=is_speaking, + blacklisted_intents=blacklisted_intents, + blacklisted_skills=blacklisted_skills) @staticmethod def from_message(message: Message = None): From 3b951516cdba56df821ac37b82d15509b34e7784 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Wed, 5 Jun 2024 02:17:29 +0000 Subject: [PATCH 65/91] Increment Version to 0.0.9a22 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 3c3a4cc..9811b99 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 21 +VERSION_ALPHA = 22 # END_VERSION_BLOCK From f84a8d861e5efac9482869ffd0f795717bc932b1 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Wed, 5 Jun 2024 02:17:53 +0000 Subject: [PATCH 66/91] Update Changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd101da..ec16ecc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [0.0.9a21](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a21) (2024-05-08) +## [0.0.9a22](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a22) (2024-06-05) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a21) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a22) **Breaking changes:** @@ -10,6 +10,7 @@ **Implemented enhancements:** +- feat/blacklist\_from\_session [\#98](https://github.com/OpenVoiceOS/ovos-bus-client/pull/98) ([JarbasAl](https://github.com/JarbasAl)) - feat/track\_speaking+recording\_per\_session [\#93](https://github.com/OpenVoiceOS/ovos-bus-client/pull/93) ([JarbasAl](https://github.com/JarbasAl)) - feat/add\_units\_to\_session [\#90](https://github.com/OpenVoiceOS/ovos-bus-client/pull/90) ([JarbasAl](https://github.com/JarbasAl)) - feat/targeted OCP queries [\#88](https://github.com/OpenVoiceOS/ovos-bus-client/pull/88) ([NeonJarbas](https://github.com/NeonJarbas)) From a96edb5b0d5422c70dd125805ba0f9e8cef213f1 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Thu, 20 Jun 2024 20:25:54 +0100 Subject: [PATCH 67/91] refactor/handle_new_SEIs (#97) * refactor/handle_new_SEIs requires https://github.com/OpenVoiceOS/ovos-utils/pull/246 relates to https://github.com/OpenVoiceOS/ovos-ocp-audio-plugin/issues/114 currently the new PluginStream objects are converted to the expected MediaEntry, this is to ensure whatever is listening to the OCP bus api can handle it. once this is removed old OCP wont be able to parse PluginStreams, this can only be done once we fully migrate to ovos-media and deprecate old OCP * dict2entry * Update requirements.txt --- ovos_bus_client/apis/ocp.py | 12 +++++++++--- requirements.txt | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index 05a8e4f..f2988a2 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -253,7 +253,7 @@ def _format_msg(self, msg_type, msg_data=None): @staticmethod def norm_tracks(tracks: list): try: - from ovos_utils.ocp import Playlist, MediaEntry + from ovos_utils.ocp import Playlist, MediaEntry, PluginStream, dict2entry except ImportError as e: raise RuntimeError("This method requires ovos-utils ~=0.1") from e @@ -262,7 +262,13 @@ def norm_tracks(tracks: list): # support Playlist and MediaEntry objects in tracks for idx, track in enumerate(tracks): if isinstance(track, dict): - tracks[idx] = MediaEntry.from_dict(track) + tracks[idx] = dict2entry(track) + if isinstance(track, PluginStream): + # TODO - this method will be deprecated + # once all SEI parsers can handle the new objects + # this module can serialize them just fine, + # but we dont know who is listening + tracks[idx] = track.as_media_entry() elif isinstance(track, list) and not isinstance(track, Playlist): tracks[idx] = OCPInterface.norm_tracks(track) elif not isinstance(track, MediaEntry): @@ -270,7 +276,7 @@ def norm_tracks(tracks: list): # let it fail in next assert # log all bad entries before failing LOG.error(f"Bad track, invalid type: {track}") - assert all(isinstance(t, (MediaEntry, Playlist)) for t in tracks) + assert all(isinstance(t, (MediaEntry, Playlist, PluginStream)) for t in tracks) return tracks def queue(self, tracks: list): diff --git a/requirements.txt b/requirements.txt index 3b1195e..3f71313 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,4 @@ ovos-config >= 0.0.12, < 0.2.0 ovos-utils >= 0.0.38, < 0.2.0 websocket-client>=0.54.0 pyee>=8.1.0, < 9.0.0 -orjson \ No newline at end of file +orjson From 6001f18774362deb87071eef462e4ec9867cfb40 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Thu, 20 Jun 2024 19:26:09 +0000 Subject: [PATCH 68/91] Increment Version to 0.0.9a23 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 9811b99..57d3b71 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 22 +VERSION_ALPHA = 23 # END_VERSION_BLOCK From 6975d3932756f0f3fd8380d0778839b6c8d916c4 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Thu, 20 Jun 2024 19:26:35 +0000 Subject: [PATCH 69/91] Update Changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec16ecc..40c8492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [0.0.9a22](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a22) (2024-06-05) +## [0.0.9a23](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a23) (2024-06-20) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a22) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a23) **Breaking changes:** @@ -21,6 +21,7 @@ **Merged pull requests:** +- refactor/handle\_new\_SEIs [\#97](https://github.com/OpenVoiceOS/ovos-bus-client/pull/97) ([JarbasAl](https://github.com/JarbasAl)) - Update imports to support ovos-utils~=0.0.x with compat. warnings [\#94](https://github.com/OpenVoiceOS/ovos-bus-client/pull/94) ([NeonDaniel](https://github.com/NeonDaniel)) ## [V](https://github.com/OpenVoiceOS/ovos-bus-client/tree/V) (2024-03-10) From 27bf49b7fb8577be36e3431640400de894bf5ab1 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Fri, 21 Jun 2024 14:24:30 +0100 Subject: [PATCH 70/91] hotfix/StreamPlugin (#100) its a property, not a function --- ovos_bus_client/apis/ocp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index f2988a2..71781ed 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -268,7 +268,7 @@ def norm_tracks(tracks: list): # once all SEI parsers can handle the new objects # this module can serialize them just fine, # but we dont know who is listening - tracks[idx] = track.as_media_entry() + tracks[idx] = track.as_media_entry elif isinstance(track, list) and not isinstance(track, Playlist): tracks[idx] = OCPInterface.norm_tracks(track) elif not isinstance(track, MediaEntry): From 19e47e5d1cc8648868c94ccc641114e7cbd99f13 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 21 Jun 2024 13:24:47 +0000 Subject: [PATCH 71/91] Increment Version to 0.0.9a24 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 57d3b71..866bcf6 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 23 +VERSION_ALPHA = 24 # END_VERSION_BLOCK From 1dadc4354462c70ea821897deef5d8632d491248 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 21 Jun 2024 13:25:19 +0000 Subject: [PATCH 72/91] Update Changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40c8492..d36d676 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [0.0.9a23](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a23) (2024-06-20) +## [0.0.9a24](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a24) (2024-06-21) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a23) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a24) **Breaking changes:** @@ -17,6 +17,7 @@ **Fixed bugs:** +- hotfix/StreamPlugin [\#100](https://github.com/OpenVoiceOS/ovos-bus-client/pull/100) ([JarbasAl](https://github.com/JarbasAl)) - Update setup.py to resolve version automation bug [\#95](https://github.com/OpenVoiceOS/ovos-bus-client/pull/95) ([NeonDaniel](https://github.com/NeonDaniel)) **Merged pull requests:** From 5833398fe1a7bfa94c7f128e7651f5ced98b434f Mon Sep 17 00:00:00 2001 From: Daniel McKnight <34697904+NeonDaniel@users.noreply.github.com> Date: Fri, 28 Jun 2024 15:14:59 -0700 Subject: [PATCH 73/91] Update error handling to reduce unhandled exceptions (#96) * Update error handling to prevent trying to emit an error when the client is disconnected * Wrap error emit in try/except per review comment --------- Co-authored-by: Daniel McKnight --- ovos_bus_client/client/client.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ovos_bus_client/client/client.py b/ovos_bus_client/client/client.py index ecd5e22..27aef27 100644 --- a/ovos_bus_client/client/client.py +++ b/ovos_bus_client/client/client.py @@ -116,11 +116,16 @@ def on_error(self, *args): LOG.warning('Could not send message because connection has closed') elif isinstance(error, ConnectionRefusedError): LOG.warning('Connection Refused. Is Messagebus Service running?') + elif isinstance(error, ConnectionResetError): + LOG.warning('Connection Reset. Did the Messagebus Service stop?') else: LOG.exception('=== %s ===', repr(error)) + try: + self.emitter.emit('error', error) + except Exception as e: + LOG.exception(f'Failed to emit error event: {e}') try: - self.emitter.emit('error', error) if self.client.keep_running: self.client.close() except Exception as e: From 0eae0269d171f723e4780776be95af45912933aa Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 28 Jun 2024 22:15:14 +0000 Subject: [PATCH 74/91] Increment Version to 0.0.9a25 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 866bcf6..0affc4d 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 24 +VERSION_ALPHA = 25 # END_VERSION_BLOCK From b9239c75e31f278b8dce9d0e717510176e1e6c40 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 28 Jun 2024 22:15:38 +0000 Subject: [PATCH 75/91] Update Changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d36d676..699bb10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [0.0.9a24](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a24) (2024-06-21) +## [0.0.9a25](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a25) (2024-06-28) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a24) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a25) **Breaking changes:** @@ -18,6 +18,7 @@ **Fixed bugs:** - hotfix/StreamPlugin [\#100](https://github.com/OpenVoiceOS/ovos-bus-client/pull/100) ([JarbasAl](https://github.com/JarbasAl)) +- Update error handling to reduce unhandled exceptions [\#96](https://github.com/OpenVoiceOS/ovos-bus-client/pull/96) ([NeonDaniel](https://github.com/NeonDaniel)) - Update setup.py to resolve version automation bug [\#95](https://github.com/OpenVoiceOS/ovos-bus-client/pull/95) ([NeonDaniel](https://github.com/NeonDaniel)) **Merged pull requests:** From 4ce888cee54a13aa4af67738352c9152b589e0f9 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:00:14 +0100 Subject: [PATCH 76/91] fix/ocp_uris (#102) file:// was being preprended to uris where it shouldn't, eg. spotify a log error was also wrongly logged for playlists --- ovos_bus_client/apis/ocp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index 71781ed..d2b3cd1 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -35,12 +35,12 @@ def ensure_uri(s: str): if s is uri, s is returned otherwise file:// is prepended """ if isinstance(s, str): - if '://' not in s: + if ':' not in s: return 'file://' + abspath(s) else: return s elif isinstance(s, (tuple, list)): # Handle (mime, uri) arg - if '://' not in s[0]: + if ':' not in s[0]: return 'file://' + abspath(s[0]), s[1] else: return s @@ -271,7 +271,7 @@ def norm_tracks(tracks: list): tracks[idx] = track.as_media_entry elif isinstance(track, list) and not isinstance(track, Playlist): tracks[idx] = OCPInterface.norm_tracks(track) - elif not isinstance(track, MediaEntry): + elif not isinstance(track, (Playlist, MediaEntry)): # TODO - support string uris # let it fail in next assert # log all bad entries before failing From e72b8025fde935ec2f1835ce4f43f941a02bdffa Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 5 Jul 2024 22:00:26 +0000 Subject: [PATCH 77/91] Increment Version to 0.0.9a26 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 0affc4d..adb17a6 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 25 +VERSION_ALPHA = 26 # END_VERSION_BLOCK From 5774abe2ee25d9e9215912f9a09f8142104afadf Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 5 Jul 2024 22:00:50 +0000 Subject: [PATCH 78/91] Update Changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 699bb10..928116f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [0.0.9a25](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a25) (2024-06-28) +## [0.0.9a26](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a26) (2024-07-05) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a25) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a26) **Breaking changes:** @@ -17,6 +17,7 @@ **Fixed bugs:** +- fix/ocp\_uris [\#102](https://github.com/OpenVoiceOS/ovos-bus-client/pull/102) ([JarbasAl](https://github.com/JarbasAl)) - hotfix/StreamPlugin [\#100](https://github.com/OpenVoiceOS/ovos-bus-client/pull/100) ([JarbasAl](https://github.com/JarbasAl)) - Update error handling to reduce unhandled exceptions [\#96](https://github.com/OpenVoiceOS/ovos-bus-client/pull/96) ([NeonDaniel](https://github.com/NeonDaniel)) - Update setup.py to resolve version automation bug [\#95](https://github.com/OpenVoiceOS/ovos-bus-client/pull/95) ([NeonDaniel](https://github.com/NeonDaniel)) From 13dd9476688dadd68c44bdb1d2ea90eaa53f3011 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Fri, 12 Jul 2024 12:26:04 +0100 Subject: [PATCH 79/91] fix/ocp_api_context (#103) * fix/ocp_api_context classic audio service api did not ensure correct message.context add optional kwarg for source message, in some cases dig_for_message returns None (unsure when it happens, but issues noticed with hivemind) * move to decorator * format * format --- ovos_bus_client/apis/ocp.py | 670 ++++++++++++++++++++---------------- 1 file changed, 377 insertions(+), 293 deletions(-) diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index d2b3cd1..6d0d828 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -12,9 +12,10 @@ # import time from datetime import timedelta +from functools import wraps from os.path import abspath from threading import Lock -from typing import List, Union +from typing import List, Union, Optional from ovos_utils.gui import is_gui_connected, is_gui_running from ovos_utils.log import LOG, deprecated @@ -48,6 +49,32 @@ def ensure_uri(s: str): raise ValueError('Invalid track') +def _ensure_message_kwarg(): + """ensure message kwarg is present + NOTE: this is meant for usage only in this module, it is not a generic decorator! + """ + + def message_injector(func): + # this method ensures all skills messages are .forward from the utterance + # that triggered the skill, this ensures proper routing and metadata in message.context + @wraps(func) + def call_function(*args, **kwargs): + if not any([isinstance(a, Message) for a in args]): + m = kwargs.get("source_message") + if not m: + source_message = dig_for_message(max_records=50) + if source_message: + kwargs["source_message"] = source_message + else: + LOG.warning("source message could not be determined, message.context has been lost!") + kwargs["source_message"] = Message("") + return func(*args, **kwargs) + + return call_function + + return message_injector + + class ClassicAudioServiceInterface: """AudioService class for interacting with the classic mycroft audio subsystem @@ -68,13 +95,15 @@ class ClassicAudioServiceInterface: def __init__(self, bus=None): self.bus = bus or get_mycroft_bus() - def queue(self, tracks=None): + @_ensure_message_kwarg() + def queue(self, tracks=None, source_message: Optional[Message] = None): """Queue up a track to playing playlist. Args: tracks: track uri or list of track uri's Each track can be added as a tuple with (uri, mime) to give a hint of the mime type to the system + source_message: bus message that triggered this action """ tracks = tracks or [] if isinstance(tracks, (str, tuple)): @@ -82,10 +111,11 @@ def queue(self, tracks=None): elif not isinstance(tracks, list): raise ValueError tracks = [ensure_uri(t) for t in tracks] - self.bus.emit(Message('mycroft.audio.service.queue', - data={'tracks': tracks})) + self.bus.emit(source_message.forward('mycroft.audio.service.queue', + {'tracks': tracks})) - def play(self, tracks=None, utterance=None, repeat=None): + @_ensure_message_kwarg() + def play(self, tracks=None, utterance=None, repeat=None, source_message: Optional[Message] = None): """Start playback. Args: @@ -95,6 +125,7 @@ def play(self, tracks=None, utterance=None, repeat=None): utterance: forward utterance for further processing by the audio service. repeat: if the playback should be looped + source_message: bus message that triggered this action """ repeat = repeat or False tracks = tracks or [] @@ -104,119 +135,156 @@ def play(self, tracks=None, utterance=None, repeat=None): elif not isinstance(tracks, list): raise ValueError tracks = [ensure_uri(t) for t in tracks] - self.bus.emit(Message('mycroft.audio.service.play', - data={'tracks': tracks, - 'utterance': utterance, - 'repeat': repeat})) - - def stop(self): - """Stop the track.""" - self.bus.emit(Message('mycroft.audio.service.stop')) + self.bus.emit(source_message.forward('mycroft.audio.service.play', + {'tracks': tracks, + 'utterance': utterance, + 'repeat': repeat})) + + @_ensure_message_kwarg() + def stop(self, source_message: Optional[Message] = None): + """Stop the track. + Args: + source_message: bus message that triggered this action""" + self.bus.emit(source_message.forward('mycroft.audio.service.stop')) - def next(self): - """Change to next track.""" - self.bus.emit(Message('mycroft.audio.service.next')) + @_ensure_message_kwarg() + def next(self, source_message: Optional[Message] = None): + """Change to next track. + Args: + source_message: bus message that triggered this action""" + self.bus.emit(source_message.forward('mycroft.audio.service.next')) - def prev(self): - """Change to previous track.""" - self.bus.emit(Message('mycroft.audio.service.prev')) + @_ensure_message_kwarg() + def prev(self, source_message: Optional[Message] = None): + """Change to previous track. + Args: + source_message: bus message that triggered this action""" + self.bus.emit(source_message.forward('mycroft.audio.service.prev')) - def pause(self): - """Pause playback.""" - self.bus.emit(Message('mycroft.audio.service.pause')) + @_ensure_message_kwarg() + def pause(self, source_message: Optional[Message] = None): + """Pause playback. + Args: + source_message: bus message that triggered this action""" + self.bus.emit(source_message.forward('mycroft.audio.service.pause')) - def resume(self): - """Resume paused playback.""" - self.bus.emit(Message('mycroft.audio.service.resume')) + @_ensure_message_kwarg() + def resume(self, source_message: Optional[Message] = None): + """Resume paused playback. + Args: + source_message: bus message that triggered this action""" + self.bus.emit(source_message.forward('mycroft.audio.service.resume')) - def get_track_length(self): + @_ensure_message_kwarg() + def get_track_length(self, source_message: Optional[Message] = None): """ getting the duration of the audio in seconds + Args: + source_message: bus message that triggered this action """ length = 0 info = self.bus.wait_for_response( - Message('mycroft.audio.service.get_track_length'), + source_message.forward('mycroft.audio.service.get_track_length'), timeout=1) if info: length = info.data.get("length") or 0 return length / 1000 # convert to seconds - def get_track_position(self): + @_ensure_message_kwarg() + def get_track_position(self, source_message: Optional[Message] = None): """ get current position in seconds + Args: + source_message: bus message that triggered this action """ pos = 0 info = self.bus.wait_for_response( - Message('mycroft.audio.service.get_track_position'), + source_message.forward('mycroft.audio.service.get_track_position'), timeout=1) if info: pos = info.data.get("position") or 0 return pos / 1000 # convert to seconds - def set_track_position(self, seconds): + @_ensure_message_kwarg() + def set_track_position(self, seconds, source_message: Optional[Message] = None): """Seek X seconds. Arguments: seconds (int): number of seconds to seek, if negative rewind + source_message: bus message that triggered this action """ - self.bus.emit(Message('mycroft.audio.service.set_track_position', - {"position": seconds * 1000})) # convert to ms + self.bus.emit(source_message.forward('mycroft.audio.service.set_track_position', + {"position": seconds * 1000})) # convert to ms - def seek(self, seconds: Union[int, float, timedelta] = 1): + @_ensure_message_kwarg() + def seek(self, seconds: Union[int, float, timedelta] = 1, + source_message: Optional[Message] = None): """Seek X seconds. Args: seconds (int): number of seconds to seek, if negative rewind + source_message: bus message that triggered this action """ if isinstance(seconds, timedelta): seconds = seconds.total_seconds() if seconds < 0: - self.seek_backward(abs(seconds)) + self.seek_backward(abs(seconds), source_message=source_message) else: - self.seek_forward(seconds) + self.seek_forward(seconds, source_message=source_message) - def seek_forward(self, seconds: Union[int, float, timedelta] = 1): + @_ensure_message_kwarg() + def seek_forward(self, seconds: Union[int, float, timedelta] = 1, + source_message: Optional[Message] = None): """Skip ahead X seconds. Args: seconds (int): number of seconds to skip + source_message: bus message that triggered this action """ if isinstance(seconds, timedelta): seconds = seconds.total_seconds() - self.bus.emit(Message('mycroft.audio.service.seek_forward', - {"seconds": seconds})) + self.bus.emit(source_message.forward('mycroft.audio.service.seek_forward', + {"seconds": seconds})) - def seek_backward(self, seconds: Union[int, float, timedelta] = 1): + @_ensure_message_kwarg() + def seek_backward(self, seconds: Union[int, float, timedelta] = 1, source_message: Optional[Message] = None): """Rewind X seconds Args: seconds (int): number of seconds to rewind + source_message: bus message that triggered this action """ if isinstance(seconds, timedelta): seconds = seconds.total_seconds() - self.bus.emit(Message('mycroft.audio.service.seek_backward', - {"seconds": seconds})) + self.bus.emit(source_message.forward('mycroft.audio.service.seek_backward', + {"seconds": seconds})) - def track_info(self): + @_ensure_message_kwarg() + def track_info(self, source_message: Optional[Message] = None): """Request information of current playing track. + Args: + source_message: bus message that triggered this action Returns: Dict with track info. """ info = self.bus.wait_for_response( - Message('mycroft.audio.service.track_info'), + source_message.forward('mycroft.audio.service.track_info'), reply_type='mycroft.audio.service.track_info_reply', timeout=1) return info.data if info else {} - def available_backends(self): + @_ensure_message_kwarg() + def available_backends(self, source_message: Optional[Message] = None): """Return available audio backends. + Args: + source_message: bus message that triggered this action Returns: dict with backend names as keys """ - msg = Message('mycroft.audio.service.list_backends') - response = self.bus.wait_for_response(msg) + m = source_message.forward('mycroft.audio.service.list_backends') + response = self.bus.wait_for_response(m) return response.data if response else {} @property @@ -234,21 +302,6 @@ class OCPInterface: def __init__(self, bus=None): self.bus = bus or get_mycroft_bus() - def _format_msg(self, msg_type, msg_data=None): - # this method ensures all skills are .forward from the utterance - # that triggered the skill, this ensures proper routing and metadata - msg_data = msg_data or {} - msg = dig_for_message() - if msg: - msg = msg.forward(msg_type, msg_data) - else: - msg = Message(msg_type, msg_data) - # at this stage source == skills, lets indicate audio service took over - sauce = msg.context.get("source") - if sauce == "skills": - msg.context["source"] = "audio_service" - return msg - # OCP bus api @staticmethod def norm_tracks(tracks: list): @@ -279,130 +332,341 @@ def norm_tracks(tracks: list): assert all(isinstance(t, (MediaEntry, Playlist, PluginStream)) for t in tracks) return tracks - def queue(self, tracks: list): + @_ensure_message_kwarg() + def queue(self, tracks: list, source_message: Optional[Message] = None): """Queue up a track to OCP playing playlist. Args: tracks: track dict or list of track dicts (OCP result style) + source_message: bus message that triggered this action """ tracks = self.norm_tracks(tracks) - msg = self._format_msg('ovos.common_play.playlist.queue', - {'tracks': tracks}) - self.bus.emit(msg) + self.bus.emit(source_message.forward('ovos.common_play.playlist.queue', + {'tracks': tracks})) - def play(self, tracks: list, utterance=None): + @_ensure_message_kwarg() + def play(self, tracks: list, utterance=None, source_message: Optional[Message] = None): """Start playback. Args: tracks: track dict or list of track dicts (OCP result style) utterance: forward utterance for further processing by OCP + source_message: bus message that triggered this action """ tracks = self.norm_tracks(tracks) utterance = utterance or '' tracks = [t.as_dict for t in tracks] - msg = self._format_msg('ovos.common_play.play', - {"media": tracks[0], - "playlist": tracks, - "utterance": utterance}) - self.bus.emit(msg) - - def stop(self): - """Stop the track.""" - msg = self._format_msg("ovos.common_play.stop") - self.bus.emit(msg) + self.bus.emit(source_message.forward('ovos.common_play.play', + {"media": tracks[0], + "playlist": tracks, + "utterance": utterance})) + + @_ensure_message_kwarg() + def stop(self, source_message: Optional[Message] = None): + """Stop the track. + Args: + source_message: bus message that triggered this action""" + self.bus.emit(source_message.forward("ovos.common_play.stop")) - def next(self): - """Change to next track.""" - msg = self._format_msg("ovos.common_play.next") - self.bus.emit(msg) + @_ensure_message_kwarg() + def next(self, source_message: Optional[Message] = None): + """Change to next track. + Args: + source_message: bus message that triggered this action""" + self.bus.emit(source_message.forward("ovos.common_play.next")) - def prev(self): - """Change to previous track.""" - msg = self._format_msg("ovos.common_play.previous") - self.bus.emit(msg) + @_ensure_message_kwarg() + def prev(self, source_message: Optional[Message] = None): + """Change to previous track. + Args: + source_message: bus message that triggered this action""" + self.bus.emit(source_message.forward("ovos.common_play.previous")) - def pause(self): - """Pause playback.""" - msg = self._format_msg("ovos.common_play.pause") - self.bus.emit(msg) + @_ensure_message_kwarg() + def pause(self, source_message: Optional[Message] = None): + """Pause playback. + Args: + source_message: bus message that triggered this action""" + self.bus.emit(source_message.forward("ovos.common_play.pause")) - def resume(self): - """Resume paused playback.""" - msg = self._format_msg("ovos.common_play.resume") - self.bus.emit(msg) + @_ensure_message_kwarg() + def resume(self, source_message: Optional[Message] = None): + """Resume paused playback. + Args: + source_message: bus message that triggered this action""" + self.bus.emit(source_message.forward("ovos.common_play.resume")) - def seek_forward(self, seconds=1): + @_ensure_message_kwarg() + def seek_forward(self, seconds=1, source_message: Optional[Message] = None): """Skip ahead X seconds. Args: seconds (int): number of seconds to skip + source_message: bus message that triggered this action """ if isinstance(seconds, timedelta): seconds = seconds.total_seconds() - msg = self._format_msg('ovos.common_play.seek', - {"seconds": seconds}) - self.bus.emit(msg) + self.bus.emit(source_message.forward('ovos.common_play.seek', + {"seconds": seconds})) - def seek_backward(self, seconds=1): + @_ensure_message_kwarg() + def seek_backward(self, seconds=1, source_message: Optional[Message] = None): """Rewind X seconds Args: seconds (int): number of seconds to rewind + source_message: bus message that triggered this action """ if isinstance(seconds, timedelta): seconds = seconds.total_seconds() - msg = self._format_msg('ovos.common_play.seek', - {"seconds": seconds * -1}) - self.bus.emit(msg) + self.bus.emit(source_message.forward('ovos.common_play.seek', + {"seconds": seconds * -1})) - def get_track_length(self): + @_ensure_message_kwarg() + def get_track_length(self, source_message: Optional[Message] = None): """ getting the duration of the audio in miliseconds + Args: + source_message: bus message that triggered this action """ length = 0 - msg = self._format_msg('ovos.common_play.get_track_length') + msg = source_message.forward('ovos.common_play.get_track_length') info = self.bus.wait_for_response(msg, timeout=1) if info: length = info.data.get("length", 0) return length - def get_track_position(self): + @_ensure_message_kwarg() + def get_track_position(self, source_message: Optional[Message] = None): """ get current position in miliseconds + Args: + source_message: bus message that triggered this action """ pos = 0 - msg = self._format_msg('ovos.common_play.get_track_position') + msg = source_message.forward('ovos.common_play.get_track_position') info = self.bus.wait_for_response(msg, timeout=1) if info: pos = info.data.get("position", 0) return pos - def set_track_position(self, miliseconds): + @_ensure_message_kwarg() + def set_track_position(self, miliseconds, source_message: Optional[Message] = None): """Go to X position. Arguments: - miliseconds (int): position to go to in miliseconds + miliseconds (int): position to go to in miliseconds + source_message: bus message that triggered this action """ - msg = self._format_msg('ovos.common_play.set_track_position', - {"position": miliseconds}) - self.bus.emit(msg) + self.bus.emit(source_message.forward('ovos.common_play.set_track_position', + {"position": miliseconds})) - def track_info(self): + @_ensure_message_kwarg() + def track_info(self, source_message: Optional[Message] = None): """Request information of current playing track. + Args: + source_message: bus message that triggered this action Returns: Dict with track info. """ - msg = self._format_msg('ovos.common_play.track_info') + msg = source_message.forward('ovos.common_play.track_info') response = self.bus.wait_for_response(msg) return response.data if response else {} - def available_backends(self): + @_ensure_message_kwarg() + def available_backends(self, source_message: Optional[Message] = None): """Return available audio backends. + Args: + source_message: bus message that triggered this action Returns: dict with backend names as keys """ - msg = self._format_msg('ovos.common_play.list_backends') + msg = source_message.forward('ovos.common_play.list_backends') response = self.bus.wait_for_response(msg) return response.data if response else {} +class OCPQuery: + try: + from ovos_utils.ocp import MediaType + cast2audio = [ + MediaType.MUSIC, + MediaType.PODCAST, + MediaType.AUDIOBOOK, + MediaType.RADIO, + MediaType.RADIO_THEATRE, + MediaType.VISUAL_STORY, + MediaType.NEWS + ] + except ImportError as e: + from enum import IntEnum + + class MediaType(IntEnum): + GENERIC = 0 # nothing else matches + + cast2audio = None + + def __init__(self, query, bus, media_type=MediaType.GENERIC, config=None): + if self.cast2audio is None: + raise RuntimeError("This class requires ovos-utils ~=0.1") + LOG.debug(f"Created {media_type.name} query: {query}") + self.query = query + self.media_type = media_type + self.bus = bus + self.config = config or {} + self.reset() + + def reset(self): + try: + from ovos_utils.ocp import PlaybackMode + except ImportError as e: + raise RuntimeError("This method requires ovos-utils ~=0.1") from e + self.active_skills = {} + self.active_skills_lock = Lock() + self.query_replies = [] + self.searching = False + self.search_start = 0 + self.query_timeouts = self.config.get("min_timeout", 5) + if self.config.get("playback_mode") in [PlaybackMode.AUDIO_ONLY]: + self.has_gui = False + else: + self.has_gui = is_gui_running() or is_gui_connected(self.bus) + + def send(self, skill_id: str = None): + self.query_replies = [] + self.query_timeouts = self.config.get("min_timeout", 5) + self.search_start = time.time() + self.searching = True + self.register_events() + if skill_id: + self.bus.emit(Message(f'ovos.common_play.query.{skill_id}', + {"phrase": self.query, + "question_type": self.media_type})) + else: + self.bus.emit(Message('ovos.common_play.query', + {"phrase": self.query, + "question_type": self.media_type})) + + def wait(self): + try: + from ovos_utils.ocp import MediaType + except ImportError as e: + raise RuntimeError("This method requires ovos-utils ~=0.1") from e + # if there is no match type defined, lets increase timeout a bit + # since all skills need to search + if self.media_type == MediaType.GENERIC: + timeout = self.config.get("max_timeout", 15) + 3 # timeout bonus + else: + timeout = self.config.get("max_timeout", 15) + while self.searching and time.time() - self.search_start <= timeout: + time.sleep(0.1) + self.searching = False + self.remove_events() + + @property + def results(self) -> List[dict]: + return [s for s in self.query_replies if s.get("results")] + + def register_events(self): + LOG.debug("Registering Search Bus Events") + self.bus.on("ovos.common_play.skill.search_start", self.handle_skill_search_start) + self.bus.on("ovos.common_play.skill.search_end", self.handle_skill_search_end) + self.bus.on("ovos.common_play.query.response", self.handle_skill_response) + + def remove_events(self): + LOG.debug("Removing Search Bus Events") + self.bus.remove_all_listeners("ovos.common_play.skill.search_start") + self.bus.remove_all_listeners("ovos.common_play.skill.search_end") + self.bus.remove_all_listeners("ovos.common_play.query.response") + + def handle_skill_search_start(self, message): + skill_id = message.data["skill_id"] + LOG.debug(f"{message.data['skill_id']} is searching") + with self.active_skills_lock: + if skill_id not in self.active_skills: + self.active_skills[skill_id] = Lock() + + def handle_skill_response(self, message): + search_phrase = message.data["phrase"] + if search_phrase != self.query: + # not an answer for this search query + return + timeout = message.data.get("timeout") + skill_id = message.data['skill_id'] + # LOG.debug(f"OVOSCommonPlay result: {skill_id}") + + # in case this handler fires before the search start handler + with self.active_skills_lock: + if skill_id not in self.active_skills: + self.active_skills[skill_id] = Lock() + with self.active_skills[skill_id]: + if message.data.get("searching"): + # extend the timeout by N seconds + if timeout and self.config.get("allow_extensions", True): + self.query_timeouts += timeout + # else -> expired search + + else: + # Collect replies until the timeout + if not self.searching and not len(self.query_replies): + LOG.debug(" too late!! ignored in track selection process") + LOG.warning(f"{skill_id} is not answering fast enough!") + return + + # populate search playlist + res = message.data.get("results", []) + LOG.debug(f'got {len(res)} results from {skill_id}') + if res: + self.query_replies.append(message.data) + + # abort searching if we gathered enough results + # TODO ensure we have a decent confidence match, if all matches + # are < 50% conf extend timeout instead + if time.time() - self.search_start > self.query_timeouts: + if self.searching: + self.searching = False + LOG.debug("common play query timeout, parsing results") + + elif self.searching: + for res in message.data.get("results", []): + if res.get("match_confidence", 0) >= \ + self.config.get("early_stop_thresh", 85): + # got a really good match, dont search further + LOG.info( + "Receiving very high confidence match, stopping " + "search early") + + # allow other skills to "just miss" + early_stop_grace = \ + self.config.get("early_stop_grace_period", 0.5) + if early_stop_grace: + LOG.debug( + f" - grace period: {early_stop_grace} seconds") + time.sleep(early_stop_grace) + self.searching = False + return + + def handle_skill_search_end(self, message): + skill_id = message.data["skill_id"] + LOG.debug(f"{message.data['skill_id']} finished search") + with self.active_skills_lock: + if skill_id in self.active_skills: + with self.active_skills[skill_id]: + del self.active_skills[skill_id] + + # if this was the last skill end searching period + time.sleep(0.5) + # TODO this sleep is hacky, but avoids a race condition in + # case some skill just decides to respond before the others even + # acknowledge search is starting, this gives more than enough time + # for self.active_skills to be populated, a better approach should + # be employed but this works fine for now + if not self.active_skills and self.searching: + LOG.info("Received search responses from all skills!") + self.searching = False + + +########################################################## +# WIP ZONE - APIs below used for ovos-media + + class OCPAudioServiceInterface: """Internal OCP audio subsystem most likely you should use OCPInterface instead @@ -848,183 +1112,3 @@ def available_backends(self): def is_playing(self): """True if the webservice is playing, else False.""" return self.track_info() != {} - - -class OCPQuery: - try: - from ovos_utils.ocp import MediaType - cast2audio = [ - MediaType.MUSIC, - MediaType.PODCAST, - MediaType.AUDIOBOOK, - MediaType.RADIO, - MediaType.RADIO_THEATRE, - MediaType.VISUAL_STORY, - MediaType.NEWS - ] - except ImportError as e: - from enum import IntEnum - - class MediaType(IntEnum): - GENERIC = 0 # nothing else matches - - cast2audio = None - - def __init__(self, query, bus, media_type=MediaType.GENERIC, config=None): - if self.cast2audio is None: - raise RuntimeError("This class requires ovos-utils ~=0.1") - LOG.debug(f"Created {media_type.name} query: {query}") - self.query = query - self.media_type = media_type - self.bus = bus - self.config = config or {} - self.reset() - - def reset(self): - try: - from ovos_utils.ocp import PlaybackMode - except ImportError as e: - raise RuntimeError("This method requires ovos-utils ~=0.1") from e - self.active_skills = {} - self.active_skills_lock = Lock() - self.query_replies = [] - self.searching = False - self.search_start = 0 - self.query_timeouts = self.config.get("min_timeout", 5) - if self.config.get("playback_mode") in [PlaybackMode.AUDIO_ONLY]: - self.has_gui = False - else: - self.has_gui = is_gui_running() or is_gui_connected(self.bus) - - def send(self, skill_id: str = None): - self.query_replies = [] - self.query_timeouts = self.config.get("min_timeout", 5) - self.search_start = time.time() - self.searching = True - self.register_events() - if skill_id: - self.bus.emit(Message(f'ovos.common_play.query.{skill_id}', - {"phrase": self.query, - "question_type": self.media_type})) - else: - self.bus.emit(Message('ovos.common_play.query', - {"phrase": self.query, - "question_type": self.media_type})) - - def wait(self): - try: - from ovos_utils.ocp import MediaType - except ImportError as e: - raise RuntimeError("This method requires ovos-utils ~=0.1") from e - # if there is no match type defined, lets increase timeout a bit - # since all skills need to search - if self.media_type == MediaType.GENERIC: - timeout = self.config.get("max_timeout", 15) + 3 # timeout bonus - else: - timeout = self.config.get("max_timeout", 15) - while self.searching and time.time() - self.search_start <= timeout: - time.sleep(0.1) - self.searching = False - self.remove_events() - - @property - def results(self) -> List[dict]: - return [s for s in self.query_replies if s.get("results")] - - def register_events(self): - LOG.debug("Registering Search Bus Events") - self.bus.on("ovos.common_play.skill.search_start", self.handle_skill_search_start) - self.bus.on("ovos.common_play.skill.search_end", self.handle_skill_search_end) - self.bus.on("ovos.common_play.query.response", self.handle_skill_response) - - def remove_events(self): - LOG.debug("Removing Search Bus Events") - self.bus.remove_all_listeners("ovos.common_play.skill.search_start") - self.bus.remove_all_listeners("ovos.common_play.skill.search_end") - self.bus.remove_all_listeners("ovos.common_play.query.response") - - def handle_skill_search_start(self, message): - skill_id = message.data["skill_id"] - LOG.debug(f"{message.data['skill_id']} is searching") - with self.active_skills_lock: - if skill_id not in self.active_skills: - self.active_skills[skill_id] = Lock() - - def handle_skill_response(self, message): - search_phrase = message.data["phrase"] - if search_phrase != self.query: - # not an answer for this search query - return - timeout = message.data.get("timeout") - skill_id = message.data['skill_id'] - # LOG.debug(f"OVOSCommonPlay result: {skill_id}") - - # in case this handler fires before the search start handler - with self.active_skills_lock: - if skill_id not in self.active_skills: - self.active_skills[skill_id] = Lock() - with self.active_skills[skill_id]: - if message.data.get("searching"): - # extend the timeout by N seconds - if timeout and self.config.get("allow_extensions", True): - self.query_timeouts += timeout - # else -> expired search - - else: - # Collect replies until the timeout - if not self.searching and not len(self.query_replies): - LOG.debug(" too late!! ignored in track selection process") - LOG.warning(f"{skill_id} is not answering fast enough!") - return - - # populate search playlist - res = message.data.get("results", []) - LOG.debug(f'got {len(res)} results from {skill_id}') - if res: - self.query_replies.append(message.data) - - # abort searching if we gathered enough results - # TODO ensure we have a decent confidence match, if all matches - # are < 50% conf extend timeout instead - if time.time() - self.search_start > self.query_timeouts: - if self.searching: - self.searching = False - LOG.debug("common play query timeout, parsing results") - - elif self.searching: - for res in message.data.get("results", []): - if res.get("match_confidence", 0) >= \ - self.config.get("early_stop_thresh", 85): - # got a really good match, dont search further - LOG.info( - "Receiving very high confidence match, stopping " - "search early") - - # allow other skills to "just miss" - early_stop_grace = \ - self.config.get("early_stop_grace_period", 0.5) - if early_stop_grace: - LOG.debug( - f" - grace period: {early_stop_grace} seconds") - time.sleep(early_stop_grace) - self.searching = False - return - - def handle_skill_search_end(self, message): - skill_id = message.data["skill_id"] - LOG.debug(f"{message.data['skill_id']} finished search") - with self.active_skills_lock: - if skill_id in self.active_skills: - with self.active_skills[skill_id]: - del self.active_skills[skill_id] - - # if this was the last skill end searching period - time.sleep(0.5) - # TODO this sleep is hacky, but avoids a race condition in - # case some skill just decides to respond before the others even - # acknowledge search is starting, this gives more than enough time - # for self.active_skills to be populated, a better approach should - # be employed but this works fine for now - if not self.active_skills and self.searching: - LOG.info("Received search responses from all skills!") - self.searching = False From 0b7911cb274584f34f6df3035443fe72f8400a05 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 12 Jul 2024 11:26:23 +0000 Subject: [PATCH 80/91] Increment Version to 0.0.9a27 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index adb17a6..c3aafe9 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 26 +VERSION_ALPHA = 27 # END_VERSION_BLOCK From 67e3c574f7db9789b0d100bc27d30d0747707abd Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 12 Jul 2024 11:26:51 +0000 Subject: [PATCH 81/91] Update Changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 928116f..0bf0f9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [0.0.9a26](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a26) (2024-07-05) +## [0.0.9a27](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a27) (2024-07-12) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a26) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a27) **Breaking changes:** @@ -17,6 +17,7 @@ **Fixed bugs:** +- fix/ocp\_api\_context [\#103](https://github.com/OpenVoiceOS/ovos-bus-client/pull/103) ([JarbasAl](https://github.com/JarbasAl)) - fix/ocp\_uris [\#102](https://github.com/OpenVoiceOS/ovos-bus-client/pull/102) ([JarbasAl](https://github.com/JarbasAl)) - hotfix/StreamPlugin [\#100](https://github.com/OpenVoiceOS/ovos-bus-client/pull/100) ([JarbasAl](https://github.com/JarbasAl)) - Update error handling to reduce unhandled exceptions [\#96](https://github.com/OpenVoiceOS/ovos-bus-client/pull/96) ([NeonDaniel](https://github.com/NeonDaniel)) From 8f29333e2a08e930a53903c71acd44ac5c923225 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Fri, 12 Jul 2024 13:03:04 +0100 Subject: [PATCH 82/91] fix/ocp_missing_context (#104) missed OCPQuery class in previous PR --- ovos_bus_client/apis/ocp.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ovos_bus_client/apis/ocp.py b/ovos_bus_client/apis/ocp.py index 6d0d828..f9a49aa 100644 --- a/ovos_bus_client/apis/ocp.py +++ b/ovos_bus_client/apis/ocp.py @@ -529,20 +529,21 @@ def reset(self): else: self.has_gui = is_gui_running() or is_gui_connected(self.bus) - def send(self, skill_id: str = None): + @_ensure_message_kwarg() + def send(self, skill_id: str = None, source_message: Optional[Message] = None): self.query_replies = [] self.query_timeouts = self.config.get("min_timeout", 5) self.search_start = time.time() self.searching = True self.register_events() if skill_id: - self.bus.emit(Message(f'ovos.common_play.query.{skill_id}', - {"phrase": self.query, - "question_type": self.media_type})) + self.bus.emit(source_message.forward(f'ovos.common_play.query.{skill_id}', + {"phrase": self.query, + "question_type": self.media_type})) else: - self.bus.emit(Message('ovos.common_play.query', - {"phrase": self.query, - "question_type": self.media_type})) + self.bus.emit(source_message.forward('ovos.common_play.query', + {"phrase": self.query, + "question_type": self.media_type})) def wait(self): try: From e6183113d0eef0cd07d6667f5e370c4c00a1617a Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 12 Jul 2024 12:03:18 +0000 Subject: [PATCH 83/91] Increment Version to 0.0.9a28 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index c3aafe9..3503aa8 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 27 +VERSION_ALPHA = 28 # END_VERSION_BLOCK From 7b1745110f7367e0e8e1265b0c332d6361a7687d Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Fri, 12 Jul 2024 12:03:43 +0000 Subject: [PATCH 84/91] Update Changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bf0f9e..0e67559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [0.0.9a27](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a27) (2024-07-12) +## [0.0.9a28](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a28) (2024-07-12) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a27) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a28) **Breaking changes:** @@ -17,6 +17,7 @@ **Fixed bugs:** +- fix/ocp\_missing\_context [\#104](https://github.com/OpenVoiceOS/ovos-bus-client/pull/104) ([JarbasAl](https://github.com/JarbasAl)) - fix/ocp\_api\_context [\#103](https://github.com/OpenVoiceOS/ovos-bus-client/pull/103) ([JarbasAl](https://github.com/JarbasAl)) - fix/ocp\_uris [\#102](https://github.com/OpenVoiceOS/ovos-bus-client/pull/102) ([JarbasAl](https://github.com/JarbasAl)) - hotfix/StreamPlugin [\#100](https://github.com/OpenVoiceOS/ovos-bus-client/pull/100) ([JarbasAl](https://github.com/JarbasAl)) From b8d1ee68cfbb16c83e9fad7cadd47dec713d7eb3 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Mon, 15 Jul 2024 20:12:14 +0100 Subject: [PATCH 85/91] fix/KeyError (#105) handle KeyError when trying to remove an event that isnt registered the debug logs and handling are there, but only checked for ValueError --- ovos_bus_client/client/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/client/client.py b/ovos_bus_client/client/client.py index 27aef27..eea4ca1 100644 --- a/ovos_bus_client/client/client.py +++ b/ovos_bus_client/client/client.py @@ -340,7 +340,7 @@ def _remove_normal(self, event_name, func): if event_name not in self.emitter._events: LOG.debug("Not able to find '%s'", event_name) self.emitter.remove_listener(event_name, func) - except ValueError: + except (ValueError, KeyError): LOG.warning('Failed to remove event %s: %s', event_name, str(func)) for line in traceback.format_stack(): From e7f3d6e0e436044f82084ca3792aa16721ce3bdf Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Mon, 15 Jul 2024 19:12:31 +0000 Subject: [PATCH 86/91] Increment Version to 0.0.9a29 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 3503aa8..9e6de50 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 28 +VERSION_ALPHA = 29 # END_VERSION_BLOCK From e0379932be9d326e835d62e14dc9d8af8dc28d0c Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Mon, 15 Jul 2024 19:13:01 +0000 Subject: [PATCH 87/91] Update Changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e67559..3e798bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [0.0.9a28](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a28) (2024-07-12) +## [0.0.9a29](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a29) (2024-07-15) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a28) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a29) **Breaking changes:** @@ -17,6 +17,7 @@ **Fixed bugs:** +- fix/KeyError [\#105](https://github.com/OpenVoiceOS/ovos-bus-client/pull/105) ([JarbasAl](https://github.com/JarbasAl)) - fix/ocp\_missing\_context [\#104](https://github.com/OpenVoiceOS/ovos-bus-client/pull/104) ([JarbasAl](https://github.com/JarbasAl)) - fix/ocp\_api\_context [\#103](https://github.com/OpenVoiceOS/ovos-bus-client/pull/103) ([JarbasAl](https://github.com/JarbasAl)) - fix/ocp\_uris [\#102](https://github.com/OpenVoiceOS/ovos-bus-client/pull/102) ([JarbasAl](https://github.com/JarbasAl)) From 04b2f6a83fa8014866e53b802d2d33786b5143c4 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Mon, 2 Sep 2024 16:24:52 +0000 Subject: [PATCH 88/91] Increment Version to 0.0.9 --- ovos_bus_client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_bus_client/version.py b/ovos_bus_client/version.py index 9e6de50..5bb8a4e 100644 --- a/ovos_bus_client/version.py +++ b/ovos_bus_client/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 VERSION_BUILD = 9 -VERSION_ALPHA = 29 +VERSION_ALPHA = 0 # END_VERSION_BLOCK From 1a9793fc41c82d528eba2909ac0d6b7c10bfb88a Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Mon, 2 Sep 2024 16:25:24 +0000 Subject: [PATCH 89/91] Update Changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e798bd..8eab4cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [0.0.9a29](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9a29) (2024-07-15) +## [0.0.9](https://github.com/OpenVoiceOS/ovos-bus-client/tree/0.0.9) (2024-09-02) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9a29) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-bus-client/compare/V...0.0.9) **Breaking changes:** From 9acbce6c6f1923d417ee2ac788caac063aeebf50 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:42:37 +0100 Subject: [PATCH 90/91] Update LICENSE copyright --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 617e3cd..d33befd 100644 --- a/LICENSE +++ b/LICENSE @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2024 Casimiro Ferreira + Copyright 2024 OpenVoiceOS Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 170986b93351a3b8289779c23a02d31ae80e082a Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:51:09 +0100 Subject: [PATCH 91/91] deprecation warnings (#111) --- ovos_bus_client/session.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ovos_bus_client/session.py b/ovos_bus_client/session.py index 723c50f..163d0f3 100644 --- a/ovos_bus_client/session.py +++ b/ovos_bus_client/session.py @@ -6,7 +6,7 @@ from ovos_config.config import Configuration from ovos_config.locale import get_default_lang -from ovos_utils.log import LOG +from ovos_utils.log import LOG, log_deprecation from ovos_bus_client.message import dig_for_message, Message @@ -289,9 +289,9 @@ def __init__(self, session_id: str = None, @param context: IntentContextManager for this Session """ if tts_prefs: - LOG.warning("tts_prefs have been deprecated! value will be ignored and fully removed in 0.1.0") + log_deprecation("'tts_prefs' kwarg has been deprecated! value will be ignored", "0.1.0") if stt_prefs: - LOG.warning("stt_prefs have been deprecated! value will be ignored and fully removed in 0.1.0") + log_deprecation("'stt_prefs' kwarg has been deprecated! value will be ignored", "0.1.0") self.session_id = session_id or str(uuid4()) self.blacklisted_skills = (blacklisted_skills or Configuration().get("skills", {}).get("blacklisted_skills", []))