-
Notifications
You must be signed in to change notification settings - Fork 298
Only show "NO MATCH" response button if active learning is active #1579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+282
−7
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
f0d7011
Removed 'no match text' button from get_qna_prompts_card + begin tests
Zerryth 35c6fca
Finished multiturn prompt test
Zerryth 68e4aaa
Refactor multiturn; started active learning test
Zerryth 7de8828
Finished active learning test
Zerryth 12dae86
linted files
Zerryth 6a2ec48
Run black again
Zerryth File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
libraries/botbuilder-ai/tests/qna/test_data/QnAMakerDialog_ActiveLearning.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
{ | ||
"answers": [ | ||
{ | ||
"questions": [ | ||
"Esper seeks" | ||
], | ||
"answer": "Esper seeks. She's a curious little explorer. Young toddlers seek out new adventures, expanding their knowledge base. It's their job to test limits, to learn about them. It's the adult's job to enforce the limits, while also allowing room for exploration", | ||
"score": 79.65, | ||
"id": 35, | ||
"source": "Editorial", | ||
"isDocumentText": false, | ||
"metadata": [], | ||
"context": { | ||
"isContextOnly": false, | ||
"prompts": [] | ||
} | ||
}, | ||
{ | ||
"questions": [ | ||
"Esper sups" | ||
], | ||
"answer": "Esper sups. She eats just about anything. She loves her broccoli. Anything that she sees her parents eating, she wants to part take in herself.\n\nCaution though. If she spots you eating dessert, you best be prepared to share with her. Best to wait until she goes down for bed and then sneak your favorite snack in, without her prying eyes.", | ||
"score": 79.65, | ||
"id": 36, | ||
"source": "Editorial", | ||
"isDocumentText": false, | ||
"metadata": [], | ||
"context": { | ||
"isContextOnly": false, | ||
"prompts": [] | ||
} | ||
}, | ||
{ | ||
"questions": [ | ||
"Esper screams" | ||
], | ||
"answer": "Esper screams. The currently 1-year old toddler has a brain that's rapidly developing, expanding to new abilities at an alarming rate. With it may come fright or possibly frustration as they understand what could be done, however they need to master how to do a task themselves", | ||
"score": 66.89, | ||
"id": 34, | ||
"source": "Editorial", | ||
"isDocumentText": false, | ||
"metadata": [], | ||
"context": { | ||
"isContextOnly": false, | ||
"prompts": [] | ||
} | ||
}, | ||
{ | ||
"questions": [ | ||
"Esper sleeps" | ||
], | ||
"answer": "Esper sleeps. Esper sleeps on her floor bed. She never had a crib, as her parents placed her directly on the floor bed since birth. With this comes the benefit of not having to have an awkward transition period from crib to bed, when she gets old enough.\n\nThe idea of using the bed is that it offers the child more freedom to move about--more autonomy. Downside is, they will definitely wander off the bed, when they don't want to sleep", | ||
"score": 65.71, | ||
"id": 33, | ||
"source": "Editorial", | ||
"isDocumentText": false, | ||
"metadata": [], | ||
"context": { | ||
"isContextOnly": false, | ||
"prompts": [] | ||
} | ||
} | ||
], | ||
"activeLearningEnabled": true | ||
} |
32 changes: 32 additions & 0 deletions
32
libraries/botbuilder-ai/tests/qna/test_data/QnAMakerDialog_MultiTurn_Answer1.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"answers": [ | ||
{ | ||
"questions": [ | ||
"Tell me about birds", | ||
"What do you know about birds" | ||
], | ||
"answer": "Choose one of the following birds to get more info", | ||
"score": 100.0, | ||
"id": 37, | ||
"source": "Editorial", | ||
"isDocumentText": false, | ||
"metadata": [], | ||
"context": { | ||
"isContextOnly": false, | ||
"prompts": [ | ||
{ | ||
"displayOrder": 1, | ||
"qnaId": 38, | ||
"displayText": "Bald Eagle" | ||
}, | ||
{ | ||
"displayOrder": 2, | ||
"qnaId": 39, | ||
"displayText": "Hummingbird" | ||
} | ||
] | ||
} | ||
} | ||
], | ||
"activeLearningEnabled": true | ||
} |
20 changes: 20 additions & 0 deletions
20
libraries/botbuilder-ai/tests/qna/test_data/QnAMakerDialog_MultiTurn_Answer2.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"answers": [ | ||
{ | ||
"questions": [ | ||
"Bald Eagle" | ||
], | ||
"answer": "Apparently these guys aren't actually bald!", | ||
"score": 100.0, | ||
"id": 38, | ||
"source": "Editorial", | ||
"isDocumentText": false, | ||
"metadata": [], | ||
"context": { | ||
"isContextOnly": true, | ||
"prompts": [] | ||
} | ||
} | ||
], | ||
"activeLearningEnabled": true | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import json | ||
from os import path | ||
from unittest.mock import patch | ||
import aiounittest | ||
|
||
# from botbuilder.ai.qna import QnAMakerEndpoint, QnAMaker, QnAMakerOptions | ||
from botbuilder.ai.qna.dialogs import QnAMakerDialog | ||
from botbuilder.schema import Activity, ActivityTypes | ||
from botbuilder.core import ConversationState, MemoryStorage, TurnContext | ||
from botbuilder.core.adapters import TestAdapter, TestFlow | ||
from botbuilder.dialogs import DialogSet, DialogTurnStatus | ||
|
||
|
||
class QnaMakerDialogTest(aiounittest.AsyncTestCase): | ||
# Note this is NOT a real QnA Maker application ID nor a real QnA Maker subscription-key | ||
# theses are GUIDs edited to look right to the parsing and validation code. | ||
|
||
_knowledge_base_id: str = "f028d9k3-7g9z-11d3-d300-2b8x98227q8w" | ||
_endpoint_key: str = "1k997n7w-207z-36p3-j2u1-09tas20ci6011" | ||
_host: str = "https://dummyqnahost.azurewebsites.net/qnamaker" | ||
|
||
_tell_me_about_birds: str = "Tell me about birds" | ||
_choose_bird: str = "Choose one of the following birds to get more info" | ||
_bald_eagle: str = "Bald Eagle" | ||
_esper: str = "Esper" | ||
|
||
DEFAULT_ACTIVE_LEARNING_TITLE: str = "Did you mean:" | ||
DEFAULT_NO_MATCH_TEXT: str = "None of the above." | ||
DEFAULT_CARD_NO_MATCH_RESPONSE: str = "Thanks for the feedback." | ||
|
||
async def test_multiturn_dialog(self): | ||
# Set Up QnAMakerDialog | ||
convo_state = ConversationState(MemoryStorage()) | ||
dialog_state = convo_state.create_property("dialogState") | ||
dialogs = DialogSet(dialog_state) | ||
|
||
qna_dialog = QnAMakerDialog( | ||
self._knowledge_base_id, self._endpoint_key, self._host | ||
) | ||
dialogs.add(qna_dialog) | ||
|
||
# Callback that runs the dialog | ||
async def execute_qna_dialog(turn_context: TurnContext) -> None: | ||
if turn_context.activity.type != ActivityTypes.message: | ||
raise TypeError( | ||
"Failed to execute QnA dialog. Should have received a message activity." | ||
) | ||
|
||
response_json = self._get_json_res(turn_context.activity.text) | ||
dialog_context = await dialogs.create_context(turn_context) | ||
with patch( | ||
"aiohttp.ClientSession.post", | ||
return_value=aiounittest.futurized(response_json), | ||
): | ||
results = await dialog_context.continue_dialog() | ||
|
||
if results.status == DialogTurnStatus.Empty: | ||
await dialog_context.begin_dialog("QnAMakerDialog") | ||
|
||
await convo_state.save_changes(turn_context) | ||
|
||
# Send and receive messages from QnA dialog | ||
test_adapter = TestAdapter(execute_qna_dialog) | ||
test_flow = TestFlow(None, test_adapter) | ||
tf2 = await test_flow.send(self._tell_me_about_birds) | ||
dialog_reply: Activity = tf2.adapter.activity_buffer[0] | ||
self._assert_has_valid_hero_card_buttons(dialog_reply, button_count=2) | ||
tf3 = await tf2.assert_reply(self._choose_bird) | ||
tf4 = await tf3.send(self._bald_eagle) | ||
await tf4.assert_reply("Apparently these guys aren't actually bald!") | ||
|
||
async def test_active_learning(self): | ||
# Set Up QnAMakerDialog | ||
convo_state = ConversationState(MemoryStorage()) | ||
dialog_state = convo_state.create_property("dialogState") | ||
dialogs = DialogSet(dialog_state) | ||
|
||
qna_dialog = QnAMakerDialog( | ||
self._knowledge_base_id, self._endpoint_key, self._host | ||
) | ||
dialogs.add(qna_dialog) | ||
|
||
# Callback that runs the dialog | ||
async def execute_qna_dialog(turn_context: TurnContext) -> None: | ||
if turn_context.activity.type != ActivityTypes.message: | ||
raise TypeError( | ||
"Failed to execute QnA dialog. Should have received a message activity." | ||
) | ||
|
||
response_json = self._get_json_res(turn_context.activity.text) | ||
dialog_context = await dialogs.create_context(turn_context) | ||
with patch( | ||
"aiohttp.ClientSession.post", | ||
return_value=aiounittest.futurized(response_json), | ||
): | ||
results = await dialog_context.continue_dialog() | ||
|
||
if results.status == DialogTurnStatus.Empty: | ||
await dialog_context.begin_dialog("QnAMakerDialog") | ||
|
||
await convo_state.save_changes(turn_context) | ||
|
||
# Send and receive messages from QnA dialog | ||
test_adapter = TestAdapter(execute_qna_dialog) | ||
test_flow = TestFlow(None, test_adapter) | ||
tf2 = await test_flow.send(self._esper) | ||
dialog_reply: Activity = tf2.adapter.activity_buffer[0] | ||
self._assert_has_valid_hero_card_buttons(dialog_reply, button_count=3) | ||
tf3 = await tf2.assert_reply(self.DEFAULT_ACTIVE_LEARNING_TITLE) | ||
tf4 = await tf3.send(self.DEFAULT_NO_MATCH_TEXT) | ||
await tf4.assert_reply(self.DEFAULT_CARD_NO_MATCH_RESPONSE) | ||
|
||
print(tf2) | ||
|
||
def _assert_has_valid_hero_card_buttons( | ||
self, activity: Activity, button_count: int | ||
): | ||
self.assertIsInstance(activity, Activity) | ||
attachments = activity.attachments | ||
self.assertTrue(attachments) | ||
self.assertEqual(len(attachments), 1) | ||
buttons = attachments[0].content.buttons | ||
button_count_err = ( | ||
f"Should have only received {button_count} buttons in multi-turn prompt" | ||
) | ||
|
||
if activity.text == self._choose_bird: | ||
self.assertEqual(len(buttons), button_count, button_count_err) | ||
self.assertEqual(buttons[0].value, self._bald_eagle) | ||
self.assertEqual(buttons[1].value, "Hummingbird") | ||
|
||
if activity.text == self.DEFAULT_ACTIVE_LEARNING_TITLE: | ||
self.assertEqual(len(buttons), button_count, button_count_err) | ||
self.assertEqual(buttons[0].value, "Esper seeks") | ||
self.assertEqual(buttons[1].value, "Esper sups") | ||
self.assertEqual(buttons[2].value, self.DEFAULT_NO_MATCH_TEXT) | ||
|
||
def _get_json_res(self, text: str) -> object: | ||
if text == self._tell_me_about_birds: | ||
return QnaMakerDialogTest._get_json_for_file( | ||
"QnAMakerDialog_MultiTurn_Answer1.json" | ||
) | ||
|
||
if text == self._bald_eagle: | ||
return QnaMakerDialogTest._get_json_for_file( | ||
"QnAMakerDialog_MultiTurn_Answer2.json" | ||
) | ||
|
||
if text == self._esper: | ||
return QnaMakerDialogTest._get_json_for_file( | ||
"QnAMakerDialog_ActiveLearning.json" | ||
) | ||
|
||
return None | ||
|
||
@staticmethod | ||
def _get_json_for_file(response_file: str) -> object: | ||
curr_dir = path.dirname(path.abspath(__file__)) | ||
response_path = path.join(curr_dir, "test_data", response_file) | ||
|
||
with open(response_path, "r", encoding="utf-8-sig") as file: | ||
response_str = file.read() | ||
response_json = json.loads(response_str) | ||
|
||
return response_json |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get_qna_prompts_card
gets called for multi-turn qna dialog scenariosget_qna_prompts_card
get_suggestions_card
, which is what is called for active learning prompt scenarios