Remove one slot in form depending on former slot several times in the same form

Hi RASA community,

I have a rather larger form in which I want to remove slots several times if other slots get filled with FALSE.

I found two approaches for removing slots. The first one worked fine but I could not find a way to make the same logic several times. So in this example I would not only remove exercise if confirm_exercise is FALSE but also remove goal if stress is FALSE.

from typing import Text, List

from rasa_sdk import Tracker, FormValidationAction
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.types import DomainDict

class ValidateHealthForm(FormValidationAction):

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

  async def required_slots(
    self,
    slots_mapped_in_domain: List[Text],
    dispatcher: "CollectingDispatcher",
    tracker: "Tracker",
    domain: "DomainDict"
  ) -> List[Text]:
    if tracker.get_slot("confirm_exercise") == True:
      return ["confirm_exercise", "exercise", "sleep", "diet", "stress", "goal"]
    else:
      return ["confirm_exercise", "sleep", "diet", "stress", "goal"]

Another option would be to use this code:

    async def required_slots(
            self,
            domain_slots: List[Text],
            dispatcher: "CollectingDispatcher",
            tracker: "Tracker",
            domain: "DomainDict",
    ) -> List[Text]:
        if tracker.get_slot("question_ball")==0:
            domain_slots.remove("question_ball_main")

        return domain_slots

My idea would here be to use the if statement for every case. But even if only having ONE case I get this error

    domain_slots.remove("question_ball_main")
ValueError: list.remove(x): x not in list

Any idea why I get the error and how I could best accomplish the described above?

Many thanks!

Hello!

I don’t know what this happens, If you do print(domain_slots) at the start of required_slots(), what do you see in the action terminal?

Maybe you can’t alter the domain_slots variable. In that case please try to make a copy of it and then alter the copy, like this:

slots = [slot for slot in domain_slots]

if tracker.get_slot("question_ball") == 0:
    slots.remove("question_ball_main")

return slots

Hi Chris,

Thank you for your quick answer! I do not get the error message anymore but unfortunately the slot question_ball_main is not removed. The bot is still asking that question… Any idea if I need to change something else?

Many thanks again!

Hmm that should not be happening.

Can you do the following and see the output?

if tracker.get_slot("question_ball") == 0:
    print('Slots before:', slots)
    slots.remove("question_ball_main")
    print('Slots after:', slots)

It stops before the print function and I get this error:

    for slot in slots_to_extract:
TypeError: 'NoneType' object is not iterable

Can you send me your whole action?

Actually, I solved it by using the append functionality instead of remove while also removing the slots that get appended from the required_slots in the domain.yml. Now it works :slight_smile:

Thank you for your help! :blush:

1 Like

Hi @ChrisRahme how can I do with frequently removing the slots from a form based on the previous slot value

domian.yml

forms:
  survey_form:
    required_slots:
      - 1st_qn
      - 1st_reason
      - 2nd_qn
      - 2nd_reason
      - 3rd_qn
      - 3rd_reason

I need to delete 1st_reason slot if the 1st_qn slot is rated below 4 and remove 2nd_reason slot if the 2nd_qn slot is rated below 4 likewise for a couple of questions action.py

class ValidateSurveyForm(FormValidationAction):
    def name(self) -> Text:
        return "validate_survey_form"
    
    async def required_slots(
        self,
        domain_slots: List[Text],
        dispatcher: "CollectingDispatcher",
        tracker: "Tracker",
        domain: "DomainDict",
    ) -> List[Text]:
        l = ["3", "2", "1"]

        updated_slots = domain_slots.copy()
        if tracker.slots.get("1st_qn") not in l:
            updated_slots.remove("1st_reason")
            return updated_slots
        elif tracker.slots.get("2nd_qn") not in l:
            updated_slots.remove("2nd_reason")
            return updated_slots
        elif tracker.slots.get("3rd_qn") not in l:
            updated_slots.remove("3rd_reason")
            return updated_slots

Please help me to rectify this problem

Thank you chandra sekhar