def from_entity( self, entity: Text, intent: Optional[Union[Text, List[Text]]] = None, not_intent: Optional[Union[Text, List[Text]]] = None, role: Optional[Text] = None, group: Optional[Text] = None, ) -> Dict[Text, Any]: """A dictionary for slot mapping to extract slot value. From: - an extracted entity - conditioned on - intent if it is not None - not_intent if it is not None, meaning user intent should not be this intent - role if it is not None - group if it is not None """ intent, not_intent = ( SlotMapping.to_list(intent), SlotMapping.to_list(not_intent), ) return { "type": str(SlotMappingType.FROM_ENTITY), "entity": entity, "intent": intent, "not_intent": not_intent, "role": role, "group": group, }
def test_slot_mapping_intent_is_desired(domain: Domain): domain = Domain.from_file("examples/formbot/domain.yml") tracker = DialogueStateTracker("sender_id_test", slots=domain.slots) event1 = UserUttered( text="I'd like to book a restaurant for 2 people.", intent={ "name": "request_restaurant", "confidence": 0.9604260921478271 }, entities=[{ "entity": "number", "value": 2 }], ) tracker.update(event1, domain) mappings_for_num_people = ( domain.as_dict().get("slots").get("num_people").get("mappings")) assert SlotMapping.intent_is_desired(mappings_for_num_people[0], tracker, domain) event2 = UserUttered( text="Yes, 2 please", intent={ "name": "affirm", "confidence": 0.9604260921478271 }, entities=[{ "entity": "number", "value": 2 }], ) tracker.update(event2, domain) assert (SlotMapping.intent_is_desired(mappings_for_num_people[0], tracker, domain) is False) event3 = UserUttered( text="Yes, please", intent={ "name": "affirm", "confidence": 0.9604260921478271 }, entities=[], ) tracker.update(event3, domain) mappings_for_preferences = ( domain.as_dict().get("slots").get("preferences").get("mappings")) assert (SlotMapping.intent_is_desired(mappings_for_preferences[0], tracker, domain) is False)
def test_slot_mappings_ignored_intents_during_active_loop(): domain = Domain.from_yaml(""" version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}" intents: - greet - chitchat slots: cuisine: type: text mappings: - type: from_text conditions: - active_loop: restaurant_form forms: restaurant_form: ignored_intents: - chitchat required_slots: - cuisine """) tracker = DialogueStateTracker("sender_id", slots=domain.slots) event1 = ActiveLoop("restaurant_form") event2 = UserUttered( text="The weather is sunny today", intent={ "name": "chitchat", "confidence": 0.9604260921478271 }, entities=[], ) tracker.update_with_events([event1, event2], domain) mappings_for_cuisine = domain.as_dict().get("slots").get("cuisine").get( "mappings") assert (SlotMapping.intent_is_desired(mappings_for_cuisine[0], tracker, domain) is False)
def test_slot_mapping_entity_is_desired(slot_name: Text, expected: bool): domain = Domain.from_file("data/test_domains/travel_form.yml") tracker = DialogueStateTracker("test_id", slots=domain.slots) event = UserUttered( text="I'm travelling to Vancouver.", intent={"name": "inform", "confidence": 0.9604260921478271}, entities=[{"entity": "GPE", "value": "Vancouver", "role": "destination"}], ) tracker.update(event, domain) slot_mappings = domain.as_dict().get("slots").get(slot_name).get("mappings") assert SlotMapping.entity_is_desired(slot_mappings[0], tracker) is expected
def extract_slot_value_from_predefined_mapping( mapping_type: SlotMappingType, mapping: Dict[Text, Any], tracker: "DialogueStateTracker", ) -> List[Any]: """Extracts slot value if slot has an applicable predefined mapping.""" should_fill_entity_slot = (mapping_type == SlotMappingType.FROM_ENTITY and SlotMapping.entity_is_desired( mapping, tracker)) should_fill_intent_slot = mapping_type == SlotMappingType.FROM_INTENT should_fill_text_slot = mapping_type == SlotMappingType.FROM_TEXT active_loops_in_mapping_conditions = [ active_loop.get(ACTIVE_LOOP) for active_loop in mapping.get(MAPPING_CONDITIONS, []) ] should_fill_trigger_slot = ( mapping_type == SlotMappingType.FROM_TRIGGER_INTENT and tracker.active_loop_name not in active_loops_in_mapping_conditions) value: List[Any] = [] if should_fill_entity_slot: value = list( tracker.get_latest_entity_values( mapping.get(ENTITY_ATTRIBUTE_TYPE), mapping.get(ENTITY_ATTRIBUTE_ROLE), mapping.get(ENTITY_ATTRIBUTE_GROUP), )) elif should_fill_intent_slot or should_fill_trigger_slot: value = [mapping.get("value")] elif should_fill_text_slot: value = [ tracker.latest_message.text if tracker.latest_message is not None else None ] return value
async def run( self, output_channel: "OutputChannel", nlg: "NaturalLanguageGenerator", tracker: "DialogueStateTracker", domain: "Domain", ) -> List[Event]: """Runs action. Please see parent class for the full docstring.""" slot_events: List[Event] = [] executed_custom_actions: Set[Text] = set() user_slots = [ slot for slot in domain.slots if slot.name not in DEFAULT_SLOT_NAMES ] for slot in user_slots: for mapping in slot.mappings: mapping_type = SlotMappingType(mapping.get(MAPPING_TYPE)) if not SlotMapping.check_mapping_validity( slot_name=slot.name, mapping_type=mapping_type, mapping=mapping, domain=domain, ): continue intent_is_desired = SlotMapping.intent_is_desired( mapping, tracker, domain) if not intent_is_desired: continue if not ActionExtractSlots._verify_mapping_conditions( mapping, tracker, slot.name): continue if self._fails_unique_entity_mapping_check( slot.name, mapping, tracker, domain): continue if mapping_type.is_predefined_type(): value = extract_slot_value_from_predefined_mapping( mapping_type, mapping, tracker) else: value = None if value: if not isinstance(slot, ListSlot): value = value[-1] if tracker.get_slot(slot.name) != value: slot_events.append(SlotSet(slot.name, value)) should_fill_custom_slot = mapping_type == SlotMappingType.CUSTOM if should_fill_custom_slot: ( custom_evts, executed_custom_actions, ) = await self._execute_custom_action( mapping, executed_custom_actions, output_channel, nlg, tracker, domain, ) slot_events.extend(custom_evts) validated_events = await self._execute_validation_action( slot_events, output_channel, nlg, tracker, domain) return validated_events