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 camel_case_split
) )
from mycroft.util.log import LOG 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_container import EventContainer, create_wrapper, get_handler_name
from ..event_scheduler import EventSchedulerInterface from ..event_scheduler import EventSchedulerInterface
@ -368,9 +370,6 @@ class MycroftSkill:
""" """
data = data or {} data = data or {}
if not self.dialog_renderer.render(dialog, data):
raise ValueError('dialog message required')
def on_fail_default(utterance): def on_fail_default(utterance):
fail_data = data.copy() fail_data = data.copy()
fail_data['utterance'] = utterance fail_data['utterance'] = utterance
@ -390,8 +389,11 @@ class MycroftSkill:
validator = validator or validator_default validator = validator or validator_default
# Speak query and wait for user response # Speak query and wait for user response
self.speak(self.dialog_renderer.render(dialog, data), utterance = self.dialog_renderer.render(dialog, data)
expect_response=True, wait=True) 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, return self._wait_response(is_cancel, validator, on_fail_fn,
num_retries) num_retries)
@ -427,7 +429,10 @@ class MycroftSkill:
return None return None
line = on_fail(response) line = on_fail(response)
if line:
self.speak(line, expect_response=True) self.speak(line, expect_response=True)
else:
self.bus.emit(Message('mycroft.mic.listen'))
def ask_yesno(self, prompt, data=None): def ask_yesno(self, prompt, data=None):
"""Read prompt and wait for a yes/no answer """Read prompt and wait for a yes/no answer
@ -451,6 +456,57 @@ class MycroftSkill:
else: else:
return resp 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): def voc_match(self, utt, voc_filename, lang=None):
"""Determine if the given utterance contains the vocabulary provided. """Determine if the given utterance contains the vocabulary provided.