Skip to content

Commit

Permalink
fix: improve game skill converse (#310)
Browse files Browse the repository at this point in the history
* dont require abandon_Game callback

* fix:Games skill

async converse

fix pause/playing state check

ensure skills are active
  • Loading branch information
JarbasAl authored Dec 19, 2024
1 parent 310f773 commit f6a6357
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 17 deletions.
6 changes: 4 additions & 2 deletions ovos_workshop/skills/common_play.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,14 +392,15 @@ def play_media(self, media, disambiguation=None, playlist=None):

# @killable_event("ovos.common_play.stop", react_to_stop=True)
def __handle_ocp_play(self, message):
self.activate()
self._playing.set()
self._paused.clear()
if self.__playback_handler:
params = signature(self.__playback_handler).parameters
kwargs = {"message": message} if "message" in params else {}
self.__playback_handler(**kwargs)
self.bus.emit(Message("ovos.common_play.player.state",
{"state": PlayerState.PLAYING}))
self._playing.set()
self._paused.clear()
else:
LOG.error(f"Playback requested but {self.skill_id} handler not "
"implemented")
Expand All @@ -417,6 +418,7 @@ def __handle_ocp_pause(self, message):
"implemented")

def __handle_ocp_resume(self, message):
self.activate()
self._paused.clear()
if self.__resume_handler:
params = signature(self.__playback_handler).parameters
Expand Down
47 changes: 32 additions & 15 deletions ovos_workshop/skills/game_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,14 @@ def stop(self) -> bool:
return True
return False

def calc_intent(self, utterance: str, lang: str) -> Optional[Dict[str, str]]:
def calc_intent(self, utterance: str, lang: str, timeout=1.0) -> Optional[Dict[str, str]]:
"""helper to check what intent would be selected by ovos-core"""
# let's see what intent ovos-core will assign to the utterance
# NOTE: converse, common_query and fallbacks are not included in this check
response = self.bus.wait_for_response(Message("intent.service.intent.get",
{"utterance": utterance, "lang": lang}),
"intent.service.intent.reply",
timeout=1.0)
timeout=timeout)
if not response:
return None
return response.data["intent"]
Expand Down Expand Up @@ -183,7 +183,6 @@ def on_game_command(self, utterance: str, lang: str):
don't forget to self.speak the game output too!
"""

@abc.abstractmethod
def on_abandon_game(self):
"""user abandoned game mid interaction
Expand All @@ -193,7 +192,7 @@ def on_abandon_game(self):
on_game_stop will be called after this handler"""

# converse
def skill_will_trigger(self, utterance: str, lang: str, skill_id: Optional[str] = None) -> bool:
def skill_will_trigger(self, utterance: str, lang: str, skill_id: Optional[str] = None, timeout=0.8) -> bool:
"""helper to check if this skill would be selected by ovos-core with the given utterance
useful in converse method
Expand All @@ -205,7 +204,7 @@ def skill_will_trigger(self, utterance: str, lang: str, skill_id: Optional[str]
# determine if an intent from this skill
# will be selected by ovos-core
id_to_check = skill_id or self.skill_id
intent = self.calc_intent(utterance, lang)
intent = self.calc_intent(utterance, lang, timeout=timeout)
skill_id = intent["skill_id"] if intent else ""
return skill_id == id_to_check

Expand All @@ -221,26 +220,44 @@ def _autosave(self):
if self.settings.get("auto_save", False) and self.save_is_implemented:
self.on_save_game()

def converse(self, message: Message):
def _async_cmd(self, message: Message):
utterance = message.data["utterances"][0]
lang = get_message_lang(message)
self.log.debug(f"Piping utterance to game: {utterance}")
self.on_game_command(utterance, lang)

def converse(self, message: Message) -> bool:
try:
utterance = message.data["utterances"][0]
lang = get_message_lang(message)
# let the user implemented intents do the job if they can handle the utterance
# otherwise pipe utterance to the game handler
if self.skill_will_trigger(utterance, lang):
self.log.debug("Skill intent will trigger, don't pipe utterance to game")
return False

if self.is_paused:
self.log.debug("game is paused")
# let ocp_pipeline unpause as appropriate
return False

self._autosave()
utterance = message.data["utterances"][0]
lang = get_message_lang(message)
# let the user implemented intents do the job if they can handle the utterance
if self.is_playing and not self.skill_will_trigger(utterance, lang):
# otherwise pipe utterance to the game handler
self.on_game_command(utterance, lang)
try:
self._autosave()
except Exception as e:
self.log.error(f"Autosave failed: {e}")

if self.is_playing:
# do this async so converse executes faster
self.bus.once(f"{self.skill_id}.game_cmd", self._async_cmd)
self.bus.emit(message.forward(f"{self.skill_id}.game_cmd", message.data))
return True

return False
except (KeyError, IndexError) as e:
self.log.error(f"Error processing converse message: {e}")
self.log.error(f"Error processing game converse message: {e}")
return False
except Exception as e:
self.log.exception(f"Unexpected error in converse: {e}")
self.log.exception(f"Unexpected error in game converse: {e}")
return False

def handle_deactivate(self, message: Message):
Expand Down

0 comments on commit f6a6357

Please sign in to comment.