Skip to content

Commit

Permalink
active skill events - enhanced version of mycroft-core/pull/1468
Browse files Browse the repository at this point in the history
- adds `self.activate()` and `self.deactivate()` in MycroftSkill class
- adds "intent.service.skills.deactivated" event when IntentService removes a skill from active list
- adds "intent.service.skills.activated" event when IntentService adds a skill to active list
- adds `def handle_deactivate(self, message):` callback in MycroftSkill class
- adds `def handle_activate(self, message):` callback in MycroftSkill class
- prepares `self.make_active()` for deprecation
  • Loading branch information
JarbasAl committed Oct 26, 2021
1 parent eebbb17 commit 676f9a5
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 8 deletions.
2 changes: 1 addition & 1 deletion mycroft/skills/fallback_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def register_fallback(self, handler, priority):

def wrapper(*args, **kwargs):
if handler(*args, **kwargs):
self.make_active()
self.activate()
return True
return False

Expand Down
32 changes: 31 additions & 1 deletion mycroft/skills/intent_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
)
from mycroft.skills.intent_service_interface import open_intent_envelope
from mycroft.skills.permissions import ConverseMode, ConverseActivationMode
from mycroft.messagebus.message import Message


def _get_message_lang(message):
Expand Down Expand Up @@ -110,6 +111,11 @@ def __init__(self, bus):
self.bus.on('mycroft.speech.recognition.unknown', self.reset_converse)
self.bus.on('mycroft.skills.loaded', self.update_skill_name_dict)

self.bus.on('intent.service.skills.activate',
self.handle_activate_skill_request)
self.bus.on('intent.service.skills.deactivate',
self.handle_deactivate_skill_request)
# TODO backwards compat, deprecate
self.bus.on('active_skill_request', self.handle_activate_skill_request)

self.active_skills = [] # [skill_id , timestamp]
Expand Down Expand Up @@ -211,6 +217,21 @@ def handle_activate_skill_request(self, message):
self.add_active_skill(skill_id)
self._consecutive_activations[skill_id] += 1

# converse handling

def handle_activate_skill_request(self, message):
self.add_active_skill(message.data['skill_id'])

def handle_deactivate_skill_request(self, message):
# TODO imperfect solution - only a skill can deactivate itself
# someone can forge this message and emit it raw, but in ovos-core all
# skill message should have skill_id in context, so let's make sure
# this doesnt happen accidentally
skill_id = message.data['skill_id']
source_skill = message.context.get("skill_id") or skill_id
if skill_id == source_skill:
self.remove_active_skill(message.data['skill_id'])

def reset_converse(self, message):
"""Let skills know there was a problem with speech recognition"""
lang = _get_message_lang(message)
Expand Down Expand Up @@ -273,6 +294,9 @@ def remove_active_skill(self, skill_id):
for skill in self.active_skills:
if skill[0] == skill_id:
self.active_skills.remove(skill)
self.bus.emit(
Message("intent.service.skills.deactivated",
{"skill_id": skill_id}))
if skill_id in self._consecutive_activations:
self._consecutive_activations[skill_id] = 0

Expand All @@ -288,9 +312,15 @@ def add_active_skill(self, skill_id):
# search the list for an existing entry that already contains it
# and remove that reference
if skill_id != '':
self.remove_active_skill(skill_id)
# do not call remove method to not send deactivate bus event!
for skill in self.active_skills:
if skill[0] == skill_id:
self.active_skills.remove(skill)
# add skill with timestamp to start of skill_list
self.active_skills.insert(0, [skill_id, time.time()])
self.bus.emit(
Message("intent.service.skills.activated",
{"skill_id": skill_id}))
else:
LOG.warning('Skill ID was empty, won\'t add to list of '
'active skills.')
Expand Down
63 changes: 57 additions & 6 deletions mycroft/skills/mycroft_skill/mycroft_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,14 @@ def stop_is_implemented():
'mycroft.skills.settings.changed',
self.handle_settings_change
)
self.events.add(f"{self.skill_id}.deactivate",
self.handle_deactivate)
self.events.add("intent.service.skills.deactivated",
self._handle_skill_deactivated)
self.events.add(f"{self.skill_id}.activate",
self.handle_activate)
self.events.add("intent.service.skills.activated",
self._handle_skill_activated)

def handle_settings_change(self, message):
"""Update settings if the remote settings changes apply to this skill.
Expand Down Expand Up @@ -462,6 +470,50 @@ def get_intro_message(self):
"""
return None

# converse handling
def _handle_skill_activated(self, message):
""" intent service activated a skill
if it was this skill fire the skill activation event"""
if message.data.get("skill_id") == self.skill_id:
self.bus.emit(message.forward(f"{self.skill_id}.activate"))

def handle_activate(self, message):
""" skill is now considered active by the intent service
converse method will be called, skills might want to prepare/resume
"""

def _handle_skill_deactivated(self, message):
""" intent service deactivated a skill
if it was this skill fire the skill deactivation event"""
if message.data.get("skill_id") == self.skill_id:
self.bus.emit(message.forward(f"{self.skill_id}.deactivate"))

def handle_deactivate(self, message):
""" skill is no longer considered active by the intent service
converse method will not be called, skills might want to reset state here
"""

def activate(self):
"""Bump skill to active_skill list in intent_service.
This enables converse method to be called even without skill being
used in last 5 minutes.
"""
msg = dig_for_message() or Message("")
if "skill_id" not in msg.context:
msg.context["skill_id"] = self.skill_id
self.bus.emit(msg.forward("intent.service.skills.activate",
data={"skill_id": self.skill_id}))

def deactivate(self):
"""remove skill from active_skill list in intent_service.
This stops converse method from being called
"""
msg = dig_for_message() or Message("")
if "skill_id" not in msg.context:
msg.context["skill_id"] = self.skill_id
self.bus.emit(msg.forward(f"intent.service.skills.deactivate",
data={"skill_id": self.skill_id}))

def converse(self, message=None):
"""Handle conversation.
Expand Down Expand Up @@ -505,7 +557,7 @@ def converse(utterances, lang=None):
return True

# install a temporary conversation handler
self.make_active()
self.activate()
converse.response = None
default_converse = self.converse
self.converse = converse
Expand Down Expand Up @@ -776,12 +828,11 @@ def make_active(self):
This enables converse method to be called even without skill being
used in last 5 minutes.
deprecated: use self.activate() instead
"""
msg = dig_for_message() or Message("")
if "skill_id" not in msg.context:
msg.context["skill_id"] = self.skill_id
self.bus.emit(msg.forward('active_skill_request',
{'skill_id': self.skill_id}))
# TODO deprecate, backwards compat
self.activate()

def _handle_collect_resting(self, message=None):
"""Handler for collect resting screen messages.
Expand Down

0 comments on commit 676f9a5

Please sign in to comment.