8000 Merge branch 'master' into daveta-fix-packages · baruchiro/botbuilder-python@c88f1f0 · GitHub
[go: up one dir, main page]

Skip to content

Commit c88f1f0

Browse files
authored
Merge branch 'master' into daveta-fix-packages
2 parents 7c88d9b + 6dc0440 commit c88f1f0

File tree

5 files changed

+168
-63
lines changed

5 files changed

+168
-63
lines changed

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

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

4+
from aiohttp import ClientSession, ClientTimeout
5+
46
from botbuilder.schema import Activity
57
from botbuilder.core import BotTelemetryClient, NullTelemetryClient, TurnContext
68
from copy import copy
7-
import json, requests
8-
from typing import Dict, List, NamedTuple
9+
import json, platform, requests
10+
from typing import Dict, List, NamedTuple, Union
911

1012
from .metadata import Metadata
1113
from .query_result import QueryResult
@@ -15,6 +17,8 @@
1517
from .qna_telemetry_constants import QnATelemetryConstants
1618
from .qnamaker_trace_info import QnAMakerTraceInfo
1719

20+
from .. import __title__, __version__
21+
1822
QNAMAKER_TRACE_NAME = 'QnAMaker'
1923
QNAMAKER_TRACE_LABEL = 'QnAMaker Trace'
2024
QNAMAKER_TRACE_TYPE = 'https://www.qnamaker.ai/schemas/trace'
@@ -31,7 +35,8 @@ class QnAMaker(QnAMakerTelemetryClient):
3135
def __init__(
3236
8000 self,
3337
endpoint: QnAMakerEndpoint,
34-
options: QnAMakerOptions = None,
38+
options: QnAMakerOptions = None,
39+
http_client: ClientSession = None,
3540
telemetry_client: BotTelemetryClient = None,
3641
log_personal_information: bool = None
3742
):
@@ -41,13 +46,16 @@ def __init__(
4146
if endpoint.host.endswith('v2.0'):
4247
raise ValueError('v2.0 of QnA Maker service is no longer supported in the Bot Framework. Please upgrade your QnA Maker service at www.qnamaker.ai.')
4348

44-
self._endpoint = endpoint
49+
self._endpoint: str = endpoint
4550
self._is_legacy_protocol: bool = self._endpoint.host.endswith('v3.0')
4651

47-
self._options: QnAMakerOptions = options or QnAMakerOptions()
52+
self._options = options or QnAMakerOptions()
4853
self._validate_options(self._options)
4954

50-
self._telemetry_client = telemetry_client or NullTelemetryClient()
55+
instance_timeout = ClientTimeout(total=self._options.timeout/1000)
56+
self._req_client = http_client or ClientSession(timeout=instance_timeout)
57+
58+
self._telemetry_client: Union[BotTelemetryClient, NullTelemetryClient] = telemetry_client or NullTelemetryClient()
5159
self._log_personal_information = log_personal_information or False
5260

5361
@property
@@ -186,11 +194,10 @@ async def get_answers(
186194
:rtype: [QueryResult]
187195
"""
188196

189-
190197
hydrated_options = self._hydrate_options(options)
191198
self._validate_options(hydrated_options)
192199

193-
result = self._query_qna_service(context.activity, hydrated_options)
200+
result = await self._query_qna_service(context, hydrated_options)
194201

195202
await self._emit_trace_info(context, result, hydrated_options)
196203

@@ -211,6 +218,9 @@ def _validate_options(self, options: QnAMakerOptions):
211218

212219
if not options.strict_filters:
213220
options.strict_filters = []
221+
222+
if not options.timeout:
223+
options.timeout = 100000
214224

215225
def _hydrate_options(self, query_options: QnAMakerOptions) -> QnAMakerOptions:
216226
"""
@@ -235,29 +245,38 @@ def _hydrate_options(self, query_options: QnAMakerOptions) -> QnAMakerOptions:
235245

236246
if (len(query_options.strict_filters) > 0):
237247
hydrated_options.strict_filters = query_options.strict_filters
248+
249+
if (query_options.timeout != hydrated_options.timeout and query_options.timeout):
250+
hydrated_options.timeout = query_options.timeout
238251

239252
return hydrated_options
240253

241-
def _query_qna_service(self, message_activity: Activity, options: QnAMakerOptions) -> [QueryResult]:
254+
async def _query_qna_service(self, turn_context: TurnContext, options: QnAMakerOptions) -> [QueryResult]:
242255
url = f'{ self._endpoint.host }/knowledgebases/{ self._endpoint.knowledge_base_id }/generateAnswer'
243-
244256
question = {
245-
'question': message_activity.text,
257+
'question': turn_context.activity.text,
246258
'top': options.top,
247259
'scoreThreshold': options.score_threshold,
248260
'strictFilters': options.strict_filters
249261
}
250-
251262
serialized_content = json.dumps(question)
252-
253263
headers = self._get_headers()
254264

255-
response = requests.post(url, data=serialized_content, headers=headers)
256-
257-
result = self._format_qna_result(response, options)
258-
265+
# Convert miliseconds to seconds (as other BotBuilder SDKs accept timeout value in miliseconds)
266+
# aiohttp.ClientSession units are in seconds
267+
timeout = ClientTimeout(total=options.timeout/1000)
268+
269+
response = await self._req_client.post(
270+
url,
271+
data = serialized_content,
272+
headers = headers,
273+
timeout = timeout
274+
)
275+
276+
result = await self._format_qna_result(response, options)
277+
259278
return result
260-
279+
261280
async def _emit_trace_info(self, turn_context: TurnContext, result: [QueryResult], options: QnAMakerOptions):
262281
trace_info = QnAMakerTraceInfo(
263282
message = turn_context.activity,
@@ -278,12 +297,13 @@ async def _emit_trace_info(self, turn_context: TurnContext, result: [QueryResult
278297

279298
await turn_context.send_activity(trace_activity)
280299

281-
def _format_qna_result(self, qna_result: requests.Response, options: QnAMakerOptions) -> [QueryResult]:
282-
result = qna_result.json()
300+
async def _format_qna_result(self, result, options: QnAMakerOptions) -> [QueryResult]:
301+
json_res = await result.json()
283302

284303
answers_within_threshold = [
285-
{ **answer,'score': answer['score']/100 } for answer in result['answers']
286-
if answer['score']/100 > options.score_threshold
304+
{ **answer,'score': answer['score']/100 }
305+
if answer['score']/100 > options.score_threshold
306+
else {**answer} for answer in json_res['answers']
287307
]
288308
sorted_answers = sorted(answers_within_threshold, key = lambda ans: ans['score'], reverse = True)
289309

@@ -298,13 +318,24 @@ def _format_qna_result(self, qna_result: requests.Response, options: QnAMakerOpt
298318
return answers_as_query_results
299319

300320
def _get_headers(self):
301-
headers = { 'Content-Type': 'application/json' }
321+
headers = {
322+
'Content-Type': 'application/json',
323+
'User-Agent': self.get_user_agent()
324+
}
302325

303326
if self._is_legacy_protocol:
304327
headers['Ocp-Apim-Subscription-Key'] = self._endpoint.endpoint_key
305328
else:
306329
headers['Authorization'] = f'EndpointKey {self._endpoint.endpoint_key}'
307330

308-
# need user-agent header
309-
310331
return headers
332+
333+
def get_user_agent(self):
334+
package_user_agent = f'{__title__}/{__version__}'
335+
uname = platform.uname()
336+
os_version = f'{uname.machine}-{uname.system}-{uname.version}'
337+
py_version = f'Python,Version={platform.python_version()}'
338+
platform_user_agent = f'({os_version}; {py_version})'
339+
user_agent = f'{package_user_agent} {platform_user_agent}'
340+
341+
return user_agent

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ def __init__(
1515
self.score_threshold = score_threshold
1616
self.timeout = timeout
1717
self.top = top
18-
self.strict_filters = strict_filters
18+
self.strict_filters = strict_filters

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,21 @@
44
from .metadata import Metadata
55

66
class QueryResult:
7-
def __init__(self, questions: str, answer: str, score: float, metadata: [Metadata], source: str, id: int):
7+
def __init__(self,
8+
questions: str,
9+
answer: str,
10+
score: float,
11+
metadata: [Metadata],
12+
source: str,
13+
id: int,
14+
context=None
15+
):
816
self.questions = questions,
917
self.answer = answer,
1018
self.score = score,
1119
self.metadata = Metadata,
1220
self.source = source
13-
self.id = id
21+
self.id = id
22+
23+
# 4.4 multi-turn
24+
self.context = context

libraries/botbuilder-ai/setup.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
from setuptools import setup
66

77
REQUIRES = [
8-
"aiounittest>=1.1.0",
98
"azure-cognitiveservices-language-luis==0.2.0",
109
"botbuilder-schema>=4.0.0.a6",
1110
"botbuilder-core>=4.0.0.a6",
11+
"aiohttp>=3.5.4"
1212
]
1313

14+
TESTS_REQUIRES = [
15+
"aiounittest>=1.1.0"
16+
]
1417

1518
root = os.path.abspath(os.path.dirname(__file__))
1619

@@ -25,11 +28,12 @@
2528
url=package_info["__uri__"],
2629
author=package_info["__author__"],
2730
description=package_info["__description__"],
28-
keywords=["BotBuilderDialogs", "bots", "ai", "botframework", "botbuilder"],
31+
keywords="botbuilder-ai LUIS QnAMaker bots ai botframework botbuilder",
2932
long_description=package_info["__summary__"],
3033
license=package_info["__license__"],
31-
packages=["botbuilder.ai","botbuilder.ai.luis", "botbuilder.ai.qna" ],
34+
packages=["botbuilder.ai", "botbuilder.ai.qna", "botbuilder.ai.luis"],
3235
install_requires=REQUIRES,
36+
tests_require=TESTS_REQUIRES,
3337
include_package_data=True,
3438
classifiers=[
3539
"Programming Language :: Python :: 3.6",

0 commit comments

Comments
 (0)
0