Tweak get_response() doc and behavior
Several minor documentation changes, plus: * 'cancel' now has to be an exact match * Cancel events return None instead of the spoken cancelation string * Reduced timeout to 10 seconds instead of 20 * Changed 'text' to 'announcement' and simplified logicpull/1293/head
parent
35d057ff9b
commit
b145e149e6
|
@ -330,9 +330,10 @@ class MycroftSkill(object):
|
||||||
|
|
||||||
def __get_response(self):
|
def __get_response(self):
|
||||||
"""
|
"""
|
||||||
Grab a reponse from the user
|
Helper to get a reponse from the user
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: STT transcription
|
str: user's response or None on a timeout
|
||||||
"""
|
"""
|
||||||
event = Event()
|
event = Event()
|
||||||
|
|
||||||
|
@ -341,48 +342,49 @@ class MycroftSkill(object):
|
||||||
event.set()
|
event.set()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# install a temporary conversation handler
|
||||||
self.make_active()
|
self.make_active()
|
||||||
converse.response = None
|
converse.response = None
|
||||||
default_converse = self.converse
|
default_converse = self.converse
|
||||||
self.converse = converse
|
self.converse = converse
|
||||||
event.wait(20)
|
event.wait(10) # after 10 seconds, timeout
|
||||||
self.converse = default_converse
|
self.converse = default_converse
|
||||||
return converse.response
|
return converse.response
|
||||||
|
|
||||||
def get_response(self, dialog='', data=None, text='', validator=None,
|
def get_response(self, dialog='', data=None, announcement='',
|
||||||
on_fail=None, num_retries=-1):
|
validator=None, on_fail=None, num_retries=-1):
|
||||||
"""
|
"""
|
||||||
Ask and return a response from the user for the given dialog. Examples:
|
Prompt user and wait for response
|
||||||
color = self.get_response(dialog='ask.favorite.color')
|
|
||||||
|
The given dialog or announcement will be spoken, the immediately
|
||||||
|
listen and return user response. The response can optionally be
|
||||||
|
validated.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
color = self.get_response('ask.favorite.color')
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
dialog (str): Intro dialog file to read to the user
|
dialog (str): Announcement dialog to read to the user
|
||||||
data (dict): Data used to render the dialog
|
data (dict): Data used to render the dialog
|
||||||
text (str): Intro text instead of dialog file
|
announcement (str): Literal string (overrides dialog)
|
||||||
validator (any): Function with following signature
|
validator (any): Function with following signature
|
||||||
def validator(utterance):
|
def validator(utterance):
|
||||||
return is_valid(utterance)
|
return utterance != "red"
|
||||||
on_fail (any): Dialog file to read on invalid input,
|
on_fail (any): Dialog or function returning literal string
|
||||||
or a function to call that returns utterance
|
to speak on invalid input. For example:
|
||||||
def on_fail(utterance):
|
def on_fail(utterance):
|
||||||
return self.dialog_renderer.render('my.dialog')
|
return "nobody likes the color red, pick another"
|
||||||
num_retries (int): Number of times to keep asking user for input
|
num_retries (int): Times to ask user for input, -1 for infinite
|
||||||
Note, the user can still stop talking or say "cancel" at any
|
NOTE: User can not respond and timeout or say "cancel" to stop
|
||||||
time to stop. -1 for infinite
|
|
||||||
Returns:
|
Returns:
|
||||||
any: None or transcription user's reply
|
str: User's reply or None if timed out or canceled
|
||||||
"""
|
"""
|
||||||
data = data or {}
|
data = data or {}
|
||||||
validator = validator or bool
|
|
||||||
|
|
||||||
def get_intro():
|
announcement = announcement or self.dialog_renderer.render(dialog, data)
|
||||||
if dialog:
|
if not announcement:
|
||||||
return self.dialog_renderer.render(dialog, data)
|
raise ValueError('announcement or dialog message required')
|
||||||
else:
|
|
||||||
return text
|
|
||||||
|
|
||||||
if not get_intro() and not text:
|
|
||||||
raise ValueError('Please specify an intro message')
|
|
||||||
|
|
||||||
def on_fail_default(utterance):
|
def on_fail_default(utterance):
|
||||||
fail_data = data.copy()
|
fail_data = data.copy()
|
||||||
|
@ -390,23 +392,30 @@ class MycroftSkill(object):
|
||||||
if on_fail:
|
if on_fail:
|
||||||
return self.dialog_renderer.render(on_fail, fail_data)
|
return self.dialog_renderer.render(on_fail, fail_data)
|
||||||
else:
|
else:
|
||||||
return get_intro()
|
return announcement
|
||||||
|
|
||||||
|
# TODO: Load with something like mycroft.dialog.get_all()
|
||||||
cancel_voc = 'text/' + self.lang + '/cancel.voc'
|
cancel_voc = 'text/' + self.lang + '/cancel.voc'
|
||||||
with open(resolve_resource_file(cancel_voc)) as f:
|
with open(resolve_resource_file(cancel_voc)) as f:
|
||||||
cancel_words = list(filter(bool, f.read().split('\n')))
|
cancel_words = list(filter(bool, f.read().split('\n')))
|
||||||
|
|
||||||
def is_cancel(utterance):
|
def is_cancel(utterance):
|
||||||
return max(w in utterance for w in cancel_words)
|
return utterance in cancel_words
|
||||||
|
|
||||||
|
def on_valid_default(utterance):
|
||||||
|
# accept anything except 'cancel'
|
||||||
|
return not is_cancel(utterance)
|
||||||
|
|
||||||
|
validator = validator or on_valid_default
|
||||||
on_fail_fn = on_fail if callable(on_fail) else on_fail_default
|
on_fail_fn = on_fail if callable(on_fail) else on_fail_default
|
||||||
|
|
||||||
self.speak(get_intro(), expect_response=True)
|
self.speak(announcement, expect_response=True)
|
||||||
num_fails = 0
|
num_fails = 0
|
||||||
while True:
|
while True:
|
||||||
response = self.__get_response()
|
response = self.__get_response()
|
||||||
|
|
||||||
if response is None:
|
if response is None:
|
||||||
|
# if nothing said, prompt one more time
|
||||||
num_none_fails = 1 if num_retries < 0 else num_retries
|
num_none_fails = 1 if num_retries < 0 else num_retries
|
||||||
if num_fails >= num_none_fails:
|
if num_fails >= num_none_fails:
|
||||||
return None
|
return None
|
||||||
|
@ -414,6 +423,7 @@ class MycroftSkill(object):
|
||||||
if validator(response):
|
if validator(response):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
# catch user saying 'cancel'
|
||||||
if is_cancel(response):
|
if is_cancel(response):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue