Rasa Form Interuption NOT WORKING if using rasa CUSTOM FORM VALIDATION

Hi, I got some problem. my bot cant detect form interuption. it is always going through the custom validation

I always got this problem when i apply custom validation

Bot: Hi what is your fav fruit? (FORM with Validation must in [apple, grape, mango])
User: user interupting (CANCEL FORM)
Bot: Sorry i dont know your fav food, i only know apple, grape, mango

it must be

Bot: Hi what is your fav fruit? (FORM with Validation must in [apple, grape, mango])
User: user interupting (CANCEL FORM)
Bot: What can i help for you?

appreciate for every feedback :grin:

Please share the stories related to the interruption as well as the form and slots in the domain

domain:

version: "2.0"

intents:
  - greet
  - stop

actions:
  - validate_fruit_form
  - reset_slot_fruit

entities:
  - FRUIT

slots:
  FRUIT:
    type: text
    auto_fill: false
    influence_conversation: true

forms:
  fruit_form:
    required_slots:
        FRUIT:
          - type: from_text

responses:
  utter_greet:
  - text: "Hey! What is your favorit fruit"

  utter_thanks:
  - text: "Ok! Thanks"

  utter_summary:
  - text: "Wow! you like {FRUIT}"

session_config:
  session_expiration_time: 60
  carry_over_slots_to_new_session: true

story:

version: "2.0"

stories:

- story: normal path
  steps:
  - intent: greet
  - action: utter_greet
  - action: reset_slot_fruit
  - action: fruit_form
  - active_loop: fruit_form
  - slot_was_set:
    - requested_slot: FRUIT
  - slot_was_set:
    - FRUIT: grapes
  - slot_was_set:
    - requested_slot: null
  - active_loop: null
  - action: utter_summary

- story: stop path
  steps:
  - intent: greet
  - action: utter_greet
  - action: reset_slot_fruit
  - action: fruit_form
  - active_loop: fruit_form
  - intent: stop
  - action: action_deactivate_loop
  - active_loop: null
  - action: utter_thanks

actions:

from typing import Any, Text, Dict, List

from rasa_sdk import Action, Tracker, FormValidationAction
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.events import SlotSet
from rasa_sdk.types import DomainDict


class ActionValidateNilaiPinjamanFormat(FormValidationAction):
    def name(self) -> Text:
        return "validate_fruit_form"

    def validate_FRUIT(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        """Validate `FRUIT` value."""
        # apple, orange, grape

        fruit = slot_value
        fruit = fruit.lower()

        # validate product type
        if fruit in ['apple', 'orange', 'grape']:
            return {"FRUIT": fruit}
        else:
            dispatcher.utter_message(text='Sorry i dont know that {} is a fruit. Please type again between apple, orange or grape'.format(fruit))
            return {"FRUIT": None}

# Reset Slot
class ActionResetLoanSimulation(Action):
    def name(self) -> Text:
        return "reset_slot_fruit"

    def run(self, dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:

        return [SlotSet("FRUIT", None)]

I find a tricky solution by adding some condition in validate_fruit_form and using a slot to trigger action_listen. if latest message is intent stop it will request a slot (ex. STOP_MARK) to trigger action_listen

# validate product type
        last_intent = tracker.latest_message['intent'].get('name')
        if latest_intent in ['stop', 'intent_goodbye', 'etc']:
            dispatcher.utter_message(response='utter_thanks')
            return {"requested_slot": "STOP_MARK"}
        else:
            if fruit in ['apple', 'orange', 'grape']:
                return {"FRUIT": fruit}
            else:
                dispatcher.utter_message(text='Sorry i dont know that {} is a fruit. Please type again between apple, orange or grape'.format(fruit))
                return {"FRUIT": None}

Glad you solved it but I still want to give you the “official” way to do it :slight_smile:

Your story is good, but your slot mapping should be disabled if the intent is stop:

forms:
  fruit_form:
    required_slots:
        FRUIT:
          - type: from_text
            intent_name: None
            not_intent: stop

The second, less optimal solution, is to check for the intent in the validate() method as you did.

1 Like

thanks for the official solution :star_struck:

1 Like