Spaces:
Build error
Build error
Validify-testbot-1
/
botbuilder-python
/libraries
/botbuilder-dialogs
/botbuilder
/dialogs
/choices
/choice_factory.py
| # Copyright (c) Microsoft Corporation. All rights reserved. | |
| # Licensed under the MIT License. | |
| from typing import List, Union | |
| from botbuilder.core import CardFactory, MessageFactory | |
| from botbuilder.schema import ActionTypes, Activity, CardAction, HeroCard, InputHints | |
| from . import Channel, Choice, ChoiceFactoryOptions | |
| class ChoiceFactory: | |
| """ | |
| Assists with formatting a message activity that contains a list of choices. | |
| """ | |
| def for_channel( | |
| channel_id: str, | |
| choices: List[Union[str, Choice]], | |
| text: str = None, | |
| speak: str = None, | |
| options: ChoiceFactoryOptions = None, | |
| ) -> Activity: | |
| """ | |
| Creates a message activity that includes a list of choices formatted based on the | |
| capabilities of a given channel. | |
| Parameters: | |
| ---------- | |
| channel_id: A channel ID. | |
| choices: List of choices to render | |
| text: (Optional) Text of the message to send. | |
| speak (Optional) SSML. Text to be spoken by your bot on a speech-enabled channel. | |
| """ | |
| if channel_id is None: | |
| channel_id = "" | |
| choices = ChoiceFactory._to_choices(choices) | |
| # Find maximum title length | |
| max_title_length = 0 | |
| for choice in choices: | |
| if choice.action is not None and choice.action.title not in (None, ""): | |
| size = len(choice.action.title) | |
| else: | |
| size = len(choice.value) | |
| if size > max_title_length: | |
| max_title_length = size | |
| # Determine list style | |
| supports_suggested_actions = Channel.supports_suggested_actions( | |
| channel_id, len(choices) | |
| ) | |
| supports_card_actions = Channel.supports_card_actions(channel_id, len(choices)) | |
| max_action_title_length = Channel.max_action_title_length(channel_id) | |
| long_titles = max_title_length > max_action_title_length | |
| if not long_titles and not supports_suggested_actions and supports_card_actions: | |
| # SuggestedActions is the preferred approach, but for channels that don't | |
| # support them (e.g. Teams, Cortana) we should use a HeroCard with CardActions | |
| return ChoiceFactory.hero_card(choices, text, speak) | |
| if not long_titles and supports_suggested_actions: | |
| # We always prefer showing choices using suggested actions. If the titles are too long, however, | |
| # we'll have to show them as a text list. | |
| return ChoiceFactory.suggested_action(choices, text, speak) | |
| if not long_titles and len(choices) <= 3: | |
| # If the titles are short and there are 3 or less choices we'll use an inline list. | |
| return ChoiceFactory.inline(choices, text, speak, options) | |
| # Show a numbered list. | |
| return ChoiceFactory.list_style(choices, text, speak, options) | |
| def inline( | |
| choices: List[Union[str, Choice]], | |
| text: str = None, | |
| speak: str = None, | |
| options: ChoiceFactoryOptions = None, | |
| ) -> Activity: | |
| """ | |
| Creates a message activity that includes a list of choices formatted as an inline list. | |
| Parameters: | |
| ---------- | |
| choices: The list of choices to render. | |
| text: (Optional) The text of the message to send. | |
| speak: (Optional) SSML. Text to be spoken by your bot on a speech-enabled channel. | |
| options: (Optional) The formatting options to use to tweak rendering of list. | |
| """ | |
| choices = ChoiceFactory._to_choices(choices) | |
| if options is None: | |
| options = ChoiceFactoryOptions() | |
| opt = ChoiceFactoryOptions( | |
| inline_separator=options.inline_separator or ", ", | |
| inline_or=options.inline_or or " or ", | |
| inline_or_more=options.inline_or_more or ", or ", | |
| include_numbers=( | |
| options.include_numbers if options.include_numbers is not None else True | |
| ), | |
| ) | |
| # Format list of choices | |
| connector = "" | |
| txt_builder: List[str] = [text] | |
| txt_builder.append(" ") | |
| for index, choice in enumerate(choices): | |
| title = ( | |
| choice.action.title | |
| if (choice.action is not None and choice.action.title is not None) | |
| else choice.value | |
| ) | |
| txt_builder.append(connector) | |
| if opt.include_numbers is True: | |
| txt_builder.append("(") | |
| txt_builder.append(f"{index + 1}") | |
| txt_builder.append(") ") | |
| txt_builder.append(title) | |
| if index == (len(choices) - 2): | |
| connector = opt.inline_or if index == 0 else opt.inline_or_more | |
| connector = connector or "" | |
| else: | |
| connector = opt.inline_separator or "" | |
| # Return activity with choices as an inline list. | |
| return MessageFactory.text( | |
| "".join(txt_builder), speak, InputHints.expecting_input | |
| ) | |
| def list_style( | |
| choices: List[Union[str, Choice]], | |
| text: str = None, | |
| speak: str = None, | |
| options: ChoiceFactoryOptions = None, | |
| ): | |
| """ | |
| Creates a message activity that includes a list of choices formatted as a numbered or bulleted list. | |
| Parameters: | |
| ---------- | |
| choices: The list of choices to render. | |
| text: (Optional) The text of the message to send. | |
| speak: (Optional) SSML. Text to be spoken by your bot on a speech-enabled channel. | |
| options: (Optional) The formatting options to use to tweak rendering of list. | |
| """ | |
| choices = ChoiceFactory._to_choices(choices) | |
| if options is None: | |
| options = ChoiceFactoryOptions() | |
| if options.include_numbers is None: | |
| include_numbers = True | |
| else: | |
| include_numbers = options.include_numbers | |
| # Format list of choices | |
| connector = "" | |
| txt_builder = [text] | |
| txt_builder.append("\n\n ") | |
| for index, choice in enumerate(choices): | |
| title = ( | |
| choice.action.title | |
| if choice.action is not None and choice.action.title is not None | |
| else choice.value | |
| ) | |
| txt_builder.append(connector) | |
| if include_numbers: | |
| txt_builder.append(f"{index + 1}") | |
| txt_builder.append(". ") | |
| else: | |
| txt_builder.append("- ") | |
| txt_builder.append(title) | |
| connector = "\n " | |
| # Return activity with choices as a numbered list. | |
| txt = "".join(txt_builder) | |
| return MessageFactory.text(txt, speak, InputHints.expecting_input) | |
| def suggested_action( | |
| choices: List[Choice], text: str = None, speak: str = None | |
| ) -> Activity: | |
| """ | |
| Creates a message activity that includes a list of choices that have been added as suggested actions. | |
| """ | |
| # Return activity with choices as suggested actions | |
| return MessageFactory.suggested_actions( | |
| ChoiceFactory._extract_actions(choices), | |
| text, | |
| speak, | |
| InputHints.expecting_input, | |
| ) | |
| def hero_card( | |
| choices: List[Union[Choice, str]], text: str = None, speak: str = None | |
| ) -> Activity: | |
| """ | |
| Creates a message activity that includes a lsit of coices that have been added as `HeroCard`'s | |
| """ | |
| attachment = CardFactory.hero_card( | |
| HeroCard(text=text, buttons=ChoiceFactory._extract_actions(choices)) | |
| ) | |
| # Return activity with choices as HeroCard with buttons | |
| return MessageFactory.attachment( | |
| attachment, None, speak, InputHints.expecting_input | |
| ) | |
| def _to_choices(choices: List[Union[str, Choice]]) -> List[Choice]: | |
| """ | |
| Takes a list of strings and returns them as [`Choice`]. | |
| """ | |
| if choices is None: | |
| return [] | |
| return [ | |
| Choice(value=choice) if isinstance(choice, str) else choice | |
| for choice in choices | |
| ] | |
| def _extract_actions(choices: List[Union[str, Choice]]) -> List[CardAction]: | |
| if choices is None: | |
| choices = [] | |
| choices = ChoiceFactory._to_choices(choices) | |
| card_actions: List[CardAction] = [] | |
| for choice in choices: | |
| if choice.action is not None: | |
| card_action = choice.action | |
| else: | |
| card_action = CardAction( | |
| type=ActionTypes.im_back, value=choice.value, title=choice.value | |
| ) | |
| card_actions.append(card_action) | |
| return card_actions | |