microsoft-agents-hosting-dialogs 0.10.0.dev2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- microsoft_agents/hosting/dialogs/__init__.py +76 -0
- microsoft_agents/hosting/dialogs/_component_registration.py +30 -0
- microsoft_agents/hosting/dialogs/_telemetry_client.py +78 -0
- microsoft_agents/hosting/dialogs/choices/__init__.py +38 -0
- microsoft_agents/hosting/dialogs/choices/channel.py +121 -0
- microsoft_agents/hosting/dialogs/choices/choice_factory.py +262 -0
- microsoft_agents/hosting/dialogs/choices/choice_recognizer.py +148 -0
- microsoft_agents/hosting/dialogs/choices/find.py +242 -0
- microsoft_agents/hosting/dialogs/choices/models/__init__.py +23 -0
- microsoft_agents/hosting/dialogs/choices/models/choice.py +14 -0
- microsoft_agents/hosting/dialogs/choices/models/choice_factory_options.py +13 -0
- microsoft_agents/hosting/dialogs/choices/models/find_choices_options.py +28 -0
- microsoft_agents/hosting/dialogs/choices/models/find_values_options.py +31 -0
- microsoft_agents/hosting/dialogs/choices/models/found_choice.py +22 -0
- microsoft_agents/hosting/dialogs/choices/models/found_value.py +20 -0
- microsoft_agents/hosting/dialogs/choices/models/list_style.py +15 -0
- microsoft_agents/hosting/dialogs/choices/models/model_result.py +16 -0
- microsoft_agents/hosting/dialogs/choices/models/sorted_value.py +16 -0
- microsoft_agents/hosting/dialogs/choices/models/token.py +20 -0
- microsoft_agents/hosting/dialogs/choices/tokenizer.py +92 -0
- microsoft_agents/hosting/dialogs/component_dialog.py +284 -0
- microsoft_agents/hosting/dialogs/dialog.py +198 -0
- microsoft_agents/hosting/dialogs/dialog_component_registration.py +52 -0
- microsoft_agents/hosting/dialogs/dialog_container.py +31 -0
- microsoft_agents/hosting/dialogs/dialog_context.py +426 -0
- microsoft_agents/hosting/dialogs/dialog_extensions.py +201 -0
- microsoft_agents/hosting/dialogs/dialog_manager.py +189 -0
- microsoft_agents/hosting/dialogs/dialog_manager_result.py +17 -0
- microsoft_agents/hosting/dialogs/dialog_set.py +174 -0
- microsoft_agents/hosting/dialogs/dialog_state.py +20 -0
- microsoft_agents/hosting/dialogs/memory/__init__.py +24 -0
- microsoft_agents/hosting/dialogs/memory/component_memory_scopes_base.py +14 -0
- microsoft_agents/hosting/dialogs/memory/component_path_resolvers_base.py +15 -0
- microsoft_agents/hosting/dialogs/memory/dialog_path.py +33 -0
- microsoft_agents/hosting/dialogs/memory/dialog_state_manager.py +563 -0
- microsoft_agents/hosting/dialogs/memory/dialog_state_manager_configuration.py +11 -0
- microsoft_agents/hosting/dialogs/memory/path_resolver_base.py +8 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/__init__.py +19 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/alias_path_resolver.py +53 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/at_at_path_resolver.py +9 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/at_path_resolver.py +44 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/dollar_path_resolver.py +9 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/hash_path_resolver.py +9 -0
- microsoft_agents/hosting/dialogs/memory/path_resolvers/percent_path_resolver.py +9 -0
- microsoft_agents/hosting/dialogs/memory/scope_path.py +38 -0
- microsoft_agents/hosting/dialogs/memory/scopes/__init__.py +31 -0
- microsoft_agents/hosting/dialogs/memory/scopes/bot_state_memory_scope.py +66 -0
- microsoft_agents/hosting/dialogs/memory/scopes/class_memory_scope.py +64 -0
- microsoft_agents/hosting/dialogs/memory/scopes/conversation_memory_scope.py +12 -0
- microsoft_agents/hosting/dialogs/memory/scopes/dialog_class_memory_scope.py +52 -0
- microsoft_agents/hosting/dialogs/memory/scopes/dialog_context_memory_scope.py +68 -0
- microsoft_agents/hosting/dialogs/memory/scopes/dialog_memory_scope.py +75 -0
- microsoft_agents/hosting/dialogs/memory/scopes/memory_scope.py +91 -0
- microsoft_agents/hosting/dialogs/memory/scopes/settings_memory_scope.py +38 -0
- microsoft_agents/hosting/dialogs/memory/scopes/this_memory_scope.py +36 -0
- microsoft_agents/hosting/dialogs/memory/scopes/turn_memory_scope.py +86 -0
- microsoft_agents/hosting/dialogs/memory/scopes/user_memory_scope.py +12 -0
- microsoft_agents/hosting/dialogs/models/__init__.py +15 -0
- microsoft_agents/hosting/dialogs/models/dialog_event.py +13 -0
- microsoft_agents/hosting/dialogs/models/dialog_events.py +12 -0
- microsoft_agents/hosting/dialogs/models/dialog_instance.py +28 -0
- microsoft_agents/hosting/dialogs/models/dialog_reason.py +34 -0
- microsoft_agents/hosting/dialogs/models/dialog_turn_result.py +17 -0
- microsoft_agents/hosting/dialogs/models/dialog_turn_status.py +26 -0
- microsoft_agents/hosting/dialogs/object_path.py +315 -0
- microsoft_agents/hosting/dialogs/persisted_state.py +22 -0
- microsoft_agents/hosting/dialogs/persisted_state_keys.py +8 -0
- microsoft_agents/hosting/dialogs/prompts/__init__.py +41 -0
- microsoft_agents/hosting/dialogs/prompts/activity_prompt.py +203 -0
- microsoft_agents/hosting/dialogs/prompts/attachment_prompt.py +87 -0
- microsoft_agents/hosting/dialogs/prompts/choice_prompt.py +156 -0
- microsoft_agents/hosting/dialogs/prompts/confirm_prompt.py +161 -0
- microsoft_agents/hosting/dialogs/prompts/datetime_prompt.py +90 -0
- microsoft_agents/hosting/dialogs/prompts/datetime_resolution.py +16 -0
- microsoft_agents/hosting/dialogs/prompts/number_prompt.py +81 -0
- microsoft_agents/hosting/dialogs/prompts/oauth_prompt.py +569 -0
- microsoft_agents/hosting/dialogs/prompts/oauth_prompt_settings.py +43 -0
- microsoft_agents/hosting/dialogs/prompts/prompt.py +224 -0
- microsoft_agents/hosting/dialogs/prompts/prompt_culture_models.py +222 -0
- microsoft_agents/hosting/dialogs/prompts/prompt_options.py +42 -0
- microsoft_agents/hosting/dialogs/prompts/prompt_recognizer_result.py +11 -0
- microsoft_agents/hosting/dialogs/prompts/prompt_validator.py +0 -0
- microsoft_agents/hosting/dialogs/prompts/prompt_validator_context.py +44 -0
- microsoft_agents/hosting/dialogs/prompts/text_prompt.py +82 -0
- microsoft_agents/hosting/dialogs/waterfall_dialog.py +266 -0
- microsoft_agents/hosting/dialogs/waterfall_step_context.py +109 -0
- microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/METADATA +87 -0
- microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/RECORD +91 -0
- microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/WHEEL +5 -0
- microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/licenses/LICENSE +21 -0
- microsoft_agents_hosting_dialogs-0.10.0.dev2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
class OAuthPromptSettings:
|
|
4
|
+
def __init__(
|
|
5
|
+
self,
|
|
6
|
+
connection_name: str,
|
|
7
|
+
title: str,
|
|
8
|
+
text: str | None = None,
|
|
9
|
+
timeout: int | None = None,
|
|
10
|
+
oauth_app_credentials=None,
|
|
11
|
+
end_on_invalid_message: bool = False,
|
|
12
|
+
):
|
|
13
|
+
"""
|
|
14
|
+
Settings used to configure an `OAuthPrompt` instance.
|
|
15
|
+
Parameters:
|
|
16
|
+
connection_name (str): Name of the OAuth connection being used.
|
|
17
|
+
title (str): The title of the cards signin button.
|
|
18
|
+
text (str): (Optional) additional text included on the signin card.
|
|
19
|
+
timeout (int): (Optional) number of milliseconds the prompt will wait for the user to authenticate.
|
|
20
|
+
`OAuthPrompt` defaults value to `900,000` ms (15 minutes).
|
|
21
|
+
oauth_app_credentials (AppCredentials): (Optional) AppCredentials to use for OAuth. If None,
|
|
22
|
+
the Agent credentials are used.
|
|
23
|
+
end_on_invalid_message (bool): (Optional) value indicating whether the OAuthPrompt should end upon
|
|
24
|
+
receiving an invalid message. Generally the OAuthPrompt will ignore incoming messages from the
|
|
25
|
+
user during the auth flow, if they are not related to the auth flow. This flag enables ending the
|
|
26
|
+
OAuthPrompt rather than ignoring the user's message. Typically, this flag will be set to 'true',
|
|
27
|
+
but is 'false' by default for backwards compatibility.
|
|
28
|
+
"""
|
|
29
|
+
self.connection_name = connection_name
|
|
30
|
+
self.title = title
|
|
31
|
+
self.text = text
|
|
32
|
+
self.timeout = timeout
|
|
33
|
+
self.oauth_app_credentials = oauth_app_credentials
|
|
34
|
+
self.end_on_invalid_message = end_on_invalid_message
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def oath_app_credentials(self):
|
|
38
|
+
"""Backward-compatible alias for the misspelled attribute name."""
|
|
39
|
+
return self.oauth_app_credentials
|
|
40
|
+
|
|
41
|
+
@oath_app_credentials.setter
|
|
42
|
+
def oath_app_credentials(self, value):
|
|
43
|
+
self.oauth_app_credentials = value
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
from abc import abstractmethod
|
|
5
|
+
import copy
|
|
6
|
+
from typing import Any, Callable, Awaitable, cast
|
|
7
|
+
|
|
8
|
+
from microsoft_agents.hosting.core import TurnContext
|
|
9
|
+
from microsoft_agents.activity import InputHints, ActivityTypes, Activity
|
|
10
|
+
|
|
11
|
+
from ..choices import (
|
|
12
|
+
Choice,
|
|
13
|
+
ChoiceFactory,
|
|
14
|
+
ChoiceFactoryOptions,
|
|
15
|
+
ListStyle,
|
|
16
|
+
)
|
|
17
|
+
from .prompt_options import PromptOptions
|
|
18
|
+
from .prompt_recognizer_result import PromptRecognizerResult
|
|
19
|
+
from .prompt_validator_context import PromptValidatorContext
|
|
20
|
+
from ..models.dialog_reason import DialogReason
|
|
21
|
+
from ..dialog import Dialog
|
|
22
|
+
from ..models.dialog_instance import DialogInstance
|
|
23
|
+
from ..models.dialog_turn_result import DialogTurnResult
|
|
24
|
+
from ..dialog_context import DialogContext
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Prompt(Dialog):
|
|
28
|
+
"""
|
|
29
|
+
Defines the core behavior of prompt dialogs. Extends the Dialog base class.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
ATTEMPT_COUNT_KEY = "AttemptCount"
|
|
33
|
+
persisted_options = "options"
|
|
34
|
+
persisted_state = "state"
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
dialog_id: str,
|
|
39
|
+
validator: Callable[[PromptValidatorContext], Any] | None = None,
|
|
40
|
+
):
|
|
41
|
+
"""
|
|
42
|
+
Creates a new Prompt instance.
|
|
43
|
+
"""
|
|
44
|
+
super(Prompt, self).__init__(dialog_id)
|
|
45
|
+
self._validator = validator
|
|
46
|
+
|
|
47
|
+
async def begin_dialog(
|
|
48
|
+
self, dialog_context: DialogContext, options: object = None
|
|
49
|
+
) -> DialogTurnResult:
|
|
50
|
+
if not dialog_context:
|
|
51
|
+
raise TypeError("Prompt(): dc cannot be None.")
|
|
52
|
+
if not isinstance(options, PromptOptions):
|
|
53
|
+
raise TypeError("Prompt(): Prompt options are required for Prompt dialogs.")
|
|
54
|
+
|
|
55
|
+
# Ensure prompts have input hint set
|
|
56
|
+
if options.prompt is not None and not options.prompt.input_hint:
|
|
57
|
+
options.prompt.input_hint = InputHints.expecting_input
|
|
58
|
+
|
|
59
|
+
if options.retry_prompt is not None and not options.retry_prompt.input_hint:
|
|
60
|
+
options.retry_prompt.input_hint = InputHints.expecting_input
|
|
61
|
+
|
|
62
|
+
# Initialize prompt state
|
|
63
|
+
assert dialog_context.active_dialog is not None
|
|
64
|
+
state = dialog_context.active_dialog.state
|
|
65
|
+
state[self.persisted_options] = options
|
|
66
|
+
state[self.persisted_state] = {self.ATTEMPT_COUNT_KEY: 0}
|
|
67
|
+
|
|
68
|
+
# Send initial prompt
|
|
69
|
+
await self.on_prompt(
|
|
70
|
+
dialog_context.context,
|
|
71
|
+
state[self.persisted_state],
|
|
72
|
+
state[self.persisted_options],
|
|
73
|
+
False,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return Dialog.end_of_turn
|
|
77
|
+
|
|
78
|
+
async def continue_dialog(self, dialog_context: DialogContext):
|
|
79
|
+
if not dialog_context:
|
|
80
|
+
raise TypeError("Prompt(): dc cannot be None.")
|
|
81
|
+
|
|
82
|
+
# Don't do anything for non-message activities
|
|
83
|
+
if dialog_context.context.activity.type != ActivityTypes.message:
|
|
84
|
+
return Dialog.end_of_turn
|
|
85
|
+
|
|
86
|
+
# Perform base recognition
|
|
87
|
+
instance = dialog_context.active_dialog
|
|
88
|
+
assert instance is not None
|
|
89
|
+
state = cast(dict[str, object], instance.state[self.persisted_state])
|
|
90
|
+
options = cast(PromptOptions, instance.state[self.persisted_options])
|
|
91
|
+
recognized = await self.on_recognize(dialog_context.context, state, options)
|
|
92
|
+
|
|
93
|
+
# Validate the return value
|
|
94
|
+
is_valid = False
|
|
95
|
+
state[self.ATTEMPT_COUNT_KEY] = (
|
|
96
|
+
int(cast(int, state.get(self.ATTEMPT_COUNT_KEY, 0))) + 1
|
|
97
|
+
)
|
|
98
|
+
if self._validator is not None:
|
|
99
|
+
prompt_context = PromptValidatorContext(
|
|
100
|
+
dialog_context.context, recognized, state, options
|
|
101
|
+
)
|
|
102
|
+
is_valid = await self._validator(prompt_context)
|
|
103
|
+
if options is None:
|
|
104
|
+
options = PromptOptions()
|
|
105
|
+
options.number_of_attempts += 1
|
|
106
|
+
else:
|
|
107
|
+
if recognized.succeeded:
|
|
108
|
+
is_valid = True
|
|
109
|
+
|
|
110
|
+
# Return recognized value or re-prompt
|
|
111
|
+
if is_valid:
|
|
112
|
+
return await dialog_context.end_dialog(recognized.value)
|
|
113
|
+
|
|
114
|
+
if not dialog_context.context.responded:
|
|
115
|
+
await self.on_prompt(dialog_context.context, state, options, True)
|
|
116
|
+
return Dialog.end_of_turn
|
|
117
|
+
|
|
118
|
+
async def resume_dialog(
|
|
119
|
+
self, dialog_context: DialogContext, reason: DialogReason, result: object
|
|
120
|
+
) -> DialogTurnResult:
|
|
121
|
+
assert dialog_context.active_dialog is not None
|
|
122
|
+
await self.reprompt_dialog(dialog_context.context, dialog_context.active_dialog)
|
|
123
|
+
return Dialog.end_of_turn
|
|
124
|
+
|
|
125
|
+
async def reprompt_dialog(self, context: TurnContext, instance: DialogInstance):
|
|
126
|
+
state = instance.state[self.persisted_state]
|
|
127
|
+
options = instance.state[self.persisted_options]
|
|
128
|
+
await self.on_prompt(context, state, options, False)
|
|
129
|
+
|
|
130
|
+
@abstractmethod
|
|
131
|
+
async def on_prompt(
|
|
132
|
+
self,
|
|
133
|
+
turn_context: TurnContext,
|
|
134
|
+
state: dict[str, object],
|
|
135
|
+
options: PromptOptions,
|
|
136
|
+
is_retry: bool,
|
|
137
|
+
):
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
@abstractmethod
|
|
141
|
+
async def on_recognize(
|
|
142
|
+
self,
|
|
143
|
+
turn_context: TurnContext,
|
|
144
|
+
state: dict[str, object],
|
|
145
|
+
options: PromptOptions,
|
|
146
|
+
) -> PromptRecognizerResult:
|
|
147
|
+
pass
|
|
148
|
+
|
|
149
|
+
def append_choices(
|
|
150
|
+
self,
|
|
151
|
+
prompt: Activity | None,
|
|
152
|
+
channel_id: str,
|
|
153
|
+
choices: list[Choice],
|
|
154
|
+
style: ListStyle | int,
|
|
155
|
+
options: ChoiceFactoryOptions | None = None,
|
|
156
|
+
) -> Activity:
|
|
157
|
+
"""
|
|
158
|
+
Composes an output activity containing a set of choices.
|
|
159
|
+
"""
|
|
160
|
+
# Get base prompt text (if any)
|
|
161
|
+
text = prompt.text if prompt is not None and prompt.text else ""
|
|
162
|
+
|
|
163
|
+
# Create temporary msg
|
|
164
|
+
def inline() -> Activity:
|
|
165
|
+
return ChoiceFactory.inline(choices, text, None, options)
|
|
166
|
+
|
|
167
|
+
def list_style() -> Activity:
|
|
168
|
+
return ChoiceFactory.list_style(choices, text, None, options)
|
|
169
|
+
|
|
170
|
+
def suggested_action() -> Activity:
|
|
171
|
+
return ChoiceFactory.suggested_action(choices, text)
|
|
172
|
+
|
|
173
|
+
def hero_card() -> Activity:
|
|
174
|
+
return ChoiceFactory.hero_card(choices, text)
|
|
175
|
+
|
|
176
|
+
def list_style_none() -> Activity:
|
|
177
|
+
from microsoft_agents.activity import (
|
|
178
|
+
Activity as _Activity,
|
|
179
|
+
ActivityTypes as _AT,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
activity = _Activity(type=_AT.message) # type: ignore[call-arg]
|
|
183
|
+
activity.text = text
|
|
184
|
+
return activity
|
|
185
|
+
|
|
186
|
+
def default() -> Activity:
|
|
187
|
+
return ChoiceFactory.for_channel(channel_id, choices, text, None, options)
|
|
188
|
+
|
|
189
|
+
# Maps to values in ListStyle Enum
|
|
190
|
+
switcher = {
|
|
191
|
+
0: list_style_none,
|
|
192
|
+
1: default,
|
|
193
|
+
2: inline,
|
|
194
|
+
3: list_style,
|
|
195
|
+
4: suggested_action,
|
|
196
|
+
5: hero_card,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
msg = switcher.get(int(style), default)()
|
|
200
|
+
|
|
201
|
+
# Update prompt with text, actions and attachments
|
|
202
|
+
if prompt:
|
|
203
|
+
# clone the prompt set in the options
|
|
204
|
+
prompt = copy.copy(prompt)
|
|
205
|
+
|
|
206
|
+
prompt.text = msg.text
|
|
207
|
+
|
|
208
|
+
if (
|
|
209
|
+
msg.suggested_actions is not None
|
|
210
|
+
and msg.suggested_actions.actions is not None
|
|
211
|
+
and msg.suggested_actions.actions
|
|
212
|
+
):
|
|
213
|
+
prompt.suggested_actions = msg.suggested_actions
|
|
214
|
+
|
|
215
|
+
if msg.attachments:
|
|
216
|
+
if prompt.attachments:
|
|
217
|
+
prompt.attachments.extend(msg.attachments)
|
|
218
|
+
else:
|
|
219
|
+
prompt.attachments = msg.attachments
|
|
220
|
+
|
|
221
|
+
return prompt
|
|
222
|
+
|
|
223
|
+
msg.input_hint = None # type: ignore[assignment]
|
|
224
|
+
return msg
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
from recognizers_text import Culture
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PromptCultureModel:
|
|
8
|
+
"""
|
|
9
|
+
Culture model used in Choice and Confirm Prompts.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
locale: str,
|
|
15
|
+
separator: str,
|
|
16
|
+
inline_or: str,
|
|
17
|
+
inline_or_more: str,
|
|
18
|
+
yes_in_language: str,
|
|
19
|
+
no_in_language: str,
|
|
20
|
+
):
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
:param locale: Culture Model's Locale. Example: "en-US".
|
|
24
|
+
:param separator: Culture Model's Inline Separator. Example: ", ".
|
|
25
|
+
:param inline_or: Culture Model's Inline Or. Example: " or ".
|
|
26
|
+
:param inline_or_more Culture Model's Inline Or More. Example: ", or ".
|
|
27
|
+
:param yes_in_language: Equivalent of "Yes" in Culture Model's Language. Example: "Yes".
|
|
28
|
+
:param no_in_language: Equivalent of "No" in Culture Model's Language. Example: "No".
|
|
29
|
+
"""
|
|
30
|
+
self.locale = locale
|
|
31
|
+
self.separator = separator
|
|
32
|
+
self.inline_or = inline_or
|
|
33
|
+
self.inline_or_more = inline_or_more
|
|
34
|
+
self.yes_in_language = yes_in_language
|
|
35
|
+
self.no_in_language = no_in_language
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class PromptCultureModels:
|
|
39
|
+
"""
|
|
40
|
+
Class container for currently-supported Culture Models in Confirm and Choice Prompt.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
Bulgarian = PromptCultureModel(
|
|
44
|
+
# TODO: Replace with Culture.Bulgarian after Recognizers-Text package updates.
|
|
45
|
+
locale="bg-bg",
|
|
46
|
+
inline_or=" или ",
|
|
47
|
+
inline_or_more=", или ",
|
|
48
|
+
separator=", ",
|
|
49
|
+
no_in_language="Не",
|
|
50
|
+
yes_in_language="да",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
Chinese = PromptCultureModel(
|
|
54
|
+
locale=Culture.Chinese,
|
|
55
|
+
inline_or=" 要么 ",
|
|
56
|
+
inline_or_more=", 要么 ",
|
|
57
|
+
separator=", ",
|
|
58
|
+
no_in_language="不",
|
|
59
|
+
yes_in_language="是的",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
Dutch = PromptCultureModel(
|
|
63
|
+
locale=Culture.Dutch,
|
|
64
|
+
inline_or=" of ",
|
|
65
|
+
inline_or_more=", of ",
|
|
66
|
+
separator=", ",
|
|
67
|
+
no_in_language="Nee",
|
|
68
|
+
yes_in_language="Ja",
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
English = PromptCultureModel(
|
|
72
|
+
locale=Culture.English,
|
|
73
|
+
inline_or=" or ",
|
|
74
|
+
inline_or_more=", or ",
|
|
75
|
+
separator=", ",
|
|
76
|
+
no_in_language="No",
|
|
77
|
+
yes_in_language="Yes",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
Hindi = PromptCultureModel(
|
|
81
|
+
# TODO: Replace with Culture.Hindi after Recognizers-Text package updates.
|
|
82
|
+
locale="hi-in",
|
|
83
|
+
inline_or=" या ",
|
|
84
|
+
inline_or_more=", या ",
|
|
85
|
+
separator=", ",
|
|
86
|
+
no_in_language="नहीं",
|
|
87
|
+
yes_in_language="हां",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
French = PromptCultureModel(
|
|
91
|
+
locale=Culture.French,
|
|
92
|
+
inline_or=" ou ",
|
|
93
|
+
inline_or_more=", ou ",
|
|
94
|
+
separator=", ",
|
|
95
|
+
no_in_language="Non",
|
|
96
|
+
yes_in_language="Oui",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
German = PromptCultureModel(
|
|
100
|
+
# TODO: Replace with Culture.German after Recognizers-Text package updates.
|
|
101
|
+
locale="de-de",
|
|
102
|
+
inline_or=" oder ",
|
|
103
|
+
inline_or_more=", oder ",
|
|
104
|
+
separator=", ",
|
|
105
|
+
no_in_language="Nein",
|
|
106
|
+
yes_in_language="Ja",
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
Italian = PromptCultureModel(
|
|
110
|
+
locale=Culture.Italian,
|
|
111
|
+
inline_or=" o ",
|
|
112
|
+
inline_or_more=" o ",
|
|
113
|
+
separator=", ",
|
|
114
|
+
no_in_language="No",
|
|
115
|
+
yes_in_language="Si",
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
Japanese = PromptCultureModel(
|
|
119
|
+
locale=Culture.Japanese,
|
|
120
|
+
inline_or=" または ",
|
|
121
|
+
inline_or_more="、 または ",
|
|
122
|
+
separator="、 ",
|
|
123
|
+
no_in_language="いいえ",
|
|
124
|
+
yes_in_language="はい",
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
Korean = PromptCultureModel(
|
|
128
|
+
locale=Culture.Korean,
|
|
129
|
+
inline_or=" 또는 ",
|
|
130
|
+
inline_or_more=" 또는 ",
|
|
131
|
+
separator=", ",
|
|
132
|
+
no_in_language="아니",
|
|
133
|
+
yes_in_language="예",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
Portuguese = PromptCultureModel(
|
|
137
|
+
locale=Culture.Portuguese,
|
|
138
|
+
inline_or=" ou ",
|
|
139
|
+
inline_or_more=", ou ",
|
|
140
|
+
separator=", ",
|
|
141
|
+
no_in_language="Não",
|
|
142
|
+
yes_in_language="Sim",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
Spanish = PromptCultureModel(
|
|
146
|
+
locale=Culture.Spanish,
|
|
147
|
+
inline_or=" o ",
|
|
148
|
+
inline_or_more=", o ",
|
|
149
|
+
separator=", ",
|
|
150
|
+
no_in_language="No",
|
|
151
|
+
yes_in_language="Sí",
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
Swedish = PromptCultureModel(
|
|
155
|
+
# TODO: Replace with Culture.Swedish after Recognizers-Text package updates.
|
|
156
|
+
locale="sv-se",
|
|
157
|
+
inline_or=" eller ",
|
|
158
|
+
inline_or_more=" eller ",
|
|
159
|
+
separator=", ",
|
|
160
|
+
no_in_language="Nej",
|
|
161
|
+
yes_in_language="Ja",
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
Turkish = PromptCultureModel(
|
|
165
|
+
locale=Culture.Turkish,
|
|
166
|
+
inline_or=" veya ",
|
|
167
|
+
inline_or_more=" veya ",
|
|
168
|
+
separator=", ",
|
|
169
|
+
no_in_language="Hayır",
|
|
170
|
+
yes_in_language="Evet",
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
@classmethod
|
|
174
|
+
def map_to_nearest_language(cls, culture_code: str) -> str:
|
|
175
|
+
"""
|
|
176
|
+
Normalize various potential locale strings to a standard.
|
|
177
|
+
:param culture_code: Represents locale. Examples: "en-US, en-us, EN".
|
|
178
|
+
:return: Normalized locale.
|
|
179
|
+
:rtype: str
|
|
180
|
+
|
|
181
|
+
.. remarks::
|
|
182
|
+
In our other SDKs, this method is a copy/paste of the ones from the Recognizers-Text library.
|
|
183
|
+
However, that doesn't exist in Python.
|
|
184
|
+
"""
|
|
185
|
+
if culture_code:
|
|
186
|
+
culture_code = culture_code.lower()
|
|
187
|
+
supported_culture_codes = cls._get_supported_locales()
|
|
188
|
+
|
|
189
|
+
if culture_code not in supported_culture_codes:
|
|
190
|
+
culture_prefix = culture_code.split("-")[0]
|
|
191
|
+
|
|
192
|
+
for supported_culture_code in supported_culture_codes:
|
|
193
|
+
if supported_culture_code.startswith(culture_prefix):
|
|
194
|
+
culture_code = supported_culture_code
|
|
195
|
+
|
|
196
|
+
return culture_code
|
|
197
|
+
|
|
198
|
+
@classmethod
|
|
199
|
+
def get_supported_cultures(cls) -> list[PromptCultureModel]:
|
|
200
|
+
"""
|
|
201
|
+
Gets a list of the supported culture models.
|
|
202
|
+
"""
|
|
203
|
+
return [
|
|
204
|
+
cls.Bulgarian,
|
|
205
|
+
cls.Chinese,
|
|
206
|
+
cls.Dutch,
|
|
207
|
+
cls.English,
|
|
208
|
+
cls.French,
|
|
209
|
+
cls.German,
|
|
210
|
+
cls.Hindi,
|
|
211
|
+
cls.Italian,
|
|
212
|
+
cls.Japanese,
|
|
213
|
+
cls.Korean,
|
|
214
|
+
cls.Portuguese,
|
|
215
|
+
cls.Spanish,
|
|
216
|
+
cls.Swedish,
|
|
217
|
+
cls.Turkish,
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
@classmethod
|
|
221
|
+
def _get_supported_locales(cls) -> list[str]:
|
|
222
|
+
return [c.locale for c in cls.get_supported_cultures()]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
from microsoft_agents.activity import Activity
|
|
5
|
+
from microsoft_agents.hosting.dialogs.choices import Choice, ListStyle
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PromptOptions:
|
|
9
|
+
"""
|
|
10
|
+
Contains settings to pass to a :class:`Prompt` object when the prompt is started.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
prompt: Activity | None = None,
|
|
16
|
+
retry_prompt: Activity | None = None,
|
|
17
|
+
choices: list[Choice] | None = None,
|
|
18
|
+
style: ListStyle | None = None,
|
|
19
|
+
validations: object = None,
|
|
20
|
+
number_of_attempts: int = 0,
|
|
21
|
+
):
|
|
22
|
+
"""
|
|
23
|
+
Contains settings to pass to a :class:`Prompt` when the prompt is started.
|
|
24
|
+
|
|
25
|
+
:param prompt: The initial prompt activity to send to the user.
|
|
26
|
+
:type prompt: :class:`microsoft_agents.activity.Activity`
|
|
27
|
+
:param retry_prompt: The activity to send when the user's input fails validation.
|
|
28
|
+
:type retry_prompt: :class:`microsoft_agents.activity.Activity`
|
|
29
|
+
:param choices: The list of choices presented to the user (used by :class:`ChoicePrompt`).
|
|
30
|
+
:type choices: list[:class:`microsoft_agents.hosting.dialogs.choices.Choice`]
|
|
31
|
+
:param style: Controls how the choice list is rendered.
|
|
32
|
+
:type style: :class:`microsoft_agents.hosting.dialogs.choices.ListStyle`
|
|
33
|
+
:param validations: Additional validation data passed through to a custom validator.
|
|
34
|
+
:param number_of_attempts: Running count of how many times the prompt has been retried.
|
|
35
|
+
:type number_of_attempts: int
|
|
36
|
+
"""
|
|
37
|
+
self.prompt = prompt
|
|
38
|
+
self.retry_prompt = retry_prompt
|
|
39
|
+
self.choices = choices
|
|
40
|
+
self.style = style
|
|
41
|
+
self.validations = validations
|
|
42
|
+
self.number_of_attempts = number_of_attempts
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
"""Result returned by a prompts recognizer function."""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PromptRecognizerResult:
|
|
8
|
+
def __init__(self, succeeded: bool = False, value: object = None):
|
|
9
|
+
"""Creates result returned by a prompts recognizer function."""
|
|
10
|
+
self.succeeded = succeeded
|
|
11
|
+
self.value = value
|
|
File without changes
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
from typing import Dict, cast
|
|
4
|
+
from microsoft_agents.hosting.core import TurnContext
|
|
5
|
+
from .prompt_options import PromptOptions
|
|
6
|
+
from .prompt_recognizer_result import PromptRecognizerResult
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PromptValidatorContext:
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
turn_context: TurnContext,
|
|
13
|
+
recognized: PromptRecognizerResult,
|
|
14
|
+
state: Dict[str, object],
|
|
15
|
+
options: PromptOptions,
|
|
16
|
+
):
|
|
17
|
+
"""Creates contextual information passed to a custom `PromptValidator`.
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
turn_context
|
|
21
|
+
The context for the current turn of conversation with the user.
|
|
22
|
+
recognized
|
|
23
|
+
Result returned from the prompts recognizer function.
|
|
24
|
+
state
|
|
25
|
+
A dictionary of values persisted for each conversational turn while the prompt is active.
|
|
26
|
+
options
|
|
27
|
+
Original set of options passed to the prompt by the calling dialog.
|
|
28
|
+
"""
|
|
29
|
+
self.context = turn_context
|
|
30
|
+
self.recognized = recognized
|
|
31
|
+
self.state = state
|
|
32
|
+
self.options = options
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def attempt_count(self) -> int:
|
|
36
|
+
"""Gets the number of times the validator has been called for this prompt.
|
|
37
|
+
|
|
38
|
+
The counter starts at 1 on the first validation call and increments with
|
|
39
|
+
each subsequent user reply.
|
|
40
|
+
"""
|
|
41
|
+
# pylint: disable=import-outside-toplevel
|
|
42
|
+
from microsoft_agents.hosting.dialogs.prompts.prompt import Prompt
|
|
43
|
+
|
|
44
|
+
return int(cast(int, self.state.get(Prompt.ATTEMPT_COUNT_KEY, 0)))
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
from microsoft_agents.hosting.core import TurnContext
|
|
5
|
+
from microsoft_agents.activity import ActivityTypes
|
|
6
|
+
|
|
7
|
+
from .prompt import Prompt
|
|
8
|
+
from .prompt_options import PromptOptions
|
|
9
|
+
from .prompt_recognizer_result import PromptRecognizerResult
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TextPrompt(Prompt):
|
|
13
|
+
"""Prompts a user to enter any text.
|
|
14
|
+
|
|
15
|
+
Succeeds whenever the user sends a message activity whose ``text`` field is
|
|
16
|
+
not ``None``. Empty strings are accepted as valid because some channels
|
|
17
|
+
send an empty ``text`` alongside attachments. There is no built-in
|
|
18
|
+
recognizer: the raw ``activity.text`` string is returned as the result.
|
|
19
|
+
|
|
20
|
+
Pass an optional ``validator`` at construction time to apply additional
|
|
21
|
+
constraints (e.g. minimum length, allow-list, non-empty enforcement).
|
|
22
|
+
|
|
23
|
+
.. note::
|
|
24
|
+
Non-message activities and messages where ``activity.text`` is ``None``
|
|
25
|
+
cause recognition to fail and will trigger the retry prompt if one was
|
|
26
|
+
provided.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
async def on_prompt(
|
|
30
|
+
self,
|
|
31
|
+
turn_context: TurnContext,
|
|
32
|
+
state: dict[str, object],
|
|
33
|
+
options: PromptOptions,
|
|
34
|
+
is_retry: bool,
|
|
35
|
+
):
|
|
36
|
+
"""Sends the initial or retry prompt activity to the user.
|
|
37
|
+
|
|
38
|
+
:param turn_context: The context for the current turn.
|
|
39
|
+
:param state: Persisted prompt state (unused by TextPrompt).
|
|
40
|
+
:param options: Prompt options containing the prompt and optional retry prompt.
|
|
41
|
+
:param is_retry: ``True`` when re-prompting after a failed validation.
|
|
42
|
+
"""
|
|
43
|
+
if not turn_context:
|
|
44
|
+
raise TypeError("TextPrompt.on_prompt(): turn_context cannot be None.")
|
|
45
|
+
if not options:
|
|
46
|
+
raise TypeError("TextPrompt.on_prompt(): options cannot be None.")
|
|
47
|
+
|
|
48
|
+
if is_retry and options.retry_prompt is not None:
|
|
49
|
+
await turn_context.send_activity(options.retry_prompt)
|
|
50
|
+
else:
|
|
51
|
+
if options.prompt is not None:
|
|
52
|
+
await turn_context.send_activity(options.prompt)
|
|
53
|
+
|
|
54
|
+
async def on_recognize(
|
|
55
|
+
self,
|
|
56
|
+
turn_context: TurnContext,
|
|
57
|
+
state: dict[str, object],
|
|
58
|
+
options: PromptOptions,
|
|
59
|
+
) -> PromptRecognizerResult:
|
|
60
|
+
"""Attempts to recognise text from the incoming activity.
|
|
61
|
+
|
|
62
|
+
Succeeds only when the activity is a message **and** ``activity.text``
|
|
63
|
+
is not ``None``. Empty strings are considered valid (``succeeded=True``
|
|
64
|
+
with an empty string value), since some channels send empty text with
|
|
65
|
+
attachments.
|
|
66
|
+
|
|
67
|
+
:param turn_context: The context for the current turn.
|
|
68
|
+
:param state: Persisted prompt state (unused by TextPrompt).
|
|
69
|
+
:param options: Prompt options (unused by TextPrompt).
|
|
70
|
+
:return: Recognition result with ``succeeded=True`` and the raw text when
|
|
71
|
+
a message with text is received; ``succeeded=False`` otherwise.
|
|
72
|
+
"""
|
|
73
|
+
if not turn_context:
|
|
74
|
+
raise TypeError("TextPrompt.on_recognize(): turn_context cannot be None.")
|
|
75
|
+
|
|
76
|
+
result = PromptRecognizerResult()
|
|
77
|
+
if turn_context.activity.type == ActivityTypes.message:
|
|
78
|
+
message = turn_context.activity
|
|
79
|
+
if message.text is not None:
|
|
80
|
+
result.succeeded = True
|
|
81
|
+
result.value = message.text
|
|
82
|
+
return result
|