def test_remote_action_validate_all_event_subclasses(event_class: Type[Event]): if event_class.type_name == "slot": response = { "events": [{ "event": "slot", "name": "test", "value": "example" }], "responses": [], } elif event_class.type_name == "entities": response = { "events": [{ "event": "entities", "entities": [] }], "responses": [] } else: response = { "events": [{ "event": event_class.type_name }], "responses": [] } # ignore the below events since these are not sent or received outside Rasa if event_class.type_name not in [ "wrong_utterance", "wrong_action", "warning_predicted", ]: validate(response, RemoteAction.action_response_format_spec())
async def validate_slots( self, slot_candidates: Dict[Text, Any], tracker: "DialogueStateTracker", domain: Domain, output_channel: OutputChannel, nlg: NaturalLanguageGenerator, ) -> List[Union[SlotSet, Event]]: """Validate the extracted slots. If a custom action is available for validating the slots, we call it to validate them. Otherwise there is no validation. Args: slot_candidates: Extracted slots which are candidates to fill the slots required by the form. tracker: The current conversation tracker. domain: The current model domain. output_channel: The output channel which can be used to send messages to the user. nlg: `NaturalLanguageGenerator` to use for response generation. Returns: The validation events including potential bot messages and `SlotSet` events for the validated slots. """ logger.debug(f"Validating extracted slots: {slot_candidates}") events: List[Union[SlotSet, Event]] = [ SlotSet(slot_name, value) for slot_name, value in slot_candidates.items() ] validate_name = f"validate_{self.name()}" if validate_name not in domain.action_names_or_texts: return events _tracker = self._temporary_tracker(tracker, events, domain) _action = RemoteAction(validate_name, self.action_endpoint) validate_events = await _action.run(output_channel, nlg, _tracker, domain) validated_slot_names = [ event.key for event in validate_events if isinstance(event, SlotSet) ] # If the custom action doesn't return a SlotSet event for an extracted slot # candidate we assume that it was valid. The custom action has to return a # SlotSet(slot_name, None) event to mark a Slot as invalid. return validate_events + [ event for event in events if event.key not in validated_slot_names ]
async def validate_slots( self, slot_candidates: Dict[Text, Any], tracker: "DialogueStateTracker", domain: Domain, output_channel: OutputChannel, nlg: NaturalLanguageGenerator, ) -> List[Union[SlotSet, Event]]: """Validate the extracted slots. If a custom action is available for validating the slots, we call it to validate them. Otherwise there is no validation. Args: slot_candidates: Extracted slots which are candidates to fill the slots required by the form. tracker: The current conversation tracker. domain: The current model domain. output_channel: The output channel which can be used to send messages to the user. nlg: `NaturalLanguageGenerator` to use for response generation. Returns: The validation events including potential bot messages and `SlotSet` events for the validated slots, if the custom form validation action is present in domain actions. Otherwise, returns empty list since the extracted slots already have corresponding `SlotSet` events in the tracker. """ logger.debug(f"Validating extracted slots: {slot_candidates}") events: List[Union[SlotSet, Event]] = [ SlotSet(slot_name, value) for slot_name, value in slot_candidates.items() ] validate_name = f"validate_{self.name()}" if validate_name not in domain.action_names_or_texts: return [] # create temporary tracker with only the SlotSet events added # since last user utterance _tracker = self._temporary_tracker(tracker, events, domain) _action = RemoteAction(validate_name, self.action_endpoint) validate_events = await _action.run(output_channel, nlg, _tracker, domain) # Only return the validated SlotSet events by the custom form validation action # to avoid adding duplicate SlotSet events for slots that are already valid. return validate_events
async def validate_slots( self, slot_dict: Dict[Text, Any], output_channel: "OutputChannel", nlg: "NaturalLanguageGenerator", tracker: "DialogueStateTracker", domain: "Domain", ) -> List[Event]: events = [] for slot, value in list(slot_dict.items()): validation_rule = self.get_field_for_slot(slot, "validation") if validation_rule is None: events += [SlotSet(slot, value)] validated = True else: operator, comparatum = ( validation_rule.get("operator"), validation_rule.get("comparatum"), ) if operator == 'contains' and comparatum == 'custom': validate_name = f"bf_{self.name()}" if validate_name in domain.action_names_or_texts: _tracker = self._temporary_tracker( tracker, events, domain) _action = RemoteAction(validate_name, self.action_endpoint) validate_events = await _action.run( output_channel, nlg, _tracker, domain) validated_slot_names = [ event.key for event in validate_events if isinstance(event, SlotSet) ] if slot not in validated_slot_names: validate_events += [SlotSet(slot, None)] events += validate_events tracker.update_with_events(validate_events, domain) validated = True else: logger.info(f"Action not found: {validate_name}") validated = False else: validated = validate_with_rule(value, validation_rule) events += [SlotSet(slot, value if validated else None)] # is it changing during this conversational turn? if it did, then: # either tracker value is different, or if tracker was updated # through regular entity recognition, then this happened in latest event # (will not work if multiple entities were extracted in user utterance) if tracker.get_slot(slot) != value or ( isinstance(tracker.events[-1], SlotSet) and tracker.events[-1].key == slot and tracker.events[-1].value == value): events += await self.utter_post_validation( slot, value, validated, output_channel, nlg, tracker, domain) return events