How to restrict slot filling

how to decide which slot to be filled at a time? How to have control over slot filling?

eg: need to collect details for a hotel room booking, slots are hotel name, person name There is a hotel name “Hotel Michael” (synonym: michael), and if the chatbot asks for the hotel name and user types “Michael” it will be extracted as enity hotel_name and PERSON. Thereby filling two slots at the same time.

I tried collecting details through two different form, but it didn’t work, in both forms, both slots are filled at the same time (and i am not sure if i am doing it right)

Hello

Please look at Custom Slot Mappings.

You can return {"hotel_name": name} without returning a value for person:

def extract_hotel_name(self, dispatcher, tracker, domain):
    name = tracker.get_latest_entity_values("hotel_name")
    return {"hotel_name": name}

I am really grateful for your response, I also have one another doubt, the slot values are rest to None after all slots of a form are filled, but i want the slot values to persist.

That’s weird. Your others slots should not be reset when you do that!

How did you implement the code?

forms:
  hotel_booking_form:
    required_slots:
      hotel_name:
        - type: from_entity
          entity: hotel_name
          intent: room_booking
      PERSON:
        - type: from_entity
          entity: PERSON
          intent: info
      phone-number:
        - type: from_entity
          entity: phone-number
      checkin:
        - type: from_entity
          entity: time
      checkout:
        - type: from_entity
          entity: time
      room_type:
        - type : from_entity
          entity: room_ty

Story:

stories:

  • story: test steps:
    • intent: greet
    • action: utter_greet
    • intent: room_booking
    • action: hotel_booking_form
    • active_loop : hotel_booking_form
    • action : utter_reached_here

last action of this story is utter_reach_here, before uttering that all the slot values are None.

What about the code of the Custom Slot Mapping?

I haven’t wrote any code for custom slot mapping yet, the only actions i am running right now is to utter prompt questions(or some texts) for filling slot of a form

class AskForSlotHotelName(Action)

Please try a form with my above suggestion and tell me how it goes

1 Like

does this fucntion has to be asynchronous?

I tried what you suggested

I saw this on the custom slot mapping documentation " Make sure that in the domain file you list for your form only those slots that use predefined mappings."

so I removed hotel_name from my form hotel_booking_form, Now the form doesn’t ask the prompt question.

it didn’t work for me

Action:

class ValidateHotelBookingForm(FormValidationAction):
    def name(self) -> Text:
        return "validate_hotel_booking_form"

    async def required_slots(
            self,
            slots_mapped_in_domain: List[Text],
            dispatcher: "CollectingDispatcher",
            tracker: "Tracker",
            domain: "DomainDict",
    ) -> Optional[List[Text]]:
        required_slots = slots_mapped_in_domain + ["hotelname"]
        return required_slots

    async def extract_hotelname(
            self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> Dict[Text, Any]:
        name = tracker.get_latest_entity_values("hotel_name")
        return {"hotelname": name}

Since i extended FormValidationAction class i am getting this error Skipping validation for hotelname: there is no validation method specified. Earlier entity and slot was having name now, the entity is hotel_name and slot is hotelname

This is how I coded custom slot mapping, is this the right way to do it?

I am facing one other problem. I have a Synonym mapper that maps [“Michael”, “Hotel Michael”, “Hotel Michael, New York”, “Hotel Michael NYC”] into “Hotel Michael”, So if someone enters their name “Michael” it is transformed into “Hotel Michael” and stored in the PERSON slot.

Hello!

You need to write either an Utterance or Custom Action named utter_ask_slotname or action_ask_slotname respectively (See Ask For the Next Slot).

To validate the slot, you need to implement the validate_slotname method in the class and return an output of {"slotname": slotvalue} (See Validating Form Input).

I do have a custom action to ask for prompt class AskForSlotHotelName(Action): def name(self) → Text: return “action_ask_hotelname”

    def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        dispatcher.utter_message(text="There are beautiful hotels in Sentosa.")
        dispatcher.utter_message(text="Which hotel are you looking for?")
        hotel_list = list(hotel_info.keys())
        dispatcher.utter_message(text= f" We provide booking for {', '.join(hotel_list[:-1])} and {hotel_list[-1]}")
        return []

i am sorry “skipping validation for hotelname” was just an info shown on log screen. The actual error is

TypeError: <generator object Tracker.get_latest_entity_values.<locals>.<genexpr> at 0x7f3b95bdfa98> is not JSON serializable

i resolved the issue by using name = next(tracker.get_latest_entity_values("hotel_name"),None) still the form is not asking the prompt to enter the hotel name, I do have a custom action to ask for prompt class AskForSlotHotelName(Action)

My doubt is how will the form knows to utter for a prompt if the slot is not mentioned inside the form (Forms 2nd point)

thank you @ChrisRahme i understand my mistake, I should add hotelname at the beginning of the required_slot, instead of appending it to the end of required_slot list.

1 Like

Yes! Sorry I haven’t realized it!

Glad you got it working :slight_smile:

1 Like

i have a doubt @ChrisRahme , if we are using extract_slotname(), then do we have to write another slot validation code to validate slot value? validation can also be done in extract_slotname() method itself, right?

I have a entity conflict between DIETClassifiier and SpacyEntityExtractor, and when I use next(tracker.get_latest_entity_values("hotel_name"),None) I get the next entity value from the generator object, Is there a way I can choose the extractor

Yes, technically, you can do validation while extracting!

tracker.get_latest_entity_values is supposed to work after the pipeline did all its work, so it shouldn’t matter what extracted it.

Can you explain more what you mean by “the next entity value from the generator objector”?

Is there a way we could decide among the results of different entity extractor?

tracker.get_latest_entity_values() is a python generator object, right? we iterate over it using next().

regarding validation during extracting is that the right way to do? I thought of making the chatbot faster by validating during extraction, But I am not sure if it would cause trouble in some corner condition.