Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from .number_prompt import NumberPrompt
from .oauth_prompt import OAuthPrompt
from .oauth_prompt_settings import OAuthPromptSettings
from .prompt_culture_models import PromptCultureModel, PromptCultureModels
from .prompt_options import PromptOptions
from .prompt_recognizer_result import PromptRecognizerResult
from .prompt_validator_context import PromptValidatorContext
Expand All @@ -30,6 +31,8 @@
"NumberPrompt",
"OAuthPrompt",
"OAuthPromptSettings",
"PromptCultureModel",
"PromptCultureModels",
"PromptOptions",
"PromptRecognizerResult",
"PromptValidatorContext",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from typing import Callable, Dict, List, Union
from typing import Callable, Dict, List

from recognizers_text import Culture
from botbuilder.core import TurnContext
from botbuilder.dialogs.choices import (
Choice,
Expand All @@ -15,6 +14,7 @@
from botbuilder.schema import Activity, ActivityTypes

from .prompt import Prompt
from .prompt_culture_models import PromptCultureModels
from .prompt_options import PromptOptions
from .prompt_validator_context import PromptValidatorContext
from .prompt_recognizer_result import PromptRecognizerResult
Expand All @@ -29,69 +29,43 @@ class ChoicePrompt(Prompt):
"""

_default_choice_options: Dict[str, ChoiceFactoryOptions] = {
Culture.Spanish: ChoiceFactoryOptions(
inline_separator=", ",
inline_or=" o ",
inline_or_more=", o ",
c.locale: ChoiceFactoryOptions(
inline_separator=c.separator,
inline_or=c.inline_or_more,
inline_or_more=c.inline_or_more,
include_numbers=True,
),
Culture.Dutch: ChoiceFactoryOptions(
inline_separator=", ",
inline_or=" of ",
inline_or_more=", of ",
include_numbers=True,
),
Culture.English: ChoiceFactoryOptions(
inline_separator=", ",
inline_or=" or ",
inline_or_more=", or ",
include_numbers=True,
),
Culture.French: ChoiceFactoryOptions(
inline_separator=", ",
inline_or=" ou ",
inline_or_more=", ou ",
include_numbers=True,
),
"de-de": ChoiceFactoryOptions(
inline_separator=", ",
inline_or=" oder ",
inline_or_more=", oder ",
include_numbers=True,
),
Culture.Japanese: ChoiceFactoryOptions(
inline_separator="、 ",
inline_or=" または ",
inline_or_more="、 または ",
include_numbers=True,
),
Culture.Portuguese: ChoiceFactoryOptions(
inline_separator=", ",
inline_or=" ou ",
inline_or_more=", ou ",
include_numbers=True,
),
Culture.Chinese: ChoiceFactoryOptions(
inline_separator=", ",
inline_or=" 要么 ",
inline_or_more=", 要么 ",
include_numbers=True,
),
)
for c in PromptCultureModels.get_supported_cultures()
}

def __init__(
self,
dialog_id: str,
validator: Callable[[PromptValidatorContext], bool] = None,
default_locale: str = None,
choice_defaults: Dict[str, ChoiceFactoryOptions] = None,
):
"""
:param dialog_id: Unique ID of the dialog within its parent `DialogSet`.
:param validator: (Optional) validator that will be called each time the user responds to the prompt.
If the validator replies with a message no additional retry prompt will be sent.
:param default_locale: (Optional) locale to use if `dc.context.activity.locale` not specified.
Defaults to a value of `en-us`.
:param choice_defaults: (Optional) Overrides the dictionary of
Bot Framework SDK-supported _default_choice_options.
As type Dict[str, ChoiceFactoryOptions], the key is a string of the locale, such as "en-us".
* Must be passed in to each ConfirmPrompt that needs the custom choice defaults.
"""
super().__init__(dialog_id, validator)

self.style = ListStyle.auto
self.default_locale = default_locale
self.choice_options: ChoiceFactoryOptions = None
self.recognizer_options: FindChoicesOptions = None

if choice_defaults is not None:
self._default_choice_options = choice_defaults

async def on_prompt(
self,
turn_context: TurnContext,
Expand All @@ -106,20 +80,15 @@ async def on_prompt(
raise TypeError("ChoicePrompt.on_prompt(): options cannot be None.")

# Determine culture
culture: Union[
str, None
] = turn_context.activity.locale if turn_context.activity.locale else self.default_locale

if not culture or culture not in ChoicePrompt._default_choice_options:
culture = Culture.English
culture = self._determine_culture(turn_context.activity)

# Format prompt to send
choices: List[Choice] = options.choices if options.choices else []
channel_id: str = turn_context.activity.channel_id
choice_options: ChoiceFactoryOptions = (
self.choice_options
if self.choice_options
else ChoicePrompt._default_choice_options[culture]
else self._default_choice_options[culture]
)
choice_style = (
0 if options.style == 0 else options.style if options.style else self.style
Expand Down Expand Up @@ -155,15 +124,25 @@ async def on_recognize(
if not utterance:
return result
opt: FindChoicesOptions = self.recognizer_options if self.recognizer_options else FindChoicesOptions()
opt.locale = (
activity.locale
if activity.locale
else (self.default_locale or Culture.English)
)
opt.locale = self._determine_culture(turn_context.activity, opt)
results = ChoiceRecognizers.recognize_choices(utterance, choices, opt)

if results is not None and results:
result.succeeded = True
result.value = results[0].resolution

return result

def _determine_culture(
self, activity: Activity, opt: FindChoicesOptions = FindChoicesOptions()
) -> str:
culture = (
PromptCultureModels.map_to_nearest_language(activity.locale)
or opt.locale
or self.default_locale
or PromptCultureModels.English.locale
)
if not culture or not self._default_choice_options.get(culture):
culture = PromptCultureModels.English.locale

return culture
Original file line number Diff line number Diff line change
Expand Up @@ -12,60 +12,30 @@
ListStyle,
)
from .prompt import Prompt
from .prompt_culture_models import PromptCultureModels
from .prompt_options import PromptOptions
from .prompt_recognizer_result import PromptRecognizerResult


class ConfirmPrompt(Prompt):
# TODO: Fix to reference recognizer to use proper constants
choice_defaults: Dict[str, object] = {
"Spanish": (
Choice("Si"),
Choice("No"),
ChoiceFactoryOptions(", ", " o ", ", o ", True),
),
"Dutch": (
Choice("Ja"),
Choice("Nee"),
ChoiceFactoryOptions(", ", " of ", ", of ", True),
),
"English": (
Choice("Yes"),
Choice("No"),
ChoiceFactoryOptions(", ", " or ", ", or ", True),
),
"French": (
Choice("Oui"),
Choice("Non"),
ChoiceFactoryOptions(", ", " ou ", ", ou ", True),
),
"German": (
Choice("Ja"),
Choice("Nein"),
ChoiceFactoryOptions(", ", " oder ", ", oder ", True),
),
"Japanese": (
Choice("はい"),
Choice("いいえ"),
ChoiceFactoryOptions("、 ", " または ", "、 または ", True),
),
"Portuguese": (
Choice("Sim"),
Choice("Não"),
ChoiceFactoryOptions(", ", " ou ", ", ou ", True),
),
"Chinese": (
Choice("是的"),
Choice("不"),
ChoiceFactoryOptions(", ", " 要么 ", ", 要么 ", True),
),
_default_choice_options: Dict[str, object] = {
c.locale: (
Choice(c.yes_in_language),
Choice(c.no_in_language),
ChoiceFactoryOptions(c.separator, c.inline_or, c.inline_or_more, True),
)
for c in PromptCultureModels.get_supported_cultures()
}

# TODO: PromptValidator
def __init__(
self, dialog_id: str, validator: object = None, default_locale: str = None
self,
dialog_id: str,
validator: object = None,
default_locale: str = None,
choice_defaults: Dict[str, object] = None,
):
super(ConfirmPrompt, self).__init__(dialog_id, validator)
super().__init__(dialog_id, validator)
if dialog_id is None:
raise TypeError("ConfirmPrompt(): dialog_id cannot be None.")
# TODO: Port ListStyle
Expand All @@ -75,6 +45,9 @@ def __init__(
self.choice_options = None
self.confirm_choices = None

if choice_defaults is not None:
self._default_choice_options = choice_defaults

async def on_prompt(
self,
turn_context: TurnContext,
Expand All @@ -89,8 +62,8 @@ async def on_prompt(

# Format prompt to send
channel_id = turn_context.activity.channel_id
culture = self.determine_culture(turn_context.activity)
defaults = self.choice_defaults[culture]
culture = self._determine_culture(turn_context.activity)
defaults = self._default_choice_options[culture]
choice_opts = (
self.choice_options if self.choice_options is not None else defaults[2]
)
Expand Down Expand Up @@ -125,7 +98,7 @@ async def on_recognize(
utterance = turn_context.activity.text
if not utterance:
return result
culture = self.determine_culture(turn_context.activity)
culture = self._determine_culture(turn_context.activity)
results = recognize_boolean(utterance, culture)
if results:
first = results[0]
Expand All @@ -135,7 +108,7 @@ async def on_recognize(
else:
# First check whether the prompt was sent to the user with numbers
# if it was we should recognize numbers
defaults = self.choice_defaults[culture]
defaults = self._default_choice_options[culture]
opts = (
self.choice_options
if self.choice_options is not None
Expand All @@ -161,12 +134,13 @@ async def on_recognize(

return result

def determine_culture(self, activity: Activity) -> str:
def _determine_culture(self, activity: Activity) -> str:
culture = (
activity.locale if activity.locale is not None else self.default_locale
PromptCultureModels.map_to_nearest_language(activity.locale)
or self.default_locale
or PromptCultureModels.English.locale
)
if not culture or culture not in self.choice_defaults:
culture = (
"English" # TODO: Fix to reference recognizer to use proper constants
)
if not culture or not self._default_choice_options.get(culture):
culture = PromptCultureModels.English.locale

return culture
Loading