pythonchatbotrasarasa-corerasa-sdk

Deactivate the Rasa form in middle of Form Validation when an intent is triggered



Hey geniuses out there, I recently started doing work on RASA and came across a problem and wondering if that could be solved. I have a form called ‘registration_form’, which takes necessary signup details from a user. All the slots in the form are of text type and their mapping comes from the condition of active_loop : registration_form. domain.yml

slots:
  email:
    type: text
    influence_conversation: false
    mappings:
      - type: from_text
        conditions:
          - active_loop: registration_form
            requested_slot: email
  username:
    type: text
    influence_conversation: false
    mappings:
      - type: from_text
        conditions:
          - active_loop: registration_form
            requested_slot: username
  quit_form:
    type: bool
    influence_conversation: true
    mappings:
      - type: from_text

Now since I was doing well with all of this, a requirement popped up and now we want to deactivate the form if lets say user type ‘/exit’ , so when a slot is being validated and if it detects ‘/exit’ in the text, the form must be deactivated and it should come to the starting point by uttering the greet message.

I was successful in deactivating the form, but I suspect the issue was caused either by influence_conversation: true/flase or the mapping condition in the slot that is active_loop:registration_form followed by requested_slot:<slot_name>. It gave me this 'UserWarning: Cannot validate email: make sure the validation method returns the correct output.' message in the action-server terminal and then continued asking the following slot, i.e. username it is in this case.

Also when I tried to add a rule or a story basically indication that if quit_form slot is set to be true, action ‘action_deactivate_loop’ will be triggered and active_loop will be set to null. But while training, rasa said that the rules are contradicting, registration_form wants to listen and the rule is triggering action_deactivate_loop. stories.yml

- story: User gets out of form
    # deactivated the form
    steps:
      - intent: request_reg
      - action: registration_form
      - active_loop: registration_form
      - intent: deactivate
      - action: action_deactivate_loop
      - active_loop: null

I also tried adding a different kind of story, which basically sets a slot value and tries to deactivate the form.

- story: User gets out of form
    # deactivated the form
    steps:
      - intent: request_reg
      - action: registration_form
      - active_loop: registration_form
      - intent: deactivate
      - slot_was_set:
        - quit_form: true
      - action: action_deactivate_loop
      - active_loop: null

But after adding this story(also tried same rule), while training rasa says rules/stories are contradicting each other, 'action_listen' was predicted but the code says 'action_deactivate_loop'.

This is how my actions file look like. actions.py

class ValidateForm(FormValidationAction ,FormAction):
    data = {}
    signup_response = {}

    def name(self)->Text:
        return "validate_registration_form" 

    def validate_email(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        """Validate email"""
        print("Intent", tracker.get_intent_of_latest_message())
        slot_value = slot_value.lower()
        if '/quit' in slot_value.lower() or tracker.get_intent_of_latest_message()=="deactivate":
            # return self.deactivate()
            # return [ActiveLoop(None)]
            # return []
            return [SlotSet({'active_loop':None})]
        else:
            if email_validation(slot_value):  
                if user_validation_from_local_db("email", slot_value) or     user_validation(value=slot_value):
                    dispatcher.utter_message(text="Email exists, try entering another email")
                    return {"email": None}
                
                self.data['email'] = slot_value
                print(self.data)
                return {"email": slot_value}
            else: 
                print("Not a valid email was entered")
                dispatcher.utter_message(text="Email is not valid, please enter a valid email.")
                return {"email": None}
        
    def validate_username(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        """Validate name value."""

             
        if username_validation(slot_value):
            if user_validation_from_local_db('username', slot_value) or user_validation(value=slot_value): 
                dispatcher.utter_message(text="Username exists, try entering another username")
                return {"username":None}
            self.data['username'] = slot_value
            print(self.data)
            return {"username": slot_value}
        else:
            dispatcher.utter_message("Please enter a valid Username.\nMake sure username only consists lower-case characters, numbers, underscore(_) and no spaces.")
            return {'username':None}

Again the form got deactivate and terminal showed the message that cannot validate email, but instead of getting out of loop, it asked for username and same happened for the other values as well.

Any answer will be highly appreciated, please comment your suggestions and help if I have done something wrong with Rasa or this question.

Will be glad to be answered. THANKS.


Solution

  • I suggest having one rule for breaking the form, deactivating it, and taking care of the control (resettling slots, ...) on passing to the targeted step (greet msg here). You can have the following:

    - rule: Force-break form
    steps:
    - intent: deactivate
    - action: action_deactivate_loop
    - active_loop: null
    - action: action_back_to_greet
    - action: action_greet
    

    On the other side, on your stories (forms and the rest), there is no need to involve the deactivation logic as there's one unified rule for handling any call to deactivate.

    - story: User registration
    steps:
    - intent: request_reg
    - action: registration_form
    - active_loop: registration_form
    - active_loop: null
    - action: action_submit_reg_form
    

    There's no need to check for this logic on the validation methods as your training data can handle them.