Skip to content

Commit

Permalink
move to proper base class
Browse files Browse the repository at this point in the history
  • Loading branch information
JarbasAl committed Apr 20, 2023
1 parent 5307299 commit cbdd20f
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 104 deletions.
81 changes: 80 additions & 1 deletion ovos_workshop/skills/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from lingua_franca.parse import yes_or_no, extract_number
from ovos_backend_client.api import EmailApi, MetricsApi
from ovos_bus_client.message import Message, dig_for_message
from ovos_bus_client.session import SessionManager
from ovos_config.config import Configuration
from ovos_config.locations import get_xdg_config_save_path
from ovos_utils import camel_case_split
Expand Down Expand Up @@ -875,7 +876,7 @@ def converse(self, message=None):
"""
return False

def __get_response(self):
def __get_response_v1(self):
"""Helper to get a response from the user
NOTE: There is a race condition here. There is a small amount of
Expand Down Expand Up @@ -905,6 +906,7 @@ def converse(utterances, lang=None):
# 10 for listener, 5 for SST, then timeout
# NOTE: a threading.Event is not used otherwise we can't raise the
# AbortEvent exception to kill the thread
# this is for compat with killable_intents decorators
start = time.time()
while time.time() - start <= 15 and not converse.finished:
time.sleep(0.1)
Expand All @@ -917,6 +919,83 @@ def converse(utterances, lang=None):
self.converse = self.__original_converse
return converse.response

# get response V2
def __get_response(self):
"""Helper to get a response from the user
this method is unsafe and contains a race condition for
multiple simultaneous queries in ovos-core < 0.0.8
Returns:
str: user's response or None on a timeout
"""

# in ovos-core < 0.0.8 we reassign the converse method itself
is_old = False
try:
from mycroft.version import OVOS_VERSION_MAJOR, OVOS_VERSION_MINOR, OVOS_VERSION_BUILD, OVOS_VERSION_ALPHA
if OVOS_VERSION_MAJOR == 0 and OVOS_VERSION_MINOR == 0 and OVOS_VERSION_BUILD <= 8 and OVOS_VERSION_ALPHA < 5:
is_old = True
except ImportError:
# standalone usage without core
pass

self.bus.emit(Message("skill.converse.get_response.enable",
{"skill_id": self.skill_id}))

if is_old: # NOT SAFE for multiple users at same time
res = self.__get_response_v1()
self.bus.emit(Message("skill.converse.get_response.disable",
{"skill_id": self.skill_id}))
return res

self._activate()
utterances = []
lang = self.lang # unused, but we get this info together with utterance if needed
# user could switch lang midway, maybe ignore response in this case (?)

sess = SessionManager.get()

def _handle_get_response(message):
nonlocal utterances, lang

skill_id = message.data["skill_id"]
if skill_id != self.skill_id:
return # not for us!

# validate session_id to ensure this isnt another
# user querying the skill at same time
sess2 = SessionManager.get(message)
if sess.session_id != sess2.session_id:
return # not for us!

utterances = message.data["utterances"]
lang = message.data["lang"]
# received get_response

self.bus.on("skill.converse.get_response", _handle_get_response)

# NOTE: a threading.Event is not used otherwise we can't raise the
# AbortEvent exception to kill the thread
# this is for compat with killable_intents decorators
start = time.time()
while time.time() - start <= 15 and not len(utterances):
time.sleep(0.1)
if self.__response is not False:
if self.__response is None:
# aborted externally (if None)
self.log.debug("get_response aborted")
else:
utterances = [self.__response] # external override

self.bus.remove("skill.converse.get_response", _handle_get_response)
self.bus.emit(Message("skill.converse.get_response.disable",
{"skill_id": self.skill_id}))

if utterances:
return utterances[0]
return None

def get_response(self, dialog='', data=None, validator=None,
on_fail=None, num_retries=-1):
"""Get response from user.
Expand Down
103 changes: 0 additions & 103 deletions ovos_workshop/skills/ovos.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,109 +215,6 @@ def send_stop_signal(self, stop_event=None):
self.bus.emit(msg.forward("mycroft.audio.speech.stop"))


# get response V2
def __get_response(self):
"""Helper to get a response from the user
this method is unsafe and contains a race condition for
multiple simultaneous queries in ovos-core < 0.0.8
Returns:
str: user's response or None on a timeout
"""

# in ovos-core < 0.0.8 we reassign the converse method itself
is_old = False
try:
from mycroft.version import OVOS_VERSION_MAJOR, OVOS_VERSION_MINOR, OVOS_VERSION_BUILD, OVOS_VERSION_ALPHA
if OVOS_VERSION_MAJOR == 0 and OVOS_VERSION_MINOR == 0 and OVOS_VERSION_BUILD <= 8 and OVOS_VERSION_ALPHA < 5:
is_old = True
except ImportError:
# standalone usage without core
pass

self.bus.emit(Message("skill.converse.get_response.enable",
{"skill_id": self.skill_id}))
self._activate()

if is_old: # NOT SAFE for multiple users at same time

def converse(utterances, lang=None):
converse.response = utterances[0] if utterances else None
converse.finished = True
return True

converse.finished = False
converse.response = None

# replace converse method to capture utterance by hijacking the pipeline
self.converse = converse

# 10 for listener, 5 for SST, then timeout
# NOTE: a threading.Event is not used otherwise we can't raise the
# AbortEvent exception to kill the thread
start = time.time()
while time.time() - start <= 15 and not converse.finished:
time.sleep(0.1)
if self.__response is not False:
if self.__response is None:
# aborted externally (if None)
self.log.debug("get_response aborted")
converse.finished = True
converse.response = self.__response # external override

# restore converse method
self.converse = self.__original_converse

return converse.response

utterances = []
lang = self.lang # unused, but we get this info together with utterance if needed
# user could switch lang midway, maybe ignore response in this case (?)

from ovos_bus_client.session import SessionManager
sess = SessionManager.get()

def _handle_get_response(message):
nonlocal utterances, lang

skill_id = message.data["skill_id"]
if skill_id != self.skill_id:
return # not for us!

# validate session_id to ensure this isnt another
# user querying the skill at same time
sess2 = SessionManager.get(message)
if sess.session_id != sess2.session_id:
return # not for us!

utterances = message.data["utterances"]
lang = message.data["lang"]
# received get_response

self.bus.on("skill.converse.get_response", _handle_get_response)

# NOTE: a threading.Event is not used otherwise we can't raise the
# AbortEvent exception to kill the thread
start = time.time()
while time.time() - start <= 15 and not len(utterances):
time.sleep(0.1)
if self.__response is not False:
if self.__response is None:
# aborted externally (if None)
self.log.debug("get_response aborted")
else:
utterances = [self.__response] # external override

self.bus.remove("skill.converse.get_response", _handle_get_response)
self.bus.emit(Message("skill.converse.get_response.disable",
{"skill_id": self.skill_id}))

if utterances:
return utterances[0]
return None


# backwards compat alias, no functional difference
class OVOSFallbackSkill(OVOSSkill):
def __new__(cls, *args, **kwargs):
Expand Down

0 comments on commit cbdd20f

Please sign in to comment.