Repository: microsoft/botbuilder-python
Pull request #209 (2019-06-14 23:11:03)

206 add luis prediction options to recognizer
Fixes: #206

Add ability for user to pass luis prediction options into 'Recognizer.recognize' function. Whatever fields are present should override what was set previously via constructor to 'Recognizer._options', for the duration of the request.




Patch:
diff --git a/libraries/botbuilder-ai/botbuilder/ai/luis/luis_recognizer.py b/libraries/botbuilder-ai/botbuilder/ai/luis/luis_recognizer.py
index 8015d0e3..a432178e 100644
--- a/libraries/botbuilder-ai/botbuilder/ai/luis/luis_recognizer.py
+++ b/libraries/botbuilder-ai/botbuilder/ai/luis/luis_recognizer.py
@@ -154,6 +154,7 @@ class LuisRecognizer(object):
         turn_context: TurnContext,
         telemetry_properties: Dict[str, str] = None,
         telemetry_metrics: Dict[str, float] = None,
+        luis_prediction_options: LuisPredictionOptions = None
     ) -> RecognizerResult:
         """Return results of the analysis (Suggested actions and intents).
         
@@ -168,7 +169,7 @@ class LuisRecognizer(object):
         """
 
         return await self._recognize_internal(
-            turn_context, telemetry_properties, telemetry_metrics
+            turn_context, telemetry_properties, telemetry_metrics, luis_prediction_options
         )
 
     def on_recognizer_result(
@@ -288,6 +289,7 @@ class LuisRecognizer(object):
         turn_context: TurnContext,
         telemetry_properties: Dict[str, str],
         telemetry_metrics: Dict[str, float],
+        luis_prediction_options: LuisPredictionOptions = None
     ) -> RecognizerResult:
 
         BotAssert.context_not_none(turn_context)
@@ -299,6 +301,11 @@ class LuisRecognizer(object):
         recognizer_result: RecognizerResult = None
         luis_result: LuisResult = None
 
+        if luis_prediction_options:
+            options = self._merge_options(luis_prediction_options)
+        else: 
+            options = self._options
+
         if not utterance or utterance.isspace():
             recognizer_result = RecognizerResult(
                 text=utterance, intents={"": IntentScore(score=1.0)}, entities={}
@@ -307,12 +314,12 @@ class LuisRecognizer(object):
             luis_result = self._runtime.prediction.resolve(
                 self._application.application_id,
                 utterance,
-                timezone_offset=self._options.timezone_offset,
-                verbose=self._options.include_all_intents,
-                staging=self._options.staging,
-                spell_check=self._options.spell_check,
-                bing_spell_check_subscription_key=self._options.bing_spell_check_subscription_key,
-                log=self._options.log if self._options.log is not None else True,
+                timezone_offset=options.timezone_offset,
+                verbose=options.include_all_intents,
+                staging=options.staging,
+                spell_check=options.spell_check,
+                bing_spell_check_subscription_key=options.bing_spell_check_subscription_key,
+                log=options.log if options.log is not None else True,
             )
 
             recognizer_result = RecognizerResult(
@@ -322,8 +329,8 @@ class LuisRecognizer(object):
                 entities=LuisUtil.extract_entities_and_metadata(
                     luis_result.entities,
                     luis_result.composite_entities,
-                    self._options.include_instance_data
-                    if self._options.include_instance_data is not None
+                    options.include_instance_data
+                    if options.include_instance_data is not None
                     else True,
                 ),
             )
@@ -336,7 +343,7 @@ class LuisRecognizer(object):
             recognizer_result, turn_context, telemetry_properties, telemetry_metrics
         )
 
-        await self._emit_trace_info(turn_context, luis_result, recognizer_result)
+        await self._emit_trace_info(turn_context, luis_result, recognizer_result, options)
 
         return recognizer_result
 
@@ -345,11 +352,12 @@ class LuisRecognizer(object):
         turn_context: TurnContext,
         luis_result: LuisResult,
         recognizer_result: RecognizerResult,
+        options: LuisPredictionOptions
     ) -> None:
         trace_info: Dict[str, object] = {
             "recognizerResult": LuisUtil.recognizer_result_as_dict(recognizer_result),
             "luisModel": {"ModelID": self._application.application_id},
-            "luisOptions": {"Staging": self._options.staging},
+            "luisOptions": {"Staging": options.staging},
             "luisResult": LuisUtil.luis_result_as_dict(luis_result),
         }
 
@@ -362,3 +370,11 @@ class LuisRecognizer(object):
         )
 
         await turn_context.send_activity(trace_activity)
+
+    def _merge_options(
+        self,
+        user_defined_options: LuisPredictionOptions
+    ) -> LuisPredictionOptions:
+        merged_options = LuisPredictionOptions()
+        merged_options.__dict__.update(user_defined_options.__dict__)
+        return merged_options


Test patch:
diff --git a/libraries/botbuilder-ai/tests/luis/luis_recognizer_test.py b/libraries/botbuilder-ai/tests/luis/luis_recognizer_test.py
index 5f05a0f2..177d96e2 100644
--- a/libraries/botbuilder-ai/tests/luis/luis_recognizer_test.py
+++ b/libraries/botbuilder-ai/tests/luis/luis_recognizer_test.py
@@ -635,6 +635,42 @@ class LuisRecognizerTest(AsyncTestCase):
         self.assertTrue("fromId" in call0_args[1])
         self.assertTrue("entities" in call0_args[1])
 
+    def test_pass_luis_prediction_options_to_recognizer(self):
+        # Arrange
+        my_app = LuisApplication(
+            LuisRecognizerTest._luisAppId,
+            LuisRecognizerTest._subscriptionKey,
+            endpoint=None,
+        )
+
+        luis_prediction_options = LuisPredictionOptions(
+            log_personal_information=True, include_all_intents=True, include_instance_data=True
+        )
+
+        # Assert
+        recognizer = LuisRecognizer(my_app)
+        merged_options = recognizer._merge_options(luis_prediction_options)
+        self.assertTrue(merged_options.log_personal_information)
+        self.assertTrue(merged_options.include_all_intents)
+        self.assertTrue(merged_options.include_instance_data)
+        self.assertFalse(recognizer._options.log_personal_information)
+        self.assertFalse(recognizer._options.include_all_intents)
+        self.assertFalse(recognizer._options.include_instance_data)
+
+    def test_dont_pass_luis_prediction_options_to_recognizer(self):
+        # Arrange
+        my_app = LuisApplication(
+            LuisRecognizerTest._luisAppId,
+            LuisRecognizerTest._subscriptionKey,
+            endpoint=None,
+        )
+
+        # Assert
+        recognizer = LuisRecognizer(my_app)
+        self.assertFalse(recognizer._options.log_personal_information)
+        self.assertFalse(recognizer._options.include_all_intents)
+        self.assertFalse(recognizer._options.include_instance_data)
+
     async def test_composite1(self):
         await self._test_json("Composite1.json")