8000 add user agent · rsliang/botbuilder-python@395f95b · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit 395f95b

Browse files
committed
add user agent
* add user agent * add test for user agent
1 parent a56b55f commit 395f95b

File tree

5 files changed

+97
-62
lines changed

5 files changed

+97
-62
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from .about import __title__, __version__
5+
6+
__all__ = ["__title__", "__version__"]

libraries/botbuilder-ai/botbuilder/ai/luis/luis_recognizer.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def __init__(
7272

7373
credentials = CognitiveServicesCredentials(self._application.endpoint_key)
7474
self._runtime = LUISRuntimeClient(self._application.endpoint, credentials)
75+
self._runtime.config.add_user_agent(LuisUtil.get_user_agent())
7576

7677
@property
7778
def log_personal_information(self) -> bool:

libraries/botbuilder-ai/botbuilder/ai/luis/luis_util.py

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

4+
import platform
45
from collections import OrderedDict
56
from typing import Dict, List, Set, Union
67

@@ -10,6 +11,7 @@
1011
LuisResult,
1112
)
1213

14+
from .. import __title__, __version__
1315
from . import IntentScore, RecognizerResult
1416

1517

@@ -283,3 +285,13 @@ def add_properties(luis: LuisResult, result: RecognizerResult) -> None:
283285
"label": luis.sentiment_analysis.label,
284286
"score": luis.sentiment_analysis.score,
285287
}
288+
289+
@staticmethod
290+
def get_user_agent():
291+
package_user_agent = f"{__title__}/{__version__}"
292+
uname = platform.uname()
293+
os_version = f"{uname.machine}-{uname.system}-{uname.version}"
294+
py_version = f"Python,Version={platform.python_version()}"
295+
platform_user_agent = f"({os_version}; {py_version})"
296+
user_agent = f"{package_user_agent} {platform_user_agent}"
297+
return user_agent

libraries/botbuilder-ai/tests/luis/luis_recognizer_test.py

Lines changed: 54 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@
44
import json
55
import unittest
66
from os import path
7+
from typing import Tuple
78
from unittest.mock import Mock, patch
89

910
import requests
11+
from azure.cognitiveservices.language.luis.runtime import LUISRuntimeClient
12+
from azure.cognitiveservices.language.luis.runtime.luis_runtime_client import (
13+
LUISRuntimeClientConfiguration,
14+
)
1015
from msrest import Deserializer
1116
from requests.models import Response
1217

@@ -18,7 +23,7 @@
1823
RecognizerResult,
1924
TopIntent,
2025
)
21-
from botbuilder.core import TurnContext
26+
from botbuilder.core import BotAdapter, TurnContext
2227
from botbuilder.core.adapters import TestAdapter
2328
from botbuilder.schema import (
2429
Activity,
@@ -27,6 +32,8 @@
2732
ConversationAccount,
2833
)
2934

35+
from .null_adapter import NullAdapter
36+
3037

3138
class LuisRecognizerTest(unittest.TestCase):
3239
_luisAppId: str = "b31aeaf3-3511-495b-a07f-571fc873214b"
@@ -88,47 +95,10 @@ def test_luis_recognizer_none_luis_app_arg(self):
8895

8996
def test_single_intent_simply_entity(self):
9097
utterance: str = "My name is Emad"
91-
response_str: str = """{
92-
"query": "my name is Emad",
93-
"topScoringIntent": {
94-
"intent": "SpecifyName",
95-
"score": 0.8785189
96-
},
97-
"intents": [
98-
{
99-
"intent": "SpecifyName",
100-
"score": 0.8785189
101-
}
102-
],
103-
"entities": [
104-
{
105-
"entity": "emad",
106-
"type": "Name",
107-
"startIndex": 11,
108-
"endIndex": 14,
109-
"score": 0.8446753
110-
}
111-
]
112-
}"""
113-
response_json = json.loads(response_str)
98+
response_path: str = "SingleIntent_SimplyEntity.json"
99+
100+
_, result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
114101

115-
my_app = LuisApplication(
116-
LuisRecognizerTest._luisAppId,
117-
LuisRecognizerTest._subscriptionKey,
118-
endpoint="",
119-
)
120-
recognizer = LuisRecognizer(my_app, prediction_options=None)
121-
context = LuisRecognizerTest._get_context(utterance)
122-
response = Mock(spec=Response)
123-
response.status_code = 200
124-
response.headers = {}
125-
response.reason = ""
126-
with patch("requests.Session.send", return_value=response):
127-
with patch(
128-
"msrest.serialization.Deserializer._unpack_content",
129-
return_value=response_json,
130-
):
131-
result = recognizer.recognize(context)
132102
self.assertIsNotNone(result)
133103
self.assertIsNone(result.altered_text)
134104
self.assertEqual(utterance, result.text)
@@ -149,7 +119,7 @@ def test_null_utterance(self):
149119
utterance: str = None
150120
response_path: str = "SingleIntent_SimplyEntity.json" # The path is irrelevant in this case
151121

152-
result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
122+
_, result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
153123

154124
self.assertIsNotNone(result)
155125
self.assertIsNone(result.altered_text)
@@ -165,7 +135,7 @@ def test_multiple_intents_prebuilt_entity(self):
165135
utterance: str = "Please deliver February 2nd 2001"
166136
response_path: str = "MultipleIntents_PrebuiltEntity.json"
167137

168-
result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
138+
_, result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
169139

170140
self.assertIsNotNone(result)
171141
self.assertEqual(utterance, result.text)
@@ -202,7 +172,7 @@ def test_multiple_intents_prebuilt_entities_with_multi_values(self):
202172
utterance: str = "Please deliver February 2nd 2001 in room 201"
203173
response_path: str = "MultipleIntents_PrebuiltEntitiesWithMultiValues.json"
204174

205-
result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
175+
_, result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
206176

207177
self.assertIsNotNone(result)
208178
self.assertIsNotNone(result.text)
@@ -221,7 +191,7 @@ def test_multiple_intents_list_entity_with_single_value(self):
221191
utterance: str = "I want to travel on united"
222192
response_path: str = "MultipleIntents_ListEntityWithSingleValue.json"
223193

224-
result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
194+
_, result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
225195

226196
self.assertIsNotNone(result)
227197
self.assertIsNotNone(result.text)
@@ -241,7 +211,7 @@ def test_multiple_intents_list_entity_with_multi_values(self):
241211
utterance: str = "I want to travel on DL"
242212
response_path: str = "MultipleIntents_ListEntityWithMultiValues.json"
243213

244-
result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
214+
_, result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
245215

246216
self.assertIsNotNone(result)
247217
self.assertIsNotNone(result.text)
@@ -263,7 +233,7 @@ def test_multiple_intents_composite_entity_model(self):
263233
utterance: str = "Please deliver it to 98033 WA"
264234
response_path: str = "MultipleIntents_CompositeEntityModel.json"
265235

266-
result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
236+
_, result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
267237

268238
self.assertIsNotNone(result)
269239
self.assertIsNotNone(result.text)
@@ -313,7 +283,7 @@ def test_multiple_date_time_entities(self):
313283
utterance: str = "Book a table on Friday or tomorrow at 5 or tomorrow at 4"
314284
response_path: str = "MultipleDateTimeEntities.json"
315285

316-
result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
286+
_, result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
317287

318288
self.assertIsNotNone(result.entities["datetime"])
319289
self.assertEqual(3, len(result.entities["datetime"]))
@@ -332,7 +302,7 @@ def test_v1_datetime_resolution(self):
332302
utterance: str = "at 4"
333303
response_path: str = "V1DatetimeResolution.json"
334304

335-
result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
305+
_, result = LuisRecognizerTest._get_recognizer_result(utterance, response_path)
336306

337307
self.assertIsNotNone(result.entities["datetime_time"])
338308
self.assertEqual(1, len(result.entities["datetime_time"]))
@@ -367,28 +337,41 @@ def test_top_intent_returns_top_intent_if_score_equals_min_score(self):
367337
)
368338
self.assertEqual(default_intent, "Greeting")
369339

340+
def test_user_agent_contains_product_version(self):
341+
utterance: str = "please book from May 5 to June 6"
342+
response_path: str = "MultipleDateTimeEntities.json" # it doesn't matter to use which file.
343+
344+
recognizer, _ = LuisRecognizerTest._get_recognizer_result(
345+
utterance, response_path, bot_adapter=NullAdapter()
346+
)
347+
348+
runtime: LUISRuntimeClient = recognizer._runtime
349+
config: LUISRuntimeClientConfiguration = runtime.config
350+
user_agent = config.user_agent
351+
352+
# Verify we didn't unintentionally stamp on the user-agent from the client.
353+
self.assertTrue("azure-cognitiveservices-language-luis" in user_agent)
354+
355+
# And that we added the bot.builder package details.
356+
self.assertTrue("botbuilder-ai/4" in user_agent)
357+
370358
def assert_score(self, score: float) -> None:
371359
self.assertTrue(score >= 0)
372360
self.assertTrue(score <= 1)
373361

374362
@classmethod
375363
def _get_recognizer_result(
376-
cls, utterance: str, response_file: str
377-
) -> RecognizerResult:
378-
curr_dir = path.dirname(path.abspath(__file__))
379-
response_path = path.join(curr_dir, "test_data", response_file)
380-
381-
with open(response_path, "r", encoding="utf-8-sig") as f:
382-
response_str = f.read()
383-
response_json = json.loads(response_str)
364+
cls, utterance: str, response_file: str, bot_adapter: BotAdapter = TestAdapter()
365+
) -> Tuple[LuisRecognizer, RecognizerResult]:
366+
response_json = LuisRecognizerTest._get_json_for_file(response_file)
384367

385368
my_app = LuisApplication(
386369
LuisRecognizerTest._luisAppId,
387370
LuisRecognizerTest._subscriptionKey,
388371
endpoint="",
389372
)
390373
recognizer = LuisRecognizer(my_app, prediction_options=None)
391-
context = LuisRecognizerTest._get_context(utterance)
374+
context = LuisRecognizerTest._get_context(utterance, bot_adapter)
392375
response = Mock(spec=Response)
393376
response.status_code = 200
394377
response.headers = {}
@@ -399,7 +382,17 @@ def _get_recognizer_result(
399382
return_value=response_json,
400383
):
401384
result = recognizer.recognize(context)
402-
return result
385+
return recognizer, result
386+
387+
@classmethod
388+
def _get_json_for_file(cls, response_file: str) -> object:
389+
curr_dir = path.dirname(path.abspath(__file__))
390+
response_path = path.join(curr_dir, "test_data", response_file)
391+
392+
with open(response_path, "r", encoding="utf-8-sig") as f:
393+
response_str = f.read()
394+
response_json = json.loads(response_str)
395+
return response_json
403396

404397
@classmethod
405398
def _get_luis_recognizer(
@@ -409,13 +402,12 @@ def _get_luis_recognizer(
409402
return LuisRecognizer(luis_app, options, verbose)
410403

411404
@staticmethod
412-
def _get_context(utterance: str) -> TurnContext:
413-
test_adapter = TestAdapter()
405+
def _get_context(utterance: str, bot_adapter: BotAdapter) -> TurnContext:
414406
activity = Activity(
415407
type=ActivityTypes.message,
416408
text=utterance,
417409
conversation=ConversationAccount(),
418410
recipient=ChannelAccount(),
419411
from_property=ChannelAccount(),
420412
)
421-
return TurnContext(test_adapter, activity)
413+
return TurnContext(bot_adapter, activity)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from typing import List
5+
6+
from botbuilder.core import BotAdapter, TurnContext
7+
from botbuilder.schema import Activity, ConversationReference, ResourceResponse
8+
9+
10+
class NullAdapter(BotAdapter):
11+
"""
12+
This is a BotAdapter that does nothing on the Send operation, equivalent to piping to /dev/null.
13+
"""
14+
15+
def send_activities(self, context: TurnContext, activities: List[Activity]):
16+
return [ResourceResponse()]
17+
18+
async def update_activity(self, context: TurnContext, activity: Activity):
19+
raise NotImplementedError()
20+
21+
async def delete_activity(
22+
self, context: TurnContext, reference: ConversationReference
23+
):
24+
raise NotImplementedError()

0 commit comments

Comments
 (0)
0