def test_rule_with_multiple_types() -> None: ordinal_entity = BaseEntity( range={ "from": 0, "to": 15 }, body="12th december", dim="default", entity_type="ordinal", values=[{ "key": "12th" }], slot_names=["basic_slot"], ) number_entity = BaseEntity( range={ "from": 0, "to": 15 }, body="12 december", dim="default", entity_type="number", values=[{ "key": "12" }], slot_names=["basic_slot"], ) rules = {"intent": {"basic_slot": ["ordinal", "number"]}} intent = Intent(name="intent", score=0.8) intent.apply(rules) intent.fill_slot(number_entity, fill_multiple=True) intent.fill_slot(ordinal_entity, fill_multiple=True) assert intent.slots["basic_slot"].values[0] == number_entity assert intent.slots["basic_slot"].values[1] == ordinal_entity
def test_slot_filling_multiple() -> None: """ Let's try filling both the slots this time with fill_multiple=True! `intent_2` supports both `entity_1` and `entity_2`. """ def access(workflow: Workflow) -> Any: return workflow.output intent_name = "intent_2" # Setting up the slot-filler, both instantiation and plugin is created. (notice two calls). slot_filler = RuleBasedSlotFillerPlugin(rules=rules, access=access, fill_multiple=True)() # Create a mock `workflow` workflow = Workflow(preprocessors=[], postprocessors=[slot_filler]) # ... a mock `Intent` intent = Intent(name=intent_name, score=0.8) # and mock `Entity`-ies. body = "12th december" entity_1 = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", type="entity_1", values=[{ "key": "value" }], slot_names=["entity_1_slot"], ) entity_2 = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", type="entity_2", values=[{ "key": "value" }], slot_names=["entity_2_slot"], ) # The RuleBasedSlotFillerPlugin specifies that it expects `Tuple[Intent, List[Entity])` on `access(workflow)`. workflow.output = (intent, [entity_1, entity_2]) workflow.run(body) # `workflow.output[0]` is the `Intent` we created. # The `entity_1_slot` and `entity_2_slot` are filled. assert workflow.output[0].slots["entity_1_slot"].values == [entity_1] assert workflow.output[0].slots["entity_2_slot"].values == [entity_2]
def test_entity_parser_from_dict(): mock_entity = make_mock_entity() mock_entity["range"] = {"start": mock_entity["start"], "end": mock_entity["end"]} mock_entity["type"] = "basic" del mock_entity["start"] del mock_entity["end"] mock_entity["values"] = mock_entity["value"]["values"] del mock_entity["value"] BaseEntity.from_dict(mock_entity)
def test_entity_set_value_values_missing(): body = "four" entity = BaseEntity( range={"from": 0, "to": len(body)}, body=body, dim="default", type="basic", ) entity.set_value(value=4) assert entity.value == 4
def test_slot_competition() -> None: """ What happens when we have two entities of the same type but different value? """ def access(workflow: Workflow) -> Any: return workflow.output intent_name = "intent_1" # Setting up the slot-filler, both instantiation and plugin is created. (notice two calls). slot_filler = RuleBasedSlotFillerPlugin(rules=rules, access=access)() # Create a mock `workflow` workflow = Workflow(preprocessors=[], postprocessors=[slot_filler]) # ... a mock `Intent` intent = Intent(name=intent_name, score=0.8) # Here we have two entities which compete for the same slot but have different values. body = "12th december" entity_1 = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", type="entity_1", values=[{ "key": "value_1" }], slot_names=["entity_1_slot"], ) entity_2 = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", type="entity_1", values=[{ "key": "value_2" }], slot_names=["entity_1_slot"], ) # The RuleBasedSlotFillerPlugin specifies that it expects `Tuple[Intent, List[Entity])` on `access(workflow)`. workflow.output = (intent, [entity_1, entity_2]) workflow.run(body) # `workflow.output[0]` is the `Intent` we created. # The `entity_1_slot` and `entity_2_slot` are filled. assert "entity_1_slot" not in workflow.output[0].slots
def test_entity_values_index_error(): body = "12th december" entity = BaseEntity( range={"from": 0, "to": len(body)}, body=body, dim="default", type="basic", values=[], ) with pytest.raises(IndexError): entity.get_value()
def test_slot_competition_fill_one() -> None: """ What happens when we have two entities of the same type but different value? """ intent_name = "intent_1" # Setting up the slot-filler, both instantiation and plugin is created. (notice two calls). slot_filler = RuleBasedSlotFillerPlugin(rules=rules, dest="output.intents", fill_multiple=False) # Create a mock `workflow` workflow = Workflow([slot_filler]) # ... a mock `Intent` intent = Intent(name=intent_name, score=0.8) # Here we have two entities which compete for the same slot but have different values. body = "12th december" entity_1 = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", entity_type="entity_1", values=[{ "key": "value_1" }], ) entity_2 = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", entity_type="entity_1", values=[{ "key": "value_2" }], ) workflow.set("output.intents", [intent]).set("output.entities", [entity_1, entity_2]) _, output = workflow.run(Input(utterances=body)) # `workflow.output[0]` is the `Intent` we created. # The `entity_1_slot` and `entity_2_slot` are filled. assert "entity_1_slot" not in output[const.INTENTS][0]["slots"]
def test_entity_parser(): body = "12th december" entity = BaseEntity( range={"from": 0, "to": len(body)}, body=body, dim="default", type="basic", values=[{"value": 0}], ) entity.add_parser(mock_plugin) assert entity.parsers == ["mock_plugin"], "parser was not added" assert entity.get_value() == 0, "value incorrect"
def test_entity_deep_copy(): body = "12th december" entity = BaseEntity( range={"from": 0, "to": len(body)}, body=body, type="basic", dim="default", values=[], ) entity_copy = entity.copy() entity_copy.body = "12th november" # Had this not been a deep copy, it would have matched. assert entity_copy.body != entity.body, "Shouldn't be same"
def test_entity_jsonify_unrestricted() -> None: body = "12th december" value = "value" values = [{"key": value}] entity = BaseEntity( range={"from": 0, "to": len(body)}, body=body, dim="default", type="basic", values=values, ) entity_json = entity.json(add=["dim", "values"]) assert entity_json.get("dim") == "default" assert entity_json.get("body") == body assert entity_json.get("values") == values
def test_entity_jsonify() -> None: body = "12th december" value = "value" values = [{"key": value}] entity = BaseEntity( range={"from": 0, "to": len(body)}, body=body, dim="default", type="basic", values=values, ) entity.set_value(value) entity_json = entity.json() assert "dim" not in entity_json assert entity_json.get("value") == value
def test_base_entity_value_setter(): body = "12th december" entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, entity_type="basic", dim="default", values=[], ) # Had this not been a deep copy, it would have matched. assert entity.get_value({"value": 5}) == 5, "Should be same"
def test_entity_values_key_error(): body = "12th december" entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", entity_type="basic", values=[{ "key": "value" }], ) with pytest.raises(KeyError): entity.get_value()
def test_entity_jsonify_skip() -> None: body = "12th december" value = "value" values = [{"key": value}] entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", entity_type="basic", values=values, ) entity_json = entity.json(skip=["values"]) assert "values" not in entity_json
def test_slot_filling() -> None: """ This test shows rule application, and filling an entity within a slot. """ body = "12th december" entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", entity_type="basic", values=[{ "key": "value" }], slot_names=["basic_slot"], ) rules = {"intent": {"basic_slot": "basic"}} intent = Intent(name="intent", score=0.8) intent.apply(rules) intent.fill_slot(entity) assert intent.slots["basic_slot"].values[0] == entity
def test_missing_access_fn() -> None: """ This test shows that the plugin needs an `access` provided or else it raises a type error. """ slot_filler = RuleBasedSlotFillerPlugin(rules=rules)() workflow = Workflow(preprocessors=[], postprocessors=[slot_filler]) intent = Intent(name="intent", score=0.8) body = "12th december" entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", type="basic", values=[{ "key": "value" }], slot_names=["basic_slot"], ) workflow.output = (intent, [entity]) with pytest.raises(TypeError): workflow.run("")
def test_slot_invalid_intent() -> None: """ Here, we will see that an entity will not fill an intent unless the intent has a slot for it. `intent_1` doesn't have a slot for an entity of type `entity_2`. """ intent_name = "intent_1" # ... a mock `Intent` intent = Intent(name=intent_name, score=0.8) # Setting up the slot-filler, both instantiation and plugin is created. (notice two calls). slot_filler = RuleBasedSlotFillerPlugin(rules=rules, dest="output.intents") # Create a mock `workflow` workflow = Workflow([slot_filler]) # and a mock `Entity`. body = "12th december" entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", entity_type="entity_1", values=[{ "key": "value" }], ) # The RuleBasedSlotFillerPlugin specifies that it expects `Tuple[Intent, List[Entity])` on `access(workflow)`. workflow.set("output.intents", [1]).set("output.entities", [entity]) with pytest.raises(AttributeError): workflow.run(Input(utterances=body))
def test_incorrect_access_fn() -> None: """ This test shows that the plugin needs `access` function to be a `PluginFn`, or else it throws a `TypeError`. """ rules = {"basic": {"slot_name": "basic_slot", "entity_type": "basic"}} access = 5 slot_filler = RuleBasedSlotFillerPlugin(rules=rules, access=access)() workflow = Workflow(preprocessors=[], postprocessors=[slot_filler]) intent = Intent(name="intent", score=0.8) body = "12th december" entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", type="basic", values=[{ "key": "value" }], slot_names=["basic_slot"], ) workflow.output = (intent, [entity]) with pytest.raises(TypeError): workflow.run("")
def test_entity_synthesis(): body = "12th december" entity = BaseEntity( range={"from": 0, "to": len(body)}, body=body, dim="default", type="basic", values=[], ) synthetic_entity = entity_synthesis(entity, "body", "12th november") assert synthetic_entity.body != entity.body, "Shouldn't be same"
def test_both_entity_type_attributes_match() -> None: body = "4 things" value = {"value": 4} entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, entity_type="base", values=[value], ) assert "base" == entity.entity_type
def test_slot_filling_multiple() -> None: """ Let's try filling both the slots this time with fill_multiple=True! `intent_2` supports both `entity_1` and `entity_2`. """ intent_name = "intent_2" # Setting up the slot-filler, both instantiation and plugin is created. (notice two calls). slot_filler = RuleBasedSlotFillerPlugin(rules=rules, dest="output.intents", fill_multiple=True) # Create a mock `workflow` workflow = Workflow([slot_filler]) # ... a mock `Intent` intent = Intent(name=intent_name, score=0.8) # and mock `Entity`-ies. body = "12th december" entity_1 = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", entity_type="entity_1", values=[{ "key": "value" }], ) entity_2 = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", entity_type="entity_2", values=[{ "key": "value" }], ) # The RuleBasedSlotFillerPlugin specifies that it expects `Tuple[Intent, List[Entity])` on `access(workflow)`. workflow.set("output.intents", [intent]).set("output.entities", [entity_1, entity_2]) _, output = workflow.run(Input(utterances=body)) # `workflow.output[0]` is the `Intent` we created. # The `entity_1_slot` and `entity_2_slot` are filled. assert output[const.INTENTS][0]["slots"]["entity_1_slot"]["values"] == [ entity_1.json() ] assert output[const.INTENTS][0]["slots"]["entity_2_slot"]["values"] == [ entity_2.json() ]
def test_slot_filling() -> None: """ This test case covers a trivial usage of a slot-filler. We have `rules` that demonstrate association of intents with entities and their respective slot-configuration. """ intent_name = "intent_1" slot_filler = RuleBasedSlotFillerPlugin(rules=rules, dest="output.intents") # Create a mock `workflow` workflow = Workflow([slot_filler]) # ... a mock `Intent` intent = Intent(name=intent_name, score=0.8) # and a mock `Entity`. body = "12th december" entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", entity_type="entity_1", values=[{ "key": "value" }], ) # The RuleBasedSlotFillerPlugin specifies that it expects `Tuple[Intent, List[Entity])` on `access(workflow)`. workflow.set("output.intents", [intent]).set("output.entities", [entity]) _, output = workflow.run(Input(utterances=body)) intent, *_ = output[const.INTENTS] # `workflow.output[0]` is the `Intent` we created. # so we are checking if the `entity_1_slot` is filled by our mock entity. assert intent["slots"]["entity_1_slot"]["values"][0] == entity.json()
def test_slot_no_fill() -> None: """ Here, we will see that an entity will not fill an intent unless the intent has a slot for it. `intent_1` doesn't have a slot for an entity of type `entity_2`. """ def access(workflow: Workflow) -> Any: return workflow.output intent_name = "intent_1" # Setting up the slot-filler, both instantiation and plugin is created. (notice two calls). slot_filler = RuleBasedSlotFillerPlugin(rules=rules, access=access)() # Create a mock `workflow` workflow = Workflow(preprocessors=[], postprocessors=[slot_filler]) # ... a mock `Intent` intent = Intent(name=intent_name, score=0.8) # and a mock `Entity`. body = "12th december" entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", type="entity_2", values=[{ "key": "value" }], slot_names=["entity_2_slot"], ) # The RuleBasedSlotFillerPlugin specifies that it expects `Tuple[Intent, List[Entity])` on `access(workflow)`. workflow.output = (intent, [entity]) workflow.run(body) # `workflow.output[0]` is the `Intent` we created. # we can see that the `entity_2_slot` is not filled by our mock entity. assert "entity_1_slot" not in workflow.output[0].slots
def test_slot_filling() -> None: """ This test case covers a trivial usage of a slot-filler. We have `rules` that demonstrate association of intents with entities and their respective slot-configuration. """ def access(workflow: Workflow) -> Any: return workflow.output intent_name = "intent_1" # Setting up the slot-filler, both instantiation and plugin is created. (notice two calls). slot_filler = RuleBasedSlotFillerPlugin(rules=rules, access=access)() # Create a mock `workflow` workflow = Workflow(preprocessors=[], postprocessors=[slot_filler]) # ... a mock `Intent` intent = Intent(name=intent_name, score=0.8) # and a mock `Entity`. body = "12th december" entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", type="entity_1", values=[{ "key": "value" }], slot_names=["entity_1_slot"], ) # The RuleBasedSlotFillerPlugin specifies that it expects `Tuple[Intent, List[Entity])` on `access(workflow)`. workflow.output = (intent, [entity]) workflow.run(body) # `workflow.output[0]` is the `Intent` we created. # so we are checking if the `entity_1_slot` is filled by our mock entity. assert workflow.output[0].slots["entity_1_slot"].values[0] == entity
def test_slot_no_fill() -> None: """ Here, we will see that an entity will not fill an intent unless the intent has a slot for it. `intent_1` doesn't have a slot for an entity of type `entity_2`. """ intent_name = "intent_1" # Setting up the slot-filler, both instantiation and plugin is created. (notice two calls). slot_filler = RuleBasedSlotFillerPlugin(rules=rules, dest="output.intents") # Create a mock `workflow` workflow = Workflow([slot_filler]) # ... a mock `Intent` intent = Intent(name=intent_name, score=0.8) # and a mock `Entity`. body = "12th december" entity = BaseEntity( range={ "from": 0, "to": len(body) }, body=body, dim="default", entity_type="entity_2", values=[{ "key": "value" }], ) # The RuleBasedSlotFillerPlugin specifies that it expects `Tuple[Intent, List[Entity])` on `access(workflow)`. workflow.set("output.intents", [intent]).set("output.entities", [entity]) _, output = workflow.run(Input(utterances=body)) # `workflow.output[0]` is the `Intent` we created. # we can see that the `entity_2_slot` is not filled by our mock entity. assert "entity_1_slot" not in output[const.INTENTS][0]["slots"]
def test_entity_parser_from_dict(): mock_entity = make_mock_entity() BaseEntity.from_dict(mock_entity)