Spaces:
Build error
Build error
Validify-testbot-1
/
botbuilder-python
/libraries
/botbuilder-dialogs
/botbuilder
/dialogs
/prompts
/activity_prompt.py
| # Copyright (c) Microsoft Corporation. All rights reserved. | |
| # Licensed under the MIT License. | |
| from typing import Callable, Dict | |
| from botbuilder.core import TurnContext | |
| from botbuilder.dialogs import ( | |
| Dialog, | |
| DialogContext, | |
| DialogInstance, | |
| DialogReason, | |
| DialogTurnResult, | |
| ) | |
| from botbuilder.schema import ActivityTypes, InputHints | |
| from .prompt import Prompt | |
| from .prompt_options import PromptOptions | |
| from .prompt_recognizer_result import PromptRecognizerResult | |
| from .prompt_validator_context import PromptValidatorContext | |
| class ActivityPrompt(Dialog): | |
| """ | |
| Waits for an activity to be received. | |
| .. remarks:: | |
| This prompt requires a validator be passed in and is useful when waiting for non-message | |
| activities like an event to be received. The validator can ignore received events until the | |
| expected activity is received. | |
| :var persisted_options: | |
| :typevar persisted_options: str | |
| :var persisted_state: | |
| :vartype persisted_state: str | |
| """ | |
| persisted_options = "options" | |
| persisted_state = "state" | |
| def __init__( | |
| self, dialog_id: str, validator: Callable[[PromptValidatorContext], bool] | |
| ): | |
| """ | |
| Initializes a new instance of the :class:`ActivityPrompt` class. | |
| :param dialog_id: Unique ID of the dialog within its parent :class:`DialogSet` or :class:`ComponentDialog`. | |
| :type dialog_id: str | |
| :param validator: Validator that will be called each time a new activity is received. | |
| :type validator: :class:`typing.Callable[[:class:`PromptValidatorContext`], bool]` | |
| """ | |
| Dialog.__init__(self, dialog_id) | |
| if validator is None: | |
| raise TypeError("validator was expected but received None") | |
| self._validator = validator | |
| async def begin_dialog( | |
| self, dialog_context: DialogContext, options: PromptOptions = None | |
| ) -> DialogTurnResult: | |
| """ | |
| Called when a prompt dialog is pushed onto the dialog stack and is being activated. | |
| :param dialog_context: The dialog context for the current turn of the conversation. | |
| :type dialog_context: :class:`DialogContext` | |
| :param options: Optional, additional information to pass to the prompt being started. | |
| :type options: :class:`PromptOptions` | |
| :return Dialog.end_of_turn: | |
| :rtype Dialog.end_of_turn: :class:`Dialog.DialogTurnResult` | |
| """ | |
| if not dialog_context: | |
| raise TypeError("ActivityPrompt.begin_dialog(): dc cannot be None.") | |
| if not isinstance(options, PromptOptions): | |
| raise TypeError( | |
| "ActivityPrompt.begin_dialog(): Prompt options are required for ActivityPrompts." | |
| ) | |
| # Ensure prompts have input hint set | |
| if options.prompt is not None and not options.prompt.input_hint: | |
| options.prompt.input_hint = InputHints.expecting_input | |
| if options.retry_prompt is not None and not options.retry_prompt.input_hint: | |
| options.retry_prompt.input_hint = InputHints.expecting_input | |
| # Initialize prompt state | |
| state: Dict[str, object] = dialog_context.active_dialog.state | |
| state[self.persisted_options] = options | |
| state[self.persisted_state] = {Prompt.ATTEMPT_COUNT_KEY: 0} | |
| # Send initial prompt | |
| await self.on_prompt( | |
| dialog_context.context, | |
| state[self.persisted_state], | |
| state[self.persisted_options], | |
| False, | |
| ) | |
| return Dialog.end_of_turn | |
| async def continue_dialog(self, dialog_context: DialogContext) -> DialogTurnResult: | |
| """ | |
| Called when a prompt dialog is the active dialog and the user replied with a new activity. | |
| :param dialog_context: The dialog context for the current turn of the conversation. | |
| :type dialog_context: :class:`DialogContext` | |
| :return Dialog.end_of_turn: | |
| :rtype Dialog.end_of_turn: :class:`Dialog.DialogTurnResult` | |
| """ | |
| if not dialog_context: | |
| raise TypeError( | |
| "ActivityPrompt.continue_dialog(): DialogContext cannot be None." | |
| ) | |
| # Perform base recognition | |
| instance = dialog_context.active_dialog | |
| state: Dict[str, object] = instance.state[self.persisted_state] | |
| options: Dict[str, object] = instance.state[self.persisted_options] | |
| recognized: PromptRecognizerResult = await self.on_recognize( | |
| dialog_context.context, state, options | |
| ) | |
| # Increment attempt count | |
| state[Prompt.ATTEMPT_COUNT_KEY] += 1 | |
| # Validate the return value | |
| is_valid = False | |
| if self._validator is not None: | |
| prompt_context = PromptValidatorContext( | |
| dialog_context.context, recognized, state, options | |
| ) | |
| is_valid = await self._validator(prompt_context) | |
| if options is None: | |
| options = PromptOptions() | |
| options.number_of_attempts += 1 | |
| elif recognized.succeeded: | |
| is_valid = True | |
| # Return recognized value or re-prompt | |
| if is_valid: | |
| return await dialog_context.end_dialog(recognized.value) | |
| if ( | |
| dialog_context.context.activity.type == ActivityTypes.message | |
| and not dialog_context.context.responded | |
| ): | |
| await self.on_prompt(dialog_context.context, state, options, True) | |
| return Dialog.end_of_turn | |
| async def resume_dialog( # pylint: disable=unused-argument | |
| self, dialog_context: DialogContext, reason: DialogReason, result: object = None | |
| ): | |
| """ | |
| Called when a prompt dialog resumes being the active dialog on the dialog stack, such | |
| as when the previous active dialog on the stack completes. | |
| .. remarks:: | |
| Prompts are typically leaf nodes on the stack but the dev is free to push other dialogs | |
| on top of the stack which will result in the prompt receiving an unexpected call to | |
| :meth:`ActivityPrompt.resume_dialog()` when the pushed on dialog ends. | |
| To avoid the prompt prematurely ending, we need to implement this method and | |
| simply re-prompt the user. | |
| :param dialog_context: The dialog context for the current turn of the conversation | |
| :type dialog_context: :class:`DialogContext` | |
| :param reason: An enum indicating why the dialog resumed. | |
| :type reason: :class:`DialogReason` | |
| :param result: Optional, value returned from the previous dialog on the stack. | |
| :type result: object | |
| """ | |
| await self.reprompt_dialog(dialog_context.context, dialog_context.active_dialog) | |
| return Dialog.end_of_turn | |
| async def reprompt_dialog(self, context: TurnContext, instance: DialogInstance): | |
| state: Dict[str, object] = instance.state[self.persisted_state] | |
| options: PromptOptions = instance.state[self.persisted_options] | |
| await self.on_prompt(context, state, options, False) | |
| async def on_prompt( | |
| self, | |
| context: TurnContext, | |
| state: Dict[str, dict], # pylint: disable=unused-argument | |
| options: PromptOptions, | |
| is_retry: bool = False, | |
| ): | |
| """ | |
| Called anytime the derived class should send the user a prompt. | |
| :param dialog_context: The dialog context for the current turn of the conversation | |
| :type dialog_context: :class:`DialogContext` | |
| :param state: Additional state being persisted for the prompt. | |
| :type state: :class:`typing.Dict[str, dict]` | |
| :param options: Options that the prompt started with in the call to :meth:`DialogContext.prompt()`. | |
| :type options: :class:`PromptOptions` | |
| :param isRetry: If `true` the users response wasn't recognized and the re-prompt should be sent. | |
| :type isRetry: bool | |
| """ | |
| if is_retry and options.retry_prompt: | |
| options.retry_prompt.input_hint = InputHints.expecting_input | |
| await context.send_activity(options.retry_prompt) | |
| elif options.prompt: | |
| options.prompt.input_hint = InputHints.expecting_input | |
| await context.send_activity(options.prompt) | |
| async def on_recognize( # pylint: disable=unused-argument | |
| self, context: TurnContext, state: Dict[str, object], options: PromptOptions | |
| ) -> PromptRecognizerResult: | |
| """ | |
| When overridden in a derived class, attempts to recognize the incoming activity. | |
| :param context: Context for the current turn of conversation with the user. | |
| :type context: :class:`botbuilder.core.TurnContext` | |
| :param state: Contains state for the current instance of the prompt on the dialog stack. | |
| :type state: :class:`typing.Dict[str, dict]` | |
| :param options: A prompt options object | |
| :type options: :class:`PromptOptions` | |
| :return result: constructed from the options initially provided in the call to :meth:`async def on_prompt()` | |
| :rtype result: :class:`PromptRecognizerResult` | |
| """ | |
| result = PromptRecognizerResult() | |
| result.succeeded = (True,) | |
| result.value = context.activity | |
| return result | |