Help with custom action slots

I’ve been having difficulty coming up with a custom action to fill slots with open ended texts (after reading all the documentation and looking at the working examples on github). Below is my code. I’d really like some help. Here, I want the bot to ask two questions in order (and I would like it to do it in custom actions).

  1. Would you like to talk about your sleep?
  2. How would you describe your sleep?

I want the second question to capture any text, no matter how long, and return it in a variable that I can dump in a spreadsheet later. I’m really confused how I ask both questions in the action.py file.

The form is triggered by this intent in the NLU

- intent: sleep_log
  examples: |
    - I'd like to log my sleep

The domain of the form is:

responses:
  utter_confirm_sleep:
  - text: Do you want to talk about how you slept?

forms:
  sleep_form:
    sleep_confirm:
      - type: from_intent
        intent: affirm
        value: True
      - type: from_intent
        intent: deny
        value: False
      - type: from_intent
        intent: inform
        value: True

And, STORIES:

- story: sleep happy path
  steps:
  - intent: sleep_log
  - action: utter_confirm_sleep
  - intent: affirm
  - action: sleep_form
  - active_loop: sleep_form

ACTIONS

class ValidateSleep(FormValidationAction):
    print ("sleep form triggered")
    def name(self) -> Text:
        print ('validation run sleep')
        return "validate_sleep_form"

    
    async def validate_sleep_confirm(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        if value:
            print ('true value of sleep confirmed')
            return {"sleep_confirm": True}
        else:
            print ('false value sleep confirmed')
            return {"sleep_confirm": False }
    
    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 + ["sleep_description"]
        print ('required slot triggered')
        return required_slots

    async def extract_sleep_description(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> Dict[Text, Any]:
        text_of_last_user_message = tracker.latest_message.get("text")
        sleep_description = "slept" in text_of_last_user_message
        dispatcher.utter_message(text="please describe your sleep")

        return {"sleep_description": sleep_description}

Please let me know how I can make this question any more clear. I’m new but eager to learn how to do this. Thank you!!

I may have misunderstood what you want to achieve, but this reminds me of a similar case for me, tagging user messages with a language.

I think a possible solution is to tag the whole user input as an entity. Then, create a slot with the same name as your entity, with auto_fill set to true.

In my case, I created a custom component to set the entity, and put it as the first one in my pipeline (as I had to also detect the language).

I think in your case, adding a regex will suffish (i.e. a regex like “.*”). You can see about regex here: Training Data Format. You need to add RegexFeaturizer to your pipeline: Components

do you have an example of action.py code that could ask both of those questions and take in open text input? thanks!

This is being dealt with in another thread here.