Prevent Slots from being Overwritten

Hi, I am creating a Flight Booking System, where I take the Departure, Destination location and the nature of the trip from the user. I have used Entities with Roles for Slot-filling and want to prevent the FormAction to overwrite slots that have already been filled. How can I override the Validate method or some other method to do this?

Here is the actions.py file that I have implemented:

class TicketForm(FormAction):

def name(self):
    return "ticket_form"

@staticmethod
def required_slots(tracker:Tracker) ->List[Text]:
	return ["departure","destination","round_trip"]

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

    dispatcher.utter_message("thanks")

    return []

def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict]]]:
	return {
		"departure":[ self.from_entity( entity="city", role="dept"), self.from_text(),],
		"destination":[ self.from_entity( entity="city", role="dest"), self.from_text(),],
		"round_trip":[self.from_entity(entity="trip_type"), 
					  self.from_intent(intent="affirm", value="True"),
					  self.from_intent(intent="deny", value="False"), ],
	}

Since the NLU is not always accurate in classifying between and departure and destination, it sometimes mixes them up and overwrites prefilled slots. How do I prevent this from happening? TIA!

just need to specify in the domain file the slots like this

slots: here_put_your_slot_name: type: unfeaturized auto_fill: False

with auto_fill: false your problem will be solve

I have already done that. But while extracting the slots in the FormAction, it also looks for other slots and overwrites them if it finds any. For eg: It fills the first slot Departure and then moves on to the next slot. While extracting the entity for the next slot, if it misclassifies the user information as Departure it will simply overwrite it. This causes the loss of previous info and I want to prevent that.

I hope you get what I am implying…

@sohamcoder007 It is possible but you’ll need to override some of the method from forms.py

Heres a small overview of rasa forms.

  1. empty slots are selected one by one and is requested from the user
  2. once a value is received, the value is stored to the currently requested slot. along with this step, rasa also attempts to fill other slots (slots that are not currently requested)

These other slot filling is causing the issue you’ve mentioned.

Currently rasa doesn’t provide a method to get around it out of the box. So lets introduce a concept of STRICT SLOTS. A strict slot is a slot that can be filled only when its requested.

To implement it

  1. In you FormAction class in actions.py file create a new method are return a list of strict slots.

@staticmethod
def strict_slots() → List[Text]:
“”" If a slot is strict, then it will be filled only when requested"“”
return [“slot_1”,“slot_2”]

  1. copy the extract_other_slots method from forms.py to you actions,py file inside the FormAction class. Look for the loop that iterates over the slots. add a condition to check whether the slot is present in strict_slot. If it is present, then don’t fill. other wise the slot can be filled,

     def extract_other_slots(
             self,
             dispatcher: "CollectingDispatcher",
             tracker: "Tracker",
             domain: Dict[Text, Any],
     ) -> Dict[Text, Any]:
         """Extract the values of the other slots
             if they are set by corresponding entities from the user input
             else return None. Strict slots will not be filled
         """
         slot_to_fill = tracker.get_slot(self.REQUESTED_SLOT)
         strict_slots = self.strict_slots()
    
     slot_values = {}
     for slot in self.required_slots(tracker):
         # look for other slots
        if slot != slot_to_fill and slot not in strict_slots:
             # list is used to cover the case of list slot type
             other_slot_mappings = self.get_mappings_for_slot(slot)
    
             for other_slot_mapping in other_slot_mappings:
                 # check whether the slot should be filled by an entity in the input
                 should_fill_entity_slot = (
                         other_slot_mapping["type"] == "from_entity"
                         and self.intent_is_desired(other_slot_mapping, tracker)
                         and self.entity_is_desired(other_slot_mapping, slot, tracker)
                 )
                 # check whether the slot should be
                 # filled from trigger intent mapping
                 should_fill_trigger_slot = (
                         tracker.active_form.get("name") != self.name()
                         and other_slot_mapping["type"] == "from_trigger_intent"
                         and self.intent_is_desired(other_slot_mapping, tracker)
                 )
                 if should_fill_entity_slot:
                     value = self.get_entity_value(
                         other_slot_mapping["entity"],
                         tracker,
                         other_slot_mapping.get("role"),
                         other_slot_mapping.get("group"),
                     )
                 elif should_fill_trigger_slot:
                     value = other_slot_mapping.get("value")
                 else:
                     value = None
    
                 if value is not None:
                     self.logger.debug(f"Extracted '{value}' for extra slot '{slot}'.")
                     slot_values[slot] = value
                     # this slot is done, check  next
                     break
    
     return slot_values
    

@a-anand-91119 This seems like a good idea. Could you just tell me for which version of Rasa this code works, I am currently using version 1.10.14. Also I was going through the source code of Rasa and couldn’t find the FormAction class. Can you tell me where it is so I can better override these functions? TIA!

in your actions.py file, there is a class which you have created that extends FormAction. It’ll look something like this.

def CustomFormClass(FormAction)