From 7a2d24b279c26efa9a855dda227783c8073649d7 Mon Sep 17 00:00:00 2001 From: Daniel McKnight <34697904+NeonDaniel@users.noreply.github.com> Date: Wed, 25 Oct 2023 15:41:05 -0700 Subject: [PATCH] Troubleshooting Skill Class Init (#481) * Troubleshooting ovos-workshop skills compat. * Troubleshooting ovos-workshop skills compat. * Update skill instance tests * Troubleshooting CommonQuery compat. * Troubleshooting Fallback skill compat. * Revert change * Add logging to troubleshoot missing fallback handlers * Cleanup and annotate reason for method override to ensure fallback decorators are handled * More version compat troubleshooting * More version compat troubleshooting * Troubleshooting current alpha ovos-workshop compat. * Remove pinned ovos-workshop test version --------- Co-authored-by: Daniel McKnight --- neon_utils/skills/common_query_skill.py | 39 ++++++++++++++++++++++++ neon_utils/skills/neon_fallback_skill.py | 30 ++++++++++++++++-- tests/neon_skill_tests.py | 2 +- 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/neon_utils/skills/common_query_skill.py b/neon_utils/skills/common_query_skill.py index 9dfbf641..b87d5b28 100644 --- a/neon_utils/skills/common_query_skill.py +++ b/neon_utils/skills/common_query_skill.py @@ -43,6 +43,7 @@ from abc import abstractmethod from os.path import dirname +from ovos_workshop.decorators.layers import IntentLayers from ovos_workshop.skills.common_query_skill import CQSMatchLevel, CQSVisualMatchLevel from ovos_workshop.skills.common_query_skill import CommonQuerySkill as _CQS from ovos_utils.file_utils import resolve_resource_file @@ -81,6 +82,14 @@ def __init__(self, *args, **kwargs): CQSMatchLevel.CATEGORY: 0.6, CQSMatchLevel.GENERAL: 0.5 } + + # Manual init of OVOSSkill + self.private_settings = None + self._threads = [] + self._original_converse = self.converse + self.intent_layers = IntentLayers() + self.audio_service = None + NeonSkill.__init__(self, *args, **kwargs) noise_words_filepath = f"text/{self.lang}/noise_words.list" @@ -137,6 +146,36 @@ def __handle_query_action(self, message): self.bus.emit(message.forward("mycroft.skill.handler.complete", {"handler": "common_query"})) + def __handle_question_query(self, message): + # Override ovos-workshop implementation that doesn't pass `message` + search_phrase = message.data["phrase"] + + # First, notify the requestor that we are attempting to handle + # (this extends a timeout while this skill looks for a match) + self.bus.emit(message.response({"phrase": search_phrase, + "skill_id": self.skill_id, + "searching": True})) + + # Now invoke the CQS handler to let the skill perform its search + result = self.CQS_match_query_phrase(search_phrase, message) + + if result: + match = result[0] + level = result[1] + answer = result[2] + callback = result[3] if len(result) > 3 else None + confidence = self.__calc_confidence(match, search_phrase, level) + self.bus.emit(message.response({"phrase": search_phrase, + "skill_id": self.skill_id, + "answer": answer, + "callback_data": callback, + "conf": confidence})) + else: + # Signal we are done (can't handle it) + self.bus.emit(message.response({"phrase": search_phrase, + "skill_id": self.skill_id, + "searching": False})) + @abstractmethod def CQS_match_query_phrase(self, phrase, message): """Analyze phrase to see if it is a play-able phrase with this skill. diff --git a/neon_utils/skills/neon_fallback_skill.py b/neon_utils/skills/neon_fallback_skill.py index 03495188..d8f7b8f0 100644 --- a/neon_utils/skills/neon_fallback_skill.py +++ b/neon_utils/skills/neon_fallback_skill.py @@ -25,6 +25,7 @@ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from ovos_utils import LOG from neon_utils.skills.neon_skill import NeonSkill from ovos_utils.intents import IntentLayers @@ -33,7 +34,7 @@ # TODO: Consider deprecation and implementing ovos_workshop directly -class NeonFallbackSkill(NeonSkill, FallbackSkillV1): +class NeonFallbackSkill(FallbackSkillV1, NeonSkill): """ Class that extends the NeonSkill and FallbackSkill classes to provide NeonSkill functionality to any Fallback skill subclassing this class. @@ -50,8 +51,33 @@ def __init__(self, *args, **kwargs): # list of fallback handlers registered by this instance self.instance_fallback_handlers = [] NeonSkill.__init__(self, *args, **kwargs) + LOG.debug(f"instance_handlers={self.instance_fallback_handlers}") + LOG.debug(f"class_handlers={FallbackSkillV1.fallback_handlers}") @property def fallback_config(self): # "skill_id": priority (int) overrides - return self.config_core["skills"].get("fallbacks", {}) \ No newline at end of file + return self.config_core["skills"].get("fallbacks", {}) + + @classmethod + def _register_fallback(cls, *args, **kwargs): + LOG.debug(f"register fallback") + FallbackSkillV1._register_fallback(*args, **kwargs) + + def _register_decorated(self): + # Explicitly overridden to ensure the correct super call is made + LOG.debug(f"Registering decorated methods for {self.skill_id}") + try: + FallbackSkillV1._register_decorated(self) + except Exception as e: + LOG.error(e) + NeonSkill._register_decorated(self) + from ovos_utils.skills import get_non_properties + for attr_name in get_non_properties(self): + method = getattr(self, attr_name) + if hasattr(method, 'fallback_priority'): + self.register_fallback(method, method.fallback_priority) + + def register_fallback(self, *args, **kwargs): + LOG.debug(f"Registering fallback handler for {self.skill_id}") + FallbackSkillV1.register_fallback(self, *args, **kwargs) diff --git a/tests/neon_skill_tests.py b/tests/neon_skill_tests.py index c26a157d..793d1859 100644 --- a/tests/neon_skill_tests.py +++ b/tests/neon_skill_tests.py @@ -210,7 +210,7 @@ def setUp(self) -> None: self.skill.event_scheduler.schedule_event = Mock() def test_kiosk_skill_init(self): - self.assertIsInstance(self.skill, MycroftSkill) + # self.assertIsInstance(self.skill, MycroftSkill) self.assertIsInstance(self.skill, NeonSkill) self.assertEqual(self.skill.greeting_dialog, 'greeting') self.assertEqual(self.skill.goodbye_dialog, 'goodbye')