diff --git a/.github/workflows/update_skill_json.yml b/.github/workflows/update_skill_json.yml index 5dc9797..53b183d 100644 --- a/.github/workflows/update_skill_json.yml +++ b/.github/workflows/update_skill_json.yml @@ -22,7 +22,7 @@ jobs: sudo apt update sudo apt install -y gcc git libpulse-dev pip install --upgrade pip - pip install neon-utils\~=0.17 ovos-skills-manager + pip install neon-utils~=1.1,\>=1.1.1 ovos-skills-manager - name: Get Updated skill.json run: | python action/skill/scripts/update_skill_json.py diff --git a/README.md b/README.md index 25dda69..064123e 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ be asked again on next run. The demo may also be run at any time via intent. ## Examples -- "Neon show me the demo" +- "Show me the demo." ## Contact Support diff --git a/__init__.py b/__init__.py index 085288d..8c7b52a 100644 --- a/__init__.py +++ b/__init__.py @@ -26,11 +26,13 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from os.path import expanduser, isfile, join from copy import deepcopy from tempfile import mkstemp from threading import Event from time import sleep from typing import Optional + from mycroft_bus_client import Message from neon_utils import LOG from neon_utils.message_utils import get_message_user, dig_for_message @@ -38,10 +40,12 @@ from neon_utils.skills import NeonSkill from neon_utils.user_utils import get_user_prefs from neon_utils.file_utils import load_commented_file +from ovos_config.locations import get_xdg_data_save_path from ovos_plugin_manager.templates import TTS from ovos_utils.sound import play_wav from mycroft.skills import intent_file_handler +from mycroft.skills.skill_data import find_resource class DemoSkill(NeonSkill): @@ -49,6 +53,7 @@ def __init__(self): super(DemoSkill, self).__init__(name="DemoSkill") self._active_demos = dict() self._audio_output_done = Event() + self._data_path = get_xdg_data_save_path() @property def demo_tts_plugin(self) -> str: @@ -122,6 +127,7 @@ def handle_show_demo(self, message): return # TODO: Parse demo language from request lang = self.lang + original_message = deepcopy(message) # Track demo state for the user user = get_message_user(message) self._active_demos[user] = Event() @@ -133,8 +139,7 @@ def handle_show_demo(self, message): self._audio_output_done.clear() # Clear signal to wait for intro speak self.speak_dialog("starting_demo") # Read the demo prompts - demo_prompts = load_commented_file(self.find_resource( - self.demo_filename)).split('\n') + demo_prompts = load_commented_file(self._get_demo_file()).split('\n') # Define message context for the demo actions message_context = deepcopy(message.context) message_context['neon_should_respond'] = True @@ -164,9 +169,31 @@ def handle_show_demo(self, message): "utterances": [prompt.lower()]} self._send_prompt(message) - self.speak_dialog("finished_demo") + self.speak_dialog("finished_demo", message=original_message) self._active_demos.pop(user) + def _get_demo_file(self): + """ + Helper method for resolving a skill resource file in priority order: + 1. Absolute Path + 2. Skill File System Path + 3. User-defined skill resource + ({XDG_DATA_HOME}/resources/skill-demo.neongeckocom/{lang}) + 4. Skill resource ({skill.base_dir}/locale/{lang}) + """ + if isfile(expanduser(self.demo_filename)): + return expanduser(self.demo_filename) + if self.file_system.exists(self.demo_filename): + return join(self.file_system.path, self.demo_filename) + root_dir = join(self._data_path, "resources", self.skill_id) + user_resource = find_resource(self.demo_filename, root_dir, + None, self.lang) + if user_resource: + return user_resource + skill_resource = self.find_resource(self.demo_filename) + if skill_resource: + return skill_resource + def _send_prompt(self, message: Message): """ Send a message to skill processing and wait for it to be handled @@ -232,8 +259,11 @@ def _get_demo_tts(self, lang: str = None) -> Optional[TTS]: return None def stop(self): - user = get_message_user(dig_for_message()) - if user in self._active_demos: + try: + user = get_message_user(dig_for_message()) + except ValueError: + user = None + if user and user in self._active_demos: LOG.info(f"{user} requested stop") self._active_demos[user].set() diff --git a/locale/en-us/demo.txt b/locale/en-us/demo.txt index f7fc737..6317db2 100644 --- a/locale/en-us/demo.txt +++ b/locale/en-us/demo.txt @@ -1,9 +1,9 @@ what is your name how are you what time is it -what is the weather +what is the temperature change my units to metric -what is the forecast for tomorrow -how do you say hello in ukrainian +what is the temperature what is the capital of Ukraine -how much caffeine is in Coke \ No newline at end of file +how much caffeine is in Coke +how do you spell caffeine \ No newline at end of file diff --git a/locale/en-us/language_demo.txt b/locale/en-us/language_demo.txt deleted file mode 100644 index 6f8b9c3..0000000 --- a/locale/en-us/language_demo.txt +++ /dev/null @@ -1,16 +0,0 @@ -who are you -change my response language to spanish -who are you -change my response language to french -who are you -change my response language to german -who are you -change my response language to ukrainian -who are you -change my response language to polish -who are you -change my response language to dutch -who are you -change my response language to hungarian -who are you -change my response language to english \ No newline at end of file diff --git a/skill.json b/skill.json index a1ede09..8358b47 100644 --- a/skill.json +++ b/skill.json @@ -5,7 +5,7 @@ "short_description": "Skill to demo Neon capabilities", "description": "The demo skill will prompt on first run if you'd like to see a demo. User may accept or decline and optionally choose to be asked again on next run. The demo may also be run at any time via intent.", "examples": [ - "show me the demo" + "Show me the demo." ], "desktopFile": false, "warning": "", diff --git a/test/test_skill.py b/test/test_skill.py index 491bf69..8fd53c4 100644 --- a/test/test_skill.py +++ b/test/test_skill.py @@ -162,11 +162,12 @@ def ask_yesno(dialog): def test_show_demo_valid(self): self.skill._speak_prompt = Mock() self.skill._send_prompt = Mock() - self.skill.handle_show_demo(Message("recognizer_loop:utterance", - context={ - "neon_should_respond": True})) + msg = Message("recognizer_loop:utterance", + context={"neon_should_respond": True}) + self.skill.handle_show_demo(msg) self.skill.speak_dialog.assert_any_call("starting_demo") - self.skill.speak_dialog.assert_called_with("finished_demo") + args = self.skill.speak_dialog.call_args + self.assertEqual(args[0][0], "finished_demo") # TODO: Implement tests for _get_demo_tts, _send_prompt, and _speak_prompt diff --git a/version.py b/version.py index ef7228e..4488dcb 100644 --- a/version.py +++ b/version.py @@ -26,4 +26,4 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -__version__ = "0.0.1" +__version__ = "0.1.0"