Slot values being overwritten in Rasa - Rasa Open Source - Rasa Community Forum

Slot values being overwritten in Rasa

post by afnaan on Oct 5, 2021

I have two slots that are age and salary. The bot is getting confused and is overwriting these values


age:
      - entity: age_english
        type: from_entity
        not_intent: salary_english

salary:
      - entity: salary
        type: from_entity
        not_intent: age_english

I have even tried not intents. Any help regarding this would be greatly appreciated


post by afnaan on Oct 6, 2021

@kearnsw any idea on how this might work?


age:
    type: text
    influence_conversation: True
    auto_fill: False

I have set the auto_fill to False and even then the slots are being overwritten


post by j.mosig on Oct 6, 2021

Hello @afnaan

What do you mean by “overwritten”? If entity extraction yields wrong results, you might need to provide more (or more realistic) training data.


post by afnaan on Oct 6, 2021

hey @j.mosig what I mean when I am saying that the slots are being overwritten is that I have two numeric values in my form that is age and the salary. For both of these I have to just write their numerical values instead of giving values to bot like Age 30 salary 50000 So the bot confuses these values and overwrites the value of age in salary even though it has been filled before


post by afnaan on Oct 6, 2021


20211006_1754581920×976 242 KB](https://europe1.discourse-cdn.com/flex013/uploads/rasa/original/3X/a/f/af0847c6cb017b60063c6ea8c59e730a8b20ac1b.jpeg "20211006_175458")


20211006_1755231920×897 217 KB](https://europe1.discourse-cdn.com/flex013/uploads/rasa/original/3X/b/c/bc0b896301b047b3bf07ffc7f81b79eb166c8022.jpeg "20211006_175523")

You can see in these images that age is already stored in a slot but when I enter the salary it gets overwritten in the age slot @j.mosig


post by j.mosig on Oct 7, 2021

Ok, so because both age and salary are integers, both slots get mapped from the same entity. You can use a form validation action to fix this. In your validation action, you can check that age is some number below 200 and salary something above 10000. You can also check what the requested slot is and make sure age only gets filled when age is requested. Does this help?


post by afnaan on Oct 8, 2021

@j.mosig I tried what you told me but the thing is I do not know we will write the story. I have edited the function for form validation action


class ValidateAgeForm(FormValidationAction):

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

@staticmethod
    def age() -> List[Text]:

age = [age for age in range(19, 101)]
        print(age)
        return age

def validate_cuisine(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        """Validate age value."""
        print('Age validated')
        if slot_value in self.age():

return {"age": slot_value}
        else:
            # validation failed, set this slot to None so that the
            # user will be asked for the slot again
            return {"age": None}

I think this function should verify that the age is between 18-100 but I don’t know how to write its story. Also before the slot is validated it needs to has some input to be validated I guess? but as soon as I enter the salary the age slot gets overwritten.


post by j.mosig on Oct 15, 2021


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

should be


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

if your form is called user_age_form.


post by afnaan on Oct 15, 2021

@j.mosig so I have tried it and this works but the issue that I am now having is that when I enter salary even after validation it tries to overwrite the age but is unable to do so because of the validation check. so to validate other slots do we have to make a separate class or if we do it in the same class? what will be the process.

I have even tried slot mappings and still it is not working. Thank you so much for the help


class ValidateAgeForm(FormValidationAction):
    def name(self) -> Text:
        return "validate_user_details_form"

def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict]]]:
        return {
            "age": self.from_entity(entity="age", intent="age_english"),
            "salary": self.from_entity(entity="salary", intent="salary_english")
        }

def validate_age(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict
    ) -> Dict[Text, Any]:
        if int(slot_value) >= 18 and int(slot_value) <= 100:
            print(slot_value)
            return {"age": slot_value}
        else:
            dispatcher.utter_message('Age must be between 18 and 100')
            return {"age": None}

def validate_salary(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict
    ) -> Dict[Text, Any]:
        print('Salary:', slot_value)
        if len(slot_value) >= 4 and len(slot_value) <= 7:
            print(slot_value)
            return {"salary": slot_value}
        else:
            dispatcher.utter_message('Salary must be between 1000 and 1000000')
            return {"salary": None}

post by afnaan on Oct 15, 2021

@ChrisRahme do you have any idea how we might be able to do this?


post by ChrisRahme on Oct 16, 2021

Your validation seems fine. What do you mean by that? What is happening?

No, you write it in a same class same it is for a same action.


post by ChrisRahme on Oct 16, 2021

Maybe try mapping from text:


class ValidateAgeForm(FormValidationAction):
    def name(self) -> Text:
        return "validate_user_details_form"

def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict]]]:
        return {
            "age": self.from_text(),
            "salary": self.from_text()
        }

def validate_age(self, slot_value, dispatcher, tracker, domain) -> Dict[Text, Any]:
        try:
            slot_value = float(slot_value)
        except:
            dispatcher.utter_message('Age must be a number')
            return {"age": None}

if 18 <= slot_value <= 100:
            print(slot_value)
            return {"age": slot_value}
        else:
            dispatcher.utter_message('Age must be between 18 and 100')
            return {"age": None}

def validate_salary(self, slot_value, dispatcher, tracker, domain) -> Dict[Text, Any]:
        try:
            slot_value = float(slot_value)
        except:
            dispatcher.utter_message('Salary must be a number')
            return {"salary": None}

if 1000 <= slot_value <= 1000000:
            print(slot_value)
            return {"salary": slot_value}
        else:
            dispatcher.utter_message('Salary must be between 1000 and 1000000')
            return {"salary": None}

post by afnaan on Oct 18, 2021

No this does not resolves the issue. I mean by that is slot validation is working fine but when I write the salary it still overwrites the age slot. Now in the age slot there is a validation check and due to that it throws the exception that age must be between 18 & 100. The issue is still there that the bot is getting confused between age and salary as both the values are integers i.e age:18 salary:18000


post by j.mosig on Oct 19, 2021

To validate slot mappings of this kind, it’s probably best to just overwrite the run method:


class ValidateUserDetailsForm(Action):
    def name(self) -> Text:
        return "validate_user_details_form"

def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        print(f"slots_to_validate: {tracker.slots_to_validate()}")
        # ...

post by afnaan on Oct 27, 2021

@j.mosig Can you please elaborate on how to overwrite the run method, I have written the following code but it is still overwriting the slots.


def name(self) -> Text:
        return "validate_balance_inquiry_form"
    def run(
          self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: DomainDict
      ) -> List[EventType]:

slot_picked = tracker.slots_to_validate()
          validation_events = []
          try:
            slot_name = (list(slot_picked.keys())[0])
            slot_value = (list(slot_picked.values())[0])
            print(slot_name, slot_value, )
            if 6 < len(slot_value) < 15:
                validation_events.append(SlotSet("acc_num", slot_value))
            elif len(slot_value) <= 6:
                validation_events.append(SlotSet("otp", slot_value))
            else:
                validation_events.append(SlotSet(slot_name, slot_value))
          except Exception as e:
            print(e)

PLEASE IGNORE THE LIST OUT OF INDEX ERROR. Thanks for your help. Regards


post by afnaan on Oct 27, 2021

@ChrisRahme Can you help me figuring out how to do it?


post by afnaan on Nov 1, 2021

@j.mosig can you please help me?


post by afnaan on Nov 2, 2021

@nik202 can you help me on this?


post by afnaan on Nov 4, 2021

@Juste I am having trouble with this. I am thinking of a new approach where I make an intent inform and get my otp and account no in the same intent. Will that somehow work?


post by j.mosig on Nov 8, 2021

@afnaan the run method has to return a list of events. Your function doesn’t return anything. You should have something like return [SlotSet("acc_num", your_value)] somewhere.


post by maseh on Apr 6, 2022

Hi Afnaan, I had a similar problem with two integer slots that are similar and were overwriting each other: account number and transfer amount. What I did was create one entity called “number” with two roles, one for “account number” and one for “transfer amount”. In my nlu.yml, I put all examples of these entities in a single “inform” intent. I allowed the nlu to identify the number entity without any role attached to it when only a number was given, as well as more detailed examples with entity and role identified:


nlu:
- intent: inform
  examples: |
    - [1]{"entity": "number"}
    - [2]{"entity": "number"}
    - [3]{"entity": "number"}
    - [4]{"entity": "number"}
    - [5]{"entity": "number"}
    - [100]{"entity": "number"}
    - [2567]{"entity": "number"}
    - [721321567]{"entity": "number"}
    - [534412]{"entity": "number"}
    - I want to send [333]{"entity": "number", "role": "transfer_amount"}
    - Send to [2]{"entity": "number", "role": "transfer_recipient"}

I then set up my slots to extract from the number entity when the role was identified (i.e. when the user said “account 3” for example) and to extract from the number entity when no role was identified (i.e. when the user just said “3”) under the condition that my form was active and the requested slot was the respective slot. See below.


slots:
  transfer_recipient:
    type: text
    influence_conversation: true
    mappings:
    - type: from_entity
      entity: number
      role: transfer_recipient
    - type: from_entity
      entity: number
      conditions:
      - active_loop: send_transfer_form
        requested_slot: transfer_recipient
  transfer_amount:
    type: text
    influence_conversation: true
    mappings:
    - type: from_entity
      entity: number
      role: transfer_amount
    - type: from_entity
      entity: number
      conditions:
      - active_loop: send_transfer_form
        requested_slot: transfer_amount

Caveat that I’m new to rasa, but this has been working for me so far.


post by BrownMunda on Dec 27, 2023

Hi, I had the same problem. It turned out that while validating the slots in actions.py, I was returning the other slot to be set. eg: in my case i had place and budget as slots, in budget i was returning this: return {“place”: slot_value}. So make sure you keep this in mind. Hope this helps.