8000 QnA Parity: Adding Active Learning Feature (#264) · sherlock666/botbuilder-python@1f541e4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1f541e4

Browse files
authored
QnA Parity: Adding Active Learning Feature (microsoft#264)
* Initial active learning commit w/FeedbackRecord model * port FeedbackRecords & added param types to FeedbackRecord * added all qna models * begin porting HttpRequestUtils * ported GenerateAnswerUtils * used black to auto format qna library * ported TrainUtils * TrainUtil now calls Train API in call_train() * black to format all libraries * ported ActiveLearningUtils class * Ported all QnAMaker methods; reorganized folder structure according to dotnet QnA update * resolved conflicts AND SAVED CHANGES this time * merge conflicts 3 * conflicts 4 * fixed linting errors * black to format * made QnA classes serializable using msrest * changed class name to GenerateAnswerRequestBody to be consistent with TrainRequestBody * updated GenerateAnswerRequestBody's to document params correctly * added call train api test case * completed tests for low score variation * removed context; changed matched kb ans to check id; removed legacy support * removed legacy tests * removed TODO comment from qna __init__ file
1 parent 01afe81 commit 1f541e4

24 files changed

+995
-301
lines changed

libraries/botbuilder-ai/botbuilder/ai/qna/__init__.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,35 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
33

4-
from .metadata import Metadata
5-
from .query_result import QueryResult
64
from .qnamaker import QnAMaker
75
from .qnamaker_endpoint import QnAMakerEndpoint
86
from .qnamaker_options import QnAMakerOptions
97
from .qnamaker_telemetry_client import QnAMakerTelemetryClient
10-
from .qna_telemetry_constants import QnATelemetryConstants
11-
from .qnamaker_trace_info import QnAMakerTraceInfo
8+
from .utils import (
9+
ActiveLearningUtils,
10+
GenerateAnswerUtils,
11+
HttpRequestUtils,
12+
QnATelemetryConstants,
13+
)
14+
15+
from .models import (
16+
FeedbackRecord,
17+
FeedbackRecords,
18+
Metadata,
19+
QnAMakerTraceInfo,
20+
QueryResult,
21+
QueryResults,
22+
)
1223

1324
__all__ = [
25+
"ActiveLearningUtils",
26+
"FeedbackRecord",
27+
"FeedbackRecords",
28+
"GenerateAnswerUtils",
29+
"HttpRequestUtils",
1430
"Metadata",
1531
"QueryResult",
32+
"QueryResults",
1633
"QnAMaker",
1734
"QnAMakerEndpoint",
1835
"QnAMakerOptions",

libraries/botbuilder-ai/botbuilder/ai/qna/metadata.py

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# coding=utf-8
2+
# --------------------------------------------------------------------------
3+
# Copyright (c) Microsoft Corporation. All rights reserved.
4+
# Licensed under the MIT License. See License.txt in the project root for
5+
# license information.
6+
# --------------------------------------------------------------------------
7+
8+
from .feedback_record import FeedbackRecord
9+
from .feedback_records import FeedbackRecords
10+
from .generate_answer_request_body import GenerateAnswerRequestBody
11+
from .metadata import Metadata
12+
from .qnamaker_trace_info import QnAMakerTraceInfo
13+
from .query_result import QueryResult
14+
from .query_results import QueryResults
15+
from .train_request_body import TrainRequestBody
16+
17+
__all__ = [
18+
"FeedbackRecord",
19+
"FeedbackRecords",
20+
"GenerateAnswerRequestBody",
21+
"Metadata",
22+
"QnAMakerTraceInfo",
23+
"QueryResult",
24+
"QueryResults",
25+
"TrainRequestBody",
26+
]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from msrest.serialization import Model
5+
6+
7+
class FeedbackRecord(Model):
8+
""" Active learning feedback record. """
9+
10+
_attribute_map = {
11+
"user_id": {"key": "userId", "type": "str"},
12+
"user_question": {"key": "userQuestion", "type": "str"},
13+
"qna_id": {"key": "qnaId", "type": "int"},
14+
}
15+
16+
def __init__(self, user_id: str, user_question: str, qna_id: int, **kwargs):
17+
"""
18+
Parameters:
19+
-----------
20+
21+
user_id: ID of the user.
22+
23+
user_question: User question.
24+
25+
qna_id: QnA ID.
26+
"""
27+
28+
super().__init__(**kwargs)
29+
30+
self.user_id = user_id
31+
self.user_question = user_question
32+
self.qna_id = qna_id
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from typing import List
5+
6+
from msrest.serialization import Model
7+
8+
from .feedback_record import FeedbackRecord
9+
10+
11+
class FeedbackRecords(Model):
12+
""" Active learning feedback records. """
13+
14+
_attribute_map = {"records": {"key": "records", "type": "[FeedbackRecord]"}}
15+
16+
def __init__(self, records: List[FeedbackRecord], **kwargs):
17+
"""
18+
Parameter(s):
19+
-------------
20+
21+
records: List of feedback records.
22+
"""
23+
24+
super().__init__(**kwargs)
25+
26+
self.records = records
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from typing import List
5+
6+
from msrest.serialization import Model
7+
8+
from .metadata import Metadata
9+
10+
11+
class GenerateAnswerRequestBody(Model):
12+
""" Question used as the payload body for QnA Maker's Generate Answer API. """
13+
14+
_attribute_map = {
15+
"question": {"key": "question", "type": "str"},
16+
"top": {"key": "top", "type": "int"},
17+
"score_threshold": {"key": "scoreThreshold", "type": "float"},
18+
"strict_filters": {"key": "strictFilters", "type": "[Metadata]"},
19+
}
20+
21+
def __init__(
22+
self,
23+
question: str,
24+
top: int,
25+
score_threshold: float,
26+
strict_filters: List[Metadata],
27+
**kwargs
28+
):
29+
"""
30+
Parameters:
31+
-----------
32+
33+
question: The user question to query against the knowledge base.
34+
35+
top: Max number of answers to be returned for the question.
36+
37+
score_threshold: Threshold for answers returned based on score.
38+
39+
strict_filters: Find only answers that contain these metadata.
40+
"""
41+
42+
super().__init__(**kwargs)
43+
44+
self.question = question
45+
self.top = top
46+
self.score_threshold = score_threshold
47+
self.strict_filters = strict_filters
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from msrest.serialization import Model
5+
6+
7+
class Metadata(Model):
8+
""" Metadata associated with the answer. """
9+
10+
_attribute_map = {
11+
"name": {"key": "name", "type": "str"},
12+
"value": {"key": "value", "type": "str"},
13+
}
14+
15+
def __init__(self, name: str, value: str, **kwargs):
16+
"""
17+
Parameters:
18+
-----------
19+
20+
name: Metadata name. Max length: 100.
21+
22+
value: Metadata value. Max length: 100.
23+
"""
24+
25+
super().__init__(**kwargs)
26+
27+
self.name = name
28+
self.value = value
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from typing import List
5+
6+
from botbuilder.schema import Activity
7+
from .metadata import Metadata
8+
from .query_result import QueryResult
9+
10+
11+
class QnAMakerTraceInfo:
12+
""" Represents all the trice info that we collect from the QnAMaker Middleware. """
13+
14+
def __init__(
15+
self,
16+
message: Activity,
17+
query_results: List[QueryResult],
18+
knowledge_base_id: str,
19+
score_threshold: float,
20+
top: int,
21+
strict_filters: List[Metadata],
22+
):
23+
"""
24+
Parameters:
25+
-----------
26+
27+
message: Message which instigated the query to QnA Maker.
28+
29+
query_results: Results that QnA Maker returned.
30+
31+
knowledge_base_id: ID of the knowledge base that is being queried.
32+
33+
score_threshold: The minimum score threshold, used to filter returned results.
34+
35+
top: Number of ranked results that are asked to be returned.
36+
37+
strict_filters: Filters used on query.
38+
"""
39+
self.message = message
40+
self.query_results = query_results
41+
self.knowledge_base_id = knowledge_base_id
42+
self.score_threshold = score_threshold
43+
self.top = top
44+
self.strict_filters = strict_filters
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from typing import List
5+
6+
from .metadata import Metadata
7+
8+
9+
class QueryResult:
10+
""" Represents an individual result from a knowledge base query. """
11+
12+
def __init__(
13+
self,
14+
questions: List[str],
15+
answer: str,
16+
score: float,
17+
metadata: object = None,
18+
source: str = None,
19+
id: int = None, # pylint: disable=invalid-name
20+
):
21+
"""
22+
Parameters:
23+
-----------
24+
25+
questions: The list of questions indexed in the QnA Service for the given answer (if any).
26+
27+
answer: Answer from the knowledge base.
28+
29+
score: Confidence on a scale from 0.0 to 1.0 that the answer matches the user's intent.
30+
31+
metadata: Metadata associated with the answer (if any).
32+
33+
source: The source from which the QnA was extracted (if any).
34+
35+
id: The index of the answer in the knowledge base. V3 uses 'qnaId', V4 uses 'id' (if any).
36+
"""
37+
self.questions = questions
38+
self.answer = answer
39+
self.score = score
40+
self.metadata = list(map(lambda meta: Metadata(**meta), metadata))
41+
self.source = source
42+
self.id = id # pylint: disable=invalid-name
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from typing import List
5+
6+
from .query_result import QueryResult
7+
8+
9+
class QueryResults:
10+
""" Contains answers for a user query. """
11+
12+
def __init__(self, answers: List[QueryResult]):
13+
"""
14+
Parameters:
15+
-----------
16+
17+
answers: The answers for a user query.
18+
"""
19+
self.answers = answers
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from typing import List
5+
from msrest.serialization import Model
6+
7+
from .feedback_record import FeedbackRecord
8+
9+
10+
class TrainRequestBody(Model):
11+
""" Class the models the request body that is sent as feedback to the Train API. """
12+
13+
_attribute_map = {
14+
"feedback_records": {"key": "feedbackRecords", "type": "[FeedbackRecord]"}
15+
}
16+
17+
def __init__(self, feedback_records: List[FeedbackRecord], **kwargs):
18+
"""
19+
Parameters:
20+
-----------
21+
22+
feedback_records: List of feedback records.
23+
"""
24+
25+
super().__init__(**kwargs)
26+
27+
self.feedback_records = feedback_records

0 commit comments

Comments
 (0)
0