def test_should_serialize_duplicated_intent_parsers(self): # Given register_processing_unit(TestIntentParser1) parser1_config = TestIntentParser1Config() parser1bis_config = TestIntentParser1Config() parsers_configs = [parser1_config, parser1bis_config] config = NLUEngineConfig(parsers_configs) engine = SnipsNLUEngine(config).fit(BEVERAGE_DATASET) # When engine.persist(self.tmp_file_path) # Then expected_engine_dict = { "unit_name": "nlu_engine", "dataset_metadata": { "language_code": "en", "entities": { "Temperature": { "automatically_extensible": True, "utterances": { "boiling": "hot", "Boiling": "hot", "cold": "cold", "Cold": "cold", "hot": "hot", "Hot": "hot", "iced": "cold", "Iced": "cold" } } }, "slot_name_mappings": { "MakeCoffee": { "number_of_cups": "snips/number" }, "MakeTea": { "beverage_temperature": "Temperature", "number_of_cups": "snips/number" } }, }, "config": config.to_dict(), "intent_parsers": [ "test_intent_parser1", "test_intent_parser1_2" ], "model_version": snips_nlu.__model_version__, "training_package_version": snips_nlu.__version__ } self.assertJsonContent(self.tmp_file_path / "nlu_engine.json", expected_engine_dict) self.assertJsonContent( self.tmp_file_path / "test_intent_parser1" / "metadata.json", {"unit_name": "test_intent_parser1"}) self.assertJsonContent( self.tmp_file_path / "test_intent_parser1_2" / "metadata.json", {"unit_name": "test_intent_parser1"})
def test_should_be_serializable(self): # Given register_processing_unit(TestIntentClassifier) register_processing_unit(TestSlotFiller) parser_config = ProbabilisticIntentParserConfig( intent_classifier_config=TestIntentClassifierConfig(), slot_filler_config=TestSlotFillerConfig()) parser = ProbabilisticIntentParser(parser_config) parser.fit(validate_and_format_dataset(BEVERAGE_DATASET)) # When parser.persist(self.tmp_file_path) # Then expected_parser_config = { "unit_name": "probabilistic_intent_parser", "slot_filler_config": { "unit_name": "test_slot_filler" }, "intent_classifier_config": { "unit_name": "test_intent_classifier" } } expected_parser_dict = { "unit_name": "probabilistic_intent_parser", "config": expected_parser_config, "slot_fillers": [{ "intent": "MakeCoffee", "slot_filler_name": "slot_filler_0" }, { "intent": "MakeTea", "slot_filler_name": "slot_filler_1" }] } metadata = {"unit_name": "probabilistic_intent_parser"} metadata_slot_filler = {"unit_name": "test_slot_filler"} metadata_intent_classifier = {"unit_name": "test_intent_classifier"} self.assertJsonContent(self.tmp_file_path / "metadata.json", metadata) self.assertJsonContent(self.tmp_file_path / "intent_parser.json", expected_parser_dict) self.assertJsonContent( self.tmp_file_path / "intent_classifier" / "metadata.json", metadata_intent_classifier) self.assertJsonContent( self.tmp_file_path / "slot_filler_0" / "metadata.json", metadata_slot_filler) self.assertJsonContent( self.tmp_file_path / "slot_filler_1" / "metadata.json", metadata_slot_filler)
def test_should_be_deserializable(self): # When register_processing_unit(TestIntentClassifier) register_processing_unit(TestSlotFiller) config = ProbabilisticIntentParserConfig( intent_classifier_config=TestIntentClassifierConfig(), slot_filler_config=TestSlotFillerConfig() ) parser_dict = { "unit_name": "probabilistic_intent_parser", "slot_fillers": [ { "intent": "MakeCoffee", "slot_filler_name": "slot_filler_MakeCoffee" }, { "intent": "MakeTea", "slot_filler_name": "slot_filler_MakeTea" } ], "config": config.to_dict(), } self.tmp_file_path.mkdir() (self.tmp_file_path / "intent_classifier").mkdir() (self.tmp_file_path / "slot_filler_MakeCoffee").mkdir() (self.tmp_file_path / "slot_filler_MakeTea").mkdir() self.writeJsonContent(self.tmp_file_path / "intent_parser.json", parser_dict) self.writeJsonContent( self.tmp_file_path / "intent_classifier" / "metadata.json", {"unit_name": "test_intent_classifier"}) self.writeJsonContent( self.tmp_file_path / "slot_filler_MakeCoffee" / "metadata.json", {"unit_name": "test_slot_filler"}) self.writeJsonContent( self.tmp_file_path / "slot_filler_MakeTea" / "metadata.json", {"unit_name": "test_slot_filler"}) # When parser = ProbabilisticIntentParser.from_path(self.tmp_file_path) # Then self.assertDictEqual(parser.config.to_dict(), config.to_dict()) self.assertIsNotNone(parser.intent_classifier) self.assertListEqual(sorted(parser.slot_fillers), ["MakeCoffee", "MakeTea"])
def test_should_be_deserializable(self): # When class TestIntentParser1Config(ProcessingUnitConfig): unit_name = "test_intent_parser1" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentParser1Config() class TestIntentParser1(IntentParser): unit_name = "test_intent_parser1" config_type = TestIntentParser1Config def fit(self, dataset, force_retrain): self._fitted = True return self @property def fitted(self): return hasattr(self, '_fitted') and self._fitted def parse(self, text, intents): return empty_result(text) def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): config = cls.config_type() return TestIntentParser1(config) class TestIntentParser2Config(ProcessingUnitConfig): unit_name = "test_intent_parser2" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentParser2Config() class TestIntentParser2(IntentParser): unit_name = "test_intent_parser2" config_type = TestIntentParser2Config def fit(self, dataset, force_retrain): self._fitted = True return self @property def fitted(self): return hasattr(self, '_fitted') and self._fitted def parse(self, text, intents): return empty_result(text) def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): config = cls.config_type() return TestIntentParser2(config) register_processing_unit(TestIntentParser1) register_processing_unit(TestIntentParser2) dataset_metadata = { "language_code": "en", "entities": { "Temperature": { "automatically_extensible": True, "utterances": { "boiling": "hot", "cold": "cold", "hot": "hot", "iced": "cold" } } }, "slot_name_mappings": { "MakeCoffee": { "number_of_cups": "snips/number" }, "MakeTea": { "beverage_temperature": "Temperature", "number_of_cups": "snips/number" } }, } parser1_config = TestIntentParser1Config() parser2_config = TestIntentParser2Config() engine_config = NLUEngineConfig([parser1_config, parser2_config]) engine_dict = { "unit_name": "nlu_engine", "dataset_metadata": dataset_metadata, "config": engine_config.to_dict(), "intent_parsers": [ { "unit_name": "test_intent_parser1" }, { "unit_name": "test_intent_parser2" }, ], "model_version": snips_nlu.__model_version__, "training_package_version": snips_nlu.__version__ } engine = SnipsNLUEngine.from_dict(engine_dict) # Then parser1_config = TestIntentParser1Config() parser2_config = TestIntentParser2Config() expected_engine_config = NLUEngineConfig( [parser1_config, parser2_config]).to_dict() # pylint:disable=protected-access self.assertDictEqual(engine._dataset_metadata, dataset_metadata) # pylint:enable=protected-access self.assertDictEqual(engine.config.to_dict(), expected_engine_config)
def test_should_use_parsers_sequentially(self): # Given input_text = "hello world" intent = intent_classification_result(intent_name='dummy_intent_1', probability=0.7) slots = [ unresolved_slot(match_range=(6, 11), value='world', entity='mocked_entity', slot_name='mocked_slot_name') ] class TestIntentParser1Config(ProcessingUnitConfig): unit_name = "test_intent_parser1" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentParser1Config() class TestIntentParser1(IntentParser): unit_name = "test_intent_parser1" config_type = TestIntentParser1Config def fit(self, dataset, force_retrain): self._fitted = True return self @property def fitted(self): return hasattr(self, '_fitted') and self._fitted def parse(self, text, intents): return empty_result(text) def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): conf = cls.config_type() return TestIntentParser1(conf) class TestIntentParser2Config(ProcessingUnitConfig): unit_name = "test_intent_parser2" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentParser2Config() class TestIntentParser2(IntentParser): unit_name = "test_intent_parser2" config_type = TestIntentParser2Config def fit(self, dataset, force_retrain): self._fitted = True return self @property def fitted(self): return hasattr(self, '_fitted') and self._fitted def parse(self, text, intents): if text == input_text: return parsing_result(text, intent, slots) return empty_result(text) def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): conf = cls.config_type() return TestIntentParser2(conf) register_processing_unit(TestIntentParser1) register_processing_unit(TestIntentParser2) mocked_dataset_metadata = { "language_code": "en", "entities": { "mocked_entity": { "automatically_extensible": True, "utterances": dict() } }, "slot_name_mappings": { "dummy_intent_1": { "mocked_slot_name": "mocked_entity" } } } config = NLUEngineConfig( [TestIntentParser1Config(), TestIntentParser2Config()]) engine = SnipsNLUEngine(config).fit(SAMPLE_DATASET) # pylint:disable=protected-access engine._dataset_metadata = mocked_dataset_metadata # pylint:enable=protected-access # When parse = engine.parse(input_text) # Then expected_slots = [custom_slot(s) for s in slots] expected_parse = parsing_result(input_text, intent, expected_slots) self.assertDictEqual(expected_parse, parse)
def test_should_retrain_only_non_trained_subunits(self): # Given class TestIntentParserConfig(ProcessingUnitConfig): unit_name = "test_intent_parser" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentParserConfig() class TestIntentParser(IntentParser): unit_name = "test_intent_parser" config_type = TestIntentParserConfig def __init__(self, config): super(TestIntentParser, self).__init__(config) self.sub_unit_1 = dict(fitted=False, calls=0) self.sub_unit_2 = dict(fitted=False, calls=0) def fit(self, dataset, force_retrain): if force_retrain: self.sub_unit_1["fitted"] = True self.sub_unit_1["calls"] += 1 self.sub_unit_2["fitted"] = True self.sub_unit_2["calls"] += 1 else: if not self.sub_unit_1["fitted"]: self.sub_unit_1["fitted"] = True self.sub_unit_1["calls"] += 1 if not self.sub_unit_2["fitted"]: self.sub_unit_2["fitted"] = True self.sub_unit_2["calls"] += 1 return self @property def fitted(self): return self.sub_unit_1["fitted"] and \ self.sub_unit_2["fitted"] def parse(self, text, intents): return empty_result(text) def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): conf = cls.config_type() return TestIntentParser(conf) register_processing_unit(TestIntentParser) intent_parser_config = TestIntentParserConfig() nlu_engine_config = NLUEngineConfig([intent_parser_config]) nlu_engine = SnipsNLUEngine(nlu_engine_config) intent_parser = TestIntentParser(intent_parser_config) intent_parser.sub_unit_1.update(dict(fitted=True, calls=0)) nlu_engine.intent_parsers.append(intent_parser) # When nlu_engine.fit(SAMPLE_DATASET, force_retrain=False) # Then self.assertDictEqual(dict(fitted=True, calls=0), intent_parser.sub_unit_1) self.assertDictEqual(dict(fitted=True, calls=1), intent_parser.sub_unit_2)
def test_should_be_deserializable(self): # When class TestIntentClassifierConfig(ProcessingUnitConfig): unit_name = "test_intent_classifier" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentClassifierConfig() class TestIntentClassifier(IntentClassifier): unit_name = "test_intent_classifier" config_type = TestIntentClassifierConfig def get_intent(self, text, intents_filter): return None def fit(self, dataset): return self def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): conf = cls.config_type() return TestIntentClassifier(conf) class TestSlotFillerConfig(ProcessingUnitConfig): unit_name = "test_slot_filler" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestSlotFillerConfig() class TestSlotFiller(SlotFiller): unit_name = "test_slot_filler" config_type = TestSlotFillerConfig def get_slots(self, text): return [] def fit(self, dataset, intent): return self def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): conf = cls.config_type() return TestSlotFiller(conf) register_processing_unit(TestIntentClassifier) register_processing_unit(TestSlotFiller) config = ProbabilisticIntentParserConfig( intent_classifier_config=TestIntentClassifierConfig(), slot_filler_config=TestSlotFillerConfig()) parser_dict = { "unit_name": "probabilistic_intent_parser", "intent_classifier": { "unit_name": "test_intent_classifier" }, "slot_fillers": { "MakeCoffee": { "unit_name": "test_slot_filler" }, "MakeTea": { "unit_name": "test_slot_filler" } }, "config": config.to_dict(), } # When parser = ProbabilisticIntentParser.from_dict(parser_dict) # Then self.assertDictEqual(parser.config.to_dict(), config.to_dict()) self.assertIsNotNone(parser.intent_classifier) self.assertListEqual(sorted(parser.slot_fillers), ["MakeCoffee", "MakeTea"])
def test_should_be_serializable(self): # Given class TestIntentClassifierConfig(ProcessingUnitConfig): unit_name = "test_intent_classifier" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentClassifierConfig() class TestIntentClassifier(IntentClassifier): unit_name = "test_intent_classifier" config_type = TestIntentClassifierConfig def get_intent(self, text, intents_filter): return None def fit(self, dataset): return self def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): config = cls.config_type() return TestIntentClassifier(config) class TestSlotFillerConfig(ProcessingUnitConfig): unit_name = "test_slot_filler" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestSlotFillerConfig() class TestSlotFiller(SlotFiller): unit_name = "test_slot_filler" config_type = TestSlotFillerConfig def get_slots(self, text): return [] def fit(self, dataset, intent): return self def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): config = cls.config_type() return TestSlotFiller(config) register_processing_unit(TestIntentClassifier) register_processing_unit(TestSlotFiller) parser_config = ProbabilisticIntentParserConfig( intent_classifier_config=TestIntentClassifierConfig(), slot_filler_config=TestSlotFillerConfig()) parser = ProbabilisticIntentParser(parser_config) parser.fit(validate_and_format_dataset(BEVERAGE_DATASET)) # When actual_parser_dict = parser.to_dict() # Then expected_parser_config = { "unit_name": "probabilistic_intent_parser", "slot_filler_config": { "unit_name": "test_slot_filler" }, "intent_classifier_config": { "unit_name": "test_intent_classifier" } } expected_parser_dict = { "unit_name": "probabilistic_intent_parser", "config": expected_parser_config, "intent_classifier": { "unit_name": "test_intent_classifier" }, "slot_fillers": { "MakeCoffee": { "unit_name": "test_slot_filler" }, "MakeTea": { "unit_name": "test_slot_filler" }, }, } self.assertDictEqual(actual_parser_dict, expected_parser_dict)
def test_should_be_deserializable_from_dir(self): # Given register_processing_unit(TestIntentParser1) register_processing_unit(TestIntentParser2) dataset_metadata = { "language_code": "en", "entities": { "Temperature": { "automatically_extensible": True, "utterances": { "boiling": "hot", "cold": "cold", "hot": "hot", "iced": "cold" } } }, "slot_name_mappings": { "MakeCoffee": { "number_of_cups": "snips/number" }, "MakeTea": { "beverage_temperature": "Temperature", "number_of_cups": "snips/number" } }, } parser1_config = TestIntentParser1Config() parser2_config = TestIntentParser2Config() engine_config = NLUEngineConfig([parser1_config, parser2_config]) engine_dict = { "unit_name": "nlu_engine", "dataset_metadata": dataset_metadata, "config": engine_config.to_dict(), "intent_parsers": [ "test_intent_parser1", "test_intent_parser2", ], "model_version": snips_nlu.__model_version__, "training_package_version": snips_nlu.__version__ } self.tmp_file_path.mkdir() parser1_path = self.tmp_file_path / "test_intent_parser1" parser1_path.mkdir() parser2_path = self.tmp_file_path / "test_intent_parser2" parser2_path.mkdir() (self.tmp_file_path / "resources").mkdir() self.writeJsonContent(self.tmp_file_path / "nlu_engine.json", engine_dict) self.writeJsonContent(parser1_path / "metadata.json", {"unit_name": "test_intent_parser1"}) self.writeJsonContent(parser2_path / "metadata.json", {"unit_name": "test_intent_parser2"}) # When engine = SnipsNLUEngine.from_path(self.tmp_file_path) # Then parser1_config = TestIntentParser1Config() parser2_config = TestIntentParser2Config() expected_engine_config = NLUEngineConfig( [parser1_config, parser2_config]).to_dict() # pylint:disable=protected-access self.assertDictEqual(engine._dataset_metadata, dataset_metadata) # pylint:enable=protected-access self.assertDictEqual(engine.config.to_dict(), expected_engine_config)
def test_should_use_parsers_sequentially(self): # Given input_text = "hello world" intent = intent_classification_result(intent_name='dummy_intent_1', probability=0.7) slots = [ unresolved_slot(match_range=(6, 11), value='world', entity='mocked_entity', slot_name='mocked_slot_name') ] class FirstIntentParserConfig(ProcessingUnitConfig): unit_name = "first_intent_parser" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return FirstIntentParserConfig() def get_required_resources(self): return None class FirstIntentParser(IntentParser): unit_name = "first_intent_parser" config_type = FirstIntentParserConfig def fit(self, dataset, force_retrain): self._fitted = True return self @property def fitted(self): return hasattr(self, '_fitted') and self._fitted def parse(self, text, intents): return empty_result(text) def persist(self, path): path = Path(path) path.mkdir() with (path / "metadata.json").open(mode="w") as f: f.write(json_string({"unit_name": self.unit_name})) @classmethod def from_path(cls, path): cfg = cls.config_type() return cls(cfg) class SecondIntentParserConfig(ProcessingUnitConfig): unit_name = "second_intent_parser" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return SecondIntentParserConfig() def get_required_resources(self): return None class SecondIntentParser(IntentParser): unit_name = "second_intent_parser" config_type = SecondIntentParserConfig def fit(self, dataset, force_retrain): self._fitted = True return self @property def fitted(self): return hasattr(self, '_fitted') and self._fitted def parse(self, text, intents): if text == input_text: return parsing_result(text, intent, slots) return empty_result(text) def persist(self, path): path = Path(path) path.mkdir() with (path / "metadata.json").open(mode="w") as f: f.write(json_string({"unit_name": self.unit_name})) @classmethod def from_path(cls, path): cfg = cls.config_type() return cls(cfg) register_processing_unit(FirstIntentParser) register_processing_unit(SecondIntentParser) mocked_dataset_metadata = { "language_code": "en", "entities": { "mocked_entity": { "automatically_extensible": True, "utterances": dict() } }, "slot_name_mappings": { "dummy_intent_1": { "mocked_slot_name": "mocked_entity" } } } config = NLUEngineConfig( [FirstIntentParserConfig(), SecondIntentParserConfig()]) engine = SnipsNLUEngine(config).fit(SAMPLE_DATASET) # pylint:disable=protected-access engine._dataset_metadata = mocked_dataset_metadata # pylint:enable=protected-access # When parse = engine.parse(input_text) # Then expected_slots = [custom_slot(s) for s in slots] expected_parse = parsing_result(input_text, intent, expected_slots) self.assertDictEqual(expected_parse, parse)
def test_should_retrain_only_non_trained_subunits(self): # Given class TestIntentParserConfig(ProcessingUnitConfig): unit_name = "test_intent_parser" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentParserConfig() def get_required_resources(self): return None class TestIntentParser(IntentParser): unit_name = "test_intent_parser" config_type = TestIntentParserConfig def __init__(self, config): super(TestIntentParser, self).__init__(config) self.sub_unit_1 = dict(fitted=False, calls=0) self.sub_unit_2 = dict(fitted=False, calls=0) def fit(self, dataset, force_retrain): if force_retrain: self.sub_unit_1["fitted"] = True self.sub_unit_1["calls"] += 1 self.sub_unit_2["fitted"] = True self.sub_unit_2["calls"] += 1 else: if not self.sub_unit_1["fitted"]: self.sub_unit_1["fitted"] = True self.sub_unit_1["calls"] += 1 if not self.sub_unit_2["fitted"]: self.sub_unit_2["fitted"] = True self.sub_unit_2["calls"] += 1 return self @property def fitted(self): return self.sub_unit_1["fitted"] and \ self.sub_unit_2["fitted"] def parse(self, text, intents): return empty_result(text) def persist(self, path): path = Path(path) path.mkdir() with (path / "metadata.json").open(mode="w") as f: f.write(json_string({"unit_name": self.unit_name})) @classmethod def from_path(cls, path): cfg = cls.config_type() return cls(cfg) register_processing_unit(TestIntentParser) intent_parser_config = TestIntentParserConfig() nlu_engine_config = NLUEngineConfig([intent_parser_config]) nlu_engine = SnipsNLUEngine(nlu_engine_config) intent_parser = TestIntentParser(intent_parser_config) intent_parser.sub_unit_1.update(dict(fitted=True, calls=0)) nlu_engine.intent_parsers.append(intent_parser) # When nlu_engine.fit(SAMPLE_DATASET, force_retrain=False) # Then self.assertDictEqual(dict(fitted=True, calls=0), intent_parser.sub_unit_1) self.assertDictEqual(dict(fitted=True, calls=1), intent_parser.sub_unit_2)
def test_should_be_deserializable(self): # When class TestIntentParser1Config(ProcessingUnitConfig): unit_name = "test_intent_parser1" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentParser1Config() class TestIntentParser1(IntentParser): unit_name = "test_intent_parser1" config_type = TestIntentParser1Config def fit(self, dataset, force_retrain): self._fitted = True return self @property def fitted(self): return hasattr(self, '_fitted') and self._fitted def parse(self, text, intents): return empty_result(text) def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): config = cls.config_type() return TestIntentParser1(config) class TestIntentParser2Config(ProcessingUnitConfig): unit_name = "test_intent_parser2" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentParser2Config() class TestIntentParser2(IntentParser): unit_name = "test_intent_parser2" config_type = TestIntentParser2Config def fit(self, dataset, force_retrain): self._fitted = True return self @property def fitted(self): return hasattr(self, '_fitted') and self._fitted def parse(self, text, intents): return empty_result(text) def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): config = cls.config_type() return TestIntentParser2(config) register_processing_unit(TestIntentParser1) register_processing_unit(TestIntentParser2) dataset_metadata = { "language_code": "en", "entities": { "Temperature": { "automatically_extensible": True, "utterances": { "boiling": "hot", "cold": "cold", "hot": "hot", "iced": "cold" } } }, "slot_name_mappings": { "MakeCoffee": { "number_of_cups": "snips/number" }, "MakeTea": { "beverage_temperature": "Temperature", "number_of_cups": "snips/number" } }, } parser1_config = TestIntentParser1Config() parser2_config = TestIntentParser2Config() engine_config = NLUEngineConfig([parser1_config, parser2_config]) engine_dict = { "unit_name": "nlu_engine", "dataset_metadata": dataset_metadata, "config": engine_config.to_dict(), "intent_parsers": [ {"unit_name": "test_intent_parser1"}, {"unit_name": "test_intent_parser2"}, ], "model_version": snips_nlu.version.__model_version__, "training_package_version": snips_nlu.__version__ } engine = SnipsNLUEngine.from_dict(engine_dict) # Then parser1_config = TestIntentParser1Config() parser2_config = TestIntentParser2Config() expected_engine_config = NLUEngineConfig( [parser1_config, parser2_config]).to_dict() # pylint:disable=protected-access self.assertDictEqual(engine._dataset_metadata, dataset_metadata) # pylint:enable=protected-access self.assertDictEqual(engine.config.to_dict(), expected_engine_config)
def test_should_use_parsers_sequentially(self): # Given input_text = "hello world" intent = intent_classification_result( intent_name='dummy_intent_1', probability=0.7) slots = [unresolved_slot(match_range=(6, 11), value='world', entity='mocked_entity', slot_name='mocked_slot_name')] class TestIntentParser1Config(ProcessingUnitConfig): unit_name = "test_intent_parser1" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentParser1Config() class TestIntentParser1(IntentParser): unit_name = "test_intent_parser1" config_type = TestIntentParser1Config def fit(self, dataset, force_retrain): self._fitted = True return self @property def fitted(self): return hasattr(self, '_fitted') and self._fitted def parse(self, text, intents): return empty_result(text) def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): conf = cls.config_type() return TestIntentParser1(conf) class TestIntentParser2Config(ProcessingUnitConfig): unit_name = "test_intent_parser2" def to_dict(self): return {"unit_name": self.unit_name} @classmethod def from_dict(cls, obj_dict): return TestIntentParser2Config() class TestIntentParser2(IntentParser): unit_name = "test_intent_parser2" config_type = TestIntentParser2Config def fit(self, dataset, force_retrain): self._fitted = True return self @property def fitted(self): return hasattr(self, '_fitted') and self._fitted def parse(self, text, intents): if text == input_text: return parsing_result(text, intent, slots) return empty_result(text) def to_dict(self): return { "unit_name": self.unit_name, } @classmethod def from_dict(cls, unit_dict): conf = cls.config_type() return TestIntentParser2(conf) register_processing_unit(TestIntentParser1) register_processing_unit(TestIntentParser2) mocked_dataset_metadata = { "language_code": "en", "entities": { "mocked_entity": { "automatically_extensible": True, "utterances": dict() } }, "slot_name_mappings": { "dummy_intent_1": { "mocked_slot_name": "mocked_entity" } } } config = NLUEngineConfig([TestIntentParser1Config(), TestIntentParser2Config()]) engine = SnipsNLUEngine(config).fit(SAMPLE_DATASET) # pylint:disable=protected-access engine._dataset_metadata = mocked_dataset_metadata # pylint:enable=protected-access # When parse = engine.parse(input_text) # Then expected_slots = [custom_slot(s) for s in slots] expected_parse = parsing_result(input_text, intent, expected_slots) self.assertDictEqual(expected_parse, parse)