feat/ask_selection

pull/2302/head
jarbasal 2019-09-13 01:58:42 +01:00 committed by Åke Forslund
parent 324fe988aa
commit 978ece53ca
2 changed files with 65 additions and 6 deletions

View File

@ -0,0 +1,3 @@
last choice
last option
last one

View File

@ -42,6 +42,8 @@ from mycroft.util import (
camel_case_split
)
from mycroft.util.log import LOG
from mycroft.util.format import pronounce_number, join_list
from mycroft.util.parse import match_one, extract_number
from .event_container import EventContainer, create_wrapper, get_handler_name
from ..event_scheduler import EventSchedulerInterface
@ -368,9 +370,6 @@ class MycroftSkill:
"""
data = data or {}
if not self.dialog_renderer.render(dialog, data):
raise ValueError('dialog message required')
def on_fail_default(utterance):
fail_data = data.copy()
fail_data['utterance'] = utterance
@ -390,8 +389,11 @@ class MycroftSkill:
validator = validator or validator_default
# Speak query and wait for user response
self.speak(self.dialog_renderer.render(dialog, data),
expect_response=True, wait=True)
utterance = self.dialog_renderer.render(dialog, data)
if utterance:
self.speak(utterance, expect_response=True, wait=True)
else:
self.bus.emit(Message('mycroft.mic.listen'))
return self._wait_response(is_cancel, validator, on_fail_fn,
num_retries)
@ -427,7 +429,10 @@ class MycroftSkill:
return None
line = on_fail(response)
self.speak(line, expect_response=True)
if line:
self.speak(line, expect_response=True)
else:
self.bus.emit(Message('mycroft.mic.listen'))
def ask_yesno(self, prompt, data=None):
"""Read prompt and wait for a yes/no answer
@ -451,6 +456,57 @@ class MycroftSkill:
else:
return resp
def ask_selection(self, options, dialog='', data=None, min_conf=0.65, numeric=False):
""" Read options, ask dialog question and wait for an answer
This automatically deals with fuzzy matching and selection by number
e.g.
"first option"
"last option"
"second option"
"option number four"
Args:
options (list): list of options to present user
dialog (str): a dialog id or string to read after presenting options
data (dict): Data used to render the dialog
min_conf (float): min confidence for fuzzy matching, None will be returned bellow this threshold
numeric (bool): speak options as a numeric menu
Returns:
string: list element selected by user, or None
"""
assert isinstance(options, list)
if not len(options):
return None
elif len(options) == 1:
return options[0]
if numeric:
for idx, opt in enumerate(options):
opt_str = "{number}, {option_text}".format(number=pronounce_number(idx + 1, self.lang),
option_text=opt)
self.speak(opt_str, wait=True)
else:
opt_str = join_list(options, "or", lang=self.lang) + "?"
self.speak(opt_str, wait=True)
resp = self.get_response(dialog=dialog, data=data)
if resp:
match, score = match_one(resp, options)
if score < min_conf:
if self.voc_match(resp, 'last'):
resp = options[-1]
else:
num = extract_number(resp, self.lang, ordinals=True)
resp = None
if num and num < len(options):
resp = options[num - 1]
else:
resp = match
return resp
def voc_match(self, utt, voc_filename, lang=None):
"""Determine if the given utterance contains the vocabulary provided.