8000 Recognizers versions updated, confirm prompt now working with tests (… · sherlock666/botbuilder-python@01afe81 · GitHub
[go: up one dir, main page]

Skip to content

Commit 01afe81

Browse files
authored
Recognizers versions updated, confirm prompt now working with tests (microsoft#276)
* recognizers versions updated, confirm prompt now working with tests * added dependency library for recognizers-text
1 parent 6cc2e00 commit 01afe81

File tree

5 files changed

+300
-16
lines changed

5 files changed

+300
-16
lines changed

libraries/botbuilder-dialogs/botbuilder/dialogs/choices/choice_factory.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ def inline(
9999
inline_separator=options.inline_separator or ", ",
100100
inline_or=options.inline_or or " or ",
101101
inline_or_more=options.inline_or_more or ", or ",
102-
include_numbers=options.include_numbers or True,
102+
include_numbers=(
103+
options.include_numbers if options.include_numbers is not None else True
104+
),
103105
)
104106

105107
# Format list of choices

libraries/botbuilder-dialogs/botbuilder/dialogs/prompts/confirm_prompt.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22
# Licensed under the MIT License.
33

44
from typing import Dict
5+
from recognizers_choice import recognize_boolean
56
from botbuilder.core.turn_context import TurnContext
67
from botbuilder.schema import ActivityTypes, Activity
7-
from botbuilder.dialogs.choices import Choice, ChoiceFactoryOptions, ListStyle
8+
from botbuilder.dialogs.choices import (
9+
Choice,
10+
ChoiceFactoryOptions,
11+
ChoiceRecognizers,
12+
ListStyle,
13+
)
814
from .prompt import Prompt
915
from .prompt_options import PromptOptions
1016
from .prompt_recognizer_result import PromptRecognizerResult
@@ -93,7 +99,7 @@ async def on_prompt(
9399
if self.confirm_choices is not None
94100
else (defaults[0], defaults[1])
95101
)
96-
choices = {confirms[0], confirms[1]}
102+
choices = [confirms[0], confirms[1]]
97103
if is_retry and options.retry_prompt is not None:
98104
prompt = self.append_choices(
99105
options.retry_prompt, channel_id, choices, self.style, choice_opts
@@ -110,7 +116,6 @@ async def on_recognize(
110116
state: Dict[str, object],
111117
options: PromptOptions,
112118
) -> PromptRecognizerResult:
113-
# pylint: disable=undefined-variable
114119
if not turn_context:
115120
raise TypeError("ConfirmPrompt.on_prompt(): turn_context cannot be None.")
116121

@@ -119,13 +124,12 @@ async def on_recognize(
119124
# Recognize utterance
120125
message = turn_context.activity
121126
culture = self.determine_culture(turn_context.activity)
122-
# TODO: Port ChoiceRecognizer
123-
results = ChoiceRecognizer.recognize_boolean(message.text, culture)
124-
if results.Count > 0:
127+
results = recognize_boolean(message.text, culture)
128+
if results:
125129
first = results[0]
126-
if "value" in first.Resolution:
130+
if "value" in first.resolution:
127131
result.succeeded = True
128-
result.value = str(first.Resolution["value"])
132+
result.value = first.resolution["value"]
129133
else:
130134
# First check whether the prompt was sent to the user with numbers
131135
# if it was we should recognize numbers
@@ -138,15 +142,14 @@ async def on_recognize(
138142

139143
# This logic reflects the fact that IncludeNumbers is nullable and True is the default set in
140144
# Inline style
141-
if opts.include_numbers.has_value or opts.include_numbers.value:
145+
if opts.include_numbers is None or opts.include_numbers:
142146
# The text may be a number in which case we will interpret that as a choice.
143147
confirm_choices = (
144148
self.confirm_choices
145149
if self.confirm_choices is not None
146150
else (defaults[0], defaults[1])
147151
)
148152
choices = {confirm_choices[0], confirm_choices[1]}
149-
# TODO: Port ChoiceRecognizer
150153
second_attempt_results = ChoiceRecognizers.recognize_choices(
151154
message.text, choices
152155
)

libraries/botbuilder-dialogs/botbuilder/dialogs/prompts/prompt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ def default() -> Activity:
204204
msg = switcher.get(int(style.value), default)()
205205

206206
# Update prompt with text, actions and attachments
207-
if not prompt:
207+
if prompt:
208208
# clone the prompt the set in the options (note ActivityEx has Properties so this is the safest mechanism)
209209
prompt = copy.copy(prompt)
210210

libraries/botbuilder-dialogs/setup.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
from setuptools import setup
66

77
REQUIRES = [
8-
"recognizers-date-time>=1.0.0a1",
9-
"recognizers-number-with-unit>=1.0.0a1",
10-
"recognizers-number>=1.0.0a2",
11-
"recognizers-text>=1.0.0a1",
8+
"recognizers-text-date-time>=1.0.1a0",
9+
"recognizers-text-number-with-unit>=1.0.1a0",
10+
"recognizers-text-number>=1.0.1a0",
11+
"recognizers-text>=1.0.1a0",
12+
"recognizers-text-choice>=1.0.1a0",
13+
"grapheme>=0.5.0",
14+
"emoji>=0.5.2",
1215
"botbuilder-schema>=4.4.0b1",
1316
"botframework-connector>=4.4.0b1",
1417
"botbuilder-core>=4.4.0b1",
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import aiounittest
5+
from botbuilder.core import (
6+
ConversationState,
7+
MemoryStorage,
8+
TurnContext,
9+
MessageFactory,
10+
)
11+
from botbuilder.core.adapters import TestAdapter
12+
from botbuilder.dialogs import DialogSet, DialogTurnResult, DialogTurnStatus
13+
from botbuilder.dialogs.choices import ChoiceFactoryOptions, ListStyle
14+
from botbuilder.dialogs.prompts import ConfirmPrompt
15+
from botbuilder.dialogs.prompts import PromptOptions
16+
from botbuilder.schema import Activity, ActivityTypes
17+
18+
19+
class ConfirmPromptTest(aiounittest.AsyncTestCase):
20+
def test_confirm_prompt_with_empty_id_should_fail(self):
21+
empty_id = ""
22+
23+
with self.assertRaises(TypeError):
24+
ConfirmPrompt(empty_id)
25+
26+
def test_confirm_prompt_with_none_id_should_fail(self):
27+
none_id = None
28+
29+
with self.assertRaises(TypeError):
30+
ConfirmPrompt(none_id)
31+
32+
async def test_confirm_prompt(self):
33+
async def exec_test(turn_context: TurnContext):
34+
dialog_context = await dialogs.create_context(turn_context)
35+
36+
results: DialogTurnResult = await dialog_context.continue_dialog()
37+
38+
if results.status == DialogTurnStatus.Empty:
39+
options = PromptOptions(
40+
prompt=Activity(type=ActivityTypes.message, text="Please confirm.")
41+
)
42+
await dialog_context.prompt("ConfirmPrompt", options)
43+
elif results.status == DialogTurnStatus.Complete:
44+
message_text = "Confirmed" if results.result else "Not confirmed"
45+
await turn_context.send_activity(MessageFactory.text(message_text))
46+
47+
await convo_state.save_changes(turn_context)
48+
49+
# Initialize TestAdapter.
50+
adapter = TestAdapter(exec_test)
51+
52+
# Create new ConversationState with MemoryStorage and register the state as middleware.
53+
convo_state = ConversationState(MemoryStorage())
54+
55+
# Create a DialogState property, DialogSet, and ChoicePrompt.
56+
dialog_state = convo_state.create_property("dialogState")
57+
dialogs = DialogSet(dialog_state)
58+
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
59+
dialogs.add(confirm_prompt)
60+
61+
step1 = await adapter.send("hello")
62+
step2 = await step1.assert_reply("Please confirm. (1) Yes or (2) No")
63+
step3 = await step2.send("yes")
64+
await step3.assert_reply("Confirmed")
65+
66+
async def test_confirm_prompt_retry(self):
67+
async def exec_test(turn_context: TurnContext):
68+
dialog_context = await dialogs.create_context(turn_context)
69+
70+
results: DialogTurnResult = await dialog_context.continue_dialog()
71+
72+
if results.status == DialogTurnStatus.Empty:
73+
options = PromptOptions(
74+
prompt=Activity(type=ActivityTypes.message, text="Please confirm."),
75+
retry_prompt=Activity(
76+
type=ActivityTypes.message,
77+
text="Please confirm, say 'yes' or 'no' or something like that.",
78+
),
79+
)
80+
await dialog_context.prompt("ConfirmPrompt", options)
81+
elif results.status == DialogTurnStatus.Complete:
82+
message_text = "Confirmed" if results.result else "Not confirmed"
83+
await turn_context.send_activity(MessageFactory.text(message_text))
84+
85+
await convo_state.save_changes(turn_context)
86+
87+
# Initialize TestAdapter.
88+
adapter = TestAdapter(exec_test)
89+
90+
# Create new ConversationState with MemoryStorage and register the state as middleware.
91+
convo_state = ConversationState(MemoryStorage())
92+
93+
# Create a DialogState property, DialogSet, and ChoicePrompt.
94+
dialog_state = convo_state.create_property("dialogState")
95+
dialogs = DialogSet(dialog_state)
96+
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
97+
dialogs.add(confirm_prompt)
98+
99+
step1 = await adapter.send("hello")
100+
step2 = await step1.assert_reply("Please confirm. (1) Yes or (2) No")
101+
step3 = await step2.send("lala")
102+
step4 = await step3.assert_reply(
103+
"Please confirm, say 'yes' or 'no' or something like that. (1) Yes or (2) No"
104+
)
105+
step5 = await step4.send("no")
106+
await step5.assert_reply("Not confirmed")
107+
108+
async def test_confirm_prompt_no_options(self):
109+
async def exec_test(turn_context: TurnContext):
110+
dialog_context = await dialogs.create_context(turn_context)
111+
112+
results: DialogTurnResult = await dialog_context.continue_dialog()
113+
114+
if results.status == DialogTurnStatus.Empty:
115+
await dialog_context.prompt("ConfirmPrompt", PromptOptions())
116+
elif results.status == DialogTurnStatus.Complete:
117+
message_text = "Confirmed" if results.result else "Not confirmed"
118+
await turn_context.send_activity(MessageFactory.text(message_text))
119+
120+
await convo_state.save_changes(turn_context)
121+
122+
# Initialize TestAdapter.
123+
adapter = TestAdapter(exec_test)
124+
125+
# Create new ConversationState with MemoryStorage and register the state as middleware.
126+
convo_state = ConversationState(MemoryStorage())
127+
128+
# Create a DialogState property, DialogSet, and ChoicePrompt.
129+
dialog_state = convo_state.create_property("dialogState")
130+
dialogs = DialogSet(dialog_state)
131+
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
132+
dialogs.add(confirm_prompt)
133+
134+
step1 = await adapter.send("hello")
135+
step2 = await step1.assert_reply(" (1) Yes or (2) No")
136+
step3 = await step2.send("lala")
137+
step4 = await step3.assert_reply(" (1) Yes or (2) No")
138+
step5 = await step4.send("no")
139+
await step5.assert_reply("Not confirmed")
140+
141+
async def test_confirm_prompt_choice_options_numbers(self):
142+
async def exec_test(turn_context: TurnContext):
143+
dialog_context = await dialogs.create_context(turn_context)
144+
145+
results: DialogTurnResult = await dialog_context.continue_dialog()
146+
147+
if results.status == DialogTurnStatus.Empty:
148+
options = PromptOptions(
149+
prompt=Activity(type=ActivityTypes.message, text="Please confirm."),
150+
retry_prompt=Activity(
151+
type=ActivityTypes.message,
152+
text="Please confirm, say 'yes' or 'no' or something like that.",
153+
),
154+
)
155+
await dialog_context.prompt("ConfirmPrompt", options)
156+
elif results.status == DialogTurnStatus.Complete:
157+
message_text = "Confirmed" if results.result else "Not confirmed"
158+
await turn_context.send_activity(MessageFactory.text(message_text))
159+
160+
await convo_state.save_changes(turn_context)
161+
162+
# Initialize TestAdapter.
163+
adapter = TestAdapter(exec_test)
164+
165+
# Create new ConversationState with MemoryStorage and register the state as middleware.
166+
convo_state = ConversationState(MemoryStorage())
167+
168+
# Create a DialogState property, DialogSet, and ChoicePrompt.
169+
dialog_state = convo_state.create_property("dialogState")
170+
dialogs = DialogSet(dialog_state)
171+
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
172+
confirm_prompt.choice_options = ChoiceFactoryOptions(include_numbers=True)
173+
confirm_prompt.style = ListStyle.in_line
174+
dialogs.add(confirm_prompt)
175+
176+
step1 = await adapter.send("hello")
177+
step2 = await step1.assert_reply("Please confirm. (1) Yes or (2) No")
178+
step3 = await step2.send("lala")
179+
step4 = await step3.assert_reply(
180+
"Please confirm, say 'yes' or 'no' or something like that. (1) Yes or (2) No"
181+
)
182+
step5 = await step4.send("2")
183+
await step5.assert_reply("Not confirmed")
184+
185+
async def test_confirm_prompt_choice_options_multiple_attempts(self):
186+
async def exec_test(turn_context: TurnContext):
187+
dialog_context = await dialogs.create_context(turn_context)
188+
189+
results: DialogTurnResult = await dialog_context.continue_dialog()
190+
191+
if results.status == DialogTurnStatus.Empty:
192+
options = PromptOptions(
193+
prompt=Activity(type=ActivityTypes.message, text="Please confirm."),
194+
retry_prompt=Activity(
195+
type=ActivityTypes.message,
196+
text="Please confirm, say 'yes' or 'no' or something like that.",
197+
),
198+
)
199+
await dialog_context.prompt("ConfirmPrompt", options)
200+
elif results.status == DialogTurnStatus.Complete:
201+
message_text = "Confirmed" if results.result else "Not confirmed"
202+
await turn_context.send_activity(MessageFactory.text(message_text))
203+
204+
await convo_state.save_changes(turn_context)
205+
206+
# Initialize TestAdapter.
207+
adapter = TestAdapter(exec_test)
208+
209+
# Create new ConversationState with MemoryStorage and register the state as middleware.
210+
convo_state = ConversationState(MemoryStorage())
211+
212+
# Create a DialogState property, DialogSet, and ChoicePrompt.
213+
dialog_state = convo_state.create_property("dialogState")
214+
dialogs = DialogSet(dialog_state)
215+
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
216+
confirm_prompt.choice_options = ChoiceFactoryOptions(include_numbers=True)
217+
confirm_prompt.style = ListStyle.in_line
218+
dialogs.add(confirm_prompt)
219+
220+
step1 = await adapter.send("hello")
221+
step2 = await step1.assert_reply("Please confirm. (1) Yes or (2) No")
222+
step3 = await step2.send("lala")
223+
step4 = await step3.assert_reply(
224+
"Please confirm, say 'yes' or 'no' or something like that. (1) Yes or (2) No"
225+
)
226+
step5 = await step4.send("what")
227+
step6 = await step5.assert_reply(
228+
"Please confirm, say 'yes' or 'no' or something like that. (1) Yes or (2) No"
229+
)
230+
step7 = await step6.send("2")
231+
await step7.assert_reply("Not confirmed")
232+
233+
async def test_confirm_prompt_options_no_numbers(self):
234+
async def exec_test(turn_context: TurnContext):
235+
dialog_context = await dialogs.create_context(turn_context)
236+
237+
results: DialogTurnResult = await dialog_context.continue_dialog()
238+
239+
if results.status == DialogTurnStatus.Empty:
240+
options = PromptOptions(
241+
prompt=Activity(type=ActivityTypes.message, text="Please confirm."),
242+
retry_prompt=Activity(
243+
type=ActivityTypes.message,
244+
text="Please confirm, say 'yes' or 'no' or something like that.",
245+
),
246+
)
247+
await dialog_context.prompt("ConfirmPrompt", options)
248+
elif results.status == DialogTurnStatus.Complete:
249+
message_text = "Confirmed" if results.result else "Not confirmed"
250+
await turn_context.send_activity(MessageFactory.text(message_text))
251+
252+
await convo_state.save_changes(turn_context)
253+
254+
# Initialize TestAdapter.
255+
adapter = TestAdapter(exec_test)
256+
257+
# Create new ConversationState with MemoryStorage and register the state as middleware.
258+
convo_state = ConversationState(MemoryStorage())
259+
260+
# Create a DialogState property, DialogSet, and ChoicePrompt.
261+
dialog_state = convo_state.create_property("dialogState")
262+
dialogs = DialogSet(dialog_state)
263+
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
264+
confirm_prompt.choice_options = ChoiceFactoryOptions(
265+
include_numbers=False, inline_separator="~"
266+
)
267+
dialogs.add(confirm_prompt)
268+
269+
step1 = await adapter.send("hello")
270+
step2 = await step1.assert_reply("Please confirm. Yes or No")
271+
step3 = await step2.send("2")
272+
step4 = await step3.assert_reply(
273+
"Please confirm, say 'yes' or 'no' or something like that. Yes or No"
274+
)
275+
step5 = await step4.send("no")
276+
await step5.assert_reply("Not confirmed")

0 commit comments

Comments
 (0)
0