8000 Merge branch 'work-in-progress' of https://github.com/Microsoft/botbu… · rsliang/botbuilder-python@d57665a · GitHub
[go: up one dir, main page]

Skip to content

Commit d57665a

Browse files
committed
Merge branch 'work-in-progress' of https://github.com/Microsoft/botbuilder-python into work-in-progress
2 parents 9371679 + 328c745 commit d57665a

File tree

5 files changed

+162
-33
lines changed

5 files changed

+162
-33
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ class LuisPredictionOptions(object):
99
Optional parameters for a LUIS prediction request.
1010
"""
1111

12-
def __init__(self):
12+
def __init__(self, timeout: float = 100000):
1313
self._bing_spell_check_subscription_key: str = None
1414
self._include_all_intents: bool = None
1515
self._include_instance_data: bool = None
1616
self._log: bool = None
1717
self._spell_check: bool = None
1818
self._staging: bool = None
19-
self._timeout: float = 100000
19+
self._timeout: float = timeout
2020
self._timezone_offset: float = None
2121
self._telemetry_client: BotTelemetryClient = NullTelemetryClient()
2222
self._log_personal_information: bool = False

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

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ def __init__(
5959
elif isinstance(application, str):
6060
self._application = LuisApplication.from_application_endpoint(application)
6161
else:
62-
raise TypeError("LuisRecognizer.__init__(): application is not an instance of LuisApplication or str.")
62+
raise TypeError(
63+
"LuisRecognizer.__init__(): application is not an instance of LuisApplication or str."
64+
)
6365

6466
self._options = prediction_options or LuisPredictionOptions()
6567

@@ -146,7 +148,7 @@ def top_intent(
146148

147149
return top_intent or default_intent
148150

149-
async def recognize(
151+
def recognize(
150152
self,
151153
turn_context: TurnContext,
152154
telemetry_properties: Dict[str, str] = None,
@@ -164,11 +166,11 @@ async def recognize(
164166
:rtype: RecognizerResult
165167
"""
166168

167-
return await self._recognize_internal(
169+
return self._recognize_internal(
168170
turn_context, telemetry_properties, telemetry_metrics
169171
)
170172

171-
async def on_recognizer_result(
173+
def on_recognizer_result(
172174
self,
173175
recognizer_result: RecognizerResult,
174176
turn_context: TurnContext,
@@ -187,7 +189,7 @@ async def on_recognizer_result(
187189
:param telemetry_metrics: Dict[str, float], optional
188190
"""
189191

190-
properties = await self.fill_luis_event_properties(
192+
properties = self.fill_luis_event_properties(
191193
recognizer_result, turn_context, telemetry_properties
192194
)
193195

@@ -205,7 +207,7 @@ def _get_top_k_intent_score(
205207
if intent_names:
206208
intent_name = intent_names[0]
207209
if intents[intent_name] is not None:
208-
intent_score = "{:.2f}".format(intents[intent_name])
210+
intent_score = "{:.2f}".format(intents[intent_name].score)
209211

210212
return intent_name, intent_score
211213

@@ -244,12 +246,12 @@ def fill_luis_event_properties(
244246

245247
# Add the intent score and conversation id properties
246248
properties: Dict[str, str] = {
247-
LuisTelemetryConstants.application_id_property: self._application.ApplicationId,
249+
LuisTelemetryConstants.application_id_property: self._application.application_id,
248250
LuisTelemetryConstants.intent_property: intent_name,
249251
LuisTelemetryConstants.intent_score_property: intent_score,
250252
LuisTelemetryConstants.intent2_property: intent2_name,
251253
LuisTelemetryConstants.intent_score2_property: intent2_score,
252-
LuisTelemetryConstants.from_id_property: turn_context.Activity.From.Id,
254+
LuisTelemetryConstants.from_id_property: turn_context.activity.from_property.id,
253255
}
254256

255257
sentiment = recognizer_result.properties.get("sentiment")
@@ -280,7 +282,7 @@ def fill_luis_event_properties(
280282

281283
return properties
282284

283-
async def _recognize_internal(
285+
def _recognize_internal(
284286
self,
285287
turn_context: TurnContext,
286288
telemetry_properties: Dict[str, str],
@@ -301,7 +303,7 @@ async def _recognize_internal(
301303
text=utterance, intents={"": IntentScore(score=1.0)}, entities={}
302304
)
303305
else:
304-
luis_result = await self._runtime.prediction.resolve(
306+
luis_result = self._runtime.prediction.resolve(
305307
self._application.application_id,
306308
utterance,
307309
timezoneOffset=self._options.timezone_offset,
@@ -329,21 +331,8 @@ async def _recognize_internal(
329331
recognizer_result.properties["luisResult"] = luis_result
330332

331333
# Log telemetry
332-
await self.on_recognizer_result(
334+
self.on_recognizer_result(
333335
recognizer_result, turn_context, telemetry_properties, telemetry_metrics
334336
)
335337

336-
trace_info = {
337-
"recognizerResult": recognizer_result,
338-
"luisModel": {"ModelID": self._application.application_id},
339-
"luisOptions": self._options,
340-
"luisResult": luis_result,
341-
}
342-
343-
await turn_context.trace_activity_async(
344-
"LuisRecognizer",
345-
trace_info,
346-
LuisRecognizer.luis_trace_type,
347-
LuisRecognizer.luis_trace_label,
348-
)
349338
return recognizer_result

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def extract_entity_metadata(entity: EntityModel) -> Dict:
160160
@staticmethod
161161
def extract_normalized_entity_name(entity: EntityModel) -> str:
162162
# Type::Role -> Role
163-
type = entity.Type.split(":")[-1]
163+
type = entity.type.split(":")[-1]
164164
if type.startswith("builtin.datetimeV2."):
165165
type = "datetime"
166166

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

-5Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,17 @@ class RecognizerResult:
1111
Contains recognition results generated by a recognizer.
1212
"""
1313

14-
def __init__(self, text:str=None, altered_text:str=None, intents: Dict[str, IntentScore]=None, entities :Dict=None):
15-
self._text: str = None
16-
self._altered_text: str = None
17-
self._intents: Dict[str, IntentScore] = None
18-
self._entities: Dict = None
14+
def __init__(
15+
self,
16+
text: str = None,
17+
altered_text: str = None,
18+
intents: Dict[str, IntentScore] = None,
19+
entities: Dict = None,
20+
):
21+
self._text: str = text
22+
self._altered_text: str = altered_text
23+
self._intents: Dict[str, IntentScore] = intents
24+
self._entities: Dict = entities
1925
self._properties: Dict[str, object] = {}
2026

2127
@property

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

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,27 @@
1+
import json
12
import unittest
3+
from unittest.mock import Mock, patch
24

3-
from botbuilder.ai.luis import LuisRecognizer
5+
import requests
6+
from msrest import Deserializer
7+
from requests.models import Response
8+
9+
from botbuilder.ai.luis import LuisApplication, LuisPredictionOptions, LuisRecognizer
10+
from botbuilder.core import TurnContext
11+
from botbuilder.core.adapters import TestAdapter
12+
from botbuilder.schema import (
13+
Activity,
14+
ActivityTypes,
15+
ChannelAccount,
16+
ConversationAccount,
17+
)
418

519

620
class LuisRecognizerTest(unittest.TestCase):
21+
_luisAppId: str = "b31aeaf3-3511-495b-a07f-571fc873214b"
22+
_subscriptionKey: str = "048ec46dc58e495482b0c447cfdbd291"
23+
_endpoint: str = "https://westus.api.cognitive.microsoft.com"
24+
725
def test_luis_recognizer_construction(self):
826
# Arrange
927
endpoint = "https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/b31aeaf3-3511-495b-a07f-571fc873214b?verbose=true&timezoneOffset=-360&subscription-key=048ec46dc58e495482b0c447cfdbd291&q="
@@ -16,3 +34,119 @@ def test_luis_recognizer_construction(self):
1634
self.assertEqual("b31aeaf3-3511-495b-a07f-571fc873214b", app.application_id)
1735
self.assertEqual("048ec46dc58e495482b0c447cfdbd291", app.endpoint_key)
1836
self.assertEqual("https://westus.api.cognitive.microsoft.com", app.endpoint)
37+
38+
def test_none_endpoint(self):
39+
# Arrange
40+
my_app = LuisApplication(
41+
LuisRecognizerTest._luisAppId,
42+
LuisRecognizerTest._subscriptionKey,
43+
endpoint=None,
44+
)
45+
46+
# Assert
47+
recognizer = LuisRecognizer(my_app, prediction_options=None)
48+
49+
# Assert
50+
app = recognizer._application
51+
self.assertEqual("https://westus.api.cognitive.microsoft.com", app.endpoint)
52+
53+
def test_empty_endpoint(self):
54+
# Arrange
55+
my_app = LuisApplication(
56+
LuisRecognizerTest._luisAppId,
57+
LuisRecognizerTest._subscriptionKey,
58+
endpoint="",
59+
)
60+
61+
# Assert
62+
recognizer = LuisRecognizer(my_app, prediction_options=None)
63+
64+
# Assert
65+
app = recognizer._application
66+
self.assertEqual("https://westus.api.cognitive.microsoft.com", app.endpoint)
67+
68+
def test_luis_recognizer_none_luis_app_arg(self):
69+
with self.assertRaises(TypeError):
70+
LuisRecognizer(application=None)
71+
72+
def test_single_intent_simply_entity(self):
73+
utterance: str = "My name is Emad"
74+
response_str: str = """{
75+
"query": "my name is Emad",
76+
"topScoringIntent": {
77+
"intent": "SpecifyName",
78+
"score": 0.8785189
79+
},
80+
"intents": [
81+
{
82+
"intent": "SpecifyName",
83+
"score": 0.8785189
84+
}
85+
],
86+
"entities": [
87+
{
88+
"entity": "emad",
89+
"type": "Name",
90+
"startIndex": 11,
91+
"endIndex": 14,
92+
"score": 0.8446753
93+
}
94+
]
95+
}"""
96+
response_json = json.loads(response_str)
97+
98+
my_app = LuisApplication(
99+
LuisRecognizerTest._luisAppId,
100+
LuisRecognizerTest._subscriptionKey,
101+
endpoint="",
102+
)
103+
recognizer = LuisRecognizer(my_app, prediction_options=None)
104+
context = LuisRecognizerTest._get_context(utterance)
105+
response = Mock(spec=Response)
106+
response.status_code = 200
107+
response.headers = {}
108+
response.reason = ""
109+
with patch("requests.Session.send", return_value=response):
110+
with patch(
111+
"msrest.serialization.Deserializer._unpack_content",
112+
return_value=response_json,
113+
):
114+
result = recognizer.recognize(context)
115+
self.assertIsNotNone(result)
116+
self.assertIsNone(result.altered_text)
117+
self.assertEqual(utterance, result.text)
118+
self.assertIsNotNone(result.intents)
119+
self.assertEqual(1, len(result.intents))
120+
self.assertIsNotNone(result.intents["SpecifyName"])
121+
self.assert_score(result.intents["SpecifyName"].score)
122+
self.assertIsNotNone(result.entities)
123+
self.assertIsNotNone(result.entities["Name"])
124+
self.assertEqual("emad", result.entities["Name"][0])
125+
self.assertIsNotNone(result.entities["$instance"])
126+
self.assertIsNotNone(result.entities["$instance"]["Name"])
127+
self.assertEqual(11, result.entities["$instance"]["Name"][0]["startIndex"])
128+
self.assertEqual(15, result.entities["$instance"]["Name"][0]["endIndex"])
129+
self.assert_score(result.entities["$instance"]["Name"][0]["score"])
130+
131+
def assert_score(self, score: float):
132+
self.assertTrue(score >= 0)
133+
self.assertTrue(score <= 1)
134+
135+
@classmethod
136+
def _get_luis_recognizer(
137+
cls, verbose: bool = False, options: LuisPredictionOptions = None
138+
) -> LuisRecognizer:
139+
luis_app = LuisApplication(cls._luisAppId, cls._subscriptionKey, cls._endpoint)
140+
return LuisRecognizer(luis_app, options, verbose)
141+
142+
@staticmethod
143+
def _get_context(utterance: str) -> TurnContext:
144+
test_adapter = TestAdapter()
145+
activity = Activity(
146+
type=ActivityTypes.message,
147+
text=utterance,
148+
conversation=ConversationAccount(),
149+
recipient=ChannelAccount(),
150+
from_property=ChannelAccount(),
151+
)
152+
return TurnContext(test_adapter, activity)

0 commit comments

Comments
 (0)
0